;* ------------------- File: boot_c6727.asm -----------------------------------*
            .title  "Flash bootup utility for C6727 EVM from DSP-Weuffen GmbH"

;************************************************************************
;* this file is based upon the file boot_c671x.s62 from spra999a.pdf/.zip from TI.
;* (C) 2006  DSP-Weuffen GmbH, Neuravensburg, GERMANY 
;************************************************************************

; comment in the below line when done with the EMIF and PLL init coding
EMIF_PLL_INIT_IS_DONE .set 1

; comment in the below line if you need to halt on startup
;WAIT_ON_STARTUP .set 1

; comment in the below line if you need to halt before finally launching the application
;WAIT_ON_FINALE .set 1



; set some global document options for assembler listing generation
            .option D,T
            .length 102
            .width  140

; global EMIF symbols defined for the c6727 family
            .include        c6727dsk.inc


; specify the section name and attributes for the below code
            .sect ".boot_load"
            .global _boot
            .global ___binit__



;************************************************************************
;* boot loader entry point
;************************************************************************
        .def _parallel_flash_signature

_boot2_handshake: ; reuse this memory locations after start
_parallel_flash_signature: ; this location has to be be loaded to IROM start (10000000h)
        .word TRANSFER_MAGIC_16 ; Magic number which tells the IROM-bootloader that the Flash width is 16Bit


;************************************************************************
;* boot loader entry point
;************************************************************************
_boot2_start_address: ; reuse this memory locations after start
_boot:  ; this location has to be be loaded to IROM start + 4 (10000004h)


        .if $isdefed("WAIT_ON_STARTUP")
;************************************************************************
;* DEBUG LOOP
;************************************************************************
        zero B2
_myloop1:
  [!B2] B _myloop1
        nop  5
_myloopend:
        nop
        .endif ; WAIT_ON_STARTUP


        .if $isdefed("EMIF_PLL_INIT_IS_DONE")
;************************************************************************
;* CONFIGURE EMIF
;************************************************************************

;   *(volatile unsigned char *)(EMIF_SDCR+3) = 0x80;          ; enter self-refresh mode
;   *(volatile unsigned int *)PLL_CSR  &= ~CSR_PLLEN;
;   *(volatile unsigned int *)PLL_CSR  &= ~CSR_PLLPWRDN;
;   /* Reset the pll.  PLL takes 125ns to reset. */
;   *(volatile unsigned int *)PLL_CSR  |= CSR_PLLRST;
        mvkl  PLL_CSR,A1
        mvkh  PLL_CSR,A1                    ; PLL_CSR
        ldw   *A1,A3
        mvkl  EMIF_SDCR+3,A0
        mvkh  EMIF_SDCR+3,A0
        mvkl  1000,B0                       ; Counter i
        mvkl  0x80,B1
        stw   B1,*A0
        mvkl  ~CSR_PLLEN,B1
        mvkh  ~CSR_PLLEN,B1
        and   A3,B1,A3
        stw   A3,*A1
        mvkl  ~CSR_PLLPWRDN,B1
        mvkh  ~CSR_PLLPWRDN,B1
        and   A3,B1,A3
        stw   A3,*A1
        mvkl  CSR_PLLRST,B1
        mvkh  CSR_PLLRST,B1
        or    A3,B1,A3
        stw   A3,*A1
        
;   {
;      register int i;
;      for(i=0;i<1000;i++) {}
;   }
PllDelay:     
   [b0] b  PllDelay
        sub   b0,1,b0
        nop   5
   
;  ------------------------------------------------------
;   PLLOUT = CLKIN/(DIV0+1) * PLLM                       
;   300    = 12/1 * 25                                   
;  ------------------------------------------------------
;  *(volatile unsigned int *)PLL_DIV0    = DIV_ENABLE + 0;
;  *(volatile unsigned int *)PLL_M       = 25;
        mvkl  DIV_ENABLE+0,B1
        mvkh  DIV_ENABLE+0,B1
        mvkl  PLL_DIV0,A0
        mvkh  PLL_DIV0,A0
        stw   b1,*a0
        mvkl  25,B1
        mvkh  25,B1
        mvkl  PLL_M,A0
        mvkh  PLL_M,A0
        stw   b1,*a0
;  ------------------------------------------------------
;   Program in reverse order.                            
;   DSP requires that pheriheral clocks be less then     
;   1/2 the CPU clock at all times.                      
;   Order not critical, since changes need GO to come into effect. 
;  ------------------------------------------------------
;  *(volatile unsigned int *)PLL_DIV3    = DIV_ENABLE + 2;
;  *(volatile unsigned int *)PLL_DIV2    = DIV_ENABLE + 1;
;  *(volatile unsigned int *)PLL_DIV1    = DIV_ENABLE + 0;
;  *(volatile unsigned int *)PLL_CMD     = CMD_GOSET;
;  *(volatile unsigned int *)PLL_CSR    &= ~CSR_PLLRST;
;  PLL_CSR &= RST 
        mvkl  DIV_ENABLE+2,B1
        mvkh  DIV_ENABLE+2,B1
        mvkl  PLL_DIV3,A0
        mvkh  PLL_DIV3,A0
        stw   b1,*a0
        mvkl  DIV_ENABLE+1,B1
        mvkh  DIV_ENABLE+1,B1
        mvkl  PLL_DIV2,A0
        mvkh  PLL_DIV2,A0
        stw   b1,*a0
        mvkl  DIV_ENABLE+0,B1
        mvkh  DIV_ENABLE+0,B1
        mvkl  PLL_DIV1,A0
        mvkh  PLL_DIV1,A0
        stw   b1,*a0
        mvkl  CMD_GOSET,B1
        mvkh  CMD_GOSET,B1
        ldw   *a1,A2
        mvkl  PLL_CMD,A0
        mvkh  PLL_CMD,A0
        stw   b1,*a0
        mvkl  ~CSR_PLLRST,B1
        mvkh  ~CSR_PLLRST,B1
        and   b1,a2,b1
        stw   b1,*a1

;  ------------------------------------------------------
;   Now enable pll path and we are off and running at    
;   300MHz with 100 MHz SDRAM.                           
;  ------------------------------------------------------
;  *(volatile unsigned int *)PLL_CSR |= CSR_PLLEN;
        mvkl  CSR_PLLEN,B2
        mvkh  CSR_PLLEN,B2
        or    b2,B1,b1
        stw   b1,*A1

;  *(volatile unsigned int *)EMIF_SDTIMR   = 0x31114610;
;  *(volatile unsigned int *)EMIF_SDSRETR  = 0x00000006;
;  *(volatile unsigned int *)EMIF_SDRCR    = 0x0000061a;
;  *(volatile unsigned int *)EMIF_SDCR     = 0x00000720;     ; 32Bit, CAS=2, 4 banks, 8 columns
;  *(volatile unsigned int *)EMIF_A1CR     = 0x886225bd;
        mvkl  EMIF_REG_START,A0
        mvkh  EMIF_REG_START,A0
        mvkl  0x31114610,B0
        mvkh  0x31114610,B0
        stw   B0,*+A0[(EMIF_SDTIMR-EMIF_REG_START)/4]
        mvkl  0x00000006,B0
        mvkh  0x00000006,B0
        stw   B0,*+A0[(EMIF_SDSRETR-EMIF_REG_START)/4]
        mvkl  0x0000061a,B0
        mvkh  0x0000061a,B0
        stw   B0,*+A0[(EMIF_SDRCR-EMIF_REG_START)/4]
        mvkl  0x00000720,B0
        mvkh  0x00000720,B0
        stw   B0,*+A0[(EMIF_SDCR-EMIF_REG_START)/4]
        mvkl  0x886225bd,B0
        mvkh  0x886225bd,B0
        stw   B0,*+A0[(EMIF_A1CR-EMIF_REG_START)/4]

        .endif ; EMIF_PLL_INIT_IS_DONE


;************************************************************************
; boot mode switch
; selects copy routine if either booting from parallel flash or from UHPI
;************************************************************************
            mvkl  CFGPIN1,A4          ; load address of cfgpin1 register
            mvkh  CFGPIN1,A4
            mvkl  CFGPIN1_nHCS, B3    ; load bitmask for /HCS bit
            mvkh  CFGPIN1_nHCS, B3

            ldw   *A4,B4
            nop   4

            and   B4,B3,B0     ; bit5 is the /HCS pin on reset: 1=>FLASH-BOOT, 0=>UHPI-BOOT

       [B0] b     _flash_boot_tablecopy ; if bit 4 is set, then we are in a flash boot scenario
            nop   5


;************************************************************************
; let UHPI host copy the sections and enter the start address from the table in the image
; this is mainly sending a request and waiting for a handshake value
;************************************************************************
_uhpi_boot_tablecopy:
            mvkl  _boot2_start_address, A4 ; load addres where symbol value of startup routine is stored
            mvkh  _boot2_start_address, A4

            ldw   *A4, B2        ; create a backup of the opcode at the entry point
            nop   4

            ; re-enable the UHPI unit, keep all registers as they were at boot
            mvkl  CFGHPI, A4 ; load address for UHPI config register
            mvkh  CFGHPI, A4

            mvkl  CFGHPI_ENA, B4 ; load bitmask for HPI enable bit
            mvkh  CFGHPI_ENA, B4

            ldw   *A4, B3        ; re-enable UHPI by simply setting its enable bit
            nop   4

            or    B3,B4,B3
            nop   4

            stw   B3, *A4
            nop   4

            ; communicate with the host
            mvkl  _boot2_handshake, A4 ; load address for handshake register
            mvkh  _boot2_handshake, A4

            mvkl  TRANSFER_REQUEST, B4 ; request value for boot loader stage 2
            mvkh  TRANSFER_REQUEST, B4

            mvkl  TRANSFER_DONE, B3 ; reply value for boot loader stage 2
            mvkh  TRANSFER_DONE, B3

            stw   B4,*A4               ; send request to UHPI master "please load all section data"
            nop   4

_uhpi_boot_wait:
            ldw   *A4, B4              ; read the value from the handshake location
            nop   4

            sub   B4, B3, B0           ; check for a match
            nop   4

      [B0]  b     _uhpi_boot_wait      ; no match until now, check once again
            nop   5

            ; keep the UHPI unit enabled - this allows UHPI to read back its very own reply: the written handshake values

            mvkl  _boot2_start_address, A3 ; load addres where symbol value of startup routine is stored
            mvkh  _boot2_start_address, A3

            ldw   *A3, B1              ; load start address into B1
            nop 4

            stw   B2, *A3              ; restore the backup of the opcode at the entry point
                                       ; this will ease debugging and other tricks from main...

            b copy_done
            nop 5


;************************************************************************
; Enable the GPIO-lines on the UHPI-interface
; some GPIOs are used as virtual address lines for addressing the FLASH
;************************************************************************
_flash_boot_tablecopy:

   ; The upper part of the UHPI is used as GPIO-lines 
   ;*GPIOEN   |= 0x00000200;      Enable pin group to be GPIO 
   ;*GPIODIR1 |= 0x007f0000;      HD16-HD22 are the address lines 
   ;*GPIODAT1 &= ~0x007f0000;     clear all address lines to 0 

        mvkl    UHPI_REG_START,A0
        mvkh    UHPI_REG_START,A0

        LDW     *+A0[(GPIOEN-UHPI_REG_START)/4],A3
        LDW     *+A0[(GPIODIR1-UHPI_REG_START)/4],A4
        LDW     *+A0[(GPIODAT1-UHPI_REG_START)/4],A5
        NOP     3
        SET     A3,9,9,A3
        STW     A3,*+A0[(GPIOEN-UHPI_REG_START)/4]   

        SET     A4,16,22,A4
        STW     A4,*+A0[(GPIODIR1-UHPI_REG_START)/4]
        
        CLR     A5,16,22,A5
        STW     A5,*+A0[(GPIODAT1-UHPI_REG_START)/4]
        NOP     4


;************************************************************************
; copy sections from FLASH to RAM using linker generated copy table.
; compare: spra999A.pdf "2.3 Writing the Secondary Bootloader" Figure 3
;************************************************************************
        mvkl  COPY_TABLE, a3 ; load pointer to the copy table
        mvkh  COPY_TABLE, a3

        ; Prepare generation of flash address signals using GPIO
        MVKL    GPIODAT1,a10
        MVKH    GPIODAT1,a10
        mvkl    0x003f8000,b10      ; 
        mvkh    0x003f8000,b10      ; 
        LDW     *a10,a11            ; *GPIODAT1 & ~0x007f0000 
        NOP     4

        ;*GPIODAT1 = (*GPIODAT1 & ~0x007f0000) | (((U32)Addr & 0x003F80000) << 1);
        AND     b10,a3,a12          ; Addr & 0x003f8000
        CLR     a11,16,22,a11       ; *GPIODAT1 & ~0x007f0000
        ADD     a12,a12,a12         ; << 1
        OR      a12,A11,A11         ; |
        STW     A11,*a10            ;
        NOP     5                   ; address simulation via GPIO block END

        ldw   *a3++, b1      ; load entry point adress

copy_section_top:
        ;*GPIODAT1 = (*GPIODAT1 & ~0x007f0000) | (((U32)Addr & 0x003F80000) << 1);
        AND     b10,a3,a12          ; Addr & 0x003f8000
        CLR     a11,16,22,a11       ; *GPIODAT1 & ~0x007f0000
        ADD     a12,a12,a12         ; << 1
        OR      a12,A11,A11         ; |
        STW     A11,*a10            ;
        NOP     5                   ; address simulation via GPIO block END
        
        ldw   *a3, b0        ; load byte count of section
        ldw   *a3++, b0      ; load byte count of section

        ;*GPIODAT1 = (*GPIODAT1 & ~0x007f0000) | (((U32)Addr & 0x003F80000) << 1);
        AND     b10,a3,a12          ; Addr & 0x003f8000
        CLR     a11,16,22,a11       ; *GPIODAT1 & ~0x007f0000
        ADD     a12,a12,a12         ; << 1
        OR      a12,A11,A11         ; |
        STW     A11,*a10            ;
        NOP     5                   ; address simulation via GPIO block END
        
        ldw   *a3, a4        ; load ram start address of section
        ldw   *a3++, a4      ; load ram start address of section
        nop   3

  [!b0] b copy_done          ; if byte count from table is 0, then we have we copied all sections
        nop   5

copy_bytes_loop:

        ;*GPIODAT1 = (*GPIODAT1 & ~0x007f0000) | (((U32)Addr & 0x003F80000) << 1);
        AND     b10,a3,a12          ; Addr & 0x003F80000
        CLR     a11,16,22,a11       ; *GPIODAT1 & ~0x007f0000
        ADD     a12,a12,a12         ; << 1
        OR      a12,A11,A11         ; |
        STW     A11,*a10            ;
        NOP     5                   ; address simulation via GPIO block END

        ldb   *a3++,b5       ; load next data byte
        sub   b0,1,b0        ; decrement byte counter by one

  [ b0] b     copy_bytes_loop  ; if there are still bytes to copy then setup a branch for the next byte
  [!b0] b     copy_section_top ; if there are no more bytes to copy then setup a branch for the next section

        zero  a1             ; speculative pre-assignment source address fraction bits with zero
  [!b0] and   3,a3,a1        ; (conditionally) determine fraction bits of source address for a 4 byte alignment
        stb   b5,*a4++       ; store previousely loaded data byte to target location

  [!b0] and   -4,a3,a5       ; (conditionally) round source address up down to 4 byte alignment, store in temp
  [ a1] add   4,a5,a3        ; (conditionally) add 4 bytes to temp, store in real source address


copy_done:

        .if $isdefed("WAIT_ON_FINALE")
;************************************************************************
;* DEBUG LOOP
;************************************************************************
        zero B2
_myloop2:
  [!B2] B _myloop2  
        nop  5
_myloopend2:
        nop
        .endif ; WAIT_ON_STARTUP


;************************************************************************
; jump to start_address in B1
;************************************************************************
        b    .S2 B1          ; jump to start address
        nop   5


; ### EOF ###
