summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/bcm63xxpart.c
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/bcm63xxpart.c
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/bcm63xxpart.c')
-rw-r--r--drivers/mtd/bcm63xxpart.c189
1 files changed, 189 insertions, 0 deletions
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");