1/* 2 * U-Boot - start.S Startup file for Blackfin U-Boot 3 * 4 * Copyright (c) 2005-2008 Analog Devices Inc. 5 * 6 * This file is based on head.S 7 * Copyright (c) 2003 Metrowerks/Motorola 8 * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, 9 * Kenneth Albanowski <kjahds@kjahds.com>, 10 * The Silver Hammer Group, Ltd. 11 * (c) 1995, Dionne & Associates 12 * (c) 1995, DKG Display Tech. 13 * 14 * SPDX-License-Identifier: GPL-2.0+ 15 */ 16 17#include <config.h> 18#include <asm/blackfin.h> 19#include <asm/mach-common/bits/watchdog.h> 20#include <asm/mach-common/bits/core.h> 21#include <asm/mach-common/bits/pll.h> 22#include <asm/serial.h> 23 24/* It may seem odd that we make calls to functions even though we haven't 25 * relocated ourselves yet out of {flash,ram,wherever}. This is OK because 26 * the "call" instruction in the Blackfin architecture is actually PC 27 * relative. So we can call functions all we want and not worry about them 28 * not being relocated yet. 29 */ 30 31.text 32ENTRY(_start) 33 34 /* Set our initial stack to L1 scratch space */ 35 sp.l = LO(L1_SRAM_SCRATCH_END - 20); 36 sp.h = HI(L1_SRAM_SCRATCH_END - 20); 37 38 /* Optimization register tricks: keep a base value in the 39 * reserved P registers so we use the load/store with an 40 * offset syntax. R0 = [P5 + <constant>]; 41 * P4 - system MMR base 42 * P5 - core MMR base 43 */ 44#ifdef CONFIG_HW_WATCHDOG 45 p4.l = 0; 46 p4.h = HI(SYSMMR_BASE); 47#endif 48 p5.l = 0; 49 p5.h = HI(COREMMR_BASE); 50 51#ifdef CONFIG_HW_WATCHDOG 52 /* Program the watchdog with default timeout of ~5 seconds. 53 * That should be long enough to bootstrap ourselves up and 54 * then the common U-Boot code can take over. 55 */ 56 r1 = WDDIS; 57# ifdef __ADSPBF60x__ 58 [p4 + (WDOG_CTL - SYSMMR_BASE)] = r1; 59# else 60 W[p4 + (WDOG_CTL - SYSMMR_BASE)] = r1; 61# endif 62 SSYNC; 63 r0 = 0; 64 r0.h = HI(MSEC_TO_SCLK(CONFIG_WATCHDOG_TIMEOUT_MSECS)); 65 [p4 + (WDOG_CNT - SYSMMR_BASE)] = r0; 66 SSYNC; 67 r1 = WDEN; 68 /* fire up the watchdog - R0.L above needs to be 0x0000 */ 69# ifdef __ADSPBF60x__ 70 [p4 + (WDOG_CTL - SYSMMR_BASE)] = r1; 71# else 72 W[p4 + (WDOG_CTL - SYSMMR_BASE)] = r1; 73# endif 74 SSYNC; 75#endif 76 77 /* Turn on the serial for debugging the init process */ 78 serial_early_init 79 serial_early_set_baud 80 81 serial_early_puts("Init Registers"); 82 83 /* Disable self-nested interrupts and enable CYCLES for udelay() */ 84 R0 = CCEN | 0x30; 85 SYSCFG = R0; 86 87 /* Zero out registers required by Blackfin ABI. 88 * http://docs.blackfin.uclinux.org/doku.php?id=application_binary_interface 89 */ 90 r1 = 0 (x); 91 /* Disable circular buffers */ 92 l0 = r1; 93 l1 = r1; 94 l2 = r1; 95 l3 = r1; 96 /* Disable hardware loops in case we were started by 'go' */ 97 lc0 = r1; 98 lc1 = r1; 99 100 /* Save RETX so we can pass it while booting Linux */ 101 r7 = RETX; 102 103#if CONFIG_MEM_SIZE 104 /* Figure out where we are currently executing so that we can decide 105 * how to best reprogram and relocate things. We'll pass below: 106 * R4: load address of _start 107 * R5: current (not load) address of _start 108 */ 109 serial_early_puts("Find ourselves"); 110 111 call _get_pc; 112.Loffset: 113 r1.l = .Loffset; 114 r1.h = .Loffset; 115 r4.l = _start; 116 r4.h = _start; 117 r3 = r1 - r4; 118 r5 = r0 - r3; 119 120 /* Inform upper layers if we had to do the relocation ourselves. 121 * This allows us to detect whether we were loaded by 'go 0x1000' 122 * or by the bootrom from an LDR. "R6" is "loaded_from_ldr". 123 */ 124 r6 = 1 (x); 125 cc = r4 == r5; 126 if cc jump .Lnorelocate; 127 r6 = 0 (x); 128 129 /* Turn off caches as they require CPLBs and a CPLB miss requires 130 * a software exception handler to process it. But we're about to 131 * clobber any previous executing software (like U-Boot that just 132 * launched a new U-Boot via 'go'), so any handler state will be 133 * unreliable after the memcpy below. 134 */ 135 serial_early_puts("Kill Caches"); 136 r0 = 0; 137 [p5 + (IMEM_CONTROL - COREMMR_BASE)] = r0; 138 [p5 + (DMEM_CONTROL - COREMMR_BASE)] = r0; 139 ssync; 140 141 /* In bypass mode, we don't have an LDR with an init block 142 * so we need to explicitly call it ourselves. This will 143 * reprogram our clocks, memory, and setup our async banks. 144 */ 145 serial_early_puts("Program Clocks"); 146 147 /* if we're executing >=0x20000000, then we dont need to dma */ 148 r3 = 0x0; 149 r3.h = 0x2000; 150 cc = r5 < r3 (iu); 151 if cc jump .Ldma_and_reprogram; 152#else 153 r6 = 1 (x); /* fake loaded_from_ldr = 1 */ 154#endif 155 r0 = 0 (x); /* set bootstruct to NULL */ 156 call _initcode; 157 jump .Lprogrammed; 158 159 /* we're sitting in external memory, so dma into L1 and reprogram */ 160.Ldma_and_reprogram: 161 r0.l = LO(L1_INST_SRAM); 162 r0.h = HI(L1_INST_SRAM); 163 r1.l = __initcode_lma; 164 r1.h = __initcode_lma; 165 r2.l = __initcode_len; 166 r2.h = __initcode_len; 167 r1 = r1 - r4; /* convert r1 from load address of initcode ... */ 168 r1 = r1 + r5; /* ... to current (not load) address of initcode */ 169 p3 = r0; 170 call _dma_memcpy_nocache; 171 r0 = 0 (x); /* set bootstruct to NULL */ 172 call (p3); 173 174 /* Since we reprogrammed SCLK, we need to update the serial divisor */ 175.Lprogrammed: 176 serial_early_set_baud 177 178#if CONFIG_MEM_SIZE 179 /* Relocate from wherever we are (FLASH/RAM/etc...) to the hardcoded 180 * monitor location in the end of RAM. We know that memcpy() only 181 * uses registers, so it is safe to call here. Note that this only 182 * copies to external memory ... we do not start executing out of 183 * it yet (see "lower to 15" below). 184 */ 185 serial_early_puts("Relocate"); 186 r0 = r4; 187 r1 = r5; 188 r2.l = LO(CONFIG_SYS_MONITOR_LEN); 189 r2.h = HI(CONFIG_SYS_MONITOR_LEN); 190 call _memcpy_ASM; 191#endif 192 193.Lnorelocate: 194 /* Initialize BSS section ... we know that memset() does not 195 * use the BSS, so it is safe to call here. The bootrom LDR 196 * takes care of clearing things for us. 197 */ 198 serial_early_puts("Zero BSS"); 199 r0.l = __bss_start; 200 r0.h = __bss_start; 201 r1 = 0 (x); 202 r2.l = __bss_len; 203 r2.h = __bss_len; 204 call _memset; 205 206 207 /* Setup the actual stack in external memory */ 208 sp.h = HI(CONFIG_STACKBASE); 209 sp.l = LO(CONFIG_STACKBASE); 210 fp = sp; 211 212 /* Now lower ourselves from the highest interrupt level to 213 * the lowest. We do this by masking all interrupts but 15, 214 * setting the 15 handler to ".Lenable_nested", raising the 15 215 * interrupt, and then returning from the highest interrupt 216 * level to the dummy "jump" until the interrupt controller 217 * services the pending 15 interrupt. If executing out of 218 * flash, these steps also changes the code flow from flash 219 * to external memory. 220 */ 221 serial_early_puts("Lower to 15"); 222 r0 = r7; 223 r1 = r6; 224 p1.l = .Lenable_nested; 225 p1.h = .Lenable_nested; 226 [p5 + (EVT15 - COREMMR_BASE)] = p1; 227 r7 = EVT_IVG15 (z); 228 sti r7; 229 raise 15; 230 p3.l = .LWAIT_HERE; 231 p3.h = .LWAIT_HERE; 232 reti = p3; 233 rti; 234 235 /* Enable nested interrupts before continuing with cpu init */ 236.Lenable_nested: 237 cli r7; 238 [--sp] = reti; 239 jump.l _cpu_init_f; 240 241.LWAIT_HERE: 242 jump .LWAIT_HERE; 243ENDPROC(_start) 244 245LENTRY(_get_pc) 246 r0 = rets; 247#if ANOMALY_05000371 248 NOP; 249 NOP; 250 NOP; 251#endif 252 rts; 253ENDPROC(_get_pc) 254 255ENTRY(_relocate_code) 256 /* Fake relocate code. Setup the new stack only */ 257 sp = r0; 258 fp = sp; 259 r0 = p3; 260 r1.h = 0x2000; 261 r1.l = 0x10; 262 jump.l _board_init_r 263ENDPROC(_relocate_code) 264