fw_arm.s
字号:
; -*-Text-*-
;
; TITLE("Integrator Firmware Initialization")
;
; $Revision: 1.13 $
; $Author: kwelton $
; $Date: 2000/08/11 23:17:33 $
;
; Copyright (c) 1997 Microsoft Corporation
; Copyright (c) 1999 ARM Limited
; All Rights Reserved
;
; Module Name:
;
; fw_arm.s
;
; Abstract:
;
; This module implements the code necessary to initialize the HW and
; Kernel interface routines.
;
;--
;
; This one source file is used to provide Startup code both for the
; Ethernet Boot Loader, and for the WinCE kernel. The default is to
; build for the WinCE kernel
;
IF :LNOT: :DEF: EBOOT
GBLL EBOOT
EBOOT SETL {FALSE}
ENDIF
GBLL SteveRavetsCode
SteveRavetsCode SETL {TRUE}
OPT 2 ; disable listing
INCLUDE kxarm.h
INCLUDE oalintra.inc
OPT 1 ; reenable listing
INCLUDE sizes.s
INCLUDE bits.s
INCLUDE platform.s
INCLUDE cpumodes.s
INCLUDE target.s
IMPORT ARMInitSerial
IMPORT ARMPutHex
IMPORT ARMWriteString
IMPORT ARMSetLEDs
IMPORT ARMSetAlpha
IF EBOOT
IMPORT EbootMain
IMPORT EverythingRelocate
ELSE
IMPORT KernelStart
ENDIF
IF FORCE_TGTCPU = "ARM720"
CP15ControlInit EQU 0x00000270 ; Little-Endian
; MMU Disabled
ENDIF
IF FORCE_TGTCPU = "ARM920"
CP15ControlInit EQU 0xc0001078 ; Async. Bus mode
; I-Cache enabled
; Little-Endian
; MMU Disabled
ENDIF
STARTUPTEXT
LEAF_ENTRY StartUp
;
; There are two ways into StartUp: from the bootmonitor/reset or from
; wake up. In either case, the processor should be in a privileged mode
; (e.g. SVC) with the MMU disabled. If the MMU might be active, there
; needs to be code to ensure that the executable is still at the next
; address when the MMU is turned off.
;
; disable all interrupts, set SVC mode
mov r0, #(SVC32Mode :OR: NoINTS)
msr cpsr_c, r0
; ****************** FALSE
[ {FALSE}
;
; XXX TRACE XXX TRACE XXX TRACE XXX
;
; This is ARM10200 AHB code, here temporarily so we can
; try and clock the chip as fast as possible. This will
; almost certainly not work on a '920 board.
;
ldr r0, =0x00000070 ; I & D cache off, wb off, mmu off
mcr p15, 0, r0, c1, c0, 0
;
; Init Integrator registers
;
mov r0, #0x10000000
ldr r1, =0xa05f
str r1, [r0, #0x14] ; unlock OSC & Init registers
;
; INIT register (bit 2 = HIVECInit, 4,5 HBUSDIV, 8-11 PLLTest,
; 12-13 = VFPTest)
;
ldr r1, [r0, #0x24]
;
; bit 1 tells whether the PLL is in bypass or not - if it isn't then we
; can proceed with the clock setup
;
tst r1, #0x02
beq pllactive
bic r1, r1, #0x3f00
bic r1, r1, #0x0034
IF SteveRavetsCode
;
; make GCLK observable on CLKTSTOUT
;
orr r1, r1, #0x0800
ENDIF
str r1, [r0, #0x24]
;
; OSC register contains clock input speed in MHz
;
ldr r1, [r0, #0x8]
bic r1, r1, #0xff
IF SteveRavetsCode
orr r1, r1, #50
ELSE
orr r1, r1, #80
ENDIF
sub r1, r1, #8
str r1, [r0, #0x8]
;
; program ARM10200 PLL
;
IF SteveRavetsCode
mov r0, #2 ; MDIV
mov r1, #1 ; F1DIV
mov r2, #2 ; F2DIV
ELSE
mov r0, #1 ; MDIV
mov r1, #1 ; F1DIV
mov r2, #1 ; F2DIV
mov r0, r0, lsl #1
ENDIF
;
; these seemingly strange subtracts are to convert from the
; required values to the values that need to be programmed
; into the PLL to acheive those requirements
;
sub r0, r0, #1
sub r1, r1, #1
sub r2, r2, #1
orr r2, r2, r1, lsl #5
orr r2, r2, r0, lsl #10
mcr p15, 0, r0, c15, c12, 0
; ****************** FALSE
[ {FALSE}
;
; we need to force a reset before the new settings take effect
;
; set yellow LED before forcing reset
;
mov r0, #YELLOW_LED
bl ARMSetLEDs
mov r0, #0x10000000
ldr r1, [r0, #0x0c]
orr r1, r1, #1 << 3
str r1, [r0, #0x0c]
;
; XXX SHOULD NOT BE REACHED
;
mov r0, #RED_LED
bl ARMSetLEDs
pllspin b pllspin
; ********************** End of FALSE
]
pllactive
mov r0, #GREEN_LED
bl ARMSetLEDs
; ********************** End of FALSE
]
;
; now reset all CP15 features
;
ldr r0, =CP15ControlInit
WRMMU_STATE r0
mov r0, #0x0
WRMMU_FlushTB r0 ; flush TLBs
WRCACHE_FlushIDC r0 ; flush caches
;
; Make sure we're running from the physical memory address and
; not an address mapped to 0 (the normal reset state).
;
GOTO_ROM r0, r1
DISABLE_INTS r0, r1 ; Ints -> IRQ; LEDs
; Now, if the reset was caused by a wake-up from sleep, control isn't
; passed to KernelStart, but some reload-saved-state mechanism instead.
; Put StrongARM wake-up test in here...
; ..and branch away from power-on start.
; NOTE: Most ARM processors don't go to sleep
INIT_RAM r0, r1, r2 ; Size returned in r2
;
; only used temporarily, but setup a stack for use by 'C' routines; the
; Integrator always has 256Kb of SSRAM, so we use that
;
; the first use of the stack is to save the memory size returned from
; the INIT_RAM macro
;
ldr sp, =(INTEGRATOR_SSRAM_BASE + INTEGRATOR_SSRAM_SIZE)
str r2, [sp, #-4]!
IF EBOOT
;
; Relocate code from Flash to RAM if necessary. This step is required
; because EBOOT code runs from physical, not virtual, addresses
;
; returns with r0 = linked address for Startup, -1 if currently
; executing in the correct place
;
bl EverythingRelocate
;
; branch to final execution address if necessary
;
cmp r0, #-1
addne r0, r0, #(RealStartup - StartUp)
movne pc, r0
ENDIF
RealStartup
SETUP_PCI r0, r1, r2, r3
;
; XXX
;
; After setting up PCI, there is some necessary settle time before the
; interface can be used. It >was< hoped that this would prove to be
; not necessary, but sadly not.
;
mov r0, #1000
mov r1, #0
bl msecswait
;
; init the debug serial port and say "hello".
;
bl ARMInitSerial
adr r0, HelloMsg
bl ARMWriteString
adr r0, MemMsg
bl ARMWriteString
ldr r0, [sp], #4
bl ARMPutHex
adr r0, StackMsg
bl ARMWriteString
mov r0, sp
bl ARMPutHex
adr r0, EndMsg
bl ARMWriteString
mov r0, #0 ; Turn off the discrete LEDs
bl ARMSetLEDs
mov r0, #0
bl ARMSetAlpha ; Turn off the Alphanumeric LEDs
IF EBOOT
bl EbootMain
ELSE
; (r0) = physical address of OEMMemoryMap
adr r0, OEMAddressTable
bl KernelStart
ENDIF
;
; control should never return to this routine; if it does, output
; some debug & spin
;
;
; Display a pattern of two stars on the Alphanumeric LEDs, and turn on
; the red LED
;
ldr r0, =0x1fe07f80 ; bit pattern for two stars
bl ARMSetAlpha
mov r0, #RED_LED
bl ARMSetLEDs
adr r0, ByeMsg
bl ARMWriteString
spin b spin
IF EBOOT
HelloMsg DCB 13, 10, "ARM Ethernet Boot Loader", 13, 10, 0
ByeMsg DCB 13, 10, "ARMInt_Eboot returned!", 13, 10, 0
ELSE
HelloMsg DCB 13, 10, "WindowsCE on ARM", 13, 10, 0
ByeMsg DCB 13, 10, "KernelStart returned!", 13, 10, 0
ENDIF
MemMsg DCB " Memory size: ", 0
StackMsg DCB 13, 10, " Stack Pointer: ", 0
EndMsg DCB 13, 10, 0
ALIGN 4
IF :LNOT: EBOOT
INCLUDE maparm.h
ENDIF
; End of initialization code & data
TEXTAREA
; **********************************************************************
;
; msecswait - uses timer2 to wait for a given number of milliseconds
;
; NOTE: this routine can only be used very early on in the system bootstrap
; process (i.e. only before OEMInit() has been called) because it
; takes no care to preserve current timer state
;
LEAF_ENTRY msecswait
;
; check that we are being asked to wait
;
cmp r0, #0
IF Thumbing
bxeq lr
ELSE
moveq pc, lr
ENDIF
str r4, [sp, #-4]!
;
; point r1 at timer2 control registers
;
ldr r2, =INTEGRATOR_TIMER2_BASE
add r1, r1, r2
;
; We use Timer2 which is clocked at 24MHz. Dividing the clock by 16 gives
; 1500 ticks per millisecond
;
mov r2, #0x44 ; clock/16, periodic, disabled
strb r2, [r1, #8]
ldr r3, =1500
strh r3, [r1, #0]
orr r2, r2, #0x80 ; set enabled bit
strb r2, [r1, #8]
;
; read the current timer register value, and check whether it reached zero
;
mov r4, r3
msloop
ldrh r2, [r1, #4]
cmp r2, #0
beq decmscount
;
; it's not zero - check whether it has gone through zero
; and reloaded already
;
cmp r2, r3
movls r3, r2
bls msloop
;
; counter has reached/gone through zero - that's another millisecond
; gone; reset underflow comparator
;
decmscount
subs r0, r0, #1
mov r3, r4
bhi msloop
;
; OK - turn counter off and return
;
mov r2, #0
strb r2, [r1, #8]
ldr r4, [sp], #4
IF Thumbing
bx lr
ELSE
mov pc, lr
ENDIF
; **********************************************************************
IF EBOOT
LEAF_ENTRY GetPC
mov r0, pc
mov pc, lr
ELSE
LEAF_ENTRY OEMPowerOff
; OEMPowerOff - OFF button handler
;
; This routine is invoked when the OFF button is pressed. It is responsible
; for any final power off state and putting the cpu into standby.
;
; Entry none
; Exit none
; Uses r0-r3
mov pc, lr
CLOCK_LEDS EQU 1
LEAF_ENTRY OEMIdle
; OEMIdle - system idle
;
; This routine is called by the kernel when there are no threads ready to
; run. The CPU should be put into a reduced power mode and halted. It is
; important to be able to resume execution quickly upon receiving an interrupt.
;
; NOTE: Exceptions are blocked when this routine called and must not be
; reenabled unless the functions is going to return immediately.
;
; Entry Interrupts disabled
; Exit none
; Uses r0-r1
IF :DEF: CLOCK_LEDS :LAND: CLOCK_LEDS = 1
IMPORT CurMSec
IMPORT OEMWriteDebugLED
; Simple debug, just show no of seconds (approx)
stmfd sp!, {r0-r1, lr}
;ldr r1, =CurMSec
;ldr r1, [r1]
;mov r1, r1, LSR #10 ; mSec / 1024 ~= Sec
;mov r0, #0
;bl OEMWriteDebugLED
ldmfd sp!, {r0-r1, pc}
ENDIF
ENDIF ; EBOOT
END
; EOF fw_arm.s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -