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