; 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.
;
init_ram
        ; Make sure all attached RAM is initialised
        ; Although x-loader will initialise some RAM for us, it might not necessarily use the best settings, and it might not initialise all the RAM that's available (e.g. CS1 on rev C beagleboard)
        ; This code roughly follows the sdrc_init()/dram_init() flow in u-boot

        LDR     v1, =SDRC_Regs
        ; CS0 setup:
        ; - If we're not running from SDRAM, (re)init CS0
        MOV     a1, pc
        CMP     a1, #CS0_SDRAM
        BGE     %FT10
        ; do_sdrc_init(CS0,EARLY_INIT)
        ; First we reset SDRC
        MOV     a1, #2
        STR     a1, [v1, #SDRC_SYSCONFIG] ; SOFTRESET
        MOV     a2, #12*1024*1024
20
        LDR     a1, [v1, #SDRC_SYSSTATUS]
        TST     a1, #1
        BNE     %FT30
        SUBS    a2, a2, #1
        BNE     %BT20
30
        MOV     a1, #0
        STR     a1, [v1, #SDRC_SYSCONFIG]
        ; Setup SDRC to ball mux. Or something.
        MOV     a1, #&100
        STR     a1, [v1, #SDRC_SHARING]
        ; Disable powerdown via CKE
        MOV     a1, #&81
        STR     a1, [v1, #SDRC_POWER_REG]
        ; Enable DLL, 90 degree phase
        MOV     a1, #&A
        STR     a1, [v1, #SDRC_DLLA_CTRL]
        ; Wait for lock (indefinitely?)
20
        LDR     a1, [v1, #SDRC_DLLA_STATUS]
        TST     a1, #4
        BEQ     %BT20

        ; Now initialise CS0
        LDR     a1, =&02584099 ; 128MB, etc.
        STR     a1, [v1, #SDRC_MCFG_0]
        LDR     a1, =&4E201
        STR     a1, [v1, #SDRC_RFR_CTRL_0]
        LDR     a1, =(21 :SHL: 27) :OR: (10 :SHL: 22) :OR: (7 :SHL: 18) :OR: (3 :SHL: 15) :OR: (3 :SHL: 12) :OR: (2 :SHL: 9) :OR: (3 :SHL: 6) :OR: 6
        STR     a1, [v1, #SDRC_ACTIM_CTRLA_0] ; 165MHz timings
        LDR     a1, =(1 :SHL: 12) :OR: 23 :OR: (5 :SHL: 8) :OR: (1 :SHL: 16)
        STR     a1, [v1, #SDRC_ACTIM_CTRLB_0]
        ; NOP, PRECHARGE, AUTOREFRESH, AUTOREFRESH sequence
        MOV     a1, #0
        STR     a1, [v1, #SDRC_MANUAL_0]
        MOV     a1, #1
        STR     a1, [v1, #SDRC_MANUAL_0]
        MOV     a1, #2
        STR     a1, [v1, #SDRC_MANUAL_0]
        STR     a1, [v1, #SDRC_MANUAL_0]
        ; CAS latency, burst length, etc.
        MOV     a1, #&32
        STR     a1, [v1, #SDRC_MR_0]
        ; Now check the setup
        ; This is the same technique as mem_ok() in u-boot
        LDR     a1, =CS0_SDRAM
        MOV     a2, #0
        LDR     a3, =&12345678
        STR     a2, [a1, #&400]
        STR     a3, [a1]
        STR     a2, [a1, #4]
        LDR     a2, [a1, #&400]
        LDR     a4, [a1]
        CMP     a2, #0
        CMPEQ   a3, a4
        BEQ     %FT10 ; It's good
        ; Else it's bad and we need to disable CS0
        MOV     a1, #0
        STR     a1, [v1, #SDRC_MCFG_0]
10
        ; Check if CS1 is active
        ; If not, and we're a rev C beagleboard, activate it
        LDR     a1, [v1, #SDRC_MCFG_1]
        LDR     a2, =&3FF00
        TST     a1, a2
        BNE     %FT10
        ; Beagleboard rev C check:
        ; Although the manual fails to mention it, apparently GPIO 171 will be low if we're on rev C
        ; Else we're rev A/B
        LDR     a2, =L4_GPIO6
        LDR     a1, [a2, #GPIO_OE]
        ORR     a1, a1, #1:SHL:11
        STR     a1, [a2, #GPIO_OE]
        ; Wait a bit just to make sure the input is up to date
        MOV     a1, #32768
5
        SUBS    a1, a1, #1
        BNE     %BT5
        LDR     a1, [a2, #GPIO_DATAIN]
        TST     a1, #1:SHL:11
        BNE     %FT10

        ; Make CS0 and CS1 contiguous, in case it helps RISC OS a bit (e.g. finding large areas of contiguous physical memory for IO)
        LDR     a1, [v1, #SDRC_MCFG_0]
        LDR     a2, =&3FF<<1
        ANDS    a1, a2, a1, LSR #7 ; CS0 size in MB
        BEQ     %FT5 ; If no CS0, just program offset of 0
        CMP     a1, #32
        MOVLT   a1, #32 ; Min 32MB offset if CS0 present
        ; Round up to power of two
        SUB     a2, a1, #1
        TST     a2, a1
        CLZNE   a2, a1
        MOVNE   a1, #1
        MOVNE   a1, a1, ROR a2
5
        AND     a2, a1, #&60 ; 32MB offset
        MOV     a1, a1, LSR #7 ; 128MB offset
        ORR     a1, a1, a2, LSL #3
        STR     a1, [v1, #SDRC_CS_CFG]

        ; Initialise CS1
        LDR     a1, =&02584099 ; 128MB, etc.
        STR     a1, [v1, #SDRC_MCFG_1]
        LDR     a1, =&4E201
        STR     a1, [v1, #SDRC_RFR_CTRL_1]
        LDR     a1, =(21 :SHL: 27) :OR: (10 :SHL: 22) :OR: (7 :SHL: 18) :OR: (3 :SHL: 15) :OR: (3 :SHL: 12) :OR: (2 :SHL: 9) :OR: (3 :SHL: 6) :OR: 6
        STR     a1, [v1, #SDRC_ACTIM_CTRLA_1] ; 165MHz timings
        LDR     a1, =(1 :SHL: 12) :OR: 23 :OR: (5 :SHL: 8) :OR: (1 :SHL: 16)
        STR     a1, [v1, #SDRC_ACTIM_CTRLB_1]
        ; NOP, PRECHARGE, AUTOREFRESH, AUTOREFRESH sequence
        MOV     a1, #0
        STR     a1, [v1, #SDRC_MANUAL_1]
        MOV     a1, #1
        STR     a1, [v1, #SDRC_MANUAL_1]
        MOV     a1, #2
        STR     a1, [v1, #SDRC_MANUAL_1]
        STR     a1, [v1, #SDRC_MANUAL_1]
        ; CAS latency, burst length, etc.
        MOV     a1, #&32
        STR     a1, [v1, #SDRC_MR_1]
        ; Now check the setup
        LDR     a1, =CS0_SDRAM
        LDR     a4, [v1, #SDRC_CS_CFG]
        AND     a3, a4, #7 ; Offset in 128MB units
        ADD     a1, a1, a3, LSL #20+7
        AND     a3, a4, #&300 ; Offset in 32MB units
        ADD     a1, a1, a3, LSL #20+5-8 ; a1 = CS1 start
        MOV     a2, #0
        LDR     a3, =&12345678
        STR     a2, [a1, #&400]
        STR     a3, [a1]
        STR     a2, [a1, #4]
        LDR     a2, [a1, #&400]
        LDR     a4, [a1]
        CMP     a2, #0
        CMPEQ   a3, a4
        BEQ     %FT10 ; It's good
        ; Else it's bad and we need to disable CS1
        MOV     a1, #0
        STR     a1, [v1, #SDRC_MCFG_1]
10
        ; Done!
        MOV     pc, lr



; a1 <= Highest physical address in RAM +1
get_end_of_ram
        LDR     v1, =SDRC_Regs
        LDR     a3, [v1, #SDRC_MCFG_1]
        LDR     a2, =&3FF00<<13
        ANDS    a3, a2, a3, LSL #13
        BEQ     %FT10
        LDR     a2, =CS0_SDRAM
        LDR     a4, [v1, #SDRC_CS_CFG]
        AND     v2, a4, #7 ; Offset in 128MB units
        ADD     a2, a2, v2, LSL #20+7
        AND     v2, a4, #&300 ; Offset in 32MB units
        ADD     a2, a2, v2, LSL #20+5-8
        ADD     a1, a3, a2
        MOV     pc, lr
10
        ; No RAM in CS1; therefore must be in CS0
        LDR     a3, [v1, #SDRC_MCFG_0]
        LDR     a2, =&3FF00<<13
        AND     a3, a2, a3, LSL #13 ; Get CS0 RAM size
        LDR     a2, =CS0_SDRAM
        ADD     a1, a3, a2
        MOV     pc, lr



clear_ram
        ; Clear everything up to a1
        ; This relies on the clear areas being multiples of 128 bytes in length
        MOV     v2, a1
        LDR     v1, =SDRC_Regs
        LDR     a3, [v1, #SDRC_MCFG_0]
        LDR     a2, =&3FF00<<13
        ANDS    a3, a2, a3, LSL #13 ; Get CS0 RAM size
        BEQ     %FT10
        LDR     a2, =CS0_SDRAM
        SUB     a1, v2, a2
        CMP     a1, a3
        MOVGT   a1, a3 ; Work out how much we're meant to be clearing
        MOV     a3, #0
        MOV     a4, #0
        MOV     v1, #0
        MOV     v3, #0
        MOV     v4, #0
        MOV     v5, #0
        MOV     sp, #0
        MOV     ip, #0
20
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 32 bytes
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 64 bytes
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 96 bytes
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 128 bytes
        SUBS    a1, a1, #128
        BGT     %BT20
10
        LDR     v1, =SDRC_Regs
        LDR     a3, [v1, #SDRC_MCFG_1]
        LDR     a2, =&3FF00<<13
        ANDS    a3, a2, a3, LSL #13
        BEQ     %FT30
        LDR     a2, =CS0_SDRAM
        LDR     a4, [v1, #SDRC_CS_CFG]
        AND     v3, a4, #7 ; Offset in 128MB units
        ADD     a2, a2, v3, LSL #20+7
        AND     v3, a4, #&300 ; Offset in 32MB units
        ADD     a2, a2, v3, LSL #20+5-8
        SUB     a1, v2, a2
        CMP     a1, a3
        MOVGT   a1, a3 ; Work out how much we're meant to be clearing
        MOV     a3, #0
        MOV     a4, #0
        MOV     v1, #0
        MOV     v3, #0
        MOV     v4, #0
        MOV     v5, #0
        MOV     sp, #0
        MOV     ip, #0
40
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 32 bytes
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 64 bytes
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 96 bytes
        STMIA   a2!,{a3,a4,v1,v3,v4,v5,sp,ip} ; 128 bytes
        SUBS    a1, a1, #128
        BGT     %BT40
30
        MOV     pc, lr

        END