1 /* 2 * Flash memory access on SA11x0 based devices 3 * 4 * (C) 2000 Nicolas Pitre <nico@fluxnic.net> 5 */ 6 #include <linux/module.h> 7 #include <linux/types.h> 8 #include <linux/ioport.h> 9 #include <linux/kernel.h> 10 #include <linux/init.h> 11 #include <linux/errno.h> 12 #include <linux/slab.h> 13 #include <linux/platform_device.h> 14 #include <linux/err.h> 15 #include <linux/io.h> 16 17 #include <linux/mtd/mtd.h> 18 #include <linux/mtd/map.h> 19 #include <linux/mtd/partitions.h> 20 #include <linux/mtd/concat.h> 21 22 #include <mach/hardware.h> 23 #include <asm/sizes.h> 24 #include <asm/mach/flash.h> 25 26 #if 0 27 /* 28 * This is here for documentation purposes only - until these people 29 * submit their machine types. It will be gone January 2005. 30 */ 31 static struct mtd_partition consus_partitions[] = { 32 { 33 .name = "Consus boot firmware", 34 .offset = 0, 35 .size = 0x00040000, 36 .mask_flags = MTD_WRITABLE, /* force read-only */ 37 }, { 38 .name = "Consus kernel", 39 .offset = 0x00040000, 40 .size = 0x00100000, 41 .mask_flags = 0, 42 }, { 43 .name = "Consus disk", 44 .offset = 0x00140000, 45 /* The rest (up to 16M) for jffs. We could put 0 and 46 make it find the size automatically, but right now 47 i have 32 megs. jffs will use all 32 megs if given 48 the chance, and this leads to horrible problems 49 when you try to re-flash the image because blob 50 won't erase the whole partition. */ 51 .size = 0x01000000 - 0x00140000, 52 .mask_flags = 0, 53 }, { 54 /* this disk is a secondary disk, which can be used as 55 needed, for simplicity, make it the size of the other 56 consus partition, although realistically it could be 57 the remainder of the disk (depending on the file 58 system used) */ 59 .name = "Consus disk2", 60 .offset = 0x01000000, 61 .size = 0x01000000 - 0x00140000, 62 .mask_flags = 0, 63 } 64 }; 65 66 /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ 67 static struct mtd_partition frodo_partitions[] = 68 { 69 { 70 .name = "bootloader", 71 .size = 0x00040000, 72 .offset = 0x00000000, 73 .mask_flags = MTD_WRITEABLE 74 }, { 75 .name = "bootloader params", 76 .size = 0x00040000, 77 .offset = MTDPART_OFS_APPEND, 78 .mask_flags = MTD_WRITEABLE 79 }, { 80 .name = "kernel", 81 .size = 0x00100000, 82 .offset = MTDPART_OFS_APPEND, 83 .mask_flags = MTD_WRITEABLE 84 }, { 85 .name = "ramdisk", 86 .size = 0x00400000, 87 .offset = MTDPART_OFS_APPEND, 88 .mask_flags = MTD_WRITEABLE 89 }, { 90 .name = "file system", 91 .size = MTDPART_SIZ_FULL, 92 .offset = MTDPART_OFS_APPEND 93 } 94 }; 95 96 static struct mtd_partition jornada56x_partitions[] = { 97 { 98 .name = "bootldr", 99 .size = 0x00040000, 100 .offset = 0, 101 .mask_flags = MTD_WRITEABLE, 102 }, { 103 .name = "rootfs", 104 .size = MTDPART_SIZ_FULL, 105 .offset = MTDPART_OFS_APPEND, 106 } 107 }; 108 109 static void jornada56x_set_vpp(int vpp) 110 { 111 if (vpp) 112 GPSR = GPIO_GPIO26; 113 else 114 GPCR = GPIO_GPIO26; 115 GPDR |= GPIO_GPIO26; 116 } 117 118 /* 119 * Machine Phys Size set_vpp 120 * Consus : SA1100_CS0_PHYS SZ_32M 121 * Frodo : SA1100_CS0_PHYS SZ_32M 122 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp 123 */ 124 #endif 125 126 struct sa_subdev_info { 127 char name[16]; 128 struct map_info map; 129 struct mtd_info *mtd; 130 struct flash_platform_data *plat; 131 }; 132 133 struct sa_info { 134 struct mtd_partition *parts; 135 struct mtd_info *mtd; 136 int num_subdev; 137 unsigned int nr_parts; 138 struct sa_subdev_info subdev[0]; 139 }; 140 141 static void sa1100_set_vpp(struct map_info *map, int on) 142 { 143 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map); 144 subdev->plat->set_vpp(on); 145 } 146 147 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev) 148 { 149 if (subdev->mtd) 150 map_destroy(subdev->mtd); 151 if (subdev->map.virt) 152 iounmap(subdev->map.virt); 153 release_mem_region(subdev->map.phys, subdev->map.size); 154 } 155 156 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res) 157 { 158 unsigned long phys; 159 unsigned int size; 160 int ret; 161 162 phys = res->start; 163 size = res->end - phys + 1; 164 165 /* 166 * Retrieve the bankwidth from the MSC registers. 167 * We currently only implement CS0 and CS1 here. 168 */ 169 switch (phys) { 170 default: 171 printk(KERN_WARNING "SA1100 flash: unknown base address " 172 "0x%08lx, assuming CS0\n", phys); 173 174 case SA1100_CS0_PHYS: 175 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; 176 break; 177 178 case SA1100_CS1_PHYS: 179 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4; 180 break; 181 } 182 183 if (!request_mem_region(phys, size, subdev->name)) { 184 ret = -EBUSY; 185 goto out; 186 } 187 188 if (subdev->plat->set_vpp) 189 subdev->map.set_vpp = sa1100_set_vpp; 190 191 subdev->map.phys = phys; 192 subdev->map.size = size; 193 subdev->map.virt = ioremap(phys, size); 194 if (!subdev->map.virt) { 195 ret = -ENOMEM; 196 goto err; 197 } 198 199 simple_map_init(&subdev->map); 200 201 /* 202 * Now let's probe for the actual flash. Do it here since 203 * specific machine settings might have been set above. 204 */ 205 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map); 206 if (subdev->mtd == NULL) { 207 ret = -ENXIO; 208 goto err; 209 } 210 subdev->mtd->owner = THIS_MODULE; 211 212 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, " 213 "%d-bit\n", phys, subdev->mtd->size >> 20, 214 subdev->map.bankwidth * 8); 215 216 return 0; 217 218 err: 219 sa1100_destroy_subdev(subdev); 220 out: 221 return ret; 222 } 223 224 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat) 225 { 226 int i; 227 228 if (info->mtd) { 229 if (info->nr_parts == 0) 230 del_mtd_device(info->mtd); 231 #ifdef CONFIG_MTD_PARTITIONS 232 else 233 del_mtd_partitions(info->mtd); 234 #endif 235 #ifdef CONFIG_MTD_CONCAT 236 if (info->mtd != info->subdev[0].mtd) 237 mtd_concat_destroy(info->mtd); 238 #endif 239 } 240 241 kfree(info->parts); 242 243 for (i = info->num_subdev - 1; i >= 0; i--) 244 sa1100_destroy_subdev(&info->subdev[i]); 245 kfree(info); 246 247 if (plat->exit) 248 plat->exit(); 249 } 250 251 static struct sa_info *__init 252 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) 253 { 254 struct sa_info *info; 255 int nr, size, i, ret = 0; 256 257 /* 258 * Count number of devices. 259 */ 260 for (nr = 0; ; nr++) 261 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr)) 262 break; 263 264 if (nr == 0) { 265 ret = -ENODEV; 266 goto out; 267 } 268 269 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr; 270 271 /* 272 * Allocate the map_info structs in one go. 273 */ 274 info = kzalloc(size, GFP_KERNEL); 275 if (!info) { 276 ret = -ENOMEM; 277 goto out; 278 } 279 280 if (plat->init) { 281 ret = plat->init(); 282 if (ret) 283 goto err; 284 } 285 286 /* 287 * Claim and then map the memory regions. 288 */ 289 for (i = 0; i < nr; i++) { 290 struct sa_subdev_info *subdev = &info->subdev[i]; 291 struct resource *res; 292 293 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 294 if (!res) 295 break; 296 297 subdev->map.name = subdev->name; 298 sprintf(subdev->name, "%s-%d", plat->name, i); 299 subdev->plat = plat; 300 301 ret = sa1100_probe_subdev(subdev, res); 302 if (ret) 303 break; 304 } 305 306 info->num_subdev = i; 307 308 /* 309 * ENXIO is special. It means we didn't find a chip when we probed. 310 */ 311 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0)) 312 goto err; 313 314 /* 315 * If we found one device, don't bother with concat support. If 316 * we found multiple devices, use concat if we have it available, 317 * otherwise fail. Either way, it'll be called "sa1100". 318 */ 319 if (info->num_subdev == 1) { 320 strcpy(info->subdev[0].name, plat->name); 321 info->mtd = info->subdev[0].mtd; 322 ret = 0; 323 } else if (info->num_subdev > 1) { 324 #ifdef CONFIG_MTD_CONCAT 325 struct mtd_info *cdev[nr]; 326 /* 327 * We detected multiple devices. Concatenate them together. 328 */ 329 for (i = 0; i < info->num_subdev; i++) 330 cdev[i] = info->subdev[i].mtd; 331 332 info->mtd = mtd_concat_create(cdev, info->num_subdev, 333 plat->name); 334 if (info->mtd == NULL) 335 ret = -ENXIO; 336 #else 337 printk(KERN_ERR "SA1100 flash: multiple devices " 338 "found but MTD concat support disabled.\n"); 339 ret = -ENXIO; 340 #endif 341 } 342 343 if (ret == 0) 344 return info; 345 346 err: 347 sa1100_destroy(info, plat); 348 out: 349 return ERR_PTR(ret); 350 } 351 352 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; 353 354 static int __devinit sa1100_mtd_probe(struct platform_device *pdev) 355 { 356 struct flash_platform_data *plat = pdev->dev.platform_data; 357 struct mtd_partition *parts; 358 const char *part_type = NULL; 359 struct sa_info *info; 360 int err, nr_parts = 0; 361 362 if (!plat) 363 return -ENODEV; 364 365 info = sa1100_setup_mtd(pdev, plat); 366 if (IS_ERR(info)) { 367 err = PTR_ERR(info); 368 goto out; 369 } 370 371 /* 372 * Partition selection stuff. 373 */ 374 #ifdef CONFIG_MTD_PARTITIONS 375 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0); 376 if (nr_parts > 0) { 377 info->parts = parts; 378 part_type = "dynamic"; 379 } else 380 #endif 381 { 382 parts = plat->parts; 383 nr_parts = plat->nr_parts; 384 part_type = "static"; 385 } 386 387 if (nr_parts == 0) { 388 printk(KERN_NOTICE "SA1100 flash: no partition info " 389 "available, registering whole flash\n"); 390 add_mtd_device(info->mtd); 391 } else { 392 printk(KERN_NOTICE "SA1100 flash: using %s partition " 393 "definition\n", part_type); 394 add_mtd_partitions(info->mtd, parts, nr_parts); 395 } 396 397 info->nr_parts = nr_parts; 398 399 platform_set_drvdata(pdev, info); 400 err = 0; 401 402 out: 403 return err; 404 } 405 406 static int __exit sa1100_mtd_remove(struct platform_device *pdev) 407 { 408 struct sa_info *info = platform_get_drvdata(pdev); 409 struct flash_platform_data *plat = pdev->dev.platform_data; 410 411 platform_set_drvdata(pdev, NULL); 412 sa1100_destroy(info, plat); 413 414 return 0; 415 } 416 417 #ifdef CONFIG_PM 418 static void sa1100_mtd_shutdown(struct platform_device *dev) 419 { 420 struct sa_info *info = platform_get_drvdata(dev); 421 if (info && info->mtd->suspend(info->mtd) == 0) 422 info->mtd->resume(info->mtd); 423 } 424 #else 425 #define sa1100_mtd_shutdown NULL 426 #endif 427 428 static struct platform_driver sa1100_mtd_driver = { 429 .probe = sa1100_mtd_probe, 430 .remove = __exit_p(sa1100_mtd_remove), 431 .shutdown = sa1100_mtd_shutdown, 432 .driver = { 433 .name = "sa1100-mtd", 434 .owner = THIS_MODULE, 435 }, 436 }; 437 438 static int __init sa1100_mtd_init(void) 439 { 440 return platform_driver_register(&sa1100_mtd_driver); 441 } 442 443 static void __exit sa1100_mtd_exit(void) 444 { 445 platform_driver_unregister(&sa1100_mtd_driver); 446 } 447 448 module_init(sa1100_mtd_init); 449 module_exit(sa1100_mtd_exit); 450 451 MODULE_AUTHOR("Nicolas Pitre"); 452 MODULE_DESCRIPTION("SA1100 CFI map driver"); 453 MODULE_LICENSE("GPL"); 454 MODULE_ALIAS("platform:sa1100-mtd"); 455