Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc2 341 lines 7.4 kB view raw
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@fluxnic.net> 13 * 14 */ 15 16#include <linux/module.h> 17#include <linux/types.h> 18#include <linux/ioport.h> 19#include <linux/kernel.h> 20#include <linux/init.h> 21#include <linux/slab.h> 22 23#include <linux/mtd/mtd.h> 24#include <linux/mtd/map.h> 25#include <linux/mtd/partitions.h> 26#include <linux/mtd/concat.h> 27 28#include <mach/hardware.h> 29#include <asm/mach-types.h> 30#include <asm/io.h> 31#include <asm/sizes.h> 32 33/* 34 * This isn't complete yet, so... 35 */ 36#define CONFIG_MTD_CEIVA_STATICMAP 37 38#ifdef CONFIG_MTD_CEIVA_STATICMAP 39/* 40 * See include/linux/mtd/partitions.h for definition of the mtd_partition 41 * structure. 42 * 43 * Please note: 44 * 1. The flash size given should be the largest flash size that can 45 * be accommodated. 46 * 47 * 2. The bus width must defined in clps_setup_flash. 48 * 49 * The MTD layer will detect flash chip aliasing and reduce the size of 50 * the map accordingly. 51 * 52 */ 53 54#ifdef CONFIG_ARCH_CEIVA 55/* Flash / Partition sizing */ 56/* For the 28F8003, we use the block mapping to calcuate the sizes */ 57#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128)) 58#define BOOT_PARTITION_SIZE_KiB (16) 59#define PARAMS_PARTITION_SIZE_KiB (8) 60#define KERNEL_PARTITION_SIZE_KiB (4*128) 61/* Use both remaining portion of first flash, and all of second flash */ 62#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) 63 64static struct mtd_partition ceiva_partitions[] = { 65 { 66 .name = "Ceiva BOOT partition", 67 .size = BOOT_PARTITION_SIZE_KiB*1024, 68 .offset = 0, 69 70 },{ 71 .name = "Ceiva parameters partition", 72 .size = PARAMS_PARTITION_SIZE_KiB*1024, 73 .offset = (16 + 8) * 1024, 74 },{ 75 .name = "Ceiva kernel partition", 76 .size = (KERNEL_PARTITION_SIZE_KiB)*1024, 77 .offset = 0x20000, 78 79 },{ 80 .name = "Ceiva root filesystem partition", 81 .offset = MTDPART_OFS_APPEND, 82 .size = (ROOT_PARTITION_SIZE_KiB)*1024, 83 } 84}; 85#endif 86 87static int __init clps_static_partitions(struct mtd_partition **parts) 88{ 89 int nb_parts = 0; 90 91#ifdef CONFIG_ARCH_CEIVA 92 if (machine_is_ceiva()) { 93 *parts = ceiva_partitions; 94 nb_parts = ARRAY_SIZE(ceiva_partitions); 95 } 96#endif 97 return nb_parts; 98} 99#endif 100 101struct clps_info { 102 unsigned long base; 103 unsigned long size; 104 int width; 105 void *vbase; 106 struct map_info *map; 107 struct mtd_info *mtd; 108 struct resource *res; 109}; 110 111#define NR_SUBMTD 4 112 113static struct clps_info info[NR_SUBMTD]; 114 115static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) 116{ 117 struct mtd_info *subdev[nr]; 118 struct map_info *maps; 119 int i, found = 0, ret = 0; 120 121 /* 122 * Allocate the map_info structs in one go. 123 */ 124 maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL); 125 if (!maps) 126 return -ENOMEM; 127 /* 128 * Claim and then map the memory regions. 129 */ 130 for (i = 0; i < nr; i++) { 131 if (clps[i].base == (unsigned long)-1) 132 break; 133 134 clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); 135 if (!clps[i].res) { 136 ret = -EBUSY; 137 break; 138 } 139 140 clps[i].map = maps + i; 141 142 clps[i].map->name = "clps flash"; 143 clps[i].map->phys = clps[i].base; 144 145 clps[i].vbase = ioremap(clps[i].base, clps[i].size); 146 if (!clps[i].vbase) { 147 ret = -ENOMEM; 148 break; 149 } 150 151 clps[i].map->virt = (void __iomem *)clps[i].vbase; 152 clps[i].map->bankwidth = clps[i].width; 153 clps[i].map->size = clps[i].size; 154 155 simple_map_init(&clps[i].map); 156 157 clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); 158 if (clps[i].mtd == NULL) { 159 ret = -ENXIO; 160 break; 161 } 162 clps[i].mtd->owner = THIS_MODULE; 163 subdev[i] = clps[i].mtd; 164 165 printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " 166 "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, 167 clps[i].width * 8); 168 found += 1; 169 } 170 171 /* 172 * ENXIO is special. It means we didn't find a chip when 173 * we probed. We need to tear down the mapping, free the 174 * resource and mark it as such. 175 */ 176 if (ret == -ENXIO) { 177 iounmap(clps[i].vbase); 178 clps[i].vbase = NULL; 179 release_resource(clps[i].res); 180 clps[i].res = NULL; 181 } 182 183 /* 184 * If we found one device, don't bother with concat support. 185 * If we found multiple devices, use concat if we have it 186 * available, otherwise fail. 187 */ 188 if (ret == 0 || ret == -ENXIO) { 189 if (found == 1) { 190 *rmtd = subdev[0]; 191 ret = 0; 192 } else if (found > 1) { 193 /* 194 * We detected multiple devices. Concatenate 195 * them together. 196 */ 197 *rmtd = mtd_concat_create(subdev, found, 198 "clps flash"); 199 if (*rmtd == NULL) 200 ret = -ENXIO; 201 } 202 } 203 204 /* 205 * If we failed, clean up. 206 */ 207 if (ret) { 208 do { 209 if (clps[i].mtd) 210 map_destroy(clps[i].mtd); 211 if (clps[i].vbase) 212 iounmap(clps[i].vbase); 213 if (clps[i].res) 214 release_resource(clps[i].res); 215 } while (i--); 216 217 kfree(maps); 218 } 219 220 return ret; 221} 222 223static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) 224{ 225 int i; 226 227 mtd_device_unregister(mtd); 228 229 if (mtd != clps[0].mtd) 230 mtd_concat_destroy(mtd); 231 232 for (i = NR_SUBMTD; i >= 0; i--) { 233 if (clps[i].mtd) 234 map_destroy(clps[i].mtd); 235 if (clps[i].vbase) 236 iounmap(clps[i].vbase); 237 if (clps[i].res) 238 release_resource(clps[i].res); 239 } 240 kfree(clps[0].map); 241} 242 243/* 244 * We define the memory space, size, and width for the flash memory 245 * space here. 246 */ 247 248static int __init clps_setup_flash(void) 249{ 250 int nr = 0; 251 252#ifdef CONFIG_ARCH_CEIVA 253 if (machine_is_ceiva()) { 254 info[0].base = CS0_PHYS_BASE; 255 info[0].size = SZ_32M; 256 info[0].width = CEIVA_FLASH_WIDTH; 257 info[1].base = CS1_PHYS_BASE; 258 info[1].size = SZ_32M; 259 info[1].width = CEIVA_FLASH_WIDTH; 260 nr = 2; 261 } 262#endif 263 return nr; 264} 265 266static struct mtd_partition *parsed_parts; 267static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; 268 269static void __init clps_locate_partitions(struct mtd_info *mtd) 270{ 271 const char *part_type = NULL; 272 int nr_parts = 0; 273 do { 274 /* 275 * Partition selection stuff. 276 */ 277 nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); 278 if (nr_parts > 0) { 279 part_type = "command line"; 280 break; 281 } 282#ifdef CONFIG_MTD_CEIVA_STATICMAP 283 nr_parts = clps_static_partitions(&parsed_parts); 284 if (nr_parts > 0) { 285 part_type = "static"; 286 break; 287 } 288 printk("found: %d partitions\n", nr_parts); 289#endif 290 } while (0); 291 292 if (nr_parts == 0) { 293 printk(KERN_NOTICE "clps flash: no partition info " 294 "available, registering whole flash\n"); 295 mtd_device_register(mtd, NULL, 0); 296 } else { 297 printk(KERN_NOTICE "clps flash: using %s partition " 298 "definition\n", part_type); 299 mtd_device_register(mtd, parsed_parts, nr_parts); 300 } 301 302 /* Always succeeds. */ 303} 304 305static void __exit clps_destroy_partitions(void) 306{ 307 kfree(parsed_parts); 308} 309 310static struct mtd_info *mymtd; 311 312static int __init clps_mtd_init(void) 313{ 314 int ret; 315 int nr; 316 317 nr = clps_setup_flash(); 318 if (nr < 0) 319 return nr; 320 321 ret = clps_setup_mtd(info, nr, &mymtd); 322 if (ret) 323 return ret; 324 325 clps_locate_partitions(mymtd); 326 327 return 0; 328} 329 330static void __exit clps_mtd_cleanup(void) 331{ 332 clps_destroy_mtd(info, mymtd); 333 clps_destroy_partitions(); 334} 335 336module_init(clps_mtd_init); 337module_exit(clps_mtd_cleanup); 338 339MODULE_AUTHOR("Rob Scott"); 340MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); 341MODULE_LICENSE("GPL");