1/* 2 * HND MIPS boards setup routines 3 * 4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: setup.c,v 1.23 2010-10-20 08:26:12 $ 19 */ 20 21#include <linux/types.h> 22#include <linux/version.h> 23#include <linux/init.h> 24#include <linux/kernel.h> 25#include <linux/serial.h> 26#include <linux/serialP.h> 27#include <linux/serial_core.h> 28#include <linux/serial_8250.h> /* for early_serial_setup */ 29#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 30#include <linux/config.h> 31#endif 32#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) 33#include <linux/blkdev.h> 34#include <linux/ide.h> 35#endif 36#include <asm/bootinfo.h> 37#include <asm/cpu.h> 38#include <asm/time.h> 39#include <asm/reboot.h> 40 41#ifdef CONFIG_MTD_PARTITIONS 42#include <linux/mtd/mtd.h> 43#include <linux/mtd/partitions.h> 44#include <linux/romfs_fs.h> 45#include <linux/cramfs_fs.h> 46#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 47#include <linux/squashfs_fs.h> 48#else 49/* #include <magic.h> */ 50#endif 51#endif 52#ifdef CONFIG_BLK_DEV_INITRD 53#include <linux/initrd.h> 54#endif 55#include <typedefs.h> 56#include <osl.h> 57#include <bcmutils.h> 58#include <bcmnvram.h> 59#include <siutils.h> 60#include <hndsoc.h> 61#include <hndcpu.h> 62#include <mips33_core.h> 63#include <mips74k_core.h> 64#include <sbchipc.h> 65#include <hndchipc.h> 66#include <hndpci.h> 67#include <trxhdr.h> 68#ifdef HNDCTF 69#include <ctf/hndctf.h> 70#endif /* HNDCTF */ 71#include "bcm947xx.h" 72#ifdef CONFIG_MTD_NFLASH 73#include "nflash.h" 74#endif 75#include "bcmdevs.h" 76 77extern void bcm947xx_time_init(void); 78extern void bcm947xx_timer_setup(struct irqaction *irq); 79 80#ifdef CONFIG_KGDB 81extern void set_debug_traps(void); 82extern void rs_kgdb_hook(struct uart_port *); 83extern void breakpoint(void); 84#endif 85 86#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) 87extern struct ide_ops std_ide_ops; 88#endif 89 90struct dummy_super_block { 91 u32 s_magic ; 92}; 93 94#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 95/* Enable CPU wait or not */ 96extern int cpu_wait_enable; 97#else 98int coherentio; /* init to 0 => no DMA cache coherency (may be set by user) */ 99int hw_coherentio;/* init to 0 => no HW DMA cache coherency (reflects real HW) */ 100#endif 101 102/* Global SB handle */ 103si_t *bcm947xx_sih = NULL; 104spinlock_t bcm947xx_sih_lock = SPIN_LOCK_UNLOCKED; 105EXPORT_SYMBOL(bcm947xx_sih); 106EXPORT_SYMBOL(bcm947xx_sih_lock); 107 108/* Convenience */ 109#define sih bcm947xx_sih 110#define sih_lock bcm947xx_sih_lock 111 112#ifdef HNDCTF 113ctf_t *kcih = NULL; 114EXPORT_SYMBOL(kcih); 115ctf_attach_t ctf_attach_fn = NULL; 116EXPORT_SYMBOL(ctf_attach_fn); 117#endif /* HNDCTF */ 118 119/* Kernel command line */ 120#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 121extern char arcs_cmdline[CL_SIZE]; 122#endif 123static int lanports_enable = 0; 124 125 126EXPORT_SYMBOL( si_router_coma ); /* for loadable modules */ 127EXPORT_SYMBOL( hnd_jtagm_init ); 128EXPORT_SYMBOL( hnd_jtagm_disable ); 129EXPORT_SYMBOL( jtag_scan ); 130 131static void 132bcm947xx_reboot_handler(void) 133{ 134 int wombo_reset; 135 136 /* Reset the PCI(e) interfaces */ 137 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) 138 hndpci_deinit(sih); 139 140 if (lanports_enable) { 141 uint lp = 1 << lanports_enable; 142 143 si_gpioout(sih, lp, 0, GPIO_DRV_PRIORITY); 144 si_gpioouten(sih, lp, lp, GPIO_DRV_PRIORITY); 145 bcm_mdelay(1); 146 } 147 148 /* gpio 0 is also valid wombo_reset */ 149 if ((wombo_reset = getgpiopin(NULL, "wombo_reset", GPIO_PIN_NOTDEFINED)) != 150 GPIO_PIN_NOTDEFINED) { 151 int reset = 1 << wombo_reset; 152 153 si_gpioout(sih, reset, 0, GPIO_DRV_PRIORITY); 154 si_gpioouten(sih, reset, reset, GPIO_DRV_PRIORITY); 155 bcm_mdelay(10); 156 } 157} 158 159void 160bcm947xx_machine_restart(char *command) 161{ 162 printk("Please stand by while rebooting the system...\n"); 163 164 /* Set the watchdog timer to reset immediately */ 165 local_irq_disable(); 166 bcm947xx_reboot_handler(); 167 hnd_cpu_reset(sih); 168} 169 170void 171bcm947xx_machine_halt(void) 172{ 173 printk("System halted\n"); 174 175 /* Disable interrupts and watchdog and spin forever */ 176 local_irq_disable(); 177 si_watchdog(sih, 0); 178 bcm947xx_reboot_handler(); 179 while (1); 180} 181 182#ifdef CONFIG_SERIAL_CORE 183 184static struct uart_port rs = { 185 line: 0, 186 flags: ASYNC_BOOT_AUTOCONF, 187 iotype: SERIAL_IO_MEM, 188}; 189 190static void __init 191serial_add(void *regs, uint irq, uint baud_base, uint reg_shift) 192{ 193 rs.membase = regs; 194 rs.irq = irq + 2; 195 rs.uartclk = baud_base; 196 rs.regshift = reg_shift; 197 198 early_serial_setup(&rs); 199 200 rs.line++; 201} 202 203static void __init 204serial_setup(si_t *sih) 205{ 206 si_serial_init(sih, serial_add); 207 208#ifdef CONFIG_KGDB 209 /* Use the last port for kernel debugging */ 210 if (rs.membase) 211 rs_kgdb_hook(&rs); 212#endif 213} 214 215#endif /* CONFIG_SERIAL_CORE */ 216 217static int boot_flags(void) 218{ 219 int bootflags = 0; 220 char *val; 221 222 /* Only support chipcommon revision == 38 or BCM4706 for now */ 223 if ((CHIPID(sih->chip) == BCM4706_CHIP_ID) || sih->ccrev == 38) { 224 if (sih->ccrev == 38 && (sih->chipst & (1 << 4)) != 0) { 225 /* This is NANDBOOT */ 226 bootflags = FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH; 227 } 228 else if ((val = nvram_get("bootflags"))) { 229 bootflags = simple_strtol(val, NULL, 0); 230 bootflags &= FLASH_KERNEL_NFLASH; 231 } 232 } 233 234 return bootflags; 235} 236 237static int rootfs_mtdblock(void) 238{ 239 int bootflags; 240 int block = 0; 241 242 bootflags = boot_flags(); 243 244 /* NANDBOOT */ 245 if ((bootflags & (FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH)) == 246 (FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH)) 247 return 3; 248 249 /* SFLASH/PFLASH only */ 250 if ((bootflags & (FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH)) == 0) 251 return 2; 252 253#ifdef BCMCONFMTD 254 block++; 255#endif 256 /* Boot from norflash and kernel in nandflash */ 257 return block+3; 258} 259 260void __init 261brcm_setup(void) 262{ 263 char *value; 264 265 /* Get global SB handle */ 266 sih = si_kattach(SI_OSH); 267 268 /* Initialize clocks and interrupts */ 269 si_mips_init(sih, SBMIPS_VIRTIRQ_BASE); 270 271 if (BCM330X(current_cpu_data.processor_id) && 272 (read_c0_diag() & BRCM_PFC_AVAIL)) { 273 /* 274 * Now that the sih is inited set the proper PFC value 275 */ 276 printk("Setting the PFC to its default value\n"); 277 enable_pfc(PFC_AUTO); 278 } 279 280 281#ifdef CONFIG_SERIAL_CORE 282 /* Initialize UARTs */ 283 serial_setup(sih); 284#endif /* CONFIG_SERIAL_CORE */ 285 286#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) 287 ide_ops = &std_ide_ops; 288#endif 289 290 sprintf(arcs_cmdline, "root=/dev/mtdblock%d console=ttyS0,115200 init=/sbin/preinit", rootfs_mtdblock()); 291 292 /* Override default command line arguments */ 293 value = nvram_get("kernel_args"); 294 if (value && strlen(value) && strncmp(value, "empty", 5)) 295 strncpy(arcs_cmdline, value, sizeof(arcs_cmdline)); 296 297 298 if ((lanports_enable = getgpiopin(NULL, "lanports_enable", GPIO_PIN_NOTDEFINED)) == 299 GPIO_PIN_NOTDEFINED) 300 lanports_enable = 0; 301 302 303#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 304 /* Check if we want to enable cpu wait */ 305 if (nvram_match("wait", "1")) 306 cpu_wait_enable = 1; 307#endif 308 309 /* Generic setup */ 310 _machine_restart = bcm947xx_machine_restart; 311 _machine_halt = bcm947xx_machine_halt; 312 pm_power_off = bcm947xx_machine_halt; 313 314#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 315 board_time_init = bcm947xx_time_init; 316#endif 317} 318 319const char * 320get_system_type(void) 321{ 322 static char s[32]; 323 324 if (bcm947xx_sih) { 325 sprintf(s, "Broadcom BCM%X chip rev %d", bcm947xx_sih->chip, 326 bcm947xx_sih->chiprev); 327 return s; 328 } 329 else 330 return "Broadcom BCM947XX"; 331} 332 333void __init 334bus_error_init(void) 335{ 336} 337 338void __init 339plat_mem_setup(void) 340{ 341 brcm_setup(); 342 return; 343} 344 345#ifdef CONFIG_MTD_PARTITIONS 346 347static struct mutex *mtd_mutex = NULL; 348 349struct mutex *partitions_mutex_init(void) 350{ 351 if (!mtd_mutex) { 352 mtd_mutex = (struct mutex *)kzalloc(sizeof(struct mutex), GFP_KERNEL); 353 if (!mtd_mutex) 354 return NULL; 355 mutex_init(mtd_mutex); 356 } 357 return mtd_mutex; 358} 359EXPORT_SYMBOL(partitions_mutex_init); 360 361/* Find out prom size */ 362static uint32 boot_partition_size(uint32 flash_phys) { 363 uint32 bootsz, *bisz; 364 365 /* Default is 256K boot partition */ 366 bootsz = 256 * 1024; 367 368 /* Do we have a self-describing binary image? */ 369 bisz = (uint32 *)KSEG1ADDR(flash_phys + BISZ_OFFSET); 370 if (bisz[BISZ_MAGIC_IDX] == BISZ_MAGIC) { 371 int isz = bisz[BISZ_DATAEND_IDX] - bisz[BISZ_TXTST_IDX]; 372 373 if (isz > (1024 * 1024)) 374 bootsz = 2048 * 1024; 375 else if (isz > (512 * 1024)) 376 bootsz = 1024 * 1024; 377 else if (isz > (256 * 1024)) 378 bootsz = 512 * 1024; 379 else if (isz <= (128 * 1024)) 380 bootsz = 128 * 1024; 381 } 382 return bootsz; 383} 384 385#if defined(BCMCONFMTD) && defined(PLC) 386#define FLASH_PARTS_NUM 7 387#elif defined(BCMCONFMTD) || defined(PLC) 388#define FLASH_PARTS_NUM 6 389#else 390#define FLASH_PARTS_NUM 5 /* boot;nvram;kernel;rootfs;empty */ 391#endif 392 393static struct mtd_partition bcm947xx_flash_parts[FLASH_PARTS_NUM] = {{0}}; 394 395static uint lookup_flash_rootfs_offset(struct mtd_info *mtd, int *trx_off, size_t size) 396{ 397 struct romfs_super_block *romfsb; 398 struct cramfs_super *cramfsb; 399#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 400 struct squashfs_super_block *squashfsb; 401#else 402 struct dummy_super_block *squashfsb; 403#endif 404 struct trx_header *trx; 405 unsigned char buf[512]; 406 int off; 407 size_t len; 408 409 romfsb = (struct romfs_super_block *) buf; 410 cramfsb = (struct cramfs_super *) buf; 411 squashfsb = (void *) buf; 412 trx = (struct trx_header *) buf; 413 414 /* Look at every 64 KB boundary */ 415 for (off = 0; off < size; off += (64 * 1024)) { 416 memset(buf, 0xe5, sizeof(buf)); 417 418 /* 419 * Read block 0 to test for romfs and cramfs superblock 420 */ 421 if (mtd->read(mtd, off, sizeof(buf), &len, buf) || 422 len != sizeof(buf)) 423 continue; 424 425 /* Try looking at TRX header for rootfs offset */ 426 if (le32_to_cpu(trx->magic) == TRX_MAGIC) { 427 *trx_off = off; 428 if (trx->offsets[1] == 0) 429 continue; 430 /* 431 * Read to test for romfs and cramfs superblock 432 */ 433 off += le32_to_cpu(trx->offsets[1]); 434 memset(buf, 0xe5, sizeof(buf)); 435 if (mtd->read(mtd, off, sizeof(buf), &len, buf) || len != sizeof(buf)) 436 continue; 437 } 438 439 /* romfs is at block zero too */ 440 if (romfsb->word0 == ROMSB_WORD0 && 441 romfsb->word1 == ROMSB_WORD1) { 442 printk(KERN_NOTICE 443 "%s: romfs filesystem found at block %d\n", 444 mtd->name, off / mtd->erasesize); 445 break; 446 } 447 448 /* so is cramfs */ 449 if (cramfsb->magic == CRAMFS_MAGIC) { 450 printk(KERN_NOTICE 451 "%s: cramfs filesystem found at block %d\n", 452 mtd->name, off / mtd->erasesize); 453 break; 454 } 455 if (squashfsb->s_magic == SQUASHFS_MAGIC) { 456 printk(KERN_NOTICE 457 "%s: squash filesystem found at block %d\n", 458 mtd->name, off / mtd->erasesize); 459 break; 460 } 461 } 462 463 return off; 464} 465struct mtd_partition * 466init_mtd_partitions(struct mtd_info *mtd, size_t size) 467{ 468 int bootflags; 469 int nparts = 0; 470 uint32 offset = 0; 471 uint rfs_off = 0; 472 uint vmlz_off, knl_size; 473 uint32 top = 0; 474 uint32 bootsz; 475 476 bootflags = boot_flags(); 477 478 if ((bootflags & FLASH_KERNEL_NFLASH) != FLASH_KERNEL_NFLASH) { 479 rfs_off = lookup_flash_rootfs_offset(mtd, &vmlz_off, size); 480 481 /* Size pmon */ 482 bcm947xx_flash_parts[nparts].name = "boot"; 483 bcm947xx_flash_parts[nparts].size = vmlz_off; 484 bcm947xx_flash_parts[nparts].offset = top; 485 bcm947xx_flash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 486 nparts++; 487 488 /* Setup kernel MTD partition */ 489 bcm947xx_flash_parts[nparts].name = "linux"; 490 bcm947xx_flash_parts[nparts].size = mtd->size - vmlz_off; 491 492#ifdef PLC 493 /* Reserve for PLC */ 494 bcm947xx_flash_parts[nparts].size -= ROUNDUP(0x1000, mtd->erasesize); 495#endif 496 /* Reserve for NVRAM */ 497 bcm947xx_flash_parts[nparts].size -= ROUNDUP(NVRAM_SPACE, mtd->erasesize); 498 499#ifdef BCMCONFMTD 500 bcm947xx_flash_parts[nparts].size -= (mtd->erasesize *4); 501#endif 502 bcm947xx_flash_parts[nparts].offset = vmlz_off; 503 knl_size = bcm947xx_flash_parts[nparts].size; 504 offset = bcm947xx_flash_parts[nparts].offset + knl_size; 505 nparts++; 506 507 /* Setup rootfs MTD partition */ 508 bcm947xx_flash_parts[nparts].name = "rootfs"; 509 bcm947xx_flash_parts[nparts].size = knl_size - (rfs_off - vmlz_off); 510 bcm947xx_flash_parts[nparts].offset = rfs_off; 511 bcm947xx_flash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 512 nparts++; 513 } else { 514 bootsz = boot_partition_size(SI_FLASH2); 515 printk("Boot partition size = %d(0x%x)\n", bootsz, bootsz); 516 /* Size pmon */ 517 bcm947xx_flash_parts[nparts].name = "boot"; 518 bcm947xx_flash_parts[nparts].size = bootsz; 519 bcm947xx_flash_parts[nparts].offset = top; 520 bcm947xx_flash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 521 offset = bcm947xx_flash_parts[nparts].size; 522 nparts++; 523 } 524 525#ifdef BCMCONFMTD 526 /* Setup CONF MTD partition */ 527 bcm947xx_flash_parts[nparts].name = "confmtd"; 528 bcm947xx_flash_parts[nparts].size = mtd->erasesize * 4; 529 bcm947xx_flash_parts[nparts].offset = offset; 530 offset = bcm947xx_flash_parts[nparts].offset + bcm947xx_flash_parts[nparts].size; 531 nparts++; 532#endif /* BCMCONFMTD */ 533 534#ifdef PLC 535 /* Setup plc MTD partition */ 536 bcm947xx_flash_parts[nparts].name = "plc"; 537 bcm947xx_flash_parts[nparts].size = ROUNDUP(0x1000, mtd->erasesize); 538 bcm947xx_flash_parts[nparts].offset = size - (ROUNDUP(NVRAM_SPACE, mtd->erasesize) + ROUNDUP(0x1000, mtd->erasesize)); 539 nparts++; 540#endif 541 542 /* Setup nvram MTD partition */ 543 bcm947xx_flash_parts[nparts].name = "nvram"; 544 bcm947xx_flash_parts[nparts].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); 545 bcm947xx_flash_parts[nparts].offset = size - bcm947xx_flash_parts[nparts].size; 546 nparts++; 547 548 return bcm947xx_flash_parts; 549} 550 551EXPORT_SYMBOL(init_mtd_partitions); 552 553#ifdef CONFIG_MTD_NFLASH 554#define NFLASH_PARTS_NUM 6 555static struct mtd_partition bcm947xx_nflash_parts[NFLASH_PARTS_NUM] = {{0}}; 556 557static uint lookup_nflash_rootfs_offset(struct mtd_info *mtd, int offset, size_t size) 558{ 559 struct romfs_super_block *romfsb; 560 struct cramfs_super *cramfsb; 561#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 562 struct squashfs_super_block *squashfsb; 563#else 564 struct dummy_super_block *squashfsb; 565#endif 566 struct trx_header *trx; 567 unsigned char buf[NFL_SECTOR_SIZE]; 568 uint blocksize, mask, blk_offset, off, shift = 0; 569 chipcregs_t *cc; 570 int ret; 571 572 romfsb = (struct romfs_super_block *) buf; 573 cramfsb = (struct cramfs_super *) buf; 574 squashfsb = (void *) buf; 575 trx = (struct trx_header *) buf; 576 577 if ((cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX)) == NULL) 578 return 0; 579 580 /* Look at every block boundary till 16MB; higher space is reserved for application data. */ 581 blocksize = mtd->erasesize; 582 printk("lookup_nflash_rootfs_offset: offset = 0x%x\n", offset); 583 for (off = offset; off < NFL_BOOT_OS_SIZE; off += blocksize) { 584 mask = blocksize - 1; 585 blk_offset = off & ~mask; 586 if (nflash_checkbadb(sih, cc, blk_offset) != 0) 587 continue; 588 memset(buf, 0xe5, sizeof(buf)); 589 if ((ret = nflash_read(sih, cc, off, sizeof(buf), buf)) != sizeof(buf)) { 590 printk(KERN_NOTICE 591 "%s: nflash_read return %d\n", mtd->name, ret); 592 continue; 593 } 594 595 /* Try looking at TRX header for rootfs offset */ 596 if (le32_to_cpu(trx->magic) == TRX_MAGIC) { 597 mask = NFL_SECTOR_SIZE - 1; 598 off = offset + (le32_to_cpu(trx->offsets[1]) & ~mask) - blocksize; 599 shift = (le32_to_cpu(trx->offsets[1]) & mask); 600 romfsb = (struct romfs_super_block *)((unsigned char *)romfsb + shift); 601 cramfsb = (struct cramfs_super *)((unsigned char *)cramfsb + shift); 602 squashfsb = (void *)((unsigned char *)squashfsb + shift); 603 continue; 604 } 605 606 /* romfs is at block zero too */ 607 if (romfsb->word0 == ROMSB_WORD0 && 608 romfsb->word1 == ROMSB_WORD1) { 609 printk(KERN_NOTICE 610 "%s: romfs filesystem found at block %d\n", 611 mtd->name, off / blocksize); 612 break; 613 } 614 615 /* so is cramfs */ 616 if (cramfsb->magic == CRAMFS_MAGIC) { 617 printk(KERN_NOTICE 618 "%s: cramfs filesystem found at block %d\n", 619 mtd->name, off / blocksize); 620 break; 621 } 622 623 if (squashfsb->s_magic == SQUASHFS_MAGIC) { 624 printk(KERN_NOTICE 625 "%s: squash filesystem found at block %d\n", 626 mtd->name, off / blocksize); 627 break; 628 } 629 } 630 return shift + off; 631} 632 633struct mtd_partition * init_nflash_mtd_partitions(struct mtd_info *mtd, size_t size) 634{ 635 int bootflags; 636 int nparts = 0; 637 uint32 offset = 0; 638 uint shift = 0; 639 uint32 top = 0; 640 uint32 bootsz; 641 642 bootflags = boot_flags(); 643 if ((bootflags & FLASH_BOOT_NFLASH) == FLASH_BOOT_NFLASH) { 644 bootsz = boot_partition_size(SI_FLASH1); 645 if (bootsz > mtd->erasesize) { 646 /* Prepare double space in case of bad blocks */ 647 bootsz = (bootsz << 1); 648 } else { 649 /* CFE occupies at least one block */ 650 bootsz = mtd->erasesize; 651 } 652 printk("Boot partition size = %d(0x%x)\n", bootsz, bootsz); 653 654 /* Size pmon */ 655 bcm947xx_nflash_parts[nparts].name = "boot"; 656 bcm947xx_nflash_parts[nparts].size = bootsz; 657 bcm947xx_nflash_parts[nparts].offset = top; 658 bcm947xx_nflash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 659 offset = bcm947xx_nflash_parts[nparts].size; 660 nparts++; 661 662 /* Setup NVRAM MTD partition */ 663 bcm947xx_nflash_parts[nparts].name = "nvram"; 664 bcm947xx_nflash_parts[nparts].size = NFL_BOOT_SIZE - offset; 665 bcm947xx_nflash_parts[nparts].offset = offset; 666 667 offset = NFL_BOOT_SIZE; 668 nparts++; 669 } 670 671 if ((bootflags & FLASH_KERNEL_NFLASH) == FLASH_KERNEL_NFLASH) { 672 /* Setup kernel MTD partition */ 673 bcm947xx_nflash_parts[nparts].name = "linux"; 674 bcm947xx_nflash_parts[nparts].size = nparts ? (NFL_BOOT_OS_SIZE - NFL_BOOT_SIZE) : NFL_BOOT_OS_SIZE; 675 bcm947xx_nflash_parts[nparts].offset = offset; 676 677 shift = lookup_nflash_rootfs_offset(mtd, offset, size); 678 679 offset = NFL_BOOT_OS_SIZE; 680 nparts++; 681 682 /* Setup rootfs MTD partition */ 683 bcm947xx_nflash_parts[nparts].name = "rootfs"; 684 bcm947xx_nflash_parts[nparts].size = NFL_BOOT_OS_SIZE - shift; 685 bcm947xx_nflash_parts[nparts].offset = shift; 686 bcm947xx_nflash_parts[nparts].mask_flags = MTD_WRITEABLE; 687 688 nparts++; 689 } 690 691 return bcm947xx_nflash_parts; 692} 693 694EXPORT_SYMBOL(init_nflash_mtd_partitions); 695#endif /* CONFIG_MTD_NFLASH */ 696 697#ifdef CONFIG_BLK_DEV_INITRD 698extern char _end; 699 700/* The check_ramdisk_trx has more exact qualification to look at TRX header from end of linux */ 701static __init int 702check_ramdisk_trx(unsigned long offset, unsigned long ram_size) 703{ 704 struct trx_header *trx; 705 uint32 crc; 706 unsigned int len; 707 uint8 *ptr = (uint8 *)offset; 708 709 trx = (struct trx_header *)ptr; 710 711 /* Not a TRX_MAGIC */ 712 if (le32_to_cpu(trx->magic) != TRX_MAGIC) { 713 printk("check_ramdisk_trx: not a valid TRX magic\n"); 714 return -1; 715 } 716 717 /* TRX len invalid */ 718 len = le32_to_cpu(trx->len); 719 if (offset + len > ram_size) { 720 printk("check_ramdisk_trx: not a valid TRX length\n"); 721 return -1; 722 } 723 724 /* Checksum over header */ 725 crc = hndcrc32((uint8 *) &trx->flag_version, 726 sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version), 727 CRC32_INIT_VALUE); 728 729 /* Move ptr to data */ 730 ptr += sizeof(struct trx_header); 731 len -= sizeof(struct trx_header); 732 733 /* Checksum over data */ 734 crc = hndcrc32(ptr, len, crc); 735 736 /* Verify checksum */ 737 if (le32_to_cpu(trx->crc32) != crc) { 738 printk("check_ramdisk_trx: checksum invalid\n"); 739 return -1; 740 } 741 742 return 0; 743} 744 745void __init init_ramdisk(unsigned long mem_end) 746{ 747 struct trx_header *trx = NULL; 748 char *from_rootfs, *to_rootfs; 749 unsigned long rootfs_size = 0; 750 unsigned long ram_size = mem_end + 0x80000000; 751 unsigned long offset; 752 char *root_cmd = "root=/dev/ram0 console=ttyS0,115200 rdinit=/sbin/preinit"; 753 754 to_rootfs = (char *)(((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK); 755 offset = ((unsigned long)&_end +0xffff) & ~0xffff; 756 757 /* Look at TRX header from end of linux */ 758 for (; offset < ram_size; offset += 0x10000) { 759 trx = (struct trx_header *)offset; 760 if (le32_to_cpu(trx->magic) == TRX_MAGIC && 761 check_ramdisk_trx(offset, ram_size) == 0) { 762 printk(KERN_NOTICE 763 "Found TRX image at %08lx\n", offset); 764 from_rootfs = (char *)((unsigned long)trx + le32_to_cpu(trx->offsets[1])); 765 rootfs_size = le32_to_cpu(trx->len) - le32_to_cpu(trx->offsets[1]); 766 rootfs_size = (rootfs_size + 0xffff) & ~0xffff; 767 printk("rootfs size is %ld bytes at 0x%p, copying to 0x%p\n", rootfs_size, from_rootfs, to_rootfs); 768 memmove(to_rootfs, from_rootfs, rootfs_size); 769 770 initrd_start = (int)to_rootfs; 771 initrd_end = initrd_start + rootfs_size; 772 strncpy(arcs_cmdline, root_cmd, sizeof(arcs_cmdline)); 773 /* 774 * In case the system warm boot, the memory won't be zeroed. 775 * So we have to erase trx magic. 776 */ 777 if (initrd_end < (unsigned long)trx) 778 trx->magic = 0; 779 break; 780 } 781 } 782} 783#endif 784#endif 785