2 * Copyright (C) 2006-2008 Florian Fainelli <florian@openwrt.org>
3 * Mike Albon <malbon@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/mtd/map.h>
23 #include <linux/mtd/mtd.h>
24 #include <linux/mtd/partitions.h>
25 #include <linux/vmalloc.h>
26 #include <linux/platform_device.h>
31 #define BUSWIDTH 2 /* Buswidth */
32 #define EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
34 #define PFX KBUILD_MODNAME ": "
36 extern int parse_redboot_partitions(struct mtd_info
*master
, struct mtd_partition
**pparts
, unsigned long fis_origin
);
37 static struct mtd_partition
*parsed_parts
;
39 static struct mtd_info
*bcm963xx_mtd_info
;
41 static struct map_info bcm963xx_map
= {
43 .bankwidth
= BUSWIDTH
,
46 static int parse_cfe_partitions( struct mtd_info
*master
, struct mtd_partition
**pparts
)
48 int nrparts
= 2, curpart
= 0; /* CFE and NVRAM are always present. */
50 struct mtd_partition
*parts
;
53 unsigned int rootfsaddr
, kerneladdr
, spareaddr
;
54 unsigned int rootfslen
, kernellen
, sparelen
, totallen
;
58 /* Allocate memory for buffer */
59 buf
= vmalloc(sizeof(struct bcm_tag
));
64 ret
= master
->read(master
,master
->erasesize
,sizeof(struct bcm_tag
), &retlen
, (void *)buf
);
65 if (retlen
!= sizeof(struct bcm_tag
)){
69 printk(KERN_INFO PFX
"CFE boot tag found with version %s and board type %s.\n",buf
->tagVersion
,buf
->boardid
);
71 /* Get the values and calculate */
72 sscanf(buf
->rootAddress
,"%u", &rootfsaddr
);
73 rootfsaddr
= rootfsaddr
- EXTENDED_SIZE
;
74 sscanf(buf
->rootLength
, "%u", &rootfslen
);
75 sscanf(buf
->kernelAddress
, "%u", &kerneladdr
);
76 kerneladdr
= kerneladdr
- EXTENDED_SIZE
;
77 sscanf(buf
->kernelLength
, "%u", &kernellen
);
78 sscanf(buf
->totalLength
, "%u", &totallen
);
79 spareaddr
= roundup(totallen
,master
->erasesize
) + master
->erasesize
;
80 sparelen
= master
->size
- spareaddr
- master
->erasesize
;
82 /* Determine number of partitions */
93 /* Ask kernel for more memory */
94 parts
= kzalloc(sizeof(*parts
) * nrparts
+ 10 * nrparts
, GFP_KERNEL
);
100 /* Start building partition list */
101 parts
[curpart
].name
= "CFE";
102 parts
[curpart
].offset
= 0;
103 parts
[curpart
].size
= master
->erasesize
;
107 parts
[curpart
].name
= "kernel";
108 parts
[curpart
].offset
= kerneladdr
;
109 parts
[curpart
].size
= kernellen
;
114 parts
[curpart
].name
= "rootfs";
115 parts
[curpart
].offset
= rootfsaddr
;
116 parts
[curpart
].size
= rootfslen
;
118 parts
[curpart
].size
+= sparelen
;
121 parts
[curpart
].name
= "nvram";
122 parts
[curpart
].offset
= master
->size
- master
->erasesize
;
123 parts
[curpart
].size
= master
->erasesize
;
125 for (i
= 0; i
< nrparts
; i
++)
126 printk(KERN_INFO PFX
"Partition %d is %s offset %x and length %x\n", i
, parts
[i
].name
, parts
[i
].offset
, parts
[i
].size
);
134 static int bcm963xx_detect_cfe(struct mtd_info
*master
)
136 int idoffset
= 0x4e0;
137 static char idstring
[8] = "CFE1CFE1";
142 ret
= master
->read(master
, idoffset
, 8, &retlen
, (void *)buf
);
144 printk(KERN_INFO PFX
"Read Signature value of %s\n", buf
);
146 return strncmp(idstring
, buf
, 8);
149 static int bcm963xx_probe(struct platform_device
*pdev
)
152 int parsed_nr_parts
= 0;
156 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
157 bcm963xx_map
.phys
= r
->start
;
158 bcm963xx_map
.size
= (r
->end
- r
->start
);
159 bcm963xx_map
.virt
= ioremap(r
->start
, r
->end
- r
->start
+ 1);
161 if (!bcm963xx_map
.virt
) {
162 printk(KERN_ERR PFX
"Failed to ioremap\n");
165 printk(KERN_INFO PFX
"0x%08x at 0x%08x\n", bcm963xx_map
.size
, bcm963xx_map
.phys
);
167 simple_map_init(&bcm963xx_map
);
169 bcm963xx_mtd_info
= do_map_probe("cfi_probe", &bcm963xx_map
);
170 if (!bcm963xx_mtd_info
) {
171 printk(KERN_ERR PFX
"Failed to probe using CFI\n");
176 bcm963xx_mtd_info
->owner
= THIS_MODULE
;
178 /* This is mutually exclusive */
179 if (bcm963xx_detect_cfe(bcm963xx_mtd_info
) == 0) {
180 printk(KERN_INFO PFX
"CFE bootloader detected\n");
181 if (parsed_nr_parts
== 0) {
182 int ret
= parse_cfe_partitions(bcm963xx_mtd_info
, &parsed_parts
);
185 parsed_nr_parts
= ret
;
189 printk(KERN_INFO PFX
"assuming RedBoot bootloader\n");
190 if (bcm963xx_mtd_info
->size
> 0x00400000) {
191 printk(KERN_INFO PFX
"Support for extended flash memory size : 0x%08X ; ONLY 64MBIT SUPPORT\n", bcm963xx_mtd_info
->size
);
192 bcm963xx_map
.virt
= (u32
)(EXTENDED_SIZE
);
195 #ifdef CONFIG_MTD_REDBOOT_PARTS
196 if (parsed_nr_parts
== 0) {
197 int ret
= parse_redboot_partitions(bcm963xx_mtd_info
, &parsed_parts
, 0);
199 part_type
= "RedBoot";
200 parsed_nr_parts
= ret
;
206 return add_mtd_partitions(bcm963xx_mtd_info
, parsed_parts
, parsed_nr_parts
);
209 iounmap(bcm963xx_map
.virt
);
213 static int bcm963xx_remove(struct platform_device
*pdev
)
215 if (bcm963xx_mtd_info
) {
216 del_mtd_partitions(bcm963xx_mtd_info
);
217 map_destroy(bcm963xx_mtd_info
);
220 if (bcm963xx_map
.virt
) {
221 iounmap(bcm963xx_map
.virt
);
222 bcm963xx_map
.virt
= 0;
228 static struct platform_driver bcm63xx_mtd_dev
= {
229 .probe
= bcm963xx_probe
,
230 .remove
= bcm963xx_remove
,
232 .name
= "bcm963xx-flash",
233 .owner
= THIS_MODULE
,
237 static int __init
bcm963xx_mtd_init(void)
239 return platform_driver_register(&bcm63xx_mtd_dev
);
242 static void __exit
bcm963xx_mtd_exit(void)
244 platform_driver_unregister(&bcm63xx_mtd_dev
);
247 module_init(bcm963xx_mtd_init
);
248 module_exit(bcm963xx_mtd_exit
);
250 MODULE_LICENSE("GPL");
251 MODULE_DESCRIPTION("Broadcom BCM63xx MTD partition parser/mapping for CFE and RedBoot");
252 MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
253 MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");