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/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/mach-types.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 *data; 134 }; 135 136 struct sa_info { 137 struct mtd_partition *parts; 138 struct mtd_info *mtd; 139 int num_subdev; 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->data->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->data->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->data->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) 227 { 228 int i; 229 230 if (info->mtd) { 231 del_mtd_partitions(info->mtd); 232 233 #ifdef CONFIG_MTD_CONCAT 234 if (info->mtd != info->subdev[0].mtd) 235 mtd_concat_destroy(info->mtd); 236 #endif 237 } 238 239 if (info->parts) 240 kfree(info->parts); 241 242 for (i = info->num_subdev - 1; i >= 0; i--) 243 sa1100_destroy_subdev(&info->subdev[i]); 244 kfree(info); 245 } 246 247 static struct sa_info *__init 248 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash) 249 { 250 struct sa_info *info; 251 int nr, size, i, ret = 0; 252 253 /* 254 * Count number of devices. 255 */ 256 for (nr = 0; ; nr++) 257 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr)) 258 break; 259 260 if (nr == 0) { 261 ret = -ENODEV; 262 goto out; 263 } 264 265 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr; 266 267 /* 268 * Allocate the map_info structs in one go. 269 */ 270 info = kmalloc(size, GFP_KERNEL); 271 if (!info) { 272 ret = -ENOMEM; 273 goto out; 274 } 275 276 memset(info, 0, size); 277 278 /* 279 * Claim and then map the memory regions. 280 */ 281 for (i = 0; i < nr; i++) { 282 struct sa_subdev_info *subdev = &info->subdev[i]; 283 struct resource *res; 284 285 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 286 if (!res) 287 break; 288 289 subdev->map.name = subdev->name; 290 sprintf(subdev->name, "sa1100-%d", i); 291 subdev->data = flash; 292 293 ret = sa1100_probe_subdev(subdev, res); 294 if (ret) 295 break; 296 } 297 298 info->num_subdev = i; 299 300 /* 301 * ENXIO is special. It means we didn't find a chip when we probed. 302 */ 303 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0)) 304 goto err; 305 306 /* 307 * If we found one device, don't bother with concat support. If 308 * we found multiple devices, use concat if we have it available, 309 * otherwise fail. Either way, it'll be called "sa1100". 310 */ 311 if (info->num_subdev == 1) { 312 strcpy(info->subdev[0].name, "sa1100"); 313 info->mtd = info->subdev[0].mtd; 314 ret = 0; 315 } else if (info->num_subdev > 1) { 316 #ifdef CONFIG_MTD_CONCAT 317 struct mtd_info *cdev[nr]; 318 /* 319 * We detected multiple devices. Concatenate them together. 320 */ 321 for (i = 0; i < info->num_subdev; i++) 322 cdev[i] = info->subdev[i].mtd; 323 324 info->mtd = mtd_concat_create(cdev, info->num_subdev, 325 "sa1100"); 326 if (info->mtd == NULL) 327 ret = -ENXIO; 328 #else 329 printk(KERN_ERR "SA1100 flash: multiple devices " 330 "found but MTD concat support disabled.\n"); 331 ret = -ENXIO; 332 #endif 333 } 334 335 if (ret == 0) 336 return info; 337 338 err: 339 sa1100_destroy(info); 340 out: 341 return ERR_PTR(ret); 342 } 343 344 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; 345 346 static int __init sa1100_mtd_probe(struct device *dev) 347 { 348 struct platform_device *pdev = to_platform_device(dev); 349 struct flash_platform_data *flash = pdev->dev.platform_data; 350 struct mtd_partition *parts; 351 const char *part_type = NULL; 352 struct sa_info *info; 353 int err, nr_parts = 0; 354 355 if (!flash) 356 return -ENODEV; 357 358 info = sa1100_setup_mtd(pdev, flash); 359 if (IS_ERR(info)) { 360 err = PTR_ERR(info); 361 goto out; 362 } 363 364 /* 365 * Partition selection stuff. 366 */ 367 #ifdef CONFIG_MTD_PARTITIONS 368 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0); 369 if (nr_parts > 0) { 370 info->parts = parts; 371 part_type = "dynamic"; 372 } else 373 #endif 374 { 375 parts = flash->parts; 376 nr_parts = flash->nr_parts; 377 part_type = "static"; 378 } 379 380 if (nr_parts == 0) { 381 printk(KERN_NOTICE "SA1100 flash: no partition info " 382 "available, registering whole flash\n"); 383 add_mtd_device(info->mtd); 384 } else { 385 printk(KERN_NOTICE "SA1100 flash: using %s partition " 386 "definition\n", part_type); 387 add_mtd_partitions(info->mtd, parts, nr_parts); 388 } 389 390 dev_set_drvdata(dev, info); 391 err = 0; 392 393 out: 394 return err; 395 } 396 397 static int __exit sa1100_mtd_remove(struct device *dev) 398 { 399 struct sa_info *info = dev_get_drvdata(dev); 400 dev_set_drvdata(dev, NULL); 401 sa1100_destroy(info); 402 return 0; 403 } 404 405 #ifdef CONFIG_PM 406 static int sa1100_mtd_suspend(struct device *dev, u32 state, u32 level) 407 { 408 struct sa_info *info = dev_get_drvdata(dev); 409 int ret = 0; 410 411 if (info && level == SUSPEND_SAVE_STATE) 412 ret = info->mtd->suspend(info->mtd); 413 414 return ret; 415 } 416 417 static int sa1100_mtd_resume(struct device *dev, u32 level) 418 { 419 struct sa_info *info = dev_get_drvdata(dev); 420 if (info && level == RESUME_RESTORE_STATE) 421 info->mtd->resume(info->mtd); 422 return 0; 423 } 424 #else 425 #define sa1100_mtd_suspend NULL 426 #define sa1100_mtd_resume NULL 427 #endif 428 429 static struct device_driver sa1100_mtd_driver = { 430 .name = "flash", 431 .bus = &platform_bus_type, 432 .probe = sa1100_mtd_probe, 433 .remove = __exit_p(sa1100_mtd_remove), 434 .suspend = sa1100_mtd_suspend, 435 .resume = sa1100_mtd_resume, 436 }; 437 438 static int __init sa1100_mtd_init(void) 439 { 440 return driver_register(&sa1100_mtd_driver); 441 } 442 443 static void __exit sa1100_mtd_exit(void) 444 { 445 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