/*!@file
*
*  @brief     Initialization code to set up the CPU and call boot_card()
*
*  This "BSP" targets the Xilinx Virtex XC5VFX70T 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.
*
*  Some portions of this code follow section 3.4 of the PPC440x5 CPU Core User's
*  Manual v7.1 from IBM.  Other parts were derived from examples provided
*  by Xilinx in their ML510 Reference Designs, e.g., ml510_bsb1_design_ppc440.
*  See boot.S in standalone/, for example.
*
*  References:
*      Embedded Processor Block in Virtex-5 FPGAs Reference Guide UG200 (v1.8)
*      http://www.xilinx.com/support/documentation/user_guides/ug200.pdf
*
*      PowerPC 440x5 Embedded Processor Core User's Manual (Version 7.1)
*      https://www-01.ibm.com/chips/techlib/techlib.nsf/products/PowerPC_440_Embedded_Core
*
*  @author    Richard Claus <claus@SLAC.Stanford.edu>
*
*  @date      March 4, 2011 -- Created
*
*  $Revision: 675 $
*
*  @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>
#include <rtems/powerpc/registers.h>

#define   V_TS_SZ_I    0x0290      // V,TS=0(Inst),SIZE=9,TID=0
#define   V_TS_SZ_D    0x0390      // V,TS=1(Data),SIZE=9,TID=0
#define   WIMG_U_S_0   0x043F      // !(U0-3),!W, I,!M,!G,!E,UX,UW,UR,SX,SW,SR
#define   WIMG_U_S_1   0x003F      // !(U0-3),!W,!I,!M,!G,!E,UX,UW,UR,SX,SW,SR
#define   PAGE_SZ      0x10000000  // 256 MB

/*
 *  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.
 *
 *  All the entry veneer has to do is to clear the BSS.
 */

        .section .entry

        PUBLIC_VAR(download_entry)
        PUBLIC_VAR(__rtems_entry_point)
SYM(download_entry):
SYM(__rtems_entry_point):
        b       startupDL         /* 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


        .eject

       /*------------------------------------------------------------------
        * This code follows section 3.4 of the PPC440x5 CPU Core User's
        * Manual.  The numbers in the comments refer to the step numbers
        * therein.  Some of the implementation comes from examples provided
        * by Xilinx in their ML510 Reference Designs, e.g.,
        * ml510_bsb1_design_ppc440.  See boot.S in standalone/.
        *------------------------------------------------------------------*/
       /*------------------------------------------------------------------
        * This code is designed to accomodate warm restarts, in which the
        * application software triggers the restart of the system by branching
        * to the following code (either boot or boot1) without causing
        * one of the hardware resets: core, chip, system or JTAG (section
        * 3.2,3 in the Power PC 440-S Embedded Processor Core User's Manual).
        *-----------------------------------------------------------------*/

       /* -----------------------------------------------------------------
        * Setup CPU
        *-----------------------------------------------------------------*/
first:  li      r0,0              // Clear r0

       /* -----------------------------------------------------------------
        * Initialize the memory system.
        *------------------------------------------------------------------*/
        iccci   r0,r0             // 2. Invalidate instruction cache
        dccci   r0,r0             // 3. Invalidate data cache
        msync                     // 4. Force in-progress data PLB ops to complete

        mfdbcr0 r2                // 5. Disable all debug events
        lis     r3,0x8100
        and     r2,r2,r3          // Ignore EDM,TRAP to allow XMD use
        mtdbcr0 r2
        li      r2,-1
        mtdbsr  r2                // 6. Initialize all debug event status

       /*------------------------------------------------------------------
        * Set Core Configuration Register 0 as follows:
        * sum: 0x00206000
        * bit  1    off  Parity Recovery Enable
        * bit  4    off  Cache Read Parity Enable
        * bit 10    on   Disable Store Gathering
        * bit 11    off  Disable APU Instruction Broadcast
        * bit 16    off  Disable Trace Broadcast
        * bit 17:18 on   Specifies behaviour of icbt,dcbt/dcbtst insts
        * bit 23    off  Force Load/Store Alignment
        * bit 28:29 off  Instruction Cache Speculative Line Count
        * bit 30:31 off  Instruction Cache Speculative Line Threshold
        *            NB: UG200/pg 21: Spec. prefetching must be disabled
        *------------------------------------------------------------------*/

        lis     r2,   0x00206000@h // 7. Set CCR0: DSTG
        ori     r2,r2,0x00206000@l //    Set CCR0: GDCBT, GICBT
        mtccr0  r2                 // Configure CCR0

        mtspr   PPC440_CCR1,r0     // 8. Clear CCR1

       /*------------------------------------------------------------------
	* 9. Configure cache regions
        *------------------------------------------------------------------*/
	mtspr   PPC440_INV0,r0
	mtspr   PPC440_INV1,r0
	mtspr   PPC440_INV2,r0
	mtspr   PPC440_INV3,r0
	mtspr   PPC440_DNV0,r0
	mtspr   PPC440_DNV1,r0
	mtspr   PPC440_DNV2,r0
	mtspr   PPC440_DNV3,r0
	mtspr   PPC440_ITV0,r0
	mtspr   PPC440_ITV1,r0
	mtspr   PPC440_ITV2,r0
	mtspr   PPC440_ITV3,r0
	mtspr   PPC440_DTV0,r0
	mtspr   PPC440_DTV1,r0
	mtspr   PPC440_DTV2,r0
	mtspr   PPC440_DTV3,r0

       /*------------------------------------------------------------------
	* Cache victim limits
	* floors 0, ceiling max to use the entire cache -- nothing locked
        *------------------------------------------------------------------*/
	lis	r2,   0x0001f800@h
	ori	r2,r2,0x0001f800@l
	mtspr   PPC440_IVLIM,r2
	mtspr   PPC440_DVLIM,r2

       /*------------------------------------------------------------------
        * Configure instruction and data cache regions:
        * Set up register constants (r6,r7), page index (r5), address
        * variable (r4), EPN_V_TS bits (r3)
        *
        * Word 0 bits:  0xX0000290, 0xX0000390
        * Bits  Field  Inst  Data  Description
        *  0:21  EPN   0-15  0-15  Effective Page Number
        *    22  V     1     1     Valid
        *    23  TS    0     1     Translation Address Space
        * 24:27  SIZE  9     9     Page Size (9 = 256 MB)
        * 38:31  TPAR  0     0     Tag Parity
        * 32:39  TID   0     0     Translation ID (in the MMUCR)
        *
        * Word 1 bits:  0x00000000, 0x00000000
        * Bits  Field  Inst  Data  Description
        *  0:21  RPN   0     0     Real Page Number
        * 22:23  PAR1  0     0     Parity for TLB word 1
        * 28:31  ERPN  0     0     Extended Real Page Number
        *
        * Word 2 bits:  0x0000043f, 0x00000c3f
        * Bits  Field  Inst  Data  Description
        *  0: 1  PAR2  0     0     Parity for TLB word 2
        *    16  U0    0     0     User-Defineable Storage Attribute 0
        *    17  U1    0     0     User-Defineable Storage Attribute 1
        *    18  U2    0     0     User-Defineable Storage Attribute 2
        *    19  U3    0     0     User-Defineable Storage Attribute 3
        *    20  W     0     0     Write-Through
        *    21  I     1     1     Caching Inhibited
        *    22  M     0     0     Memory Coherence Required
        *    23  G     0     0     Guarded
        *    24  E     0     0     Endian
        *    26  UX    1     1     User State Execute Enable
        *    27  UW    1     1     User State Write Enable
        *    28  UR    1     1     User State Read Enable
        *    29  SX    1     1     Supervisor State Execute Enable
        *    30  SW    1     1     Supervisor State Write Enable
        *    31  SR    1     1     Supervisor State Read Enable
        *------------------------------------------------------------------*/

        mtspr   PPC440_MMUCR,r0   // 10a. Clear MMUCR
        li      r7,WIMG_U_S_1     // Word 2: Pages are NOT cache inhibited
        lis     r6,   PAGE_SZ@h   // Page size constant
        ori     r6,r6,PAGE_SZ@l
        mr      r5,r0             // TLB entry index
        mr      r4,r0             // Initialize RPN to zero
        mflr    r28               // Save return address
        bl      tlbSetup          // 10b. Set up the TLBs
        mtlr    r28               // Restore return address

       /*------------------------------------------------------------------
        * Select whether Wait Enable, interrupts/exceptions and which address
        * spaces should be enabled when application starts
        *------------------------------------------------------------------*/
        lis     r3,   0x00000000@h // 10d. MSR[IS]=0 MSR[DS]=0
        ori     r3,r3,0x00000000@l
        mtsrr1  r3
        mtsrr0  r28               // Return address
        rfi                       // Context synchronize to invalidate shadow TLB contents


       /*-------------------------------------------------------------------
        * Entry point used when downloaded, e.g. through XMD
        *------------------------------------------------------------------*/
startupDL:
       /*-------------------------------------------------------------------
        * Do initialization up to the point where a context sync is required
        *------------------------------------------------------------------*/
        bl      first             // Do first things first

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

       /*------------------------------------------------------------------
        * Set up default exception and interrupt vectors
        *------------------------------------------------------------------*/
        li       r1,0
        mtivor0  r1
        addi     r1,r1,0x10
        mtivor1  r1
        addi     r1,r1,0x10
        mtivor2  r1
        addi     r1,r1,0x10
        mtivor3  r1
        addi     r1,r1,0x10
        mtivor4  r1
        addi     r1,r1,0x10
        mtivor5  r1
        addi     r1,r1,0x10
        mtivor6  r1
        addi     r1,r1,0x10
        mtivor7  r1
        addi     r1,r1,0x10
        mtivor8  r1
        addi     r1,r1,0x10
        mtivor9  r1
        addi     r1,r1,0x10
        mtivor10 r1
        addi     r1,r1,0x10
        mtivor11 r1
        addi     r1,r1,0x10
        mtivor12 r1
        addi     r1,r1,0x10
        mtivor13 r1
        addi     r1,r1,0x10
        mtivor14 r1
        addi     r1,r1,0x10
        mtivor15 r1

       /*------------------------------------------------------------------
        * 12. Configure debug facilities
        *------------------------------------------------------------------*/
        mtdbcr1 r0
        mtdbcr2 r0
        mtiac1  r0
        mtiac2  r0
        mtiac3  r0
        mtiac4  r0
        mtdac1  r0
        mtdac2  r0
        mtdvc1  r0
        mtdvc2  r0
        mfdbcr0 r2                // Freeze timers on debug events
        ori     r2,r2,0x0001
        mtdbcr0 r2
        isync

       /*-------------------------------------------------------------------
        * 13. Configure timer facilities
        *------------------------------------------------------------------*/
        mtdec   r0                // Clear Decrementer to prevent exception
        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

       /* Fall through */

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

startupBL:
       /*-------------------------------------------------------------------
        * 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(), bsp_predriver_hook(), 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              /* setup EABI and SYSV environment */

       /*-------------------------------------------------------------------
        * Zero the .bss, .sbss and .sbss2 sections.
        * Must have r2 and r13 properly set.
        *------------------------------------------------------------------*/
        bl      zero_bss            /* Assume Bank regs set up..., cache etc. */

       /*-------------------------------------------------------------------
        * 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            /* Clear r3 */
        stw     r3,0(r1)            /* Clear stack chain */
        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)     /* call the first C routine */


        .eject

       /*------------------------------------------------------------------
        * Set up TLB entries: 2 entries are needed for the same 256MB page
        * one for instruction memory and the other for data memory.
        * (TS bit=0 for instructions)
        *------------------------------------------------------------------*/
tlbSetup:
1:      ori     r3,r4,V_TS_SZ_I   // Fold V_TS_SZ in with EPN=RPN
        tlbwe   r3,r5,0           // Word 0: EPN_V_TS_SZ (Instructions)
        tlbwe   r4,r5,1           // Word 1: RPN_ERPN
        tlbwe   r7,r5,2           // Word 2: WIMG_U_S
        ori     r3,r4,V_TS_SZ_D   // Fold V_TS_SZ in with EPN=RPN
        addi    r5,r5,1           // Next TLB entry
        tlbwe   r3,r5,0           // Word 0: EPN_V_TS_SZ (Data)
        tlbwe   r4,r5,1           // Word 1: RPN_ERPN
        tlbwe   r7,r5,2           // Word 2: WIMG_U_S
        add     r4,r4,r6          // Increment RPN to next 256MB block
        addi    r5,r5,1           // Next TLB entry
        cmpwi   r5,32             // Done yet?
        bne     1b
        li      r0,0
2:                                // Zero out index 32-63 TLB entries
        tlbwe   r0,r5,0
        tlbwe   r0,r5,1
        tlbwe   r0,r5,2
        addi    r5,r5,1
        cmpwi   r5,64
        bne     2b

        blr
