aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/mtd/Kconfig8
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/bcm63xxpart.c189
-rw-r--r--drivers/mtd/maps/Kconfig1
-rw-r--r--drivers/mtd/maps/bcm963xx-flash.c153
5 files changed, 202 insertions, 150 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 318a869286ab..1be621841400 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -140,6 +140,14 @@ config MTD_AR7_PARTS
140 ---help--- 140 ---help---
141 TI AR7 partitioning support 141 TI AR7 partitioning support
142 142
143config MTD_BCM63XX_PARTS
144 tristate "BCM63XX CFE partitioning support"
145 depends on BCM63XX
146 select CRC32
147 help
148 This provides partions parsing for BCM63xx devices with CFE
149 bootloaders.
150
143comment "User Modules And Translation Layers" 151comment "User Modules And Translation Layers"
144 152
145config MTD_CHAR 153config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 9aaac3ac89f3..f90135429dc7 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
11obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o 11obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
12obj-$(CONFIG_MTD_AFS_PARTS) += afs.o 12obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
13obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o 13obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
14obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
14 15
15# 'Users' - code which presents functionality to userspace. 16# 'Users' - code which presents functionality to userspace.
16obj-$(CONFIG_MTD_CHAR) += mtdchar.o 17obj-$(CONFIG_MTD_CHAR) += mtdchar.o
diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c
new file mode 100644
index 000000000000..ac7d3c823949
--- /dev/null
+++ b/drivers/mtd/bcm63xxpart.c
@@ -0,0 +1,189 @@
1/*
2 * BCM63XX CFE image tag parser
3 *
4 * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
5 * Mike Albon <malbon@openwrt.org>
6 * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
7 * Copyright © 2011 Jonas Gorski <jonas.gorski@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/kernel.h>
29#include <linux/slab.h>
30#include <linux/vmalloc.h>
31#include <linux/mtd/mtd.h>
32#include <linux/mtd/partitions.h>
33
34#include <asm/mach-bcm63xx/bcm963xx_tag.h>
35
36#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
37
38static int bcm63xx_detect_cfe(struct mtd_info *master)
39{
40 int idoffset = 0x4e0;
41 static char idstring[8] = "CFE1CFE1";
42 char buf[9];
43 int ret;
44 size_t retlen;
45
46 ret = master->read(master, idoffset, 8, &retlen, (void *)buf);
47 buf[retlen] = 0;
48 pr_info("Read Signature value of %s\n", buf);
49
50 return strncmp(idstring, buf, 8);
51}
52
53static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
54 struct mtd_partition **pparts,
55 struct mtd_part_parser_data *data)
56{
57 /* CFE, NVRAM and global Linux are always present */
58 int nrparts = 3, curpart = 0;
59 struct bcm_tag *buf;
60 struct mtd_partition *parts;
61 int ret;
62 size_t retlen;
63 unsigned int rootfsaddr, kerneladdr, spareaddr;
64 unsigned int rootfslen, kernellen, sparelen, totallen;
65 int namelen = 0;
66 int i;
67 char *boardid;
68 char *tagversion;
69
70 if (bcm63xx_detect_cfe(master))
71 return -EINVAL;
72
73 /* Allocate memory for buffer */
74 buf = vmalloc(sizeof(struct bcm_tag));
75 if (!buf)
76 return -ENOMEM;
77
78 /* Get the tag */
79 ret = master->read(master, master->erasesize, sizeof(struct bcm_tag),
80 &retlen, (void *)buf);
81 if (retlen != sizeof(struct bcm_tag)) {
82 vfree(buf);
83 return -EIO;
84 }
85
86 sscanf(buf->kernel_address, "%u", &kerneladdr);
87 sscanf(buf->kernel_length, "%u", &kernellen);
88 sscanf(buf->total_length, "%u", &totallen);
89 tagversion = &(buf->tag_version[0]);
90 boardid = &(buf->board_id[0]);
91
92 pr_info("CFE boot tag found with version %s and board type %s\n",
93 tagversion, boardid);
94
95 kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
96 rootfsaddr = kerneladdr + kernellen;
97 spareaddr = roundup(totallen, master->erasesize) + master->erasesize;
98 sparelen = master->size - spareaddr - master->erasesize;
99 rootfslen = spareaddr - rootfsaddr;
100
101 /* Determine number of partitions */
102 namelen = 8;
103 if (rootfslen > 0) {
104 nrparts++;
105 namelen += 6;
106 }
107 if (kernellen > 0) {
108 nrparts++;
109 namelen += 6;
110 }
111
112 /* Ask kernel for more memory */
113 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
114 if (!parts) {
115 vfree(buf);
116 return -ENOMEM;
117 }
118
119 /* Start building partition list */
120 parts[curpart].name = "CFE";
121 parts[curpart].offset = 0;
122 parts[curpart].size = master->erasesize;
123 curpart++;
124
125 if (kernellen > 0) {
126 parts[curpart].name = "kernel";
127 parts[curpart].offset = kerneladdr;
128 parts[curpart].size = kernellen;
129 curpart++;
130 }
131
132 if (rootfslen > 0) {
133 parts[curpart].name = "rootfs";
134 parts[curpart].offset = rootfsaddr;
135 parts[curpart].size = rootfslen;
136 if (sparelen > 0)
137 parts[curpart].size += sparelen;
138 curpart++;
139 }
140
141 parts[curpart].name = "nvram";
142 parts[curpart].offset = master->size - master->erasesize;
143 parts[curpart].size = master->erasesize;
144
145 /* Global partition "linux" to make easy firmware upgrade */
146 curpart++;
147 parts[curpart].name = "linux";
148 parts[curpart].offset = parts[0].size;
149 parts[curpart].size = master->size - parts[0].size - parts[3].size;
150
151 for (i = 0; i < nrparts; i++)
152 pr_info("Partition %d is %s offset %lx and length %lx\n", i,
153 parts[i].name, (long unsigned int)(parts[i].offset),
154 (long unsigned int)(parts[i].size));
155
156 pr_info("Spare partition is offset %x and length %x\n", spareaddr,
157 sparelen);
158
159 *pparts = parts;
160 vfree(buf);
161
162 return nrparts;
163};
164
165static struct mtd_part_parser bcm63xx_cfe_parser = {
166 .owner = THIS_MODULE,
167 .parse_fn = bcm63xx_parse_cfe_partitions,
168 .name = "bcm63xxpart",
169};
170
171static int __init bcm63xx_cfe_parser_init(void)
172{
173 return register_mtd_parser(&bcm63xx_cfe_parser);
174}
175
176static void __exit bcm63xx_cfe_parser_exit(void)
177{
178 deregister_mtd_parser(&bcm63xx_cfe_parser);
179}
180
181module_init(bcm63xx_cfe_parser_init);
182module_exit(bcm63xx_cfe_parser_exit);
183
184MODULE_LICENSE("GPL");
185MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
186MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
187MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
188MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com");
189MODULE_DESCRIPTION("MTD partitioning for BCM63XX CFE bootloaders");
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;