📄 fw_utils.s
字号:
; Drain the write buffers
DrainWriteBuffers
mov r0, #0 ; Data SBZ (R0 = 0)
mcr p15, 0, r0, c7, c10, 4 ; Drain Write Buffers
; Disable the MMU, disable & invalidate I Cache
DisableICacheMMU
mcr p15, 0, r1, c1, c0, 0 ; Disable I cache & MMU
mcr p15, 0, r0, c7, c5, 0 ; Invalidate I Cache
mov pc, r3 ; Branch to the physical address
nop
nop
; MMU is off so we are executing from physical memory addressing
; Reenable I Cache
ReenableICache
orr r3, r1, #0x1000 ; Set the Enable I Cache bit
mcr p15, 0, r3, c1, c0, 0 ; Enable I Cache
IF :DEF: EXAMPLE_MEMCONFIG
ldr r0, =PHYS_MPMC_CNTL_BASE ; Load the MPMC physical base address
; Ensure that MPMC is idle
WaitLoop
ldr r2, [r0, #MPMCStatus] ; Read MPMC status register
and r2, r2, #(MPMCStatus_B_Idle) ; Mask
cmp r2, #(MPMCStatus_B_Idle) ; Check
bne WaitLoop ; Keep polling until MPMC is idle and write buffers are empty
; MPMC can now enter low-power mode cleanly
ldr r3, [r0, #MPMCControl]
orr r3, r3, #MPMCControl_L_LowPower
str r3, [r0, #MPMCControl]
; Set to self-refresh mode
ldr r3, [r0, #MPMCDynamicControl]
orr r3, r3, #MPMCDynamicControl_SR_SelfRefresh
str r3, [r0, #MPMCDynamicControl]
; Poll the status bit in MPMCStatus register
Poll
ldr r2, [r0, #MPMCStatus] ; Read MPMC status register
cmp r2, #MPMCStatus_SA_SelfRefreshMode
bne Poll
ENDIF ; EXAMPLE_MEMCONFIG
; Switch off HCLKSDRAM & MPMCCLK peripheral clocks.
; Leave HCLKSMC & PCLKUART2(UARTDEBUG) enabled.
; Load the System Controller physical base address
; ldr r0, =PHYS_SC_BASE
; ldr r2, =(:NOT:SCPerClkEnPhase2)
; str r2, [r0, #ARM_SCPerDis]
ldr r0, =PHYS_SC_BASE
ldr r2, =SCPerClkHclkSmc
str r2, [r0, #ARM_CLKGATED1]
ldr r0, =PHYS_SC_BASE
ldr r2, =SCPerClkPclkUart2
str r2, [r0, #ARM_CLKGATED2]
; Switch to SLEEP mode and put the core into "Wait for Interrupt" mode
SleepState
orr r3, r1, #0x1000 ; Set the Enable I Cache bit
; Workarounds for cacheable code. ARM926EJ-S Rev0.3 Errata List. CP023-PRDC-001555 5.0.
;
; If the WFI instruction is run from non-cacheable region, and located at an offset of
; between 0x3E8 and 0x3F4 (inclusive) from the previous 1KB boundary, then the WFI will
; execute with the prefetch buffer in a non-full state, and low-power state will not be
; entered correctly.
; For the workaround to operate correctly, the instruction which disables the cache,
; must be offset from the previous 1KB boundary by less then 0x3E4.
ldr r2, =DisableICache
and r2, r2, #0x3FC
cmp r2, #0x3E0
; Clear the control bits to request SLEEP state
ldr r2, [r0, #ARM_SCCtrl]
bic r2, r2, #SCCtrlSetDoze:OR:SCCtrlSetSlow:OR:SCCtrlSetNormal
str r2, [r0, #ARM_SCCtrl] ; Switch to SLEEP state
mov r2, #0 ; Data SBZ
; Branch to the second code set if the first one is near the bottom of 1kb boundary.
; This guarantees that WFI instruction will be issued at the proper offset and
; the processor will be fully switched into low-power mode.
bge WorkAround
; Put the system into low-power state by issuing Disable I Cache and WFI instructions.
DisableICache
mcr p15, 0, r1, c1, c0, 0 ; Disable I cache
mcr p15, 0, r2, c7, c0, 4 ; Wait for Interrupt
; At this point the platform is fully in the low-power state
; Get here after receiving an interrupt
mcr p15, 0, r3, c1, c0, 0 ; Enable I cache
; Set VIC physical address
ldr r2, =PHYS_VIC_BASE
; Check BATOK signal
ldr r3, [r0, #ARM_SCSysStat]
tst r3 , #SCSysStatBatOk ; Test BATOK
bne BatOK ; BATOK so Branch to next intialising section
b NotBatOK
; Put the system into low-power state by issuing Disable I Cache and WFI instructions.
; This is the second set of code sequence to put ARM926EJ-S into low-power mode,
; which is offset from the first one by 8 words.
WorkAround
mcr p15, 0, r1, c1, c0, 0 ; Disable I cache
mcr p15, 0, r2, c7, c0, 4 ; Wait for Interrupt
; At this point the platform is fully in the low-power state
; Get here after receiving an interrupt
mcr p15, 0, r3, c1, c0, 0 ; Enable I cache
; Set VIC physical address
ldr r2, =PHYS_VIC_BASE
; Check BATOK signal
ldr r3, [r0, #ARM_SCSysStat]
tst r3 , #SCSysStatBatOk ; Test BATOK
bne BatOK
; Clear any wake up interrupt sources here as bettery is not okay
NotBatOK
ldr r3, [r2, #ARM_VICIRQStatus]
; NOTE: Update this bitmask
tst r3, #0 ; Bitmask wake up sources
beq SleepState ; Not interrupt
; Clear interrupt on VIC
ldr r3, [r2, #ARM_VICVectAddr]
str r3, [r2, #ARM_VICVectAddr]
; Clear interrupts here
; NOTE: Add interrupt clearing code here
; Now return to sleep
b SleepState
BatOK
; Check if Power Fail signal is still active
ldr r2, [r2, #ARM_VICRawIntr]
tst r2, #IRQ_VIC_PWRFAIL
bne NotBatOK ; Power Fail interrupt is pending. Check for interrupt and go to SLEEP again */
; Switch to the NORMAL state
bic r3, r3, #SCCtrlSetDoze:OR:SCCtrlSetSlow:OR:SCCtrlSetNormal
orr r3, r3, #SCCtrlSetNormal
str r3, [r0, #ARM_SCCtrl] ; Switch to NORMAL state
; Now check if we are in NORMAL state, and BATOK is set
mov r2, #COUNTER ; Set counter
CheckNormal
ldr r3, [r0, #ARM_SCCtrl]
and r3, r3, #(SCCtrlModeStatusMask) ; Mask ModeStatus bits
cmp r3, #(SCCtrlStatusNormal) ; Test ModeNormal Bits
bne RetryCheck
ldr r3, [r0, #ARM_SCSysStat]
tst r3, #SCSysStatBatOk ; Test BATOK
bne StatusOK ; BATOK so Branch to next intialising section
RetryCheck
subs r2, r2, #1 ; Counter--
bne CheckNormal
b SleepState ; Go to SLEEP again
; Clocks are stable and chip is in NORMAL state
StatusOK
; Reenable the previously enabled peripheral clocks
str r4, [r0, #ARM_CLKGATED1] ;
str r5, [r0, #ARM_CLKGATED2]
; Check peripheral clocks have been setup
CheckClocks
ldr r1, [r0, #ARM_CLKGATED1] ;
cmp r1, r4
bne CheckClocks
ldr r1, [r0, #ARM_CLKGATED2] ;
cmp r1, r5
bne CheckClocks
; Wait until the peripheral clocks are running
;CheckClocksRunning
; ldr r1, [r0, #ARM_SCPerStat] ;
; cmp r1, r4
; bne CheckClocksRunning
IF :DEF: EXAMPLE_MEMCONFIG
; Load the MPMC physical base address
ldr r0, =PHYS_MPMC_CNTL_BASE
; Re-enable SDRAM, clear the self-refresh bit
ldr r1, [r0, #MPMCDynamicControl]
bic r1, r1, #MPMCDynamicControl_SR_SelfRefresh
str r1, [r0, #MPMCDynamicControl]
; Perform extra-refresh cycles to allow SDRAM to exit self-refresh mode cleanly.
; Read MPMCRefreshRegister, save the value temporarily in R2
ldr r2, [r0, #MPMCDynamicRefresh]
; Reprogram it to 0x1
mov r1, #1
str r1, [r0, #MPMCDynamicRefresh]
; Wait 66000 HCLK cycles
ldr r3, =PHYS_CT2_BASE;
; Configure Timer 2 i.e. the third timer
; Enable the timer in wrapping mode, 32-bit counter, no prescale, free run mode
mov r1, #(TIMER_ENABLE :OR: TIMER_MODE_32BIT)
; Store in Timer2Control register
str r1, [r3, #Timer0Control] ;
mov r1, #HCLK_66000 ; Wait 66000 HCLK cycles
str r1, [r3, #Timer0Load] ; Store the wait time
TimerWait
ldr r1, [r3, #Timer0Value] ; Load the current timer value
cmp r1, #0
bgt TimerWait
; Clear and disable the timer
mov r1, #0
str r1, [r3, #Timer0Control] ; Clear Timer2Control
str r1, [r3, #Timer0Load] ; Clear Timer2Load
; Restore MPMCRefreshRegister
str r2, [r0, #MPMCDynamicRefresh] ;
ENDIF ; EXAMPLE_MEMCONFIG
; Enable the MMU, disable & invalidate I Cache
mov r0, #0 ; Data SBZ
mrc p15, 0, r1, c1, c0, 0 ; Read the current MMU control register status
orr r1, r1, #1 ; Set the MMU Enable bit
bic r2, r1, #0x1000 ; Clear the Enable I Cache bit
mcr p15, 0, r2, c1, c0, 0 ; Disable I cache, enable MMU
mcr p15, 0, r0, c7, c5, 0 ; Invalidate I Cache
; Branch to the virtual address
mov pc, lr
nop
nop
; Executed from the virtual address
EnableCaches
orr r1, r1, #4 ; Set the Enable D Cache bit
mcr p15, 0, r1, c1, c0, 0 ; Enable I & D Caches
ldmfd sp!, {r0,r1,r4,r5,lr} ; Load the saved values from the stack
mcr p15, 0, r1, c13, c0, 0 ; Write the previous PID value back
; Enable interrupts
and r0, r0, #0xc0
mrs r1, cpsr
bic r1, r1, #0xc0
orr r0, r0, r1
msr cpsr, r0 ; Restore FIQ & IRQ Enable bits
mov pc, lr
ENDIF ; IF EBOOT
ENTRY_END
ENDIF ; EXAMPLE_POWERDOWN
END
; EOF fw_utils.s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -