; Copyright 2009 Castle Technology Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;

        GET     Hdr:ListOpts
        GET     Hdr:Macros
        GET     Hdr:System
        GET     Hdr:Machine.<Machine>
        GET     Hdr:HALSize.<HALSize>

        GET     Hdr:MEMM.VMSAv6

        GET     Hdr:Proc
        GET     Hdr:OSEntries
        GET     Hdr:HALEntries
        GET     Hdr:VIDCList

        GET     hdr.omap3530
        GET     hdr.StaticWS
        GET     hdr.UART
        GET     hdr.Post
        GET     hdr.SDRC
        GET     hdr.GPIO

        AREA    |!!!ROMStart|, CODE, READONLY, PIC

        IMPORT  rom_checkedout_ok
        EXPORT  HAL_Base
        IMPORT  HAL_DebugTX
        IMPORT  DebugHALPrint
        IMPORT  DebugHALPrintReg

; Using the DMA controller to relocate the ROM image is much faster than doing it with the CPU
             GBLL Use_DMA_Copy
Use_DMA_Copy SETL {TRUE}

        MACRO
        CallOSM $entry, $reg
        LDR     ip, [v8, #$entry*4]
        MOV     lr, pc
        ADD     pc, v8, ip
        MEND

        ; Jump table used to select board config on startup
        ; See board.s for ordering of configs, and therefore what entry corresponds to what board
HAL_Base
        BL      selectconfig
        BL      selectconfig
        BL      selectconfig
        BL      selectconfig
        BL      selectconfig
        BL      selectconfig
        BL      selectconfig
JumpTableEnd
        ASSERT  . - HAL_Base < 0x60
        %       0x60 - (. - HAL_Base)
        DCD     0 ; Empty - was ROMsize
        B       selectconfig_linux ; offset &64 - for booting as a uImage/Linux kernel. Uses Linux machine type ID to select board config.

        ENTRY
selectconfig
        ; Get pointer to board config
        ADR     v1, HAL_Base+4
        SUB     v1, lr, v1
        ADR     a1, BoardConfigTable
        MOV     a2, #BoardConfig_Size>>2
        MLA     v1, a2, v1, a1
foundconfig
        ; v1 = board config
        MSR     CPSR_c, #F32_bit+I32_bit+SVC32_mode ; Get into SVC mode now, so we can write to sb without much fear of losing it (we may have been in FIQ)
 [ Debug
        ; Announce ourselves if debug
        ADR     v2, HelloWorld
        MOV     sb, v1
10      LDRB    a1, [v2], #1
        CMP     a1, #0
        ADRNE   lr, %BT10
        BNE     HAL_DebugTX
        ADD     v2, v1, #BoardConfig_Name
10      LDRB    a1, [v2], #1
        CMP     a1, #0
        ADRNE   lr, %BT10
        BNE     HAL_DebugTX
        MOV     a1, #13
        BL      HAL_DebugTX
        MOV     a1, #10
        BL      HAL_DebugTX
 ]
        ; Now copy the config to SRAM
        ; We'll assume that the L3 interconnect has been correctly configured to give us access
        LDR     sb, =IntSRAM_Base
        MOV     a2, #BoardConfig_Size
10      SUBS    a2, a2, #4
        LDR     a3, [v1, a2]
        STR     a3, [sb, a2]
        BGT     %BT10
 [ DebugTiming
        ADD     sp, sb, #32768 ; Temp stack for debug code
        ; Ensure debug UART FIFO is enabled (assuming UART 3)
        MOV     a1, #0
        STRB    a1, UARTFCRSoftCopy+2
        MOV     a1, #2
        STRB    a1, [sb, #BoardConfig_NumUART] ; Hide UART from RO
        MOV     a2, #1
        IMPORT  HAL_UARTFIFOEnable
        BL      HAL_UARTFIFOEnable
        DebugTimeNoMMU a1, "@ "
 ]
        ; Now do common init
        B       restart

 [ Debug
HelloWorld DCB "OMAP3 HAL init",13,10,"Board config=",0
        ALIGN
 ]

        ; Entry point for masquerading as a Linux kernel
        ; r0=0
        ; r1=machine type ID
        ; r2=ptr to tag list (linux/include/asm/setup.h)
selectconfig_linux
        ADR     v1, BoardConfigTable_End-BoardConfig_Size
        ADR     a3, BoardConfigTable
10
        LDR     a1, [v1, #BoardConfig_MachID]
        CMP     a1, a2
        CMPNE   v1, a3 ; If we can't find a config, abort and use default? (i.e. beagleboard)
        BEQ     foundconfig
        SUB     v1, v1, #BoardConfig_Size
        B       %BT10

        LTORG
        GET     board.s
        ASSERT  ((JumpTableEnd-HAL_Base)/4) >= (BoardConfigTable_End-BoardConfigTable)/BoardConfig_Size ; If this fires, we need a bigger jump table!

; ------------------------------------------------------------------------------
; Perform some Cortex-A8 specific CPU setup
; Then start looking for RAM
; In: sb = board config ptr
restart
        DebugChar a3,a4,48
        MSR     CPSR_c, #F32_bit+I32_bit+SVC32_mode
        DebugChar a3,a4,49

        ADRL    v1, HAL_Base + OSROM_HALSize    ; v1 -> RISC OS image

        LDR     v8, [v1, #OSHdr_Entries]
        ADD     v8, v8, v1                      ; v8 -> RISC OS entry table

        ; Ensure CPU is set up
        MOV     a1, #0
        CallOSM OS_InitARM
        DebugChar a3,a4,50

        ; Initialise RAM
        BL      init_ram

        ; The first 4K of the first registered block of RAM is used by RISC OS's init code, and also contains the stack
        ; To keep things simple and safe, we'll relocate the HAL and OS image to the top end of RAM
        ; Although with the beagleboard we know we'll be booted from RAM, this code has been written so that it should work if running from ROM

        ; First, identify the top end of RAM
        ; Then check if we intersect it
        ; If we do, first copy ourselves down
        ; Then copy ourselves up

 [ Use_DMA_Copy
        ; We'll use DMA for extra speed, so start by resetting the DMA controller
        LDR     v5, =L4_sDMA
        MOV     v1, #2
        STR     v1, [v5, #DMA4_OCP_SYSCONFIG]
5
        LDR     v1, [v5, #DMA4_SYSSTATUS]
        TST     v1, #1
        BEQ     %BT5
        ; Set a sensible FIFO budget (as per SDMACReset)
        LDR     a2, =&100080
        STR     a2, [v5, #DMA4_GCR]
        ; Configure channel 0 for the right settings
        ADD     v5, v5, #DMA4_i
        LDR     v1, [v5, #DMA4_CLNK_CTRLi]
        BIC     v1, v1, #&8000 ; Disable channel linking
        STR     v1, [v5, #DMA4_CLNK_CTRLi]
        MOV     v1, #1<<4
        STR     v1, [v5, #DMA4_CICRi] ; frame end interrupt enabled
        LDR     v1, =&2E1C2 ; 32bit elements, 64 byte bursts with packing, last write non-posted
        STR     v1, [v5, #DMA4_CSDPi]
        MOV     v1, #1
        STR     v1, [v5, #DMA4_CFNi] ; 1 frame
 ]

relocate_code
        DebugChar a1,a2,66
        BL      get_end_of_ram
        DebugChar v1,v2,67

        ; How big are we?
        ADRL    v1, HAL_Base + OSROM_HALSize
        LDR     v2, [v1, #OSHdr_ImageSize]
        LDR     lr, [v1, #OSHdr_Flags]
        TST     lr, #OSHdrFlag_SupportsCompression
        LDRNE   lr, [v1, #OSHdr_CompressedSize]
        MOVEQ   lr, v2
        SUB     v1, v1, #OSROM_HALSize ; Start of HAL
        ADD     v2, v2, #OSROM_HALSize ; Size of HAL+OS
        ADD     lr, lr, #OSROM_HALSize ; Size of compressed HAL+OS
        ADD     v3, v1, lr ; End of OS
        MOV     v4, a1 ; End of RAM
        SUB     v5, v4, v2 ; New start address of HAL
        CMP     v1, v5
        BEQ     %FT10 ; No copy needed
        CMP     v1, v4
        BHI     %FT20 ; We're in some ROM above RAM. OK to continue with copy.
        CMP     v3, v5
        BLS     %FT20 ; We're in some ROM/RAM below our copy destination. OK to continue with copy.
        ; Else we currently overlap the area we want to copy ourselves into.
        SUB     v5, v1, lr ; Copy the HAL+OS to just before itself. TODO - This will fail with big ROMs (128MB beagleboard with >42MB ROM size)
20
 [ Use_DMA_Copy
        ; Transfer everything in one DMA frame; this gives us a max ROM size of 64MB-4 bytes
        LDR     a3, =L4_sDMA+DMA4_i
        LDR     a1, [a3, #DMA4_CSRi]
        STR     a1, [a3, #DMA4_CSRi] ; Clear status register
        MOV     a1, lr, LSR #2
        STR     a1, [a3, #DMA4_CENi]
        STR     v5, [a3, #DMA4_CDSAi]
        STR     v1, [a3, #DMA4_CSSAi]
        LDR     a1, =&805080 ; Enable channel with post-increment source & destination, prefetch
        STR     a1, [a3, #DMA4_CCRi]
        ; Wait for copy to complete
30
        LDR     a1, [a3, #DMA4_CSRi]
        TST     a1, #1<<4
        BEQ     %BT30
        ; Make doubly sure that it's finished by checking WR_ACTIVE/RD_ACTIVE
40
        LDR     a1, [a3, #DMA4_CCRi]
        TST     a1, #&600
        BNE     %BT40
 |
        MOV     a1, v5
        MOV     a2, v1 ; Copy source
        MOV     a3, lr
30
        LDR     a4, [a2], #4
        SUBS    a3, a3, #4
        STR     a4, [a1], #4
        BGT     %BT30
 ]
        ; Invalidate I-cache, branch predictors
        MOV     a1, #0
        MCR     p15, 0, a1, c7, c5, 0
        MCR     p15, 0, a1, c7, c5, 6
        DSB     SY ; Wait for I-cache invalidation to complete
        ISB     SY ; Wait for branch predictor invalidation to complete?
        DebugChar a1,a2,68
        ; Jump to our new copy
        ADR     a1, relocate_code ; Keep things simple by just running through the same code again
        SUB     a2, v5, v1
        ADD     a1, a1, a2 ; relocate our branch target
        ADD     v8, v8, a2 ; Update OS entry table ptr
        MOV     pc, a1
10
        ; Copy completed OK.
        ; v2 = size of HAL+OS
        ; v4 = end of OS/RAM
        ; v5 = start of HAL
        ; v8 = OS entry table ptr
        DebugChar a1,a2,69
        DebugTimeNoMMU a1, "ROM relocated @ "
        ; Clear RAM up to v5
        MOV     a1, v5
        BL      clear_ram

        DebugChar a1,a2,70
        DebugTimeNoMMU a1, "RAM cleared @ "

; TODO - NEON seems to be on by default, need to work out how to turn it off before I can test code to turn it on!
;        ; Enable power to the NEON unit, if present
;        LDR     a1, =&4800244C ; 'control OMAP status register'
;        LDR     a1, [a1]
;        TST     a1, #1<<4
;        BNE     %FT10
;;        ; NEON is available, make sure it's turned on
;        ; Enable CP10/CP11 access
;        MRC     p15, 0, a1, c1, c0, 2
;        ORR     a1, a1, #&F<<20
;        MCR     p15, 0, a1, c1, c0, 2
;        ISB     SY
;        ; Now enable the unit
;        MOV     a1, #1<<30 ; EN bit
;        DCI     &EEE80A10 ; VMSR FPEXC, a1

        B       rom_checkedout_ok

        GET     RAM.s
        LTORG

        END