Merge branch 'cleanup' into for-linus
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / mtd / afs.c
CommitLineData
1da177e4
LT
1/*======================================================================
2
3 drivers/mtd/afs.c: ARM Flash Layout/Partitioning
97894cda 4
a1452a37 5 Copyright © 2000 ARM Limited
97894cda 6
1da177e4
LT
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
97894cda 11
1da177e4
LT
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
97894cda 16
1da177e4
LT
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
97894cda
TG
20
21 This is access code for flashes using ARM's flash partitioning
1da177e4
LT
22 standards.
23
1da177e4
LT
24======================================================================*/
25
26#include <linux/module.h>
27#include <linux/types.h>
28#include <linux/kernel.h>
29#include <linux/slab.h>
30#include <linux/string.h>
31#include <linux/init.h>
32
33#include <linux/mtd/mtd.h>
34#include <linux/mtd/map.h>
35#include <linux/mtd/partitions.h>
36
37struct footer_struct {
38 u32 image_info_base; /* Address of first word of ImageFooter */
39 u32 image_start; /* Start of area reserved by this footer */
40 u32 signature; /* 'Magic' number proves it's a footer */
41 u32 type; /* Area type: ARM Image, SIB, customer */
42 u32 checksum; /* Just this structure */
43};
44
45struct image_info_struct {
46 u32 bootFlags; /* Boot flags, compression etc. */
47 u32 imageNumber; /* Unique number, selects for boot etc. */
48 u32 loadAddress; /* Address program should be loaded to */
49 u32 length; /* Actual size of image */
50 u32 address; /* Image is executed from here */
51 char name[16]; /* Null terminated */
52 u32 headerBase; /* Flash Address of any stripped header */
53 u32 header_length; /* Length of header in memory */
54 u32 headerType; /* AIF, RLF, s-record etc. */
55 u32 checksum; /* Image checksum (inc. this struct) */
56};
57
58static u32 word_sum(void *words, int num)
59{
60 u32 *p = words;
61 u32 sum = 0;
62
63 while (num--)
64 sum += *p++;
65
66 return sum;
67}
68
69static int
70afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
71 u_int off, u_int mask)
72{
73 struct footer_struct fs;
74 u_int ptr = off + mtd->erasesize - sizeof(fs);
75 size_t sz;
76 int ret;
77
329ad399 78 ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs);
1da177e4
LT
79 if (ret >= 0 && sz != sizeof(fs))
80 ret = -EINVAL;
81
82 if (ret < 0) {
83 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
84 ptr, ret);
85 return ret;
86 }
87
88 ret = 1;
89
90 /*
91 * Does it contain the magic number?
92 */
93 if (fs.signature != 0xa0ffff9f)
94 ret = 0;
95
96 /*
97 * Check the checksum.
98 */
99 if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
100 ret = 0;
101
102 /*
103 * Don't touch the SIB.
104 */
105 if (fs.type == 2)
106 ret = 0;
107
108 *iis_start = fs.image_info_base & mask;
109 *img_start = fs.image_start & mask;
110
111 /*
112 * Check the image info base. This can not
113 * be located after the footer structure.
114 */
115 if (*iis_start >= ptr)
116 ret = 0;
117
118 /*
119 * Check the start of this image. The image
120 * data can not be located after this block.
121 */
122 if (*img_start > off)
123 ret = 0;
124
125 return ret;
126}
127
128static int
129afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
130{
131 size_t sz;
132 int ret, i;
133
134 memset(iis, 0, sizeof(*iis));
329ad399 135 ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis);
1da177e4
LT
136 if (ret < 0)
137 goto failed;
138
139 if (sz != sizeof(*iis)) {
140 ret = -EINVAL;
141 goto failed;
142 }
143
144 ret = 0;
145
146 /*
147 * Validate the name - it must be NUL terminated.
148 */
149 for (i = 0; i < sizeof(iis->name); i++)
150 if (iis->name[i] == '\0')
151 break;
152
153 if (i < sizeof(iis->name))
154 ret = 1;
155
156 return ret;
157
158 failed:
159 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
160 ptr, ret);
161 return ret;
162}
163
97894cda 164static int parse_afs_partitions(struct mtd_info *mtd,
c7975330
DES
165 struct mtd_partition **pparts,
166 struct mtd_part_parser_data *data)
1da177e4
LT
167{
168 struct mtd_partition *parts;
169 u_int mask, off, idx, sz;
170 int ret = 0;
171 char *str;
172
173 /*
174 * This is the address mask; we use this to mask off out of
175 * range address bits.
176 */
177 mask = mtd->size - 1;
178
179 /*
180 * First, calculate the size of the array we need for the
181 * partition information. We include in this the size of
182 * the strings.
183 */
184 for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
185 struct image_info_struct iis;
186 u_int iis_ptr, img_ptr;
187
188 ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
189 if (ret < 0)
190 break;
191 if (ret == 0)
192 continue;
193
194 ret = afs_read_iis(mtd, &iis, iis_ptr);
195 if (ret < 0)
196 break;
197 if (ret == 0)
198 continue;
199
200 sz += sizeof(struct mtd_partition);
201 sz += strlen(iis.name) + 1;
202 idx += 1;
203 }
204
205 if (!sz)
206 return ret;
207
95b93a0c 208 parts = kzalloc(sz, GFP_KERNEL);
1da177e4
LT
209 if (!parts)
210 return -ENOMEM;
211
1da177e4
LT
212 str = (char *)(parts + idx);
213
214 /*
215 * Identify the partitions
216 */
217 for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
218 struct image_info_struct iis;
747aead3 219 u_int iis_ptr, img_ptr;
1da177e4
LT
220
221 /* Read the footer. */
222 ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
223 if (ret < 0)
224 break;
225 if (ret == 0)
226 continue;
227
228 /* Read the image info block */
229 ret = afs_read_iis(mtd, &iis, iis_ptr);
230 if (ret < 0)
231 break;
232 if (ret == 0)
233 continue;
234
235 strcpy(str, iis.name);
1da177e4
LT
236
237 parts[idx].name = str;
747aead3 238 parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
1da177e4
LT
239 parts[idx].offset = img_ptr;
240 parts[idx].mask_flags = 0;
241
0ffd24fc 242 printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n",
1da177e4
LT
243 idx, img_ptr, parts[idx].size / 1024,
244 iis.imageNumber, str);
245
246 idx += 1;
247 str = str + strlen(iis.name) + 1;
248 }
249
250 if (!idx) {
251 kfree(parts);
252 parts = NULL;
253 }
254
255 *pparts = parts;
256 return idx ? idx : ret;
257}
258
259static struct mtd_part_parser afs_parser = {
260 .owner = THIS_MODULE,
261 .parse_fn = parse_afs_partitions,
262 .name = "afs",
263};
264
265static int __init afs_parser_init(void)
266{
267 return register_mtd_parser(&afs_parser);
268}
269
270static void __exit afs_parser_exit(void)
271{
272 deregister_mtd_parser(&afs_parser);
273}
274
275module_init(afs_parser_init);
276module_exit(afs_parser_exit);
277
278
279MODULE_AUTHOR("ARM Ltd");
280MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
281MODULE_LICENSE("GPL");