• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mips/brcm-boards/bcm947xx/
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