aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps
diff options
context:
space:
mode:
authorJonas Gorski <jonas.gorski@gmail.com>2011-12-05 10:08:08 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-01-09 13:15:31 -0500
commit70a3c167c4bf38b5ffd07d8506230ecc20ef7ab1 (patch)
tree520c452c53100751d02e30bd105e633a8c3639f9 /drivers/mtd/maps
parentca105f4d9823f916a4718c4bc766fd14842056f2 (diff)
mtd: maps: bcm963xx-flash: make CFE partition parsing an mtd parser
Recent BCM63XX devices support a variety of flash types (parallel, SPI, NAND) and share the partition layout. To prevent code duplication make the CFE partition parsing code a stand alone mtd parser to allow SPI or NAND flash drivers to use it. Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com> Acked-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/maps')
-rw-r--r--drivers/mtd/maps/Kconfig1
-rw-r--r--drivers/mtd/maps/bcm963xx-flash.c153
2 files changed, 4 insertions, 150 deletions
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 8e0c4bf9f7fb..acc5e0816000 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -247,6 +247,7 @@ config MTD_BCM963XX
247 depends on BCM63XX 247 depends on BCM63XX
248 select MTD_MAP_BANK_WIDTH_2 248 select MTD_MAP_BANK_WIDTH_2
249 select MTD_CFI_I1 249 select MTD_CFI_I1
250 select MTD_BCM63XX_PARTS
250 help 251 help
251 Support for parsing CFE image tag and creating MTD partitions on 252 Support for parsing CFE image tag and creating MTD partitions on
252 Broadcom BCM63xx boards. 253 Broadcom BCM63xx boards.
diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c
index e5e3c0a04aaf..830264807bb4 100644
--- a/drivers/mtd/maps/bcm963xx-flash.c
+++ b/drivers/mtd/maps/bcm963xx-flash.c
@@ -27,16 +27,10 @@
27#include <linux/mtd/map.h> 27#include <linux/mtd/map.h>
28#include <linux/mtd/mtd.h> 28#include <linux/mtd/mtd.h>
29#include <linux/mtd/partitions.h> 29#include <linux/mtd/partitions.h>
30#include <linux/vmalloc.h>
31#include <linux/platform_device.h> 30#include <linux/platform_device.h>
32#include <linux/io.h> 31#include <linux/io.h>
33 32
34#include <asm/mach-bcm63xx/bcm963xx_tag.h>
35
36#define BCM63XX_BUSWIDTH 2 /* Buswidth */ 33#define BCM63XX_BUSWIDTH 2 /* Buswidth */
37#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
38
39static struct mtd_partition *parsed_parts;
40 34
41static struct mtd_info *bcm963xx_mtd_info; 35static struct mtd_info *bcm963xx_mtd_info;
42 36
@@ -45,134 +39,11 @@ static struct map_info bcm963xx_map = {
45 .bankwidth = BCM63XX_BUSWIDTH, 39 .bankwidth = BCM63XX_BUSWIDTH,
46}; 40};
47 41
48static int parse_cfe_partitions(struct mtd_info *master, 42static const char *part_types[] = { "bcm63xxpart", NULL };
49 struct mtd_partition **pparts)
50{
51 /* CFE, NVRAM and global Linux are always present */
52 int nrparts = 3, curpart = 0;
53 struct bcm_tag *buf;
54 struct mtd_partition *parts;
55 int ret;
56 size_t retlen;
57 unsigned int rootfsaddr, kerneladdr, spareaddr;
58 unsigned int rootfslen, kernellen, sparelen, totallen;
59 int namelen = 0;
60 int i;
61 char *boardid;
62 char *tagversion;
63
64 /* Allocate memory for buffer */
65 buf = vmalloc(sizeof(struct bcm_tag));
66 if (!buf)
67 return -ENOMEM;
68
69 /* Get the tag */
70 ret = master->read(master, master->erasesize, sizeof(struct bcm_tag),
71 &retlen, (void *)buf);
72 if (retlen != sizeof(struct bcm_tag)) {
73 vfree(buf);
74 return -EIO;
75 }
76
77 sscanf(buf->kernel_address, "%u", &kerneladdr);
78 sscanf(buf->kernel_length, "%u", &kernellen);
79 sscanf(buf->total_length, "%u", &totallen);
80 tagversion = &(buf->tag_version[0]);
81 boardid = &(buf->board_id[0]);
82
83 pr_info("CFE boot tag found with version %s and board type %s\n",
84 tagversion, boardid);
85
86 kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
87 rootfsaddr = kerneladdr + kernellen;
88 spareaddr = roundup(totallen, master->erasesize) + master->erasesize;
89 sparelen = master->size - spareaddr - master->erasesize;
90 rootfslen = spareaddr - rootfsaddr;
91
92 /* Determine number of partitions */
93 namelen = 8;
94 if (rootfslen > 0) {
95 nrparts++;
96 namelen += 6;
97 }
98 if (kernellen > 0) {
99 nrparts++;
100 namelen += 6;
101 }
102
103 /* Ask kernel for more memory */
104 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
105 if (!parts) {
106 vfree(buf);
107 return -ENOMEM;
108 }
109
110 /* Start building partition list */
111 parts[curpart].name = "CFE";
112 parts[curpart].offset = 0;
113 parts[curpart].size = master->erasesize;
114 curpart++;
115
116 if (kernellen > 0) {
117 parts[curpart].name = "kernel";
118 parts[curpart].offset = kerneladdr;
119 parts[curpart].size = kernellen;
120 curpart++;
121 }
122
123 if (rootfslen > 0) {
124 parts[curpart].name = "rootfs";
125 parts[curpart].offset = rootfsaddr;
126 parts[curpart].size = rootfslen;
127 if (sparelen > 0)
128 parts[curpart].size += sparelen;
129 curpart++;
130 }
131
132 parts[curpart].name = "nvram";
133 parts[curpart].offset = master->size - master->erasesize;
134 parts[curpart].size = master->erasesize;
135
136 /* Global partition "linux" to make easy firmware upgrade */
137 curpart++;
138 parts[curpart].name = "linux";
139 parts[curpart].offset = parts[0].size;
140 parts[curpart].size = master->size - parts[0].size - parts[3].size;
141
142 for (i = 0; i < nrparts; i++)
143 pr_info("Partition %d is %s offset %lx and length %lx\n", i,
144 parts[i].name, (long unsigned int)(parts[i].offset),
145 (long unsigned int)(parts[i].size));
146
147 pr_info("Spare partition is offset %x and length %x\n", spareaddr,
148 sparelen);
149
150 *pparts = parts;
151 vfree(buf);
152
153 return nrparts;
154};
155
156static int bcm963xx_detect_cfe(struct mtd_info *master)
157{
158 int idoffset = 0x4e0;
159 static char idstring[8] = "CFE1CFE1";
160 char buf[9];
161 int ret;
162 size_t retlen;
163
164 ret = master->read(master, idoffset, 8, &retlen, (void *)buf);
165 buf[retlen] = 0;
166 printk(KERN_INFO PFX "Read Signature value of %s\n", buf);
167
168 return strncmp(idstring, buf, 8);
169}
170 43
171static int bcm963xx_probe(struct platform_device *pdev) 44static int bcm963xx_probe(struct platform_device *pdev)
172{ 45{
173 int err = 0; 46 int err = 0;
174 int parsed_nr_parts = 0;
175 char *part_type;
176 struct resource *r; 47 struct resource *r;
177 48
178 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 49 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -208,26 +79,8 @@ static int bcm963xx_probe(struct platform_device *pdev)
208probe_ok: 79probe_ok:
209 bcm963xx_mtd_info->owner = THIS_MODULE; 80 bcm963xx_mtd_info->owner = THIS_MODULE;
210 81
211 /* This is mutually exclusive */ 82 return mtd_device_parse_register(bcm963xx_mtd_info, part_types, NULL,
212 if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) { 83 NULL, 0);
213 dev_info(&pdev->dev, "CFE bootloader detected\n");
214 if (parsed_nr_parts == 0) {
215 int ret = parse_cfe_partitions(bcm963xx_mtd_info,
216 &parsed_parts);
217 if (ret > 0) {
218 part_type = "CFE";
219 parsed_nr_parts = ret;
220 }
221 }
222 } else {
223 dev_info(&pdev->dev, "unsupported bootloader\n");
224 err = -ENODEV;
225 goto err_probe;
226 }
227
228 return mtd_device_register(bcm963xx_mtd_info, parsed_parts,
229 parsed_nr_parts);
230
231err_probe: 84err_probe:
232 iounmap(bcm963xx_map.virt); 85 iounmap(bcm963xx_map.virt);
233 return err; 86 return err;