diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/mtd/maps/ceiva.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/mtd/maps/ceiva.c')
-rw-r--r-- | drivers/mtd/maps/ceiva.c | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c new file mode 100644 index 000000000000..da8584a662f4 --- /dev/null +++ b/drivers/mtd/maps/ceiva.c | |||
@@ -0,0 +1,350 @@ | |||
1 | /* | ||
2 | * Ceiva flash memory driver. | ||
3 | * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net> | ||
4 | * | ||
5 | * Note: this driver supports jedec compatible devices. Modification | ||
6 | * for CFI compatible devices should be straight forward: change | ||
7 | * jedec_probe to cfi_probe. | ||
8 | * | ||
9 | * Based on: sa1100-flash.c, which has the following copyright: | ||
10 | * Flash memory access on SA11x0 based devices | ||
11 | * | ||
12 | * (C) 2000 Nicolas Pitre <nico@cam.org> | ||
13 | * | ||
14 | * $Id: ceiva.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $ | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | #include <linux/mtd/mtd.h> | ||
25 | #include <linux/mtd/map.h> | ||
26 | #include <linux/mtd/partitions.h> | ||
27 | #include <linux/mtd/concat.h> | ||
28 | |||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/mach-types.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/sizes.h> | ||
33 | |||
34 | /* | ||
35 | * This isn't complete yet, so... | ||
36 | */ | ||
37 | #define CONFIG_MTD_CEIVA_STATICMAP | ||
38 | |||
39 | #ifdef CONFIG_MTD_CEIVA_STATICMAP | ||
40 | /* | ||
41 | * See include/linux/mtd/partitions.h for definition of the mtd_partition | ||
42 | * structure. | ||
43 | * | ||
44 | * Please note: | ||
45 | * 1. The flash size given should be the largest flash size that can | ||
46 | * be accomodated. | ||
47 | * | ||
48 | * 2. The bus width must defined in clps_setup_flash. | ||
49 | * | ||
50 | * The MTD layer will detect flash chip aliasing and reduce the size of | ||
51 | * the map accordingly. | ||
52 | * | ||
53 | */ | ||
54 | |||
55 | #ifdef CONFIG_ARCH_CEIVA | ||
56 | /* Flash / Partition sizing */ | ||
57 | /* For the 28F8003, we use the block mapping to calcuate the sizes */ | ||
58 | #define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128)) | ||
59 | #define BOOT_PARTITION_SIZE_KiB (16) | ||
60 | #define PARAMS_PARTITION_SIZE_KiB (8) | ||
61 | #define KERNEL_PARTITION_SIZE_KiB (4*128) | ||
62 | /* Use both remaing portion of first flash, and all of second flash */ | ||
63 | #define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) | ||
64 | |||
65 | static struct mtd_partition ceiva_partitions[] = { | ||
66 | { | ||
67 | .name = "Ceiva BOOT partition", | ||
68 | .size = BOOT_PARTITION_SIZE_KiB*1024, | ||
69 | .offset = 0, | ||
70 | |||
71 | },{ | ||
72 | .name = "Ceiva parameters partition", | ||
73 | .size = PARAMS_PARTITION_SIZE_KiB*1024, | ||
74 | .offset = (16 + 8) * 1024, | ||
75 | },{ | ||
76 | .name = "Ceiva kernel partition", | ||
77 | .size = (KERNEL_PARTITION_SIZE_KiB)*1024, | ||
78 | .offset = 0x20000, | ||
79 | |||
80 | },{ | ||
81 | .name = "Ceiva root filesystem partition", | ||
82 | .offset = MTDPART_OFS_APPEND, | ||
83 | .size = (ROOT_PARTITION_SIZE_KiB)*1024, | ||
84 | } | ||
85 | }; | ||
86 | #endif | ||
87 | |||
88 | static int __init clps_static_partitions(struct mtd_partition **parts) | ||
89 | { | ||
90 | int nb_parts = 0; | ||
91 | |||
92 | #ifdef CONFIG_ARCH_CEIVA | ||
93 | if (machine_is_ceiva()) { | ||
94 | *parts = ceiva_partitions; | ||
95 | nb_parts = ARRAY_SIZE(ceiva_partitions); | ||
96 | } | ||
97 | #endif | ||
98 | return nb_parts; | ||
99 | } | ||
100 | #endif | ||
101 | |||
102 | struct clps_info { | ||
103 | unsigned long base; | ||
104 | unsigned long size; | ||
105 | int width; | ||
106 | void *vbase; | ||
107 | struct map_info *map; | ||
108 | struct mtd_info *mtd; | ||
109 | struct resource *res; | ||
110 | }; | ||
111 | |||
112 | #define NR_SUBMTD 4 | ||
113 | |||
114 | static struct clps_info info[NR_SUBMTD]; | ||
115 | |||
116 | static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) | ||
117 | { | ||
118 | struct mtd_info *subdev[nr]; | ||
119 | struct map_info *maps; | ||
120 | int i, found = 0, ret = 0; | ||
121 | |||
122 | /* | ||
123 | * Allocate the map_info structs in one go. | ||
124 | */ | ||
125 | maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); | ||
126 | if (!maps) | ||
127 | return -ENOMEM; | ||
128 | memset(maps, 0, sizeof(struct map_info) * nr); | ||
129 | /* | ||
130 | * Claim and then map the memory regions. | ||
131 | */ | ||
132 | for (i = 0; i < nr; i++) { | ||
133 | if (clps[i].base == (unsigned long)-1) | ||
134 | break; | ||
135 | |||
136 | clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); | ||
137 | if (!clps[i].res) { | ||
138 | ret = -EBUSY; | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | clps[i].map = maps + i; | ||
143 | |||
144 | clps[i].map->name = "clps flash"; | ||
145 | clps[i].map->phys = clps[i].base; | ||
146 | |||
147 | clps[i].vbase = ioremap(clps[i].base, clps[i].size); | ||
148 | if (!clps[i].vbase) { | ||
149 | ret = -ENOMEM; | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | clps[i].map->virt = (void __iomem *)clps[i].vbase; | ||
154 | clps[i].map->bankwidth = clps[i].width; | ||
155 | clps[i].map->size = clps[i].size; | ||
156 | |||
157 | simple_map_init(&clps[i].map); | ||
158 | |||
159 | clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); | ||
160 | if (clps[i].mtd == NULL) { | ||
161 | ret = -ENXIO; | ||
162 | break; | ||
163 | } | ||
164 | clps[i].mtd->owner = THIS_MODULE; | ||
165 | subdev[i] = clps[i].mtd; | ||
166 | |||
167 | printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " | ||
168 | "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, | ||
169 | clps[i].width * 8); | ||
170 | found += 1; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * ENXIO is special. It means we didn't find a chip when | ||
175 | * we probed. We need to tear down the mapping, free the | ||
176 | * resource and mark it as such. | ||
177 | */ | ||
178 | if (ret == -ENXIO) { | ||
179 | iounmap(clps[i].vbase); | ||
180 | clps[i].vbase = NULL; | ||
181 | release_resource(clps[i].res); | ||
182 | clps[i].res = NULL; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * If we found one device, don't bother with concat support. | ||
187 | * If we found multiple devices, use concat if we have it | ||
188 | * available, otherwise fail. | ||
189 | */ | ||
190 | if (ret == 0 || ret == -ENXIO) { | ||
191 | if (found == 1) { | ||
192 | *rmtd = subdev[0]; | ||
193 | ret = 0; | ||
194 | } else if (found > 1) { | ||
195 | /* | ||
196 | * We detected multiple devices. Concatenate | ||
197 | * them together. | ||
198 | */ | ||
199 | #ifdef CONFIG_MTD_CONCAT | ||
200 | *rmtd = mtd_concat_create(subdev, found, | ||
201 | "clps flash"); | ||
202 | if (*rmtd == NULL) | ||
203 | ret = -ENXIO; | ||
204 | #else | ||
205 | printk(KERN_ERR "clps flash: multiple devices " | ||
206 | "found but MTD concat support disabled.\n"); | ||
207 | ret = -ENXIO; | ||
208 | #endif | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * If we failed, clean up. | ||
214 | */ | ||
215 | if (ret) { | ||
216 | do { | ||
217 | if (clps[i].mtd) | ||
218 | map_destroy(clps[i].mtd); | ||
219 | if (clps[i].vbase) | ||
220 | iounmap(clps[i].vbase); | ||
221 | if (clps[i].res) | ||
222 | release_resource(clps[i].res); | ||
223 | } while (i--); | ||
224 | |||
225 | kfree(maps); | ||
226 | } | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) | ||
232 | { | ||
233 | int i; | ||
234 | |||
235 | del_mtd_partitions(mtd); | ||
236 | |||
237 | if (mtd != clps[0].mtd) | ||
238 | mtd_concat_destroy(mtd); | ||
239 | |||
240 | for (i = NR_SUBMTD; i >= 0; i--) { | ||
241 | if (clps[i].mtd) | ||
242 | map_destroy(clps[i].mtd); | ||
243 | if (clps[i].vbase) | ||
244 | iounmap(clps[i].vbase); | ||
245 | if (clps[i].res) | ||
246 | release_resource(clps[i].res); | ||
247 | } | ||
248 | kfree(clps[0].map); | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * We define the memory space, size, and width for the flash memory | ||
253 | * space here. | ||
254 | */ | ||
255 | |||
256 | static int __init clps_setup_flash(void) | ||
257 | { | ||
258 | int nr; | ||
259 | |||
260 | #ifdef CONFIG_ARCH_CEIVA | ||
261 | if (machine_is_ceiva()) { | ||
262 | info[0].base = CS0_PHYS_BASE; | ||
263 | info[0].size = SZ_32M; | ||
264 | info[0].width = CEIVA_FLASH_WIDTH; | ||
265 | info[1].base = CS1_PHYS_BASE; | ||
266 | info[1].size = SZ_32M; | ||
267 | info[1].width = CEIVA_FLASH_WIDTH; | ||
268 | nr = 2; | ||
269 | } | ||
270 | #endif | ||
271 | return nr; | ||
272 | } | ||
273 | |||
274 | static struct mtd_partition *parsed_parts; | ||
275 | static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; | ||
276 | |||
277 | static void __init clps_locate_partitions(struct mtd_info *mtd) | ||
278 | { | ||
279 | const char *part_type = NULL; | ||
280 | int nr_parts = 0; | ||
281 | do { | ||
282 | /* | ||
283 | * Partition selection stuff. | ||
284 | */ | ||
285 | nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); | ||
286 | if (nr_parts > 0) { | ||
287 | part_type = "command line"; | ||
288 | break; | ||
289 | } | ||
290 | #ifdef CONFIG_MTD_CEIVA_STATICMAP | ||
291 | nr_parts = clps_static_partitions(&parsed_parts); | ||
292 | if (nr_parts > 0) { | ||
293 | part_type = "static"; | ||
294 | break; | ||
295 | } | ||
296 | printk("found: %d partitions\n", nr_parts); | ||
297 | #endif | ||
298 | } while (0); | ||
299 | |||
300 | if (nr_parts == 0) { | ||
301 | printk(KERN_NOTICE "clps flash: no partition info " | ||
302 | "available, registering whole flash\n"); | ||
303 | add_mtd_device(mtd); | ||
304 | } else { | ||
305 | printk(KERN_NOTICE "clps flash: using %s partition " | ||
306 | "definition\n", part_type); | ||
307 | add_mtd_partitions(mtd, parsed_parts, nr_parts); | ||
308 | } | ||
309 | |||
310 | /* Always succeeds. */ | ||
311 | } | ||
312 | |||
313 | static void __exit clps_destroy_partitions(void) | ||
314 | { | ||
315 | if (parsed_parts) | ||
316 | kfree(parsed_parts); | ||
317 | } | ||
318 | |||
319 | static struct mtd_info *mymtd; | ||
320 | |||
321 | static int __init clps_mtd_init(void) | ||
322 | { | ||
323 | int ret; | ||
324 | int nr; | ||
325 | |||
326 | nr = clps_setup_flash(); | ||
327 | if (nr < 0) | ||
328 | return nr; | ||
329 | |||
330 | ret = clps_setup_mtd(info, nr, &mymtd); | ||
331 | if (ret) | ||
332 | return ret; | ||
333 | |||
334 | clps_locate_partitions(mymtd); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static void __exit clps_mtd_cleanup(void) | ||
340 | { | ||
341 | clps_destroy_mtd(info, mymtd); | ||
342 | clps_destroy_partitions(); | ||
343 | } | ||
344 | |||
345 | module_init(clps_mtd_init); | ||
346 | module_exit(clps_mtd_cleanup); | ||
347 | |||
348 | MODULE_AUTHOR("Rob Scott"); | ||
349 | MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); | ||
350 | MODULE_LICENSE("GPL"); | ||