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