diff options
author | Jonas Gorski <jonas.gorski@gmail.com> | 2011-12-05 10:08:08 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-01-09 13:15:31 -0500 |
commit | 70a3c167c4bf38b5ffd07d8506230ecc20ef7ab1 (patch) | |
tree | 520c452c53100751d02e30bd105e633a8c3639f9 | |
parent | ca105f4d9823f916a4718c4bc766fd14842056f2 (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/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mtd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/bcm63xxpart.c | 189 | ||||
-rw-r--r-- | drivers/mtd/maps/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mtd/maps/bcm963xx-flash.c | 153 |
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 | ||
143 | config 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 | |||
143 | comment "User Modules And Translation Layers" | 151 | comment "User Modules And Translation Layers" |
144 | 152 | ||
145 | config MTD_CHAR | 153 | config 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 | |||
11 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o | 11 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o |
12 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o | 12 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o |
13 | obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o | 13 | obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o |
14 | obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o | ||
14 | 15 | ||
15 | # 'Users' - code which presents functionality to userspace. | 16 | # 'Users' - code which presents functionality to userspace. |
16 | obj-$(CONFIG_MTD_CHAR) += mtdchar.o | 17 | obj-$(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 | |||
38 | static 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 | |||
53 | static 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 | |||
165 | static struct mtd_part_parser bcm63xx_cfe_parser = { | ||
166 | .owner = THIS_MODULE, | ||
167 | .parse_fn = bcm63xx_parse_cfe_partitions, | ||
168 | .name = "bcm63xxpart", | ||
169 | }; | ||
170 | |||
171 | static int __init bcm63xx_cfe_parser_init(void) | ||
172 | { | ||
173 | return register_mtd_parser(&bcm63xx_cfe_parser); | ||
174 | } | ||
175 | |||
176 | static void __exit bcm63xx_cfe_parser_exit(void) | ||
177 | { | ||
178 | deregister_mtd_parser(&bcm63xx_cfe_parser); | ||
179 | } | ||
180 | |||
181 | module_init(bcm63xx_cfe_parser_init); | ||
182 | module_exit(bcm63xx_cfe_parser_exit); | ||
183 | |||
184 | MODULE_LICENSE("GPL"); | ||
185 | MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); | ||
186 | MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); | ||
187 | MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>"); | ||
188 | MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com"); | ||
189 | MODULE_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 | |||
39 | static struct mtd_partition *parsed_parts; | ||
40 | 34 | ||
41 | static struct mtd_info *bcm963xx_mtd_info; | 35 | static 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 | ||
48 | static int parse_cfe_partitions(struct mtd_info *master, | 42 | static 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 | |||
156 | static 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 | ||
171 | static int bcm963xx_probe(struct platform_device *pdev) | 44 | static 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) | |||
208 | probe_ok: | 79 | probe_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 | |||
231 | err_probe: | 84 | err_probe: |
232 | iounmap(bcm963xx_map.virt); | 85 | iounmap(bcm963xx_map.virt); |
233 | return err; | 86 | return err; |