aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafał Miłecki <zajec5@gmail.com>2012-08-30 01:41:16 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-09-29 10:32:31 -0400
commit3cf7f1314ed88598b640318f60d8d5fb40509f23 (patch)
tree7bd431d4e4a653a1dd886ccf6ba184900761f66a /drivers
parentaa3c5dc52ee2fbfc3020fdc96eccb74f0fb2858d (diff)
mtd: bcm47part driver for BCM47XX chipsets
This driver provides parser detecting partitions on BCM47XX flash memories. It has many differences in comparison to BCM63XX, like: 1) Different CFE with no more trivial MAGICs 2) More partitions types (board_data, ML, POT) 3) Supporting more than 1 flash on a device which resulted in decision of writing new parser. It uses generic mtd interface and was successfully tested with Netgear WNDR4500 router which has 2 flash memories: serial one and NAND one. Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/Kconfig7
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/bcm47xxpart.c202
3 files changed, 210 insertions, 0 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 27143e042af5..73fcbbeb78d0 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -148,6 +148,13 @@ config MTD_BCM63XX_PARTS
148 This provides partions parsing for BCM63xx devices with CFE 148 This provides partions parsing for BCM63xx devices with CFE
149 bootloaders. 149 bootloaders.
150 150
151config MTD_BCM47XX_PARTS
152 tristate "BCM47XX partitioning support"
153 depends on BCM47XX
154 help
155 This provides partitions parser for devices based on BCM47xx
156 boards.
157
151comment "User Modules And Translation Layers" 158comment "User Modules And Translation Layers"
152 159
153config MTD_CHAR 160config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index f90135429dc7..18a38e55b2f0 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -12,6 +12,7 @@ obj-$(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 14obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
15obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
15 16
16# 'Users' - code which presents functionality to userspace. 17# 'Users' - code which presents functionality to userspace.
17obj-$(CONFIG_MTD_CHAR) += mtdchar.o 18obj-$(CONFIG_MTD_CHAR) += mtdchar.o
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c
new file mode 100644
index 000000000000..e06d782489a6
--- /dev/null
+++ b/drivers/mtd/bcm47xxpart.c
@@ -0,0 +1,202 @@
1/*
2 * BCM47XX MTD partitioning
3 *
4 * Copyright © 2012 Rafał Miłecki <zajec5@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/slab.h>
15#include <linux/mtd/mtd.h>
16#include <linux/mtd/partitions.h>
17#include <asm/mach-bcm47xx/nvram.h>
18
19/* 10 parts were found on sflash on Netgear WNDR4500 */
20#define BCM47XXPART_MAX_PARTS 12
21
22/*
23 * Amount of bytes we read when analyzing each block of flash memory.
24 * Set it big enough to allow detecting partition and reading important data.
25 */
26#define BCM47XXPART_BYTES_TO_READ 0x404
27
28/* Magics */
29#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
30#define POT_MAGIC1 0x54544f50 /* POTT */
31#define POT_MAGIC2 0x504f /* OP */
32#define ML_MAGIC1 0x39685a42
33#define ML_MAGIC2 0x26594131
34#define TRX_MAGIC 0x30524448
35
36struct trx_header {
37 uint32_t magic;
38 uint32_t length;
39 uint32_t crc32;
40 uint16_t flags;
41 uint16_t version;
42 uint32_t offset[3];
43} __packed;
44
45static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
46 u64 offset, uint32_t mask_flags)
47{
48 part->name = name;
49 part->offset = offset;
50 part->mask_flags = mask_flags;
51}
52
53static int bcm47xxpart_parse(struct mtd_info *master,
54 struct mtd_partition **pparts,
55 struct mtd_part_parser_data *data)
56{
57 struct mtd_partition *parts;
58 uint8_t i, curr_part = 0;
59 uint32_t *buf;
60 size_t bytes_read;
61 uint32_t offset;
62 uint32_t blocksize = 0x10000;
63 struct trx_header *trx;
64
65 /* Alloc */
66 parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
67 GFP_KERNEL);
68 buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
69
70 /* Parse block by block looking for magics */
71 for (offset = 0; offset <= master->size - blocksize;
72 offset += blocksize) {
73 /* Nothing more in higher memory */
74 if (offset >= 0x2000000)
75 break;
76
77 if (curr_part > BCM47XXPART_MAX_PARTS) {
78 pr_warn("Reached maximum number of partitions, scanning stopped!\n");
79 break;
80 }
81
82 /* Read beginning of the block */
83 if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
84 &bytes_read, (uint8_t *)buf) < 0) {
85 pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
86 offset);
87 continue;
88 }
89
90 /* CFE has small NVRAM at 0x400 */
91 if (buf[0x400 / 4] == NVRAM_HEADER) {
92 bcm47xxpart_add_part(&parts[curr_part++], "boot",
93 offset, MTD_WRITEABLE);
94 continue;
95 }
96
97 /* Standard NVRAM */
98 if (buf[0x000 / 4] == NVRAM_HEADER) {
99 bcm47xxpart_add_part(&parts[curr_part++], "nvram",
100 offset, 0);
101 continue;
102 }
103
104 /*
105 * board_data starts with board_id which differs across boards,
106 * but we can use 'MPFR' (hopefully) magic at 0x100
107 */
108 if (buf[0x100 / 4] == BOARD_DATA_MAGIC) {
109 bcm47xxpart_add_part(&parts[curr_part++], "board_data",
110 offset, MTD_WRITEABLE);
111 continue;
112 }
113
114 /* POT(TOP) */
115 if (buf[0x000 / 4] == POT_MAGIC1 &&
116 (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
117 bcm47xxpart_add_part(&parts[curr_part++], "POT", offset,
118 MTD_WRITEABLE);
119 continue;
120 }
121
122 /* ML */
123 if (buf[0x010 / 4] == ML_MAGIC1 &&
124 buf[0x014 / 4] == ML_MAGIC2) {
125 bcm47xxpart_add_part(&parts[curr_part++], "ML", offset,
126 MTD_WRITEABLE);
127 continue;
128 }
129
130 /* TRX */
131 if (buf[0x000 / 4] == TRX_MAGIC) {
132 trx = (struct trx_header *)buf;
133
134 i = 0;
135 /* We have LZMA loader if offset[2] points to sth */
136 if (trx->offset[2]) {
137 bcm47xxpart_add_part(&parts[curr_part++],
138 "loader",
139 offset + trx->offset[i],
140 0);
141 i++;
142 }
143
144 bcm47xxpart_add_part(&parts[curr_part++], "linux",
145 offset + trx->offset[i], 0);
146 i++;
147
148 /*
149 * Pure rootfs size is known and can be calculated as:
150 * trx->length - trx->offset[i]. We don't fill it as
151 * we want to have jffs2 (overlay) in the same mtd.
152 */
153 bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
154 offset + trx->offset[i], 0);
155 i++;
156
157 /*
158 * We have whole TRX scanned, skip to the next part. Use
159 * roundown (not roundup), as the loop will increase
160 * offset in next step.
161 */
162 offset = rounddown(offset + trx->length, blocksize);
163 continue;
164 }
165 }
166 kfree(buf);
167
168 /*
169 * Assume that partitions end at the beginning of the one they are
170 * followed by.
171 */
172 for (i = 0; i < curr_part - 1; i++)
173 parts[i].size = parts[i + 1].offset - parts[i].offset;
174 if (curr_part > 0)
175 parts[curr_part - 1].size =
176 master->size - parts[curr_part - 1].offset;
177
178 *pparts = parts;
179 return curr_part;
180};
181
182static struct mtd_part_parser bcm47xxpart_mtd_parser = {
183 .owner = THIS_MODULE,
184 .parse_fn = bcm47xxpart_parse,
185 .name = "bcm47xxpart",
186};
187
188static int __init bcm47xxpart_init(void)
189{
190 return register_mtd_parser(&bcm47xxpart_mtd_parser);
191}
192
193static void __exit bcm47xxpart_exit(void)
194{
195 deregister_mtd_parser(&bcm47xxpart_mtd_parser);
196}
197
198module_init(bcm47xxpart_init);
199module_exit(bcm47xxpart_exit);
200
201MODULE_LICENSE("GPL");
202MODULE_DESCRIPTION("MTD partitioning for BCM47XX flash memories");