/*!@file
*
*  @brief     Initialization code to set up the CPU and call boot_card()
*
*  This "BSP" targets the Xilinx Virtex XC4VFX60 and related parts.  This
*  BSP makes no assumptions on what firmware is loaded into the FPGA.
*
*  Provides the .entry section code. This is the first code to run in
*  the PPC after download to RAM.   Excecution in this case starts at
*  'download_entry'.
*
*  The entrypoint 'start' is provided for the case where a bootloader has
*  initialized the CPU, and all that remains to do is to set up a C
*  environment and call boot_card.
*
*  Derived from virtex dlentry and others.
*
*  IBM refers to the version of the processor as PPC405F5.
*  The processor version register returns 0x20011470.
*  References:
*      PowerPC Processor Reference Guide UG011 (v1.3)
*      http://www.xilinx.com/support/documentation/user_guides/ug011.pdf
*
*      PowerPC Block Reference Guide
*      http://www.xilinx.com/support/documentation/user_guides/ug018.pdf
*
*      PowerPC errata
*      ftp://ftp.xilinx.com/pub/documentation/misc/ppc405f6v5_2_0.pdf
*
*      PowerPC 405-S Embedded Processor Core User's Manual (Version 1.2)
*      https://www-01.ibm.com/chips/techlib/techlib.nsf/products/PowerPC_405_Embedded_Cores
*
*  @author    Richard Claus <claus@SLAC.Stanford.edu>
*
*  @date      March 4, 2011 -- Created
*
*  $Revision: 674 $
*
*  @verbatim                    Copyright 2011
*                                      by
*                         The Board of Trustees of the
*                       Leland Stanford Junior University.
*                              All rights reserved.
*
*         Work supported by the U.S. Department of Energy under contract
*       DE-AC03-76SF00515.
*
*                               Disclaimer Notice
*
*        The items furnished herewith were developed under the sponsorship
*   of the U.S. Government.  Neither the U.S., nor the U.S. D.O.E., nor the
*   Leland Stanford Junior University, nor their employees, makes any war-
*   ranty, express or implied, or assumes any liability or responsibility
*   for accuracy, completeness or usefulness of any information, apparatus,
*   product or process disclosed, or represents that its use will not in-
*   fringe privately-owned rights.  Mention of any product, its manufactur-
*   er, or suppliers shall not, nor is it intended to, imply approval, dis-
*   approval, or fitness for any particular use.  The U.S. and the Univer-
*   sity at all times retain the right to use and disseminate the furnished
*   items for any purpose whatsoever.                       Notice 91 02 01
*
*  @endverbatim
*/

#include <rtems/asm.h>
#include <rtems/powerpc/powerpc.h>

/*
 *  The virtex ELF link scripts support some special sections:
 *    .entry    The actual entry point
 *    .vectors  The section containing the interrupt entry veneers.
 */

/*
 *  Downloaded code loads the vectors separately to 0x00000100,
 *  so .entry can be over 256 bytes.
 *
 *  The other sections are linked in the following order:
 *    .entry
 *    .text
 *    .data
 *    .bss
 *  see linker command file for section placement
 *
 *  The initial stack is set to _ISR_Stack_area_end.
 *
 */

        .section .entry

        PUBLIC_VAR (download_entry)
        PUBLIC_VAR (__rtems_entry_point)
SYM(download_entry):
SYM(__rtems_entry_point):
        b       startupDow        /* Entry point used by xmd dow command */

        PUBLIC_VAR (start)
SYM(start):
        b       startupBL         /* Entry point used by bootLoader */

base_addr:
       /*-------------------------------------------------------------------
        * Parameters from linker
        *-----------------------------------------------------------------*/
toc_pointer:
        .long   __got_start
bss_length:
        .long   __bss_size
bss_addr:
        .long   __bss_start
stack_top:
        .long   _ISR_Stack_area_end
dccr_contents:
        .long   __dccr
iccr_contents:
        .long   __iccr
sgr_contents:
        .long   __sgr

       /*-------------------------------------------------------------------
        * Setup iccr, sgr, msr, cccr0, dcwr, dccr and clear bss
        *-----------------------------------------------------------------*/

startupDow:
       /*-------------------------------------------------------------------
        * Load the parameter table base address
        *------------------------------------------------------------------*/
        lis     r1,   base_addr@h
        ori     r1,r1,base_addr@l

       /* -------------------------------------------------------------------
        * Clear the Machine State Register's Critical and External
        * interrupt enables.
        *------------------------------------------------------------------*/
        mfmsr   r3
        lis     r0,   0x00028000@h
        ori     r0,r0,0x00028000@l
        andc    r3,r3,r0
        mtmsr   r3
        sync

       /* -------------------------------------------------------------------
        * Initialize the memory system.
        *------------------------------------------------------------------*/
        li      r0,0

        /* Set the Storage Guarded Register. */
        lwz     r2,sgr_contents-base_addr(r1)
        mtsgr   r2

        /* Configure endianness, compression */
        lis     r0,0x00000000@h   // Endianess value
        mtsler  r0
        lis     r0,0x00000000@h   // Compression value
        mtsu0r  r0

        /* Invalidate the entire instruction cache. */
        iccci   r0,r0

        /* Set the Instruction Cache Cacheability Register. */
        lwz     r2,iccr_contents-base_addr(r1)
        mticcr  r2
        isync

       /*-------------------------------------------------------------------
        * Tell the processor where the exception vector table will be.
        *------------------------------------------------------------------*/
        .extern SYM(__vectors)
        lis     r2, __vectors@h    /* set EVPR exc. vector prefix */
        mtevpr  r2

       /*-------------------------------------------------------------------
        * Set up the debug register to freeze timers on debug events.
        *------------------------------------------------------------------*/
        mfdbcr0 r2
        ori     r2,r2,0x0001
        mtdbcr0 r2
        isync

        /* Select whether APU, Wait Enable, interrupts/exceptions and address
           translation should be enabled when application starts */
        lis     r0,0x00000000@h   /* SRR1 value */
        mtsrr1  r0                /* Potentially: 0x80000000 >> 6 is APU */

        /* Configure timer facilities */
        mttbl   r0                /* Clear Timebase to prevent Fixed Interval.. */
        mttbu   r0                /* ..timer and Watchdog Timer exceptions */
        mtpit   r0                /* Programmable interval timer */
        li      r2,-1             /* -1 to clear TSR */
        mttsr   r2                /* Timer status register */

        /* Clear out stale values in certain registers to avoid confusion */
        mtcrf   0xff,r0           /* Need for simulation */
        mtctr   r0                /* Counter register */
        mtxer   r0                /* Fixed-point exception register */
        mtesr   r0                /* Exception syndrome register */
        mtdear  r0                /* Data exception address register */
        mtmcsr  r0                /* Machine check syndrome register */

        /* Invalidate the data cache */
        li      r2,0              /* Start address */
        li      r3,0x100          /* Number of cache lines */
        mtctr   r3                /* Transfer data cache congruence class count to CTR */
1:      dccci   0,r2              /* Invalidate this congruence class */
        addi    r2,r2,0x20        /* Point to next congruence class */
        bdnz    1b                /* Decrement counter and loop whilst not zero */

       /* -------------------------------------------------------------------
        * Set Core Configuration Register 0 as follows:
        * sum: 0x02700E00
        * bit 1 off:   as told by ppc405 errata to avoid CPU_213 ppc bug
        * bit 3 off:   as told by ppc405 errata to avoid CPU_213 ppc bug
                       (Note added later: PPC405F6 is not subject to CPU_213.)
        * bit 1 on:    Xilinx: CR 203746 Patch for PPC405 errata (RiC 12/8/11)
        * bit 2 on:    Xilinx: CR 203746 Patch for PPC405 errata (RiC 12/8/11)
        * bit 6 on:    load word as line
        * bit 7 off:   load  misses allocate cache line
        * bit 8 off:   store misses allocate cache line
        * bit 9-11 on: default settings to do with plb priority
        * bit 20 on:   prefetching for cacheable regions
        * bit 21 on:   prefetching for non-cacheable regions
        * bit 22 on:   request size of non-cacheable inst fetches is 8 words
        * bit 23 off:  fetch misses allocate cache line
        *------------------------------------------------------------------*/
        lis     r5,   0x52700E00@h
        ori     r5,r5,0x52700E00@l

       /* -------------------------------------------------------------------
        * To change CCR0 we make sure the code writing to it is
        *  running from the I-cache. This is needed because changing some
        * CCR0 fields will cause a hang if the processor is trying to
        * access memory at the same time.
        *------------------------------------------------------------------*/
        lis     r4,   2f@h
        ori     r4,r4,2f@l
        icbt    r0,r4
        b       2f

        .align  5 /* New cache line (32 bytes each) */
2:
        icbt    r0,r4       /* Put this line into the I-cache. */
        isync
        mtccr0  r5
        isync
        b       3f

        .align  5
3:
        /* Set the Data Cache Write-Through Register for no write-through, i.e., for write-back. */
        li      r0,0
        mtdcwr  r0

        /* Set the Data Cache Cacheablility Register. */
        lwz     r0,dccr_contents-base_addr(r1)
        mtdccr  r0
        isync

       /* Fall through */


       /* -------------------------------------------------------------------
        * If a bootloader has run that has already performed some
        * initialization, which among other things has loaded
        * this code into memory and jumped to start above, the initialization
        * above does not need to be done.  Execution thus resumes here.
        *------------------------------------------------------------------*/

startupBL:
       /* -------------------------------------------------------------------
        * Note that some initialization has already been performed by the
        * bootloader code in Block RAM, which among other things has loaded
        * this code into memory and jumped to start above.
        *------------------------------------------------------------------*/

       /*-------------------------------------------------------------------
        * Load the parameter table base address
        *------------------------------------------------------------------*/
        lis     r1,   base_addr@h
        ori     r1,r1,base_addr@l

       /*-------------------------------------------------------------------
        * Setup stack for RTEMS and call boot_card(). From this
        * point forward registers will be used in accordance with the
        * PowerPC EABI.
        *
        * boot_card() supervises the initialization of RTEMS and the C
        * library.  It calls bsp_start(), etc.
        *------------------------------------------------------------------*/
        lwz     r2,toc_pointer-base_addr(r1)        /* set r2 to toc */
        lwz     r1,stack_top-base_addr(r1)          /* set r1 to stack_top */

        /* Align as required by ABI */
        li      r3,PPC_STACK_ALIGNMENT-1
        andc    r1,r1,r3

       /*-------------------------------------------------------------------
        * Set up r2 and r13. Upon entry r1 must have a nonzero value
        *  as it will be stored in an "init done" flag. Stupid but true.
        *  r1 must also be set up as a stack pointer as __eabi() jumps
        *  to __init() which has a standard function prolog.
        *------------------------------------------------------------------*/
        bl      __eabi

       /*-------------------------------------------------------------------
        * Zero the .bss, .sbss and .sbss2 sections.
        * Must have r2 and r13 properly set.
        *------------------------------------------------------------------*/
        bl      zero_bss

       /*-------------------------------------------------------------------
        * Create a minimal stack frame for this code, the caller of boot_card().
        *------------------------------------------------------------------*/
        addi    r1,r1, -PPC_MINIMUM_STACK_FRAME_SIZE

        xor     r3,r3,r3
        stw     r3,0(r1)            /* Terminate the chain of stack frames. */
        stw     r3,4(r1)
        stw     r3,8(r1)
        stw     r3,12(r1)
        lis     r5,environ@ha
        la      r5,environ@l(r5)    /* environp */

       /*-------------------------------------------------------------------
        * Call boot_card() with its arguments, the command-line pointer and
        * the argument count, set to NULL.
        *------------------------------------------------------------------*/
        li      r4,0                /* argv */
        li      r3,0                /* argc */
        .extern SYM (boot_card)
        b       SYM (boot_card)
