1/* 2 * HND MIPS boards setup routines 3 * 4 * Copyright (C) 2013, 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#ifndef BCMDBG 135 int wombo_reset; 136#endif /* BCMDBG */ 137 138 /* Reset the PCI(e) interfaces */ 139 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) 140 hndpci_deinit(sih); 141 142 if (lanports_enable) { 143 uint lp = 1 << lanports_enable; 144 145 si_gpioout(sih, lp, 0, GPIO_DRV_PRIORITY); 146 si_gpioouten(sih, lp, lp, GPIO_DRV_PRIORITY); 147 bcm_mdelay(1); 148 } 149 150#ifndef BCMDBG 151 /* gpio 0 is also valid wombo_reset */ 152 if ((wombo_reset = getgpiopin(NULL, "wombo_reset", GPIO_PIN_NOTDEFINED)) != 153 GPIO_PIN_NOTDEFINED) { 154 int reset = 1 << wombo_reset; 155 156 si_gpioout(sih, reset, 0, GPIO_DRV_PRIORITY); 157 si_gpioouten(sih, reset, reset, GPIO_DRV_PRIORITY); 158 bcm_mdelay(10); 159 } 160#endif /* BCMDBG */ 161} 162 163void 164bcm947xx_machine_restart(char *command) 165{ 166 printk("Please stand by while rebooting the system...\n"); 167 168 /* Set the watchdog timer to reset immediately */ 169 local_irq_disable(); 170 bcm947xx_reboot_handler(); 171 hnd_cpu_reset(sih); 172} 173 174void 175bcm947xx_machine_halt(void) 176{ 177 printk("System halted\n"); 178 179 /* Disable interrupts and watchdog and spin forever */ 180 local_irq_disable(); 181 si_watchdog(sih, 0); 182 bcm947xx_reboot_handler(); 183 while (1); 184} 185 186#ifdef CONFIG_SERIAL_CORE 187 188static struct uart_port rs = { 189 line: 0, 190 flags: ASYNC_BOOT_AUTOCONF, 191 iotype: SERIAL_IO_MEM, 192}; 193 194static void __init 195serial_add(void *regs, uint irq, uint baud_base, uint reg_shift) 196{ 197 rs.membase = regs; 198 rs.irq = irq + 2; 199 rs.uartclk = baud_base; 200 rs.regshift = reg_shift; 201 202 early_serial_setup(&rs); 203 204 rs.line++; 205} 206 207static void __init 208serial_setup(si_t *sih) 209{ 210 si_serial_init(sih, serial_add); 211 212#ifdef CONFIG_KGDB 213 /* Use the last port for kernel debugging */ 214 if (rs.membase) 215 rs_kgdb_hook(&rs); 216#endif 217} 218 219#endif /* CONFIG_SERIAL_CORE */ 220 221static int boot_flags(void) 222{ 223 int bootflags = 0; 224 char *val; 225 226 /* Only support chipcommon revision == 38 or BCM4706 for now */ 227 if ((CHIPID(sih->chip) == BCM4706_CHIP_ID) || sih->ccrev == 38) { 228 if (sih->ccrev == 38 && (sih->chipst & (1 << 4)) != 0) { 229 /* This is NANDBOOT */ 230 bootflags = FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH; 231 } 232 else if ((val = nvram_get("bootflags"))) { 233 bootflags = simple_strtol(val, NULL, 0); 234 bootflags &= FLASH_KERNEL_NFLASH; 235 } 236 } 237 238 return bootflags; 239} 240 241static int rootfs_mtdblock(void) 242{ 243 int bootflags; 244 int block = 0; 245 246 bootflags = boot_flags(); 247 248 /* NANDBOOT */ 249 if ((bootflags & (FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH)) == 250 (FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH)) 251 return 3; 252 253 /* SFLASH/PFLASH only */ 254 if ((bootflags & (FLASH_BOOT_NFLASH | FLASH_KERNEL_NFLASH)) == 0) 255 return 2; 256 257#ifdef BCMCONFMTD 258 block++; 259#endif 260 /* Boot from norflash and kernel in nandflash */ 261 return block+3; 262} 263 264void __init 265brcm_setup(void) 266{ 267 char *value; 268 269 /* Get global SB handle */ 270 sih = si_kattach(SI_OSH); 271 272 /* Initialize clocks and interrupts */ 273 si_mips_init(sih, SBMIPS_VIRTIRQ_BASE); 274 275 if (BCM330X(current_cpu_data.processor_id) && 276 (read_c0_diag() & BRCM_PFC_AVAIL)) { 277 /* 278 * Now that the sih is inited set the proper PFC value 279 */ 280 printk("Setting the PFC to its default value\n"); 281 enable_pfc(PFC_AUTO); 282 } 283 284 285#ifdef CONFIG_SERIAL_CORE 286 /* Initialize UARTs */ 287 serial_setup(sih); 288#endif /* CONFIG_SERIAL_CORE */ 289 290#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) 291 ide_ops = &std_ide_ops; 292#endif 293 294 sprintf(arcs_cmdline, "root=/dev/mtdblock%d console=ttyS0,115200 init=/sbin/preinit", rootfs_mtdblock()); 295 296 /* Override default command line arguments */ 297 value = nvram_get("kernel_args"); 298 if (value && strlen(value) && strncmp(value, "empty", 5)) 299 strncpy(arcs_cmdline, value, sizeof(arcs_cmdline)); 300 301 302 if ((lanports_enable = getgpiopin(NULL, "lanports_enable", GPIO_PIN_NOTDEFINED)) == 303 GPIO_PIN_NOTDEFINED) 304 lanports_enable = 0; 305 306 307#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 308 /* Check if we want to enable cpu wait */ 309 if (nvram_match("wait", "1")) 310 cpu_wait_enable = 1; 311#endif 312 313 /* Generic setup */ 314 _machine_restart = bcm947xx_machine_restart; 315 _machine_halt = bcm947xx_machine_halt; 316 pm_power_off = bcm947xx_machine_halt; 317 318#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 319 board_time_init = bcm947xx_time_init; 320#endif 321} 322 323const char * 324get_system_type(void) 325{ 326 static char s[32]; 327 328 if (bcm947xx_sih) { 329 sprintf(s, "Broadcom BCM%X chip rev %d", bcm947xx_sih->chip, 330 bcm947xx_sih->chiprev); 331 return s; 332 } 333 else 334 return "Broadcom BCM947XX"; 335} 336 337void __init 338bus_error_init(void) 339{ 340} 341 342void __init 343plat_mem_setup(void) 344{ 345 brcm_setup(); 346 return; 347} 348 349#ifdef CONFIG_MTD_PARTITIONS 350 351static struct mutex *mtd_mutex = NULL; 352 353struct mutex *partitions_mutex_init(void) 354{ 355 if (!mtd_mutex) { 356 mtd_mutex = (struct mutex *)kzalloc(sizeof(struct mutex), GFP_KERNEL); 357 if (!mtd_mutex) 358 return NULL; 359 mutex_init(mtd_mutex); 360 } 361 return mtd_mutex; 362} 363EXPORT_SYMBOL(partitions_mutex_init); 364 365/* Find out prom size */ 366static uint32 boot_partition_size(uint32 flash_phys) { 367 uint32 bootsz, *bisz; 368 369 /* Default is 256K boot partition */ 370 bootsz = 256 * 1024; 371 372 /* Do we have a self-describing binary image? */ 373 bisz = (uint32 *)KSEG1ADDR(flash_phys + BISZ_OFFSET); 374 if (bisz[BISZ_MAGIC_IDX] == BISZ_MAGIC) { 375 int isz = bisz[BISZ_DATAEND_IDX] - bisz[BISZ_TXTST_IDX]; 376 377 if (isz > (1024 * 1024)) 378 bootsz = 2048 * 1024; 379 else if (isz > (512 * 1024)) 380 bootsz = 1024 * 1024; 381 else if (isz > (256 * 1024)) 382 bootsz = 512 * 1024; 383 else if (isz <= (128 * 1024)) 384 bootsz = 128 * 1024; 385 } 386 return bootsz; 387} 388 389#if defined(BCMCONFMTD) && defined(PLC) 390#define FLASH_PARTS_NUM 7 391#elif defined(BCMCONFMTD) || defined(PLC) 392#define FLASH_PARTS_NUM 6 393#else 394#define FLASH_PARTS_NUM 5 /* boot;nvram;kernel;rootfs;empty */ 395#endif 396 397static struct mtd_partition bcm947xx_flash_parts[FLASH_PARTS_NUM] = {{0}}; 398 399static uint lookup_flash_rootfs_offset(struct mtd_info *mtd, int *trx_off, size_t size) 400{ 401 struct romfs_super_block *romfsb; 402 struct cramfs_super *cramfsb; 403#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 404 struct squashfs_super_block *squashfsb; 405#else 406 struct dummy_super_block *squashfsb; 407#endif 408 struct trx_header *trx; 409 unsigned char buf[512]; 410 int off; 411 size_t len; 412 413 romfsb = (struct romfs_super_block *) buf; 414 cramfsb = (struct cramfs_super *) buf; 415 squashfsb = (void *) buf; 416 trx = (struct trx_header *) buf; 417 418 /* Look at every 64 KB boundary */ 419 for (off = 0; off < size; off += (64 * 1024)) { 420 memset(buf, 0xe5, sizeof(buf)); 421 422 /* 423 * Read block 0 to test for romfs and cramfs superblock 424 */ 425 if (mtd->read(mtd, off, sizeof(buf), &len, buf) || 426 len != sizeof(buf)) 427 continue; 428 429 /* Try looking at TRX header for rootfs offset */ 430 if (le32_to_cpu(trx->magic) == TRX_MAGIC) { 431 *trx_off = off; 432 if (trx->offsets[1] == 0) 433 continue; 434 /* 435 * Read to test for romfs and cramfs superblock 436 */ 437 off += le32_to_cpu(trx->offsets[1]); 438 memset(buf, 0xe5, sizeof(buf)); 439 if (mtd->read(mtd, off, sizeof(buf), &len, buf) || len != sizeof(buf)) 440 continue; 441 } 442 443 /* romfs is at block zero too */ 444 if (romfsb->word0 == ROMSB_WORD0 && 445 romfsb->word1 == ROMSB_WORD1) { 446 printk(KERN_NOTICE 447 "%s: romfs filesystem found at block %d\n", 448 mtd->name, off / mtd->erasesize); 449 break; 450 } 451 452 /* so is cramfs */ 453 if (cramfsb->magic == CRAMFS_MAGIC) { 454 printk(KERN_NOTICE 455 "%s: cramfs filesystem found at block %d\n", 456 mtd->name, off / mtd->erasesize); 457 break; 458 } 459 if (squashfsb->s_magic == SQUASHFS_MAGIC) { 460 printk(KERN_NOTICE 461 "%s: squash filesystem found at block %d\n", 462 mtd->name, off / mtd->erasesize); 463 break; 464 } 465 } 466 467 return off; 468} 469struct mtd_partition * 470init_mtd_partitions(struct mtd_info *mtd, size_t size) 471{ 472 int bootflags; 473 int nparts = 0; 474 uint32 offset = 0; 475 uint rfs_off = 0; 476 uint vmlz_off, knl_size; 477 uint32 top = 0; 478 uint32 bootsz; 479 480 bootflags = boot_flags(); 481 482 if ((bootflags & FLASH_KERNEL_NFLASH) != FLASH_KERNEL_NFLASH) { 483 rfs_off = lookup_flash_rootfs_offset(mtd, &vmlz_off, size); 484 485 /* Size pmon */ 486 bcm947xx_flash_parts[nparts].name = "boot"; 487 bcm947xx_flash_parts[nparts].size = vmlz_off; 488 bcm947xx_flash_parts[nparts].offset = top; 489 bcm947xx_flash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 490 nparts++; 491 492 /* Setup kernel MTD partition */ 493 bcm947xx_flash_parts[nparts].name = "linux"; 494 bcm947xx_flash_parts[nparts].size = mtd->size - vmlz_off; 495 496#ifdef PLC 497 /* Reserve for PLC */ 498 bcm947xx_flash_parts[nparts].size -= ROUNDUP(0x1000, mtd->erasesize); 499#endif 500 /* Reserve for NVRAM */ 501 bcm947xx_flash_parts[nparts].size -= ROUNDUP(NVRAM_SPACE, mtd->erasesize); 502 503#ifdef BCMCONFMTD 504 bcm947xx_flash_parts[nparts].size -= (mtd->erasesize *4); 505#endif 506 bcm947xx_flash_parts[nparts].offset = vmlz_off; 507 knl_size = bcm947xx_flash_parts[nparts].size; 508 offset = bcm947xx_flash_parts[nparts].offset + knl_size; 509 nparts++; 510 511 /* Setup rootfs MTD partition */ 512 bcm947xx_flash_parts[nparts].name = "rootfs"; 513 bcm947xx_flash_parts[nparts].size = knl_size - (rfs_off - vmlz_off); 514 bcm947xx_flash_parts[nparts].offset = rfs_off; 515 bcm947xx_flash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 516 nparts++; 517 } else { 518 bootsz = boot_partition_size(SI_FLASH2); 519 printk("Boot partition size = %d(0x%x)\n", bootsz, bootsz); 520 /* Size pmon */ 521 bcm947xx_flash_parts[nparts].name = "boot"; 522 bcm947xx_flash_parts[nparts].size = bootsz; 523 bcm947xx_flash_parts[nparts].offset = top; 524 bcm947xx_flash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 525 offset = bcm947xx_flash_parts[nparts].size; 526 nparts++; 527 } 528 529#ifdef BCMCONFMTD 530 /* Setup CONF MTD partition */ 531 bcm947xx_flash_parts[nparts].name = "confmtd"; 532 bcm947xx_flash_parts[nparts].size = mtd->erasesize * 4; 533 bcm947xx_flash_parts[nparts].offset = offset; 534 offset = bcm947xx_flash_parts[nparts].offset + bcm947xx_flash_parts[nparts].size; 535 nparts++; 536#endif /* BCMCONFMTD */ 537 538#ifdef PLC 539 /* Setup plc MTD partition */ 540 bcm947xx_flash_parts[nparts].name = "plc"; 541 bcm947xx_flash_parts[nparts].size = ROUNDUP(0x1000, mtd->erasesize); 542 bcm947xx_flash_parts[nparts].offset = size - (ROUNDUP(NVRAM_SPACE, mtd->erasesize) + ROUNDUP(0x1000, mtd->erasesize)); 543 nparts++; 544#endif 545 546 /* Setup nvram MTD partition */ 547 bcm947xx_flash_parts[nparts].name = "nvram"; 548 bcm947xx_flash_parts[nparts].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); 549 bcm947xx_flash_parts[nparts].offset = size - bcm947xx_flash_parts[nparts].size; 550 nparts++; 551 552 return bcm947xx_flash_parts; 553} 554 555EXPORT_SYMBOL(init_mtd_partitions); 556 557#ifdef CONFIG_MTD_NFLASH 558#define NFLASH_PARTS_NUM 6 559static struct mtd_partition bcm947xx_nflash_parts[NFLASH_PARTS_NUM] = {{0}}; 560 561static uint lookup_nflash_rootfs_offset(struct mtd_info *mtd, int offset, size_t size) 562{ 563 struct romfs_super_block *romfsb; 564 struct cramfs_super *cramfsb; 565#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) 566 struct squashfs_super_block *squashfsb; 567#else 568 struct dummy_super_block *squashfsb; 569#endif 570 struct trx_header *trx; 571 unsigned char buf[NFL_SECTOR_SIZE]; 572 uint blocksize, mask, blk_offset, off, shift = 0; 573 chipcregs_t *cc; 574 int ret; 575 576 romfsb = (struct romfs_super_block *) buf; 577 cramfsb = (struct cramfs_super *) buf; 578 squashfsb = (void *) buf; 579 trx = (struct trx_header *) buf; 580 581 if ((cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX)) == NULL) 582 return 0; 583 584 /* Look at every block boundary till 16MB; higher space is reserved for application data. */ 585 blocksize = mtd->erasesize; 586 printk("lookup_nflash_rootfs_offset: offset = 0x%x\n", offset); 587 for (off = offset; off < NFL_BOOT_OS_SIZE; off += blocksize) { 588 mask = blocksize - 1; 589 blk_offset = off & ~mask; 590 if (nflash_checkbadb(sih, cc, blk_offset) != 0) 591 continue; 592 memset(buf, 0xe5, sizeof(buf)); 593 if ((ret = nflash_read(sih, cc, off, sizeof(buf), buf)) != sizeof(buf)) { 594 printk(KERN_NOTICE 595 "%s: nflash_read return %d\n", mtd->name, ret); 596 continue; 597 } 598 599 /* Try looking at TRX header for rootfs offset */ 600 if (le32_to_cpu(trx->magic) == TRX_MAGIC) { 601 mask = NFL_SECTOR_SIZE - 1; 602 off = offset + (le32_to_cpu(trx->offsets[1]) & ~mask) - blocksize; 603 shift = (le32_to_cpu(trx->offsets[1]) & mask); 604 romfsb = (struct romfs_super_block *)((unsigned char *)romfsb + shift); 605 cramfsb = (struct cramfs_super *)((unsigned char *)cramfsb + shift); 606 squashfsb = (void *)((unsigned char *)squashfsb + shift); 607 continue; 608 } 609 610 /* romfs is at block zero too */ 611 if (romfsb->word0 == ROMSB_WORD0 && 612 romfsb->word1 == ROMSB_WORD1) { 613 printk(KERN_NOTICE 614 "%s: romfs filesystem found at block %d\n", 615 mtd->name, off / blocksize); 616 break; 617 } 618 619 /* so is cramfs */ 620 if (cramfsb->magic == CRAMFS_MAGIC) { 621 printk(KERN_NOTICE 622 "%s: cramfs filesystem found at block %d\n", 623 mtd->name, off / blocksize); 624 break; 625 } 626 627 if (squashfsb->s_magic == SQUASHFS_MAGIC) { 628 printk(KERN_NOTICE 629 "%s: squash filesystem found at block %d\n", 630 mtd->name, off / blocksize); 631 break; 632 } 633 } 634 return shift + off; 635} 636 637struct mtd_partition * init_nflash_mtd_partitions(struct mtd_info *mtd, size_t size) 638{ 639 int bootflags; 640 int nparts = 0; 641 uint32 offset = 0; 642 uint shift = 0; 643 uint32 top = 0; 644 uint32 bootsz; 645 646 bootflags = boot_flags(); 647 if ((bootflags & FLASH_BOOT_NFLASH) == FLASH_BOOT_NFLASH) { 648 bootsz = boot_partition_size(SI_FLASH1); 649 if (bootsz > mtd->erasesize) { 650 /* Prepare double space in case of bad blocks */ 651 bootsz = (bootsz << 1); 652 } else { 653 /* CFE occupies at least one block */ 654 bootsz = mtd->erasesize; 655 } 656 printk("Boot partition size = %d(0x%x)\n", bootsz, bootsz); 657 658 /* Size pmon */ 659 bcm947xx_nflash_parts[nparts].name = "boot"; 660 bcm947xx_nflash_parts[nparts].size = bootsz; 661 bcm947xx_nflash_parts[nparts].offset = top; 662 bcm947xx_nflash_parts[nparts].mask_flags = MTD_WRITEABLE; /* forces on read only */ 663 offset = bcm947xx_nflash_parts[nparts].size; 664 nparts++; 665 666 /* Setup NVRAM MTD partition */ 667 bcm947xx_nflash_parts[nparts].name = "nvram"; 668 bcm947xx_nflash_parts[nparts].size = NFL_BOOT_SIZE - offset; 669 bcm947xx_nflash_parts[nparts].offset = offset; 670 671 offset = NFL_BOOT_SIZE; 672 nparts++; 673 } 674 675 if ((bootflags & FLASH_KERNEL_NFLASH) == FLASH_KERNEL_NFLASH) { 676 /* Setup kernel MTD partition */ 677 bcm947xx_nflash_parts[nparts].name = "linux"; 678 bcm947xx_nflash_parts[nparts].size = nparts ? (NFL_BOOT_OS_SIZE - NFL_BOOT_SIZE) : NFL_BOOT_OS_SIZE; 679 bcm947xx_nflash_parts[nparts].offset = offset; 680 681 shift = lookup_nflash_rootfs_offset(mtd, offset, size); 682 683 offset = NFL_BOOT_OS_SIZE; 684 nparts++; 685 686 /* Setup rootfs MTD partition */ 687 bcm947xx_nflash_parts[nparts].name = "rootfs"; 688 bcm947xx_nflash_parts[nparts].size = NFL_BOOT_OS_SIZE - shift; 689 bcm947xx_nflash_parts[nparts].offset = shift; 690 bcm947xx_nflash_parts[nparts].mask_flags = MTD_WRITEABLE; 691 692 nparts++; 693 } 694 695 return bcm947xx_nflash_parts; 696} 697 698EXPORT_SYMBOL(init_nflash_mtd_partitions); 699#endif /* CONFIG_MTD_NFLASH */ 700 701#ifdef CONFIG_BLK_DEV_INITRD 702extern char _end; 703 704/* The check_ramdisk_trx has more exact qualification to look at TRX header from end of linux */ 705static __init int 706check_ramdisk_trx(unsigned long offset, unsigned long ram_size) 707{ 708 struct trx_header *trx; 709 uint32 crc; 710 unsigned int len; 711 uint8 *ptr = (uint8 *)offset; 712 713 trx = (struct trx_header *)ptr; 714 715 /* Not a TRX_MAGIC */ 716 if (le32_to_cpu(trx->magic) != TRX_MAGIC) { 717 printk("check_ramdisk_trx: not a valid TRX magic\n"); 718 return -1; 719 } 720 721 /* TRX len invalid */ 722 len = le32_to_cpu(trx->len); 723 if (offset + len > ram_size) { 724 printk("check_ramdisk_trx: not a valid TRX length\n"); 725 return -1; 726 } 727 728 /* Checksum over header */ 729 crc = hndcrc32((uint8 *) &trx->flag_version, 730 sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version), 731 CRC32_INIT_VALUE); 732 733 /* Move ptr to data */ 734 ptr += sizeof(struct trx_header); 735 len -= sizeof(struct trx_header); 736 737 /* Checksum over data */ 738 crc = hndcrc32(ptr, len, crc); 739 740 /* Verify checksum */ 741 if (le32_to_cpu(trx->crc32) != crc) { 742 printk("check_ramdisk_trx: checksum invalid\n"); 743 return -1; 744 } 745 746 return 0; 747} 748 749void __init init_ramdisk(unsigned long mem_end) 750{ 751 struct trx_header *trx = NULL; 752 char *from_rootfs, *to_rootfs; 753 unsigned long rootfs_size = 0; 754 unsigned long ram_size = mem_end + 0x80000000; 755 unsigned long offset; 756 char *root_cmd = "root=/dev/ram0 console=ttyS0,115200 rdinit=/sbin/preinit"; 757 758 to_rootfs = (char *)(((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK); 759 offset = ((unsigned long)&_end +0xffff) & ~0xffff; 760 761 /* Look at TRX header from end of linux */ 762 for (; offset < ram_size; offset += 0x10000) { 763 trx = (struct trx_header *)offset; 764 if (le32_to_cpu(trx->magic) == TRX_MAGIC && 765 check_ramdisk_trx(offset, ram_size) == 0) { 766 printk(KERN_NOTICE 767 "Found TRX image at %08lx\n", offset); 768 from_rootfs = (char *)((unsigned long)trx + le32_to_cpu(trx->offsets[1])); 769 rootfs_size = le32_to_cpu(trx->len) - le32_to_cpu(trx->offsets[1]); 770 rootfs_size = (rootfs_size + 0xffff) & ~0xffff; 771 printk("rootfs size is %ld bytes at 0x%p, copying to 0x%p\n", rootfs_size, from_rootfs, to_rootfs); 772 memmove(to_rootfs, from_rootfs, rootfs_size); 773 774 initrd_start = (int)to_rootfs; 775 initrd_end = initrd_start + rootfs_size; 776 strncpy(arcs_cmdline, root_cmd, sizeof(arcs_cmdline)); 777 /* 778 * In case the system warm boot, the memory won't be zeroed. 779 * So we have to erase trx magic. 780 */ 781 if (initrd_end < (unsigned long)trx) 782 trx->magic = 0; 783 break; 784 } 785 } 786} 787#endif 788#endif 789