0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include <linux/module.h>
0027 #include <linux/types.h>
0028 #include <linux/kernel.h>
0029 #include <linux/init.h>
0030 #include <linux/slab.h>
0031 #include <linux/device.h>
0032 #include <linux/platform_device.h>
0033 #include <linux/mtd/mtd.h>
0034 #include <linux/mtd/map.h>
0035 #include <linux/mtd/partitions.h>
0036 #include <linux/mtd/physmap.h>
0037 #include <linux/mtd/concat.h>
0038 #include <linux/mtd/cfi_endian.h>
0039 #include <linux/io.h>
0040 #include <linux/of_device.h>
0041 #include <linux/pm_runtime.h>
0042 #include <linux/gpio/consumer.h>
0043
0044 #include "physmap-bt1-rom.h"
0045 #include "physmap-gemini.h"
0046 #include "physmap-ixp4xx.h"
0047 #include "physmap-versatile.h"
0048
0049 struct physmap_flash_info {
0050 unsigned int nmaps;
0051 struct mtd_info **mtds;
0052 struct mtd_info *cmtd;
0053 struct map_info *maps;
0054 spinlock_t vpp_lock;
0055 int vpp_refcnt;
0056 const char *probe_type;
0057 const char * const *part_types;
0058 unsigned int nparts;
0059 const struct mtd_partition *parts;
0060 struct gpio_descs *gpios;
0061 unsigned int gpio_values;
0062 unsigned int win_order;
0063 };
0064
0065 static int physmap_flash_remove(struct platform_device *dev)
0066 {
0067 struct physmap_flash_info *info;
0068 struct physmap_flash_data *physmap_data;
0069 int i;
0070
0071 info = platform_get_drvdata(dev);
0072
0073 if (info->cmtd) {
0074 WARN_ON(mtd_device_unregister(info->cmtd));
0075
0076 if (info->cmtd != info->mtds[0])
0077 mtd_concat_destroy(info->cmtd);
0078 }
0079
0080 for (i = 0; i < info->nmaps; i++) {
0081 if (info->mtds[i])
0082 map_destroy(info->mtds[i]);
0083 }
0084
0085 physmap_data = dev_get_platdata(&dev->dev);
0086 if (physmap_data && physmap_data->exit)
0087 physmap_data->exit(dev);
0088
0089 pm_runtime_put(&dev->dev);
0090 pm_runtime_disable(&dev->dev);
0091 return 0;
0092 }
0093
0094 static void physmap_set_vpp(struct map_info *map, int state)
0095 {
0096 struct platform_device *pdev;
0097 struct physmap_flash_data *physmap_data;
0098 struct physmap_flash_info *info;
0099 unsigned long flags;
0100
0101 pdev = (struct platform_device *)map->map_priv_1;
0102 physmap_data = dev_get_platdata(&pdev->dev);
0103
0104 if (!physmap_data->set_vpp)
0105 return;
0106
0107 info = platform_get_drvdata(pdev);
0108
0109 spin_lock_irqsave(&info->vpp_lock, flags);
0110 if (state) {
0111 if (++info->vpp_refcnt == 1)
0112 physmap_data->set_vpp(pdev, 1);
0113 } else {
0114 if (--info->vpp_refcnt == 0)
0115 physmap_data->set_vpp(pdev, 0);
0116 }
0117 spin_unlock_irqrestore(&info->vpp_lock, flags);
0118 }
0119
0120 #if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR)
0121 static void physmap_set_addr_gpios(struct physmap_flash_info *info,
0122 unsigned long ofs)
0123 {
0124 unsigned int i;
0125
0126 ofs >>= info->win_order;
0127 if (info->gpio_values == ofs)
0128 return;
0129
0130 for (i = 0; i < info->gpios->ndescs; i++) {
0131 if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values))
0132 continue;
0133
0134 gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
0135 }
0136
0137 info->gpio_values = ofs;
0138 }
0139
0140 #define win_mask(order) (BIT(order) - 1)
0141
0142 static map_word physmap_addr_gpios_read(struct map_info *map,
0143 unsigned long ofs)
0144 {
0145 struct platform_device *pdev;
0146 struct physmap_flash_info *info;
0147 map_word mw;
0148 u16 word;
0149
0150 pdev = (struct platform_device *)map->map_priv_1;
0151 info = platform_get_drvdata(pdev);
0152 physmap_set_addr_gpios(info, ofs);
0153
0154 word = readw(map->virt + (ofs & win_mask(info->win_order)));
0155 mw.x[0] = word;
0156 return mw;
0157 }
0158
0159 static void physmap_addr_gpios_copy_from(struct map_info *map, void *buf,
0160 unsigned long ofs, ssize_t len)
0161 {
0162 struct platform_device *pdev;
0163 struct physmap_flash_info *info;
0164
0165 pdev = (struct platform_device *)map->map_priv_1;
0166 info = platform_get_drvdata(pdev);
0167
0168 while (len) {
0169 unsigned int winofs = ofs & win_mask(info->win_order);
0170 unsigned int chunklen = min_t(unsigned int, len,
0171 BIT(info->win_order) - winofs);
0172
0173 physmap_set_addr_gpios(info, ofs);
0174 memcpy_fromio(buf, map->virt + winofs, chunklen);
0175 len -= chunklen;
0176 buf += chunklen;
0177 ofs += chunklen;
0178 }
0179 }
0180
0181 static void physmap_addr_gpios_write(struct map_info *map, map_word mw,
0182 unsigned long ofs)
0183 {
0184 struct platform_device *pdev;
0185 struct physmap_flash_info *info;
0186 u16 word;
0187
0188 pdev = (struct platform_device *)map->map_priv_1;
0189 info = platform_get_drvdata(pdev);
0190 physmap_set_addr_gpios(info, ofs);
0191
0192 word = mw.x[0];
0193 writew(word, map->virt + (ofs & win_mask(info->win_order)));
0194 }
0195
0196 static void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs,
0197 const void *buf, ssize_t len)
0198 {
0199 struct platform_device *pdev;
0200 struct physmap_flash_info *info;
0201
0202 pdev = (struct platform_device *)map->map_priv_1;
0203 info = platform_get_drvdata(pdev);
0204
0205 while (len) {
0206 unsigned int winofs = ofs & win_mask(info->win_order);
0207 unsigned int chunklen = min_t(unsigned int, len,
0208 BIT(info->win_order) - winofs);
0209
0210 physmap_set_addr_gpios(info, ofs);
0211 memcpy_toio(map->virt + winofs, buf, chunklen);
0212 len -= chunklen;
0213 buf += chunklen;
0214 ofs += chunklen;
0215 }
0216 }
0217
0218 static int physmap_addr_gpios_map_init(struct map_info *map)
0219 {
0220 map->phys = NO_XIP;
0221 map->read = physmap_addr_gpios_read;
0222 map->copy_from = physmap_addr_gpios_copy_from;
0223 map->write = physmap_addr_gpios_write;
0224 map->copy_to = physmap_addr_gpios_copy_to;
0225
0226 return 0;
0227 }
0228 #else
0229 static int physmap_addr_gpios_map_init(struct map_info *map)
0230 {
0231 return -ENOTSUPP;
0232 }
0233 #endif
0234
0235 #if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF)
0236 static const struct of_device_id of_flash_match[] = {
0237 {
0238 .compatible = "cfi-flash",
0239 .data = "cfi_probe",
0240 },
0241 {
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251 .compatible = "jedec-flash",
0252 .data = "jedec_probe",
0253 },
0254 {
0255 .compatible = "mtd-ram",
0256 .data = "map_ram",
0257 },
0258 {
0259 .compatible = "mtd-rom",
0260 .data = "map_rom",
0261 },
0262 {
0263 .type = "rom",
0264 .compatible = "direct-mapped"
0265 },
0266 { },
0267 };
0268 MODULE_DEVICE_TABLE(of, of_flash_match);
0269
0270 static const char * const of_default_part_probes[] = {
0271 "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL
0272 };
0273
0274 static const char * const *of_get_part_probes(struct platform_device *dev)
0275 {
0276 struct device_node *dp = dev->dev.of_node;
0277 const char **res;
0278 int count;
0279
0280 count = of_property_count_strings(dp, "linux,part-probe");
0281 if (count < 0)
0282 return of_default_part_probes;
0283
0284 res = devm_kcalloc(&dev->dev, count + 1, sizeof(*res), GFP_KERNEL);
0285 if (!res)
0286 return NULL;
0287
0288 count = of_property_read_string_array(dp, "linux,part-probe", res,
0289 count);
0290 if (count < 0)
0291 return NULL;
0292
0293 return res;
0294 }
0295
0296 static const char *of_select_probe_type(struct platform_device *dev)
0297 {
0298 struct device_node *dp = dev->dev.of_node;
0299 const struct of_device_id *match;
0300 const char *probe_type;
0301
0302 match = of_match_device(of_flash_match, &dev->dev);
0303 probe_type = match->data;
0304 if (probe_type)
0305 return probe_type;
0306
0307 dev_warn(&dev->dev,
0308 "Device tree uses obsolete \"direct-mapped\" flash binding\n");
0309
0310 of_property_read_string(dp, "probe-type", &probe_type);
0311 if (!probe_type)
0312 return NULL;
0313
0314 if (!strcmp(probe_type, "CFI")) {
0315 probe_type = "cfi_probe";
0316 } else if (!strcmp(probe_type, "JEDEC")) {
0317 probe_type = "jedec_probe";
0318 } else if (!strcmp(probe_type, "ROM")) {
0319 probe_type = "map_rom";
0320 } else {
0321 dev_warn(&dev->dev,
0322 "obsolete_probe: don't know probe type '%s', mapping as rom\n",
0323 probe_type);
0324 probe_type = "map_rom";
0325 }
0326
0327 return probe_type;
0328 }
0329
0330 static int physmap_flash_of_init(struct platform_device *dev)
0331 {
0332 struct physmap_flash_info *info = platform_get_drvdata(dev);
0333 struct device_node *dp = dev->dev.of_node;
0334 const char *mtd_name = NULL;
0335 int err, swap = 0;
0336 bool map_indirect;
0337 unsigned int i;
0338 u32 bankwidth;
0339
0340 if (!dp)
0341 return -EINVAL;
0342
0343 info->probe_type = of_select_probe_type(dev);
0344
0345 info->part_types = of_get_part_probes(dev);
0346 if (!info->part_types)
0347 return -ENOMEM;
0348
0349 of_property_read_string(dp, "linux,mtd-name", &mtd_name);
0350
0351 map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
0352
0353 err = of_property_read_u32(dp, "bank-width", &bankwidth);
0354 if (err) {
0355 dev_err(&dev->dev, "Can't get bank width from device tree\n");
0356 return err;
0357 }
0358
0359 if (of_property_read_bool(dp, "big-endian"))
0360 swap = CFI_BIG_ENDIAN;
0361 else if (of_property_read_bool(dp, "little-endian"))
0362 swap = CFI_LITTLE_ENDIAN;
0363
0364 for (i = 0; i < info->nmaps; i++) {
0365 info->maps[i].name = mtd_name;
0366 info->maps[i].swap = swap;
0367 info->maps[i].bankwidth = bankwidth;
0368 info->maps[i].device_node = dp;
0369
0370 err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]);
0371 if (err)
0372 return err;
0373
0374 err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
0375 if (err)
0376 return err;
0377
0378 err = of_flash_probe_ixp4xx(dev, dp, &info->maps[i]);
0379 if (err)
0380 return err;
0381
0382 err = of_flash_probe_versatile(dev, dp, &info->maps[i]);
0383 if (err)
0384 return err;
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394 if (map_indirect)
0395 info->maps[i].phys = NO_XIP;
0396 }
0397
0398 return 0;
0399 }
0400 #else
0401 #define of_flash_match NULL
0402
0403 static int physmap_flash_of_init(struct platform_device *dev)
0404 {
0405 return -ENOTSUPP;
0406 }
0407 #endif
0408
0409 static const char * const rom_probe_types[] = {
0410 "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom",
0411 };
0412
0413 static const char * const part_probe_types[] = {
0414 "cmdlinepart", "RedBoot", "afs", NULL
0415 };
0416
0417 static int physmap_flash_pdata_init(struct platform_device *dev)
0418 {
0419 struct physmap_flash_info *info = platform_get_drvdata(dev);
0420 struct physmap_flash_data *physmap_data;
0421 unsigned int i;
0422 int err;
0423
0424 physmap_data = dev_get_platdata(&dev->dev);
0425 if (!physmap_data)
0426 return -EINVAL;
0427
0428 info->probe_type = physmap_data->probe_type;
0429 info->part_types = physmap_data->part_probe_types ? : part_probe_types;
0430 info->parts = physmap_data->parts;
0431 info->nparts = physmap_data->nr_parts;
0432
0433 if (physmap_data->init) {
0434 err = physmap_data->init(dev);
0435 if (err)
0436 return err;
0437 }
0438
0439 for (i = 0; i < info->nmaps; i++) {
0440 info->maps[i].bankwidth = physmap_data->width;
0441 info->maps[i].pfow_base = physmap_data->pfow_base;
0442 info->maps[i].set_vpp = physmap_set_vpp;
0443 }
0444
0445 return 0;
0446 }
0447
0448 static int physmap_flash_probe(struct platform_device *dev)
0449 {
0450 struct physmap_flash_info *info;
0451 int err = 0;
0452 int i;
0453
0454 if (!dev->dev.of_node && !dev_get_platdata(&dev->dev))
0455 return -EINVAL;
0456
0457 info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
0458 if (!info)
0459 return -ENOMEM;
0460
0461 while (platform_get_resource(dev, IORESOURCE_MEM, info->nmaps))
0462 info->nmaps++;
0463
0464 if (!info->nmaps)
0465 return -ENODEV;
0466
0467 info->maps = devm_kzalloc(&dev->dev,
0468 sizeof(*info->maps) * info->nmaps,
0469 GFP_KERNEL);
0470 if (!info->maps)
0471 return -ENOMEM;
0472
0473 info->mtds = devm_kzalloc(&dev->dev,
0474 sizeof(*info->mtds) * info->nmaps,
0475 GFP_KERNEL);
0476 if (!info->mtds)
0477 return -ENOMEM;
0478
0479 platform_set_drvdata(dev, info);
0480
0481 info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr",
0482 GPIOD_OUT_LOW);
0483 if (IS_ERR(info->gpios))
0484 return PTR_ERR(info->gpios);
0485
0486 if (info->gpios && info->nmaps > 1) {
0487 dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n");
0488 return -EINVAL;
0489 }
0490
0491 pm_runtime_enable(&dev->dev);
0492 pm_runtime_get_sync(&dev->dev);
0493
0494 if (dev->dev.of_node)
0495 err = physmap_flash_of_init(dev);
0496 else
0497 err = physmap_flash_pdata_init(dev);
0498
0499 if (err) {
0500 pm_runtime_put(&dev->dev);
0501 pm_runtime_disable(&dev->dev);
0502 return err;
0503 }
0504
0505 for (i = 0; i < info->nmaps; i++) {
0506 struct resource *res;
0507
0508 res = platform_get_resource(dev, IORESOURCE_MEM, i);
0509 info->maps[i].virt = devm_ioremap_resource(&dev->dev, res);
0510 if (IS_ERR(info->maps[i].virt)) {
0511 err = PTR_ERR(info->maps[i].virt);
0512 goto err_out;
0513 }
0514
0515 dev_notice(&dev->dev, "physmap platform flash device: %pR\n",
0516 res);
0517
0518 if (!info->maps[i].name)
0519 info->maps[i].name = dev_name(&dev->dev);
0520
0521 if (!info->maps[i].phys)
0522 info->maps[i].phys = res->start;
0523
0524 info->win_order = get_bitmask_order(resource_size(res)) - 1;
0525 info->maps[i].size = BIT(info->win_order +
0526 (info->gpios ?
0527 info->gpios->ndescs : 0));
0528
0529 info->maps[i].map_priv_1 = (unsigned long)dev;
0530
0531 if (info->gpios) {
0532 err = physmap_addr_gpios_map_init(&info->maps[i]);
0533 if (err)
0534 goto err_out;
0535 }
0536
0537 #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
0538
0539
0540
0541
0542
0543 if (!info->maps[i].read)
0544 simple_map_init(&info->maps[i]);
0545 #else
0546 simple_map_init(&info->maps[i]);
0547 #endif
0548
0549 if (info->probe_type) {
0550 info->mtds[i] = do_map_probe(info->probe_type,
0551 &info->maps[i]);
0552 } else {
0553 int j;
0554
0555 for (j = 0; j < ARRAY_SIZE(rom_probe_types); j++) {
0556 info->mtds[i] = do_map_probe(rom_probe_types[j],
0557 &info->maps[i]);
0558 if (info->mtds[i])
0559 break;
0560 }
0561 }
0562
0563 if (!info->mtds[i]) {
0564 dev_err(&dev->dev, "map_probe failed\n");
0565 err = -ENXIO;
0566 goto err_out;
0567 }
0568 info->mtds[i]->dev.parent = &dev->dev;
0569 }
0570
0571 if (info->nmaps == 1) {
0572 info->cmtd = info->mtds[0];
0573 } else {
0574
0575
0576
0577 info->cmtd = mtd_concat_create(info->mtds, info->nmaps,
0578 dev_name(&dev->dev));
0579 if (!info->cmtd)
0580 err = -ENXIO;
0581 }
0582 if (err)
0583 goto err_out;
0584
0585 spin_lock_init(&info->vpp_lock);
0586
0587 mtd_set_of_node(info->cmtd, dev->dev.of_node);
0588 err = mtd_device_parse_register(info->cmtd, info->part_types, NULL,
0589 info->parts, info->nparts);
0590 if (err)
0591 goto err_out;
0592
0593 return 0;
0594
0595 err_out:
0596 physmap_flash_remove(dev);
0597 return err;
0598 }
0599
0600 #ifdef CONFIG_PM
0601 static void physmap_flash_shutdown(struct platform_device *dev)
0602 {
0603 struct physmap_flash_info *info = platform_get_drvdata(dev);
0604 int i;
0605
0606 for (i = 0; i < info->nmaps && info->mtds[i]; i++)
0607 if (mtd_suspend(info->mtds[i]) == 0)
0608 mtd_resume(info->mtds[i]);
0609 }
0610 #else
0611 #define physmap_flash_shutdown NULL
0612 #endif
0613
0614 static struct platform_driver physmap_flash_driver = {
0615 .probe = physmap_flash_probe,
0616 .remove = physmap_flash_remove,
0617 .shutdown = physmap_flash_shutdown,
0618 .driver = {
0619 .name = "physmap-flash",
0620 .of_match_table = of_flash_match,
0621 },
0622 };
0623
0624 #ifdef CONFIG_MTD_PHYSMAP_COMPAT
0625 static struct physmap_flash_data physmap_flash_data = {
0626 .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
0627 };
0628
0629 static struct resource physmap_flash_resource = {
0630 .start = CONFIG_MTD_PHYSMAP_START,
0631 .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
0632 .flags = IORESOURCE_MEM,
0633 };
0634
0635 static struct platform_device physmap_flash = {
0636 .name = "physmap-flash",
0637 .id = 0,
0638 .dev = {
0639 .platform_data = &physmap_flash_data,
0640 },
0641 .num_resources = 1,
0642 .resource = &physmap_flash_resource,
0643 };
0644 #endif
0645
0646 static int __init physmap_init(void)
0647 {
0648 int err;
0649
0650 err = platform_driver_register(&physmap_flash_driver);
0651 #ifdef CONFIG_MTD_PHYSMAP_COMPAT
0652 if (err == 0) {
0653 err = platform_device_register(&physmap_flash);
0654 if (err)
0655 platform_driver_unregister(&physmap_flash_driver);
0656 }
0657 #endif
0658
0659 return err;
0660 }
0661
0662 static void __exit physmap_exit(void)
0663 {
0664 #ifdef CONFIG_MTD_PHYSMAP_COMPAT
0665 platform_device_unregister(&physmap_flash);
0666 #endif
0667 platform_driver_unregister(&physmap_flash_driver);
0668 }
0669
0670 module_init(physmap_init);
0671 module_exit(physmap_exit);
0672
0673 MODULE_LICENSE("GPL");
0674 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
0675 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
0676 MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
0677 MODULE_DESCRIPTION("Generic configurable MTD map driver");
0678
0679
0680 #ifndef CONFIG_MTD_PHYSMAP_COMPAT
0681
0682 MODULE_ALIAS("platform:physmap-flash");
0683 #endif