; Basic MLO - test/diagnostics ; ; by Rick Murray ; Version: 0.01b ; Date : Wednesday, 13th June 2012 ; ; Our inclusions GET ^.h.equx ; EQUB, EQUD, EQUSZ, EQUSZA... GET ^.h.SWINames ; SWI definitions GET ^.h.pushpull ; Push, Pull, PushLR, PullLR, Return, PullRet... GET ^.h.debug ; DebugMsg (only used during actual debugging) ; LED mask - USERLED0 = GPIO #149; USERLED1 = GPIO #150. USERLED0 * 1 << 21 USERLED1 * 1 << 22 ; GPIO5 base address held in code, . ; GPIO-specific register offsets (from GPIO base) GPIO_OE * &34 GPIO_DATAOUT * &3C GPIO_CLRDATAOUT * &90 GPIO_SETDATAOUT * &94 ; =========== ; Here we go! ; =========== AREA |MLO$Code|, CODE ENTRY prefix EQUD ((end - start) + 4) ; size of image EQUD &40200800 ; load address start ; What we know at this point: ; ; Our file must be called "MLO" and be less than 128K on a FAT12/16/32 ; filesystem (with/without MBR). [TRM p3578] ; ; The L2 cache is disabled [TRM p3537] ; Our code should be at &40200800 ; Stack should be at &4020F000 [TRM p3542] ; Exceptions start at 4020FFC8 [TRM p3542] ; Code must be prefixed by size [word] and address [word] [TRM p3590] ; Code is entered in "public ARM supervisor mode" [wtf? you mean SVC32?] ; R0 points to boot data structure (unimportant...) [TRM p3591] ; ; Helpfully, no mention is made of cache or MMU, so we'll assume it is all ; off at point of entry. This would be backed up by "When an MMU instance is ; released from reset, its TLB is empty and the MMU is disabled." [TRM p2673] ; We shall, however, be paranoid and force these things OFF in case the boot ; code made use of them... ; ; force ourselves into SVC32 MRS R0, CPSR BIC R0, R0, #&1F ORR R0, R0, #&D3 MSR CPSR, R0 ; invalidate TLB and L1 instruction cache [just in case] MOV R0, #0 MCR p15, 0, R0, c8, c7, 0 ; invalidate TLBs [ARM ARM 2nd pB3-26] MCR p15, 0, R0, c7, c5, 1 ; invalidate icache [ARM ARM 2nd pB5-16] ; kill the MMU [just in case] MRC p15, 0, R0, c1, c0, 0 ; read status [below, from Cortex-A8 TRM p3-59(etc)] BIC R0, R0, #&2000 ; clear bit 13 'V' (set low vectors) BIC R0, R0, #&7 ; clear bits 0-2 'CAM' (no dcache, alignchk off, mmu off) ORR R0, R0, #&2 ; set bit 1 'A' (alignchk back on) ORR R0, R0, #&1800 ; set bits 11 and 12 'IZ' (icache on, branch predict on) MCR p15, 0, R0, c1, c0, 0 ; write it back ; With the MMU disabled, virtual addresses == physical addresses [ARM ARM 2nd pB3-5] ; At this point we should probably attempt to identify the chip and fail if it ; isn't an OMAP3730. There are other (GPIO) things to do to identify for certain ; that we're running on a Beagle xM. ; Now a TI specific thing - set the protection mechanism to allow access ; to everything. The method of this was taken from the X-Loader binary, from ; offset +&1080. ; What actually happens and how is documented in the OMAP 3730 TRM p2041++. MOV R1, #&FFFFFFFF ; 32 bits LDR R2, HALFWORD ; 16 bits (&FFFF) MOV R3, #0 ; zero LDR R8, L3_PM_RT_Address ; L3_PM_RT base address [TRM p2041] LDR R9, L3_PM_GPMC_Address ; L3_PM_GPMC base address [ditto...] LDR R10, L3_PM_OCM_RAM_Address ; L3_PM_OCM_RAM base addr LDR R11, L3_PM_IVA_Address ; L3_PM_IVA base address (video acceleration) LDR R12, SMS_REGION_ATT_Address ; For SMS attribute ; *WE* don't need to do anything with the IVA, but not unlocking it could ; bugger up stuff downstream. PERMISSION_0 * &48 PERMISSION_1 * &68 READ_PRIVS * &50 WRITE_PRIVS * &58 ADDR_MATCH_1 * &60 ADDR_MATCH_2 * &80 ; First sort out the protection module itself (Register Target ("RT")) ; (order of writing from X-Loader code) ; TRM says: ; "An RT is a specialized TA used to access L3 interconnect ; internal configuration registers." ; Reads like a bloody Wiki page. It's at the bottom of p2000 onwards. STR R1, [R8, #PERMISSION_1] ; (L3_PM_RT + PERMISSION_1) = &FFFFFFF STR R1, [R8, #READ_PRIVS] STR R1, [R8, #WRITE_PRIVS] STR R3, [R8, #ADDR_MATCH_1] ; = &0; see note on TRM p2003 ;-) ; Now the General Purpose Memory Controller (GPMC) STR R2, [R9, #PERMISSION_0] ; = &FFFF STR R2, [R9, #READ_PRIVS] ; = &FFFF STR R2, [R9, #WRITE_PRIVS] ; = &FFFF ; Next the On Chip RAM STR R2, [R10, #PERMISSION_0] ; = &FFFF STR R2, [R10, #READ_PRIVS] ; = &FFFF STR R2, [R10, #WRITE_PRIVS] ; = &FFFF STR R3, [R10, #ADDR_MATCH_2] ; = &0 ; (don't need to do ROM) ; The video stuff STR R2, [R11, #PERMISSION_0] ; = &FFFF STR R2, [R11, #READ_PRIVS] ; = &FFFF STR R2, [R11, #WRITE_PRIVS] ; = &FFFF ; Finally, the SDRAM memory scheduler STR R1, [R12] ; = &FFFFFFFF B skip_addresses HALFWORD EQUD &FFFF L3_PM_RT_Address EQUD &68010000 ; L3_PM_RT base address [TRM p2041] L3_PM_GPMC_Address EQUD &68012400 ; L3_PM_GPMC base address [ditto...] L3_PM_OCM_RAM_Address EQUD &68012800 ; L3_PM_OCM_RAM base addr L3_PM_IVA_Address EQUD &68014000 ; L3_PM_IVA base address (video acceleration) SMS_REGION_ATT_Address EQUD &6C000048 ; For SMS attribute GPIO5_Address EQUD &49056000 ; GPIO5 base address skip_addresses ; At this point we should probably try to identify the memory type ; and initialise it. This is a pain in the ass so we'll skip it until ; we actually need to use SDRAM. Like, when we see an LED turn on! ; Later : We will only be able to run for ten seconds before the MPU ; watchdog kicks in and resets; so this will need to be nobbled. ; Refer to TRM p2762. ; For now, have we brought up the thing enough to turn on the LEDs? ; [t'was much easier "back in the day" getting a 6502 board running!!!] ; set LED GPIO bits for output LDR R10, GPIO5_Address ; GPIO base MOV R1, R10 ADD R1, R1, #GPIO_OE ; Address to GPIO OE in R1 MOV R2, #USERLED0 ADD R2, R2, #USERLED1 MVN R3, R2 ; Bitmask of LEDs in R2 ; Inverted copy in R3 ; force LED GPIOs to be outputs LDR R0, [R1] ; load AND R0, R0, R3 ; modify: value = value AND NOT leds STR R0, [R1] ; store ; force LEDs on MOV R1, R10 ADD R1, R1, #GPIO_SETDATAOUT STR R2, [R1] ; dead loop - we're done for now... dead_loop B dead_loop EQUS "Rick's MiniMLO test1" end END