physmap.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Normal mappings of chips in physical memory
  3. *
  4. * Copyright (C) 2003 MontaVista Software Inc.
  5. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  6. *
  7. * 031022 - [jsun] add run-time configure and partition setup
  8. */
  9. #include <linux/module.h>
  10. #include <linux/types.h>
  11. #include <linux/kernel.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #include <linux/device.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/mtd/mtd.h>
  17. #include <linux/mtd/map.h>
  18. #include <linux/mtd/partitions.h>
  19. #include <linux/mtd/physmap.h>
  20. #include <linux/mtd/concat.h>
  21. #include <linux/io.h>
  22. #define MAX_RESOURCES 4
  23. struct physmap_flash_info {
  24. struct mtd_info *mtd[MAX_RESOURCES];
  25. struct mtd_info *cmtd;
  26. struct map_info map[MAX_RESOURCES];
  27. };
  28. static int physmap_flash_remove(struct platform_device *dev)
  29. {
  30. struct physmap_flash_info *info;
  31. struct physmap_flash_data *physmap_data;
  32. int i;
  33. info = platform_get_drvdata(dev);
  34. if (info == NULL)
  35. return 0;
  36. platform_set_drvdata(dev, NULL);
  37. physmap_data = dev->dev.platform_data;
  38. if (info->cmtd) {
  39. mtd_device_unregister(info->cmtd);
  40. if (info->cmtd != info->mtd[0])
  41. mtd_concat_destroy(info->cmtd);
  42. }
  43. for (i = 0; i < MAX_RESOURCES; i++) {
  44. if (info->mtd[i] != NULL)
  45. map_destroy(info->mtd[i]);
  46. }
  47. if (physmap_data->exit)
  48. physmap_data->exit(dev);
  49. return 0;
  50. }
  51. static void physmap_set_vpp(struct map_info *map, int state)
  52. {
  53. struct platform_device *pdev;
  54. struct physmap_flash_data *physmap_data;
  55. pdev = (struct platform_device *)map->map_priv_1;
  56. physmap_data = pdev->dev.platform_data;
  57. if (physmap_data->set_vpp)
  58. physmap_data->set_vpp(pdev, state);
  59. }
  60. static const char *rom_probe_types[] = {
  61. "cfi_probe",
  62. "jedec_probe",
  63. "qinfo_probe",
  64. "map_rom",
  65. NULL };
  66. static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "afs",
  67. NULL };
  68. static int physmap_flash_probe(struct platform_device *dev)
  69. {
  70. struct physmap_flash_data *physmap_data;
  71. struct physmap_flash_info *info;
  72. const char **probe_type;
  73. int err = 0;
  74. int i;
  75. int devices_found = 0;
  76. physmap_data = dev->dev.platform_data;
  77. if (physmap_data == NULL)
  78. return -ENODEV;
  79. info = devm_kzalloc(&dev->dev, sizeof(struct physmap_flash_info),
  80. GFP_KERNEL);
  81. if (info == NULL) {
  82. err = -ENOMEM;
  83. goto err_out;
  84. }
  85. if (physmap_data->init) {
  86. err = physmap_data->init(dev);
  87. if (err)
  88. goto err_out;
  89. }
  90. platform_set_drvdata(dev, info);
  91. for (i = 0; i < dev->num_resources; i++) {
  92. printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
  93. (unsigned long long)resource_size(&dev->resource[i]),
  94. (unsigned long long)dev->resource[i].start);
  95. if (!devm_request_mem_region(&dev->dev,
  96. dev->resource[i].start,
  97. resource_size(&dev->resource[i]),
  98. dev_name(&dev->dev))) {
  99. dev_err(&dev->dev, "Could not reserve memory region\n");
  100. err = -ENOMEM;
  101. goto err_out;
  102. }
  103. info->map[i].name = dev_name(&dev->dev);
  104. info->map[i].phys = dev->resource[i].start;
  105. info->map[i].size = resource_size(&dev->resource[i]);
  106. info->map[i].bankwidth = physmap_data->width;
  107. info->map[i].set_vpp = physmap_set_vpp;
  108. info->map[i].pfow_base = physmap_data->pfow_base;
  109. info->map[i].map_priv_1 = (unsigned long)dev;
  110. info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys,
  111. info->map[i].size);
  112. if (info->map[i].virt == NULL) {
  113. dev_err(&dev->dev, "Failed to ioremap flash region\n");
  114. err = -EIO;
  115. goto err_out;
  116. }
  117. simple_map_init(&info->map[i]);
  118. probe_type = rom_probe_types;
  119. if (physmap_data->probe_type == NULL) {
  120. for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
  121. info->mtd[i] = do_map_probe(*probe_type, &info->map[i]);
  122. } else
  123. info->mtd[i] = do_map_probe(physmap_data->probe_type, &info->map[i]);
  124. if (info->mtd[i] == NULL) {
  125. dev_err(&dev->dev, "map_probe failed\n");
  126. err = -ENXIO;
  127. goto err_out;
  128. } else {
  129. devices_found++;
  130. }
  131. info->mtd[i]->owner = THIS_MODULE;
  132. info->mtd[i]->dev.parent = &dev->dev;
  133. }
  134. if (devices_found == 1) {
  135. info->cmtd = info->mtd[0];
  136. } else if (devices_found > 1) {
  137. /*
  138. * We detected multiple devices. Concatenate them together.
  139. */
  140. info->cmtd = mtd_concat_create(info->mtd, devices_found, dev_name(&dev->dev));
  141. if (info->cmtd == NULL)
  142. err = -ENXIO;
  143. }
  144. if (err)
  145. goto err_out;
  146. mtd_device_parse_register(info->cmtd, part_probe_types, 0,
  147. physmap_data->parts, physmap_data->nr_parts);
  148. return 0;
  149. err_out:
  150. physmap_flash_remove(dev);
  151. return err;
  152. }
  153. #ifdef CONFIG_PM
  154. static void physmap_flash_shutdown(struct platform_device *dev)
  155. {
  156. struct physmap_flash_info *info = platform_get_drvdata(dev);
  157. int i;
  158. for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++)
  159. if (info->mtd[i]->suspend && info->mtd[i]->resume)
  160. if (info->mtd[i]->suspend(info->mtd[i]) == 0)
  161. info->mtd[i]->resume(info->mtd[i]);
  162. }
  163. #else
  164. #define physmap_flash_shutdown NULL
  165. #endif
  166. static struct platform_driver physmap_flash_driver = {
  167. .probe = physmap_flash_probe,
  168. .remove = physmap_flash_remove,
  169. .shutdown = physmap_flash_shutdown,
  170. .driver = {
  171. .name = "physmap-flash",
  172. .owner = THIS_MODULE,
  173. },
  174. };
  175. #ifdef CONFIG_MTD_PHYSMAP_COMPAT
  176. static struct physmap_flash_data physmap_flash_data = {
  177. .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
  178. };
  179. static struct resource physmap_flash_resource = {
  180. .start = CONFIG_MTD_PHYSMAP_START,
  181. .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
  182. .flags = IORESOURCE_MEM,
  183. };
  184. static struct platform_device physmap_flash = {
  185. .name = "physmap-flash",
  186. .id = 0,
  187. .dev = {
  188. .platform_data = &physmap_flash_data,
  189. },
  190. .num_resources = 1,
  191. .resource = &physmap_flash_resource,
  192. };
  193. #endif
  194. static int __init physmap_init(void)
  195. {
  196. int err;
  197. err = platform_driver_register(&physmap_flash_driver);
  198. #ifdef CONFIG_MTD_PHYSMAP_COMPAT
  199. if (err == 0) {
  200. err = platform_device_register(&physmap_flash);
  201. if (err)
  202. platform_driver_unregister(&physmap_flash_driver);
  203. }
  204. #endif
  205. return err;
  206. }
  207. static void __exit physmap_exit(void)
  208. {
  209. #ifdef CONFIG_MTD_PHYSMAP_COMPAT
  210. platform_device_unregister(&physmap_flash);
  211. #endif
  212. platform_driver_unregister(&physmap_flash_driver);
  213. }
  214. module_init(physmap_init);
  215. module_exit(physmap_exit);
  216. MODULE_LICENSE("GPL");
  217. MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
  218. MODULE_DESCRIPTION("Generic configurable MTD map driver");
  219. /* legacy platform drivers can't hotplug or coldplg */
  220. #ifndef CONFIG_MTD_PHYSMAP_COMPAT
  221. /* work with hotplug and coldplug */
  222. MODULE_ALIAS("platform:physmap-flash");
  223. #endif