1 /* 2 * Copyright (c) 2011 The Chromium OS Authors. 3 * (C) Copyright 2002-2006 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * (C) Copyright 2002 7 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 8 * Marius Groeger <mgroeger@sysgo.de> 9 * 10 * See file CREDITS for list of people who contributed to this 11 * project. 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2 of 16 * the License, or (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 26 * MA 02111-1307 USA 27 */ 28 29 #include <common.h> 30 #include <linux/compiler.h> 31 #include <version.h> 32 #include <environment.h> 33 #include <fdtdec.h> 34 #include <initcall.h> 35 #include <logbuff.h> 36 #include <post.h> 37 #include <asm/io.h> 38 #include <asm/sections.h> 39 #include <linux/compiler.h> 40 41 /* 42 * Pointer to initial global data area 43 * 44 * Here we initialize it if needed. 45 */ 46 #ifdef XTRN_DECLARE_GLOBAL_DATA_PTR 47 #undef XTRN_DECLARE_GLOBAL_DATA_PTR 48 #define XTRN_DECLARE_GLOBAL_DATA_PTR /* empty = allocate here */ 49 DECLARE_GLOBAL_DATA_PTR = (gd_t *) (CONFIG_SYS_INIT_GD_ADDR); 50 #else 51 DECLARE_GLOBAL_DATA_PTR; 52 #endif 53 54 /* 55 * sjg: IMO this code should be 56 * refactored to a single function, something like: 57 * 58 * void led_set_state(enum led_colour_t colour, int on); 59 */ 60 /************************************************************************ 61 * Coloured LED functionality 62 ************************************************************************ 63 * May be supplied by boards if desired 64 */ 65 inline void __coloured_LED_init(void) {} 66 void coloured_LED_init(void) 67 __attribute__((weak, alias("__coloured_LED_init"))); 68 inline void __red_led_on(void) {} 69 void red_led_on(void) __attribute__((weak, alias("__red_led_on"))); 70 inline void __red_led_off(void) {} 71 void red_led_off(void) __attribute__((weak, alias("__red_led_off"))); 72 inline void __green_led_on(void) {} 73 void green_led_on(void) __attribute__((weak, alias("__green_led_on"))); 74 inline void __green_led_off(void) {} 75 void green_led_off(void) __attribute__((weak, alias("__green_led_off"))); 76 inline void __yellow_led_on(void) {} 77 void yellow_led_on(void) __attribute__((weak, alias("__yellow_led_on"))); 78 inline void __yellow_led_off(void) {} 79 void yellow_led_off(void) __attribute__((weak, alias("__yellow_led_off"))); 80 inline void __blue_led_on(void) {} 81 void blue_led_on(void) __attribute__((weak, alias("__blue_led_on"))); 82 inline void __blue_led_off(void) {} 83 void blue_led_off(void) __attribute__((weak, alias("__blue_led_off"))); 84 85 /* 86 * Why is gd allocated a register? Prior to reloc it might be better to 87 * just pass it around to each function in this file? 88 * 89 * After reloc one could argue that it is hardly used and doesn't need 90 * to be in a register. Or if it is it should perhaps hold pointers to all 91 * global data for all modules, so that post-reloc we can avoid the massive 92 * literal pool we get on ARM. Or perhaps just encourage each module to use 93 * a structure... 94 */ 95 96 /* 97 * Could the CONFIG_SPL_BUILD infection become a flag in gd? 98 */ 99 100 static int init_baud_rate(void) 101 { 102 gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE); 103 return 0; 104 } 105 106 static int display_text_info(void) 107 { 108 ulong bss_start, bss_end; 109 110 bss_start = _bss_start_ofs + _TEXT_BASE; 111 bss_end = _bss_end_ofs + _TEXT_BASE; 112 debug("U-Boot code: %08X -> %08lX BSS: -> %08lX\n", 113 CONFIG_SYS_TEXT_BASE, bss_start, bss_end); 114 115 #ifdef CONFIG_MODEM_SUPPORT 116 debug("Modem Support enabled\n"); 117 #endif 118 #ifdef CONFIG_USE_IRQ 119 debug("IRQ Stack: %08lx\n", IRQ_STACK_START); 120 debug("FIQ Stack: %08lx\n", FIQ_STACK_START); 121 #endif 122 123 return 0; 124 } 125 126 static int announce_dram_init(void) 127 { 128 puts("DRAM: "); 129 return 0; 130 } 131 132 static int show_dram_config(void) 133 { 134 ulong size; 135 136 #ifdef CONFIG_NR_DRAM_BANKS 137 int i; 138 139 debug("\nRAM Configuration:\n"); 140 for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 141 size += gd->bd->bi_dram[i].size; 142 debug("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); 143 #ifdef DEBUG 144 print_size(gd->bd->bi_dram[i].size, "\n"); 145 #endif 146 } 147 debug("\nDRAM: "); 148 #else 149 size = gd->ram_size; 150 #endif 151 152 print_size(size, "\n"); 153 154 return 0; 155 } 156 157 void __dram_init_banksize(void) 158 { 159 #if defined(CONFIG_NR_DRAM_BANKS) && defined(CONFIG_SYS_SDRAM_BASE) 160 gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; 161 gd->bd->bi_dram[0].size = get_effective_memsize(); 162 #endif 163 } 164 165 void dram_init_banksize(void) 166 __attribute__((weak, alias("__dram_init_banksize"))); 167 168 static int zero_global_data(void) 169 { 170 memset((void *)gd, '\0', sizeof(gd_t)); 171 172 return 0; 173 } 174 175 static int setup_mon_len(void) 176 { 177 gd->mon_len = _bss_end_ofs; 178 return 0; 179 } 180 181 __weak int arch_cpu_init(void) 182 { 183 return 0; 184 } 185 186 static int setup_fdt(void) 187 { 188 #ifdef CONFIG_OF_EMBED 189 /* Get a pointer to the FDT */ 190 gd->fdt_blob = _binary_dt_dtb_start; 191 #elif defined CONFIG_OF_SEPARATE 192 /* FDT is at end of image */ 193 gd->fdt_blob = (void *)(_end_ofs + CONFIG_SYS_TEXT_BASE); 194 #endif 195 /* Allow the early environment to override the fdt address */ 196 gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, 197 (uintptr_t)gd->fdt_blob); 198 return 0; 199 } 200 201 /* Get the top of usable RAM */ 202 __weak ulong board_get_usable_ram_top(ulong total_size) 203 { 204 return gd->ram_top; 205 } 206 207 static int setup_dest_addr(void) 208 { 209 debug("Monitor len: %08lX\n", gd->mon_len); 210 /* 211 * Ram is setup, size stored in gd !! 212 */ 213 debug("Ram size: %08lX\n", (ulong)gd->ram_size); 214 #if defined(CONFIG_SYS_MEM_TOP_HIDE) 215 /* 216 * Subtract specified amount of memory to hide so that it won't 217 * get "touched" at all by U-Boot. By fixing up gd->ram_size 218 * the Linux kernel should now get passed the now "corrected" 219 * memory size and won't touch it either. This should work 220 * for arch/ppc and arch/powerpc. Only Linux board ports in 221 * arch/powerpc with bootwrapper support, that recalculate the 222 * memory size from the SDRAM controller setup will have to 223 * get fixed. 224 */ 225 gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE; 226 #endif 227 #ifdef CONFIG_SYS_SDRAM_BASE 228 gd->ram_top = CONFIG_SYS_SDRAM_BASE; 229 #endif 230 gd->ram_top = board_get_usable_ram_top(gd->mon_len); 231 gd->dest_addr = gd->ram_top; 232 debug("Ram top: %08lX\n", (ulong)gd->ram_top); 233 gd->dest_addr_sp = gd->dest_addr; 234 return 0; 235 } 236 237 #if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR) 238 static int reserve_logbuffer(void) 239 { 240 /* reserve kernel log buffer */ 241 gd->dest_addr -= LOGBUFF_RESERVE; 242 debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, 243 gd->dest_addr); 244 return 0; 245 } 246 #endif 247 248 #ifdef CONFIG_PRAM 249 /* reserve protected RAM */ 250 static int reserve_pram(void) 251 { 252 ulong reg; 253 254 reg = getenv_ulong("pram", 10, CONFIG_PRAM); 255 gd->dest_addr -= (reg << 10); /* size is in kB */ 256 debug("Reserving %ldk for protected RAM at %08lx\n", reg, 257 gd->dest_addr); 258 return 0; 259 } 260 #endif /* CONFIG_PRAM */ 261 262 /* Round memory pointer down to next 4 kB limit */ 263 static int reserve_round_4k(void) 264 { 265 gd->dest_addr &= ~(4096 - 1); 266 return 0; 267 } 268 269 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \ 270 defined(CONFIG_ARM) 271 static int reserve_mmu(void) 272 { 273 /* reserve TLB table */ 274 gd->arch.tlb_size = 4096 * 4; 275 gd->dest_addr -= gd->arch.tlb_size; 276 277 /* round down to next 64 kB limit */ 278 gd->dest_addr &= ~(0x10000 - 1); 279 280 gd->arch.tlb_addr = gd->dest_addr; 281 debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr, 282 gd->arch.tlb_addr + gd->arch.tlb_size); 283 return 0; 284 } 285 #endif 286 287 #ifdef CONFIG_LCD 288 static int reserve_lcd(void) 289 { 290 #ifdef CONFIG_FB_ADDR 291 gd->fb_base = CONFIG_FB_ADDR; 292 #else 293 /* reserve memory for LCD display (always full pages) */ 294 gd->dest_addr = lcd_setmem(gd->dest_addr); 295 gd->fb_base = gd->dest_addr; 296 #endif /* CONFIG_FB_ADDR */ 297 return 0; 298 } 299 #endif /* CONFIG_LCD */ 300 301 static int reserve_uboot(void) 302 { 303 /* 304 * reserve memory for U-Boot code, data & bss 305 * round down to next 4 kB limit 306 */ 307 gd->dest_addr -= gd->mon_len; 308 gd->dest_addr &= ~(4096 - 1); 309 310 debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, 311 gd->dest_addr); 312 return 0; 313 } 314 315 #ifndef CONFIG_SPL_BUILD 316 /* reserve memory for malloc() area */ 317 static int reserve_malloc(void) 318 { 319 gd->dest_addr_sp = gd->dest_addr - TOTAL_MALLOC_LEN; 320 debug("Reserving %dk for malloc() at: %08lx\n", 321 TOTAL_MALLOC_LEN >> 10, gd->dest_addr_sp); 322 return 0; 323 } 324 325 /* (permanently) allocate a Board Info struct */ 326 static int reserve_board(void) 327 { 328 gd->dest_addr_sp -= sizeof(bd_t); 329 gd->bd = (bd_t *)gd->dest_addr_sp; 330 memset(gd->bd, '\0', sizeof(bd_t)); 331 debug("Reserving %zu Bytes for Board Info at: %08lx\n", 332 sizeof(bd_t), gd->dest_addr_sp); 333 return 0; 334 } 335 #endif 336 337 static int setup_machine(void) 338 { 339 #ifdef CONFIG_MACH_TYPE 340 gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ 341 #endif 342 return 0; 343 } 344 345 static int reserve_global_data(void) 346 { 347 gd->dest_addr_sp -= sizeof(gd_t); 348 gd->new_gd = (gd_t *)gd->dest_addr_sp; 349 debug("Reserving %zu Bytes for Global Data at: %08lx\n", 350 sizeof(gd_t), gd->dest_addr_sp); 351 return 0; 352 } 353 354 static int reserve_fdt(void) 355 { 356 /* 357 * If the device tree is sitting immediate above our image then we 358 * must relocate it. If it is embedded in the data section, then it 359 * will be relocated with other data. 360 */ 361 if (gd->fdt_blob) { 362 gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32); 363 364 gd->dest_addr_sp -= gd->fdt_size; 365 gd->new_fdt = (void *)gd->dest_addr_sp; 366 debug("Reserving %lu Bytes for FDT at: %p\n", 367 gd->fdt_size, gd->new_fdt); 368 } 369 370 return 0; 371 } 372 373 static int reserve_stacks(void) 374 { 375 #ifdef CONFIG_SPL_BUILD 376 # ifdef CONFIG_ARM 377 gd->dest_addr_sp -= 128; /* leave 32 words for abort-stack */ 378 gd->irq_sp = gd->dest_addr_sp; 379 # endif 380 #else 381 382 /* setup stack pointer for exceptions */ 383 gd->dest_addr_sp -= 16; 384 gd->dest_addr_sp &= ~0xf; 385 gd->irq_sp = gd->dest_addr_sp; 386 387 /* 388 * Handle architecture-specific things here 389 * TODO(sjg@chromium.org): Perhaps create arch_reserve_stack() 390 * to handle this and put in arch/xxx/lib/stack.c 391 */ 392 # ifdef CONFIG_ARM 393 # ifdef CONFIG_USE_IRQ 394 gd->dest_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ); 395 debug("Reserving %zu Bytes for IRQ stack at: %08lx\n", 396 CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->dest_addr_sp); 397 398 /* 8-byte alignment for ARM ABI compliance */ 399 gd->dest_addr_sp &= ~0x07; 400 # endif 401 /* leave 3 words for abort-stack, plus 1 for alignment */ 402 gd->dest_addr_sp -= 16; 403 # endif /* Architecture specific code */ 404 405 return 0; 406 #endif 407 } 408 409 static int display_new_sp(void) 410 { 411 debug("New Stack Pointer is: %08lx\n", gd->dest_addr_sp); 412 413 return 0; 414 } 415 416 #ifdef CONFIG_POST 417 static int init_post(void) 418 { 419 post_bootmode_init(); 420 post_run(NULL, POST_ROM | post_bootmode_get(0)); 421 422 return 0; 423 } 424 #endif 425 426 static int setup_baud_rate(void) 427 { 428 /* Ick, can we get rid of this line? */ 429 gd->bd->bi_baudrate = gd->baudrate; 430 431 return 0; 432 } 433 434 static int setup_dram_config(void) 435 { 436 /* Ram is board specific, so move it to board code ... */ 437 dram_init_banksize(); 438 439 return 0; 440 } 441 442 static int reloc_fdt(void) 443 { 444 if (gd->new_fdt) { 445 memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size); 446 gd->fdt_blob = gd->new_fdt; 447 } 448 449 return 0; 450 } 451 452 static int setup_reloc(void) 453 { 454 gd->relocaddr = gd->dest_addr; 455 gd->start_addr_sp = gd->dest_addr_sp; 456 gd->reloc_off = gd->dest_addr - CONFIG_SYS_TEXT_BASE; 457 memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); 458 459 debug("Relocation Offset is: %08lx\n", gd->reloc_off); 460 debug("Relocating to %08lx, new gd at %p, sp at %08lx\n", 461 gd->dest_addr, gd->new_gd, gd->dest_addr_sp); 462 463 return 0; 464 } 465 466 /* ARM calls relocate_code from its crt0.S */ 467 #if !defined(CONFIG_ARM) 468 469 static int jump_to_copy(void) 470 { 471 relocate_code(gd->dest_addr_sp, gd->new_gd, gd->dest_addr); 472 473 return 0; 474 } 475 #endif 476 477 /* Record the board_init_f() bootstage (after arch_cpu_init()) */ 478 static int mark_bootstage(void) 479 { 480 bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); 481 482 return 0; 483 } 484 485 static init_fnc_t init_sequence_f[] = { 486 setup_fdt, 487 setup_mon_len, 488 arch_cpu_init, /* basic arch cpu dependent setup */ 489 mark_bootstage, 490 #ifdef CONFIG_OF_CONTROL 491 fdtdec_check_fdt, 492 #endif 493 #if defined(CONFIG_BOARD_EARLY_INIT_F) 494 board_early_init_f, 495 #endif 496 timer_init, /* initialize timer */ 497 #ifdef CONFIG_BOARD_POSTCLK_INIT 498 board_postclk_init, 499 #endif 500 #ifdef CONFIG_FSL_ESDHC 501 get_clocks, 502 #endif 503 env_init, /* initialize environment */ 504 init_baud_rate, /* initialze baudrate settings */ 505 serial_init, /* serial communications setup */ 506 console_init_f, /* stage 1 init of console */ 507 display_options, /* say that we are here */ 508 display_text_info, /* show debugging info if required */ 509 #if defined(CONFIG_DISPLAY_CPUINFO) 510 print_cpuinfo, /* display cpu info (and speed) */ 511 #endif 512 #if defined(CONFIG_DISPLAY_BOARDINFO) 513 checkboard, /* display board info */ 514 #endif 515 announce_dram_init, 516 /* TODO: unify all these dram functions? */ 517 #ifdef CONFIG_ARM 518 dram_init, /* configure available RAM banks */ 519 #endif 520 #ifdef CONFIG_POST 521 init_post, 522 #endif 523 /* 524 * Now that we have DRAM mapped and working, we can 525 * relocate the code and continue running from DRAM. 526 * 527 * Reserve memory at end of RAM for (top down in that order): 528 * - area that won't get touched by U-Boot and Linux (optional) 529 * - kernel log buffer 530 * - protected RAM 531 * - LCD framebuffer 532 * - monitor code 533 * - board info struct 534 */ 535 setup_dest_addr, 536 #if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR) 537 reserve_logbuffer, 538 #endif 539 #ifdef CONFIG_PRAM 540 reserve_pram, 541 #endif 542 reserve_round_4k, 543 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \ 544 defined(CONFIG_ARM) 545 reserve_mmu, 546 #endif 547 #ifdef CONFIG_LCD 548 reserve_lcd, 549 #endif 550 reserve_uboot, 551 #ifndef CONFIG_SPL_BUILD 552 reserve_malloc, 553 reserve_board, 554 #endif 555 setup_machine, 556 reserve_global_data, 557 reserve_fdt, 558 reserve_stacks, 559 setup_dram_config, 560 show_dram_config, 561 setup_baud_rate, 562 display_new_sp, 563 reloc_fdt, 564 setup_reloc, 565 #ifndef CONFIG_ARM 566 jump_to_copy, 567 #endif 568 NULL, 569 }; 570 571 void board_init_f(ulong boot_flags) 572 { 573 gd_t data; 574 575 gd = &data; 576 577 gd->flags = boot_flags; 578 579 if (initcall_run_list(init_sequence_f)) 580 hang(); 581 582 #ifndef CONFIG_ARM 583 /* NOTREACHED - jump_to_copy() does not return */ 584 hang(); 585 #endif 586 } 587 588 void hang(void) 589 { 590 puts("### ERROR ### Please RESET the board ###\n"); 591 for (;;); 592 } 593