18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Normal mappings of chips in physical memory 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003 MontaVista Software Inc. 68c2ecf20Sopenharmony_ci * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * 031022 - [jsun] add run-time configure and partition setup 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Device tree support: 118c2ecf20Sopenharmony_ci * Copyright (C) 2006 MontaVista Software Inc. 128c2ecf20Sopenharmony_ci * Author: Vitaly Wool <vwool@ru.mvista.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Revised to handle newer style flash binding by: 158c2ecf20Sopenharmony_ci * Copyright (C) 2007 David Gibson, IBM Corporation. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * GPIO address extension: 188c2ecf20Sopenharmony_ci * Handle the case where a flash device is mostly addressed using physical 198c2ecf20Sopenharmony_ci * line and supplemented by GPIOs. This way you can hook up say a 8MiB flash 208c2ecf20Sopenharmony_ci * to a 2MiB memory range and use the GPIOs to select a particular range. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Copyright © 2000 Nicolas Pitre <nico@cam.org> 238c2ecf20Sopenharmony_ci * Copyright © 2005-2009 Analog Devices Inc. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/types.h> 288c2ecf20Sopenharmony_ci#include <linux/kernel.h> 298c2ecf20Sopenharmony_ci#include <linux/init.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/device.h> 328c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 338c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 348c2ecf20Sopenharmony_ci#include <linux/mtd/map.h> 358c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h> 368c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h> 378c2ecf20Sopenharmony_ci#include <linux/mtd/concat.h> 388c2ecf20Sopenharmony_ci#include <linux/mtd/cfi_endian.h> 398c2ecf20Sopenharmony_ci#include <linux/io.h> 408c2ecf20Sopenharmony_ci#include <linux/of_device.h> 418c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 428c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include "physmap-bt1-rom.h" 458c2ecf20Sopenharmony_ci#include "physmap-gemini.h" 468c2ecf20Sopenharmony_ci#include "physmap-ixp4xx.h" 478c2ecf20Sopenharmony_ci#include "physmap-versatile.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct physmap_flash_info { 508c2ecf20Sopenharmony_ci unsigned int nmaps; 518c2ecf20Sopenharmony_ci struct mtd_info **mtds; 528c2ecf20Sopenharmony_ci struct mtd_info *cmtd; 538c2ecf20Sopenharmony_ci struct map_info *maps; 548c2ecf20Sopenharmony_ci spinlock_t vpp_lock; 558c2ecf20Sopenharmony_ci int vpp_refcnt; 568c2ecf20Sopenharmony_ci const char *probe_type; 578c2ecf20Sopenharmony_ci const char * const *part_types; 588c2ecf20Sopenharmony_ci unsigned int nparts; 598c2ecf20Sopenharmony_ci const struct mtd_partition *parts; 608c2ecf20Sopenharmony_ci struct gpio_descs *gpios; 618c2ecf20Sopenharmony_ci unsigned int gpio_values; 628c2ecf20Sopenharmony_ci unsigned int win_order; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int physmap_flash_remove(struct platform_device *dev) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 688c2ecf20Sopenharmony_ci struct physmap_flash_data *physmap_data; 698c2ecf20Sopenharmony_ci int i, err = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci info = platform_get_drvdata(dev); 728c2ecf20Sopenharmony_ci if (!info) { 738c2ecf20Sopenharmony_ci err = -EINVAL; 748c2ecf20Sopenharmony_ci goto out; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (info->cmtd) { 788c2ecf20Sopenharmony_ci err = mtd_device_unregister(info->cmtd); 798c2ecf20Sopenharmony_ci if (err) 808c2ecf20Sopenharmony_ci goto out; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (info->cmtd != info->mtds[0]) 838c2ecf20Sopenharmony_ci mtd_concat_destroy(info->cmtd); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci for (i = 0; i < info->nmaps; i++) { 878c2ecf20Sopenharmony_ci if (info->mtds[i]) 888c2ecf20Sopenharmony_ci map_destroy(info->mtds[i]); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci physmap_data = dev_get_platdata(&dev->dev); 928c2ecf20Sopenharmony_ci if (physmap_data && physmap_data->exit) 938c2ecf20Sopenharmony_ci physmap_data->exit(dev); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciout: 968c2ecf20Sopenharmony_ci pm_runtime_put(&dev->dev); 978c2ecf20Sopenharmony_ci pm_runtime_disable(&dev->dev); 988c2ecf20Sopenharmony_ci return err; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void physmap_set_vpp(struct map_info *map, int state) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct platform_device *pdev; 1048c2ecf20Sopenharmony_ci struct physmap_flash_data *physmap_data; 1058c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 1068c2ecf20Sopenharmony_ci unsigned long flags; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci pdev = (struct platform_device *)map->map_priv_1; 1098c2ecf20Sopenharmony_ci physmap_data = dev_get_platdata(&pdev->dev); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!physmap_data->set_vpp) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci info = platform_get_drvdata(pdev); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->vpp_lock, flags); 1178c2ecf20Sopenharmony_ci if (state) { 1188c2ecf20Sopenharmony_ci if (++info->vpp_refcnt == 1) /* first nested 'on' */ 1198c2ecf20Sopenharmony_ci physmap_data->set_vpp(pdev, 1); 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci if (--info->vpp_refcnt == 0) /* last nested 'off' */ 1228c2ecf20Sopenharmony_ci physmap_data->set_vpp(pdev, 0); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->vpp_lock, flags); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR) 1288c2ecf20Sopenharmony_cistatic void physmap_set_addr_gpios(struct physmap_flash_info *info, 1298c2ecf20Sopenharmony_ci unsigned long ofs) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci unsigned int i; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ofs >>= info->win_order; 1348c2ecf20Sopenharmony_ci if (info->gpio_values == ofs) 1358c2ecf20Sopenharmony_ci return; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci for (i = 0; i < info->gpios->ndescs; i++) { 1388c2ecf20Sopenharmony_ci if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values)) 1398c2ecf20Sopenharmony_ci continue; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs)); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci info->gpio_values = ofs; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define win_mask(order) (BIT(order) - 1) 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic map_word physmap_addr_gpios_read(struct map_info *map, 1508c2ecf20Sopenharmony_ci unsigned long ofs) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct platform_device *pdev; 1538c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 1548c2ecf20Sopenharmony_ci map_word mw; 1558c2ecf20Sopenharmony_ci u16 word; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci pdev = (struct platform_device *)map->map_priv_1; 1588c2ecf20Sopenharmony_ci info = platform_get_drvdata(pdev); 1598c2ecf20Sopenharmony_ci physmap_set_addr_gpios(info, ofs); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci word = readw(map->virt + (ofs & win_mask(info->win_order))); 1628c2ecf20Sopenharmony_ci mw.x[0] = word; 1638c2ecf20Sopenharmony_ci return mw; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void physmap_addr_gpios_copy_from(struct map_info *map, void *buf, 1678c2ecf20Sopenharmony_ci unsigned long ofs, ssize_t len) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct platform_device *pdev; 1708c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci pdev = (struct platform_device *)map->map_priv_1; 1738c2ecf20Sopenharmony_ci info = platform_get_drvdata(pdev); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci while (len) { 1768c2ecf20Sopenharmony_ci unsigned int winofs = ofs & win_mask(info->win_order); 1778c2ecf20Sopenharmony_ci unsigned int chunklen = min_t(unsigned int, len, 1788c2ecf20Sopenharmony_ci BIT(info->win_order) - winofs); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci physmap_set_addr_gpios(info, ofs); 1818c2ecf20Sopenharmony_ci memcpy_fromio(buf, map->virt + winofs, chunklen); 1828c2ecf20Sopenharmony_ci len -= chunklen; 1838c2ecf20Sopenharmony_ci buf += chunklen; 1848c2ecf20Sopenharmony_ci ofs += chunklen; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void physmap_addr_gpios_write(struct map_info *map, map_word mw, 1898c2ecf20Sopenharmony_ci unsigned long ofs) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct platform_device *pdev; 1928c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 1938c2ecf20Sopenharmony_ci u16 word; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci pdev = (struct platform_device *)map->map_priv_1; 1968c2ecf20Sopenharmony_ci info = platform_get_drvdata(pdev); 1978c2ecf20Sopenharmony_ci physmap_set_addr_gpios(info, ofs); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci word = mw.x[0]; 2008c2ecf20Sopenharmony_ci writew(word, map->virt + (ofs & win_mask(info->win_order))); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs, 2048c2ecf20Sopenharmony_ci const void *buf, ssize_t len) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct platform_device *pdev; 2078c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci pdev = (struct platform_device *)map->map_priv_1; 2108c2ecf20Sopenharmony_ci info = platform_get_drvdata(pdev); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci while (len) { 2138c2ecf20Sopenharmony_ci unsigned int winofs = ofs & win_mask(info->win_order); 2148c2ecf20Sopenharmony_ci unsigned int chunklen = min_t(unsigned int, len, 2158c2ecf20Sopenharmony_ci BIT(info->win_order) - winofs); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci physmap_set_addr_gpios(info, ofs); 2188c2ecf20Sopenharmony_ci memcpy_toio(map->virt + winofs, buf, chunklen); 2198c2ecf20Sopenharmony_ci len -= chunklen; 2208c2ecf20Sopenharmony_ci buf += chunklen; 2218c2ecf20Sopenharmony_ci ofs += chunklen; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int physmap_addr_gpios_map_init(struct map_info *map) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci map->phys = NO_XIP; 2288c2ecf20Sopenharmony_ci map->read = physmap_addr_gpios_read; 2298c2ecf20Sopenharmony_ci map->copy_from = physmap_addr_gpios_copy_from; 2308c2ecf20Sopenharmony_ci map->write = physmap_addr_gpios_write; 2318c2ecf20Sopenharmony_ci map->copy_to = physmap_addr_gpios_copy_to; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci#else 2368c2ecf20Sopenharmony_cistatic int physmap_addr_gpios_map_init(struct map_info *map) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci return -ENOTSUPP; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci#endif 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) 2438c2ecf20Sopenharmony_cistatic const struct of_device_id of_flash_match[] = { 2448c2ecf20Sopenharmony_ci { 2458c2ecf20Sopenharmony_ci .compatible = "cfi-flash", 2468c2ecf20Sopenharmony_ci .data = "cfi_probe", 2478c2ecf20Sopenharmony_ci }, 2488c2ecf20Sopenharmony_ci { 2498c2ecf20Sopenharmony_ci /* 2508c2ecf20Sopenharmony_ci * FIXME: JEDEC chips can't be safely and reliably 2518c2ecf20Sopenharmony_ci * probed, although the mtd code gets it right in 2528c2ecf20Sopenharmony_ci * practice most of the time. We should use the 2538c2ecf20Sopenharmony_ci * vendor and device ids specified by the binding to 2548c2ecf20Sopenharmony_ci * bypass the heuristic probe code, but the mtd layer 2558c2ecf20Sopenharmony_ci * provides, at present, no interface for doing so 2568c2ecf20Sopenharmony_ci * :(. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci .compatible = "jedec-flash", 2598c2ecf20Sopenharmony_ci .data = "jedec_probe", 2608c2ecf20Sopenharmony_ci }, 2618c2ecf20Sopenharmony_ci { 2628c2ecf20Sopenharmony_ci .compatible = "mtd-ram", 2638c2ecf20Sopenharmony_ci .data = "map_ram", 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci { 2668c2ecf20Sopenharmony_ci .compatible = "mtd-rom", 2678c2ecf20Sopenharmony_ci .data = "map_rom", 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci { 2708c2ecf20Sopenharmony_ci .type = "rom", 2718c2ecf20Sopenharmony_ci .compatible = "direct-mapped" 2728c2ecf20Sopenharmony_ci }, 2738c2ecf20Sopenharmony_ci { /* sentinel */ }, 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_flash_match); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic const char * const of_default_part_probes[] = { 2788c2ecf20Sopenharmony_ci "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic const char * const *of_get_part_probes(struct platform_device *dev) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct device_node *dp = dev->dev.of_node; 2848c2ecf20Sopenharmony_ci const char **res; 2858c2ecf20Sopenharmony_ci int count; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci count = of_property_count_strings(dp, "linux,part-probe"); 2888c2ecf20Sopenharmony_ci if (count < 0) 2898c2ecf20Sopenharmony_ci return of_default_part_probes; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci res = devm_kcalloc(&dev->dev, count + 1, sizeof(*res), GFP_KERNEL); 2928c2ecf20Sopenharmony_ci if (!res) 2938c2ecf20Sopenharmony_ci return NULL; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci count = of_property_read_string_array(dp, "linux,part-probe", res, 2968c2ecf20Sopenharmony_ci count); 2978c2ecf20Sopenharmony_ci if (count < 0) 2988c2ecf20Sopenharmony_ci return NULL; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return res; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const char *of_select_probe_type(struct platform_device *dev) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct device_node *dp = dev->dev.of_node; 3068c2ecf20Sopenharmony_ci const struct of_device_id *match; 3078c2ecf20Sopenharmony_ci const char *probe_type; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci match = of_match_device(of_flash_match, &dev->dev); 3108c2ecf20Sopenharmony_ci probe_type = match->data; 3118c2ecf20Sopenharmony_ci if (probe_type) 3128c2ecf20Sopenharmony_ci return probe_type; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 3158c2ecf20Sopenharmony_ci "Device tree uses obsolete \"direct-mapped\" flash binding\n"); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci of_property_read_string(dp, "probe-type", &probe_type); 3188c2ecf20Sopenharmony_ci if (!probe_type) 3198c2ecf20Sopenharmony_ci return NULL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!strcmp(probe_type, "CFI")) { 3228c2ecf20Sopenharmony_ci probe_type = "cfi_probe"; 3238c2ecf20Sopenharmony_ci } else if (!strcmp(probe_type, "JEDEC")) { 3248c2ecf20Sopenharmony_ci probe_type = "jedec_probe"; 3258c2ecf20Sopenharmony_ci } else if (!strcmp(probe_type, "ROM")) { 3268c2ecf20Sopenharmony_ci probe_type = "map_rom"; 3278c2ecf20Sopenharmony_ci } else { 3288c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 3298c2ecf20Sopenharmony_ci "obsolete_probe: don't know probe type '%s', mapping as rom\n", 3308c2ecf20Sopenharmony_ci probe_type); 3318c2ecf20Sopenharmony_ci probe_type = "map_rom"; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return probe_type; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int physmap_flash_of_init(struct platform_device *dev) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct physmap_flash_info *info = platform_get_drvdata(dev); 3408c2ecf20Sopenharmony_ci struct device_node *dp = dev->dev.of_node; 3418c2ecf20Sopenharmony_ci const char *mtd_name = NULL; 3428c2ecf20Sopenharmony_ci int err, swap = 0; 3438c2ecf20Sopenharmony_ci bool map_indirect; 3448c2ecf20Sopenharmony_ci unsigned int i; 3458c2ecf20Sopenharmony_ci u32 bankwidth; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!dp) 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci info->probe_type = of_select_probe_type(dev); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci info->part_types = of_get_part_probes(dev); 3538c2ecf20Sopenharmony_ci if (!info->part_types) 3548c2ecf20Sopenharmony_ci return -ENOMEM; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci of_property_read_string(dp, "linux,mtd-name", &mtd_name); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access"); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci err = of_property_read_u32(dp, "bank-width", &bankwidth); 3618c2ecf20Sopenharmony_ci if (err) { 3628c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't get bank width from device tree\n"); 3638c2ecf20Sopenharmony_ci return err; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (of_property_read_bool(dp, "big-endian")) 3678c2ecf20Sopenharmony_ci swap = CFI_BIG_ENDIAN; 3688c2ecf20Sopenharmony_ci else if (of_property_read_bool(dp, "little-endian")) 3698c2ecf20Sopenharmony_ci swap = CFI_LITTLE_ENDIAN; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci for (i = 0; i < info->nmaps; i++) { 3728c2ecf20Sopenharmony_ci info->maps[i].name = mtd_name; 3738c2ecf20Sopenharmony_ci info->maps[i].swap = swap; 3748c2ecf20Sopenharmony_ci info->maps[i].bankwidth = bankwidth; 3758c2ecf20Sopenharmony_ci info->maps[i].device_node = dp; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]); 3788c2ecf20Sopenharmony_ci if (err) 3798c2ecf20Sopenharmony_ci return err; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci err = of_flash_probe_gemini(dev, dp, &info->maps[i]); 3828c2ecf20Sopenharmony_ci if (err) 3838c2ecf20Sopenharmony_ci return err; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci err = of_flash_probe_ixp4xx(dev, dp, &info->maps[i]); 3868c2ecf20Sopenharmony_ci if (err) 3878c2ecf20Sopenharmony_ci return err; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci err = of_flash_probe_versatile(dev, dp, &info->maps[i]); 3908c2ecf20Sopenharmony_ci if (err) 3918c2ecf20Sopenharmony_ci return err; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* 3948c2ecf20Sopenharmony_ci * On some platforms (e.g. MPC5200) a direct 1:1 mapping 3958c2ecf20Sopenharmony_ci * may cause problems with JFFS2 usage, as the local bus (LPB) 3968c2ecf20Sopenharmony_ci * doesn't support unaligned accesses as implemented in the 3978c2ecf20Sopenharmony_ci * JFFS2 code via memcpy(). By setting NO_XIP, the 3988c2ecf20Sopenharmony_ci * flash will not be exposed directly to the MTD users 3998c2ecf20Sopenharmony_ci * (e.g. JFFS2) any more. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci if (map_indirect) 4028c2ecf20Sopenharmony_ci info->maps[i].phys = NO_XIP; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci#else /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */ 4088c2ecf20Sopenharmony_ci#define of_flash_match NULL 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int physmap_flash_of_init(struct platform_device *dev) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci return -ENOTSUPP; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */ 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic const char * const rom_probe_types[] = { 4178c2ecf20Sopenharmony_ci "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom", 4188c2ecf20Sopenharmony_ci}; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic const char * const part_probe_types[] = { 4218c2ecf20Sopenharmony_ci "cmdlinepart", "RedBoot", "afs", NULL 4228c2ecf20Sopenharmony_ci}; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int physmap_flash_pdata_init(struct platform_device *dev) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct physmap_flash_info *info = platform_get_drvdata(dev); 4278c2ecf20Sopenharmony_ci struct physmap_flash_data *physmap_data; 4288c2ecf20Sopenharmony_ci unsigned int i; 4298c2ecf20Sopenharmony_ci int err; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci physmap_data = dev_get_platdata(&dev->dev); 4328c2ecf20Sopenharmony_ci if (!physmap_data) 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci info->probe_type = physmap_data->probe_type; 4368c2ecf20Sopenharmony_ci info->part_types = physmap_data->part_probe_types ? : part_probe_types; 4378c2ecf20Sopenharmony_ci info->parts = physmap_data->parts; 4388c2ecf20Sopenharmony_ci info->nparts = physmap_data->nr_parts; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (physmap_data->init) { 4418c2ecf20Sopenharmony_ci err = physmap_data->init(dev); 4428c2ecf20Sopenharmony_ci if (err) 4438c2ecf20Sopenharmony_ci return err; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci for (i = 0; i < info->nmaps; i++) { 4478c2ecf20Sopenharmony_ci info->maps[i].bankwidth = physmap_data->width; 4488c2ecf20Sopenharmony_ci info->maps[i].pfow_base = physmap_data->pfow_base; 4498c2ecf20Sopenharmony_ci info->maps[i].set_vpp = physmap_set_vpp; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int physmap_flash_probe(struct platform_device *dev) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct physmap_flash_info *info; 4588c2ecf20Sopenharmony_ci int err = 0; 4598c2ecf20Sopenharmony_ci int i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!dev->dev.of_node && !dev_get_platdata(&dev->dev)) 4628c2ecf20Sopenharmony_ci return -EINVAL; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); 4658c2ecf20Sopenharmony_ci if (!info) 4668c2ecf20Sopenharmony_ci return -ENOMEM; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci while (platform_get_resource(dev, IORESOURCE_MEM, info->nmaps)) 4698c2ecf20Sopenharmony_ci info->nmaps++; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (!info->nmaps) 4728c2ecf20Sopenharmony_ci return -ENODEV; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci info->maps = devm_kzalloc(&dev->dev, 4758c2ecf20Sopenharmony_ci sizeof(*info->maps) * info->nmaps, 4768c2ecf20Sopenharmony_ci GFP_KERNEL); 4778c2ecf20Sopenharmony_ci if (!info->maps) 4788c2ecf20Sopenharmony_ci return -ENOMEM; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci info->mtds = devm_kzalloc(&dev->dev, 4818c2ecf20Sopenharmony_ci sizeof(*info->mtds) * info->nmaps, 4828c2ecf20Sopenharmony_ci GFP_KERNEL); 4838c2ecf20Sopenharmony_ci if (!info->mtds) 4848c2ecf20Sopenharmony_ci return -ENOMEM; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci platform_set_drvdata(dev, info); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr", 4898c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 4908c2ecf20Sopenharmony_ci if (IS_ERR(info->gpios)) 4918c2ecf20Sopenharmony_ci return PTR_ERR(info->gpios); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (info->gpios && info->nmaps > 1) { 4948c2ecf20Sopenharmony_ci dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n"); 4958c2ecf20Sopenharmony_ci return -EINVAL; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci pm_runtime_enable(&dev->dev); 4998c2ecf20Sopenharmony_ci pm_runtime_get_sync(&dev->dev); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (dev->dev.of_node) 5028c2ecf20Sopenharmony_ci err = physmap_flash_of_init(dev); 5038c2ecf20Sopenharmony_ci else 5048c2ecf20Sopenharmony_ci err = physmap_flash_pdata_init(dev); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (err) { 5078c2ecf20Sopenharmony_ci pm_runtime_put(&dev->dev); 5088c2ecf20Sopenharmony_ci pm_runtime_disable(&dev->dev); 5098c2ecf20Sopenharmony_ci return err; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci for (i = 0; i < info->nmaps; i++) { 5138c2ecf20Sopenharmony_ci struct resource *res; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci res = platform_get_resource(dev, IORESOURCE_MEM, i); 5168c2ecf20Sopenharmony_ci info->maps[i].virt = devm_ioremap_resource(&dev->dev, res); 5178c2ecf20Sopenharmony_ci if (IS_ERR(info->maps[i].virt)) { 5188c2ecf20Sopenharmony_ci err = PTR_ERR(info->maps[i].virt); 5198c2ecf20Sopenharmony_ci goto err_out; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci dev_notice(&dev->dev, "physmap platform flash device: %pR\n", 5238c2ecf20Sopenharmony_ci res); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (!info->maps[i].name) 5268c2ecf20Sopenharmony_ci info->maps[i].name = dev_name(&dev->dev); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (!info->maps[i].phys) 5298c2ecf20Sopenharmony_ci info->maps[i].phys = res->start; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci info->win_order = get_bitmask_order(resource_size(res)) - 1; 5328c2ecf20Sopenharmony_ci info->maps[i].size = BIT(info->win_order + 5338c2ecf20Sopenharmony_ci (info->gpios ? 5348c2ecf20Sopenharmony_ci info->gpios->ndescs : 0)); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci info->maps[i].map_priv_1 = (unsigned long)dev; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (info->gpios) { 5398c2ecf20Sopenharmony_ci err = physmap_addr_gpios_map_init(&info->maps[i]); 5408c2ecf20Sopenharmony_ci if (err) 5418c2ecf20Sopenharmony_ci goto err_out; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_COMPLEX_MAPPINGS 5458c2ecf20Sopenharmony_ci /* 5468c2ecf20Sopenharmony_ci * Only use the simple_map implementation if map hooks are not 5478c2ecf20Sopenharmony_ci * implemented. Since map->read() is mandatory checking for its 5488c2ecf20Sopenharmony_ci * presence is enough. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci if (!info->maps[i].read) 5518c2ecf20Sopenharmony_ci simple_map_init(&info->maps[i]); 5528c2ecf20Sopenharmony_ci#else 5538c2ecf20Sopenharmony_ci simple_map_init(&info->maps[i]); 5548c2ecf20Sopenharmony_ci#endif 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (info->probe_type) { 5578c2ecf20Sopenharmony_ci info->mtds[i] = do_map_probe(info->probe_type, 5588c2ecf20Sopenharmony_ci &info->maps[i]); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Fall back to mapping region as ROM */ 5618c2ecf20Sopenharmony_ci if (!info->mtds[i] && IS_ENABLED(CONFIG_MTD_ROM) && 5628c2ecf20Sopenharmony_ci strcmp(info->probe_type, "map_rom")) { 5638c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 5648c2ecf20Sopenharmony_ci "map_probe() failed for type %s\n", 5658c2ecf20Sopenharmony_ci info->probe_type); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci info->mtds[i] = do_map_probe("map_rom", 5688c2ecf20Sopenharmony_ci &info->maps[i]); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } else { 5718c2ecf20Sopenharmony_ci int j; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(rom_probe_types); j++) { 5748c2ecf20Sopenharmony_ci info->mtds[i] = do_map_probe(rom_probe_types[j], 5758c2ecf20Sopenharmony_ci &info->maps[i]); 5768c2ecf20Sopenharmony_ci if (info->mtds[i]) 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (!info->mtds[i]) { 5828c2ecf20Sopenharmony_ci dev_err(&dev->dev, "map_probe failed\n"); 5838c2ecf20Sopenharmony_ci err = -ENXIO; 5848c2ecf20Sopenharmony_ci goto err_out; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci info->mtds[i]->dev.parent = &dev->dev; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (info->nmaps == 1) { 5908c2ecf20Sopenharmony_ci info->cmtd = info->mtds[0]; 5918c2ecf20Sopenharmony_ci } else { 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * We detected multiple devices. Concatenate them together. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci info->cmtd = mtd_concat_create(info->mtds, info->nmaps, 5968c2ecf20Sopenharmony_ci dev_name(&dev->dev)); 5978c2ecf20Sopenharmony_ci if (!info->cmtd) 5988c2ecf20Sopenharmony_ci err = -ENXIO; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci if (err) 6018c2ecf20Sopenharmony_ci goto err_out; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci spin_lock_init(&info->vpp_lock); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci mtd_set_of_node(info->cmtd, dev->dev.of_node); 6068c2ecf20Sopenharmony_ci err = mtd_device_parse_register(info->cmtd, info->part_types, NULL, 6078c2ecf20Sopenharmony_ci info->parts, info->nparts); 6088c2ecf20Sopenharmony_ci if (err) 6098c2ecf20Sopenharmony_ci goto err_out; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cierr_out: 6148c2ecf20Sopenharmony_ci physmap_flash_remove(dev); 6158c2ecf20Sopenharmony_ci return err; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6198c2ecf20Sopenharmony_cistatic void physmap_flash_shutdown(struct platform_device *dev) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct physmap_flash_info *info = platform_get_drvdata(dev); 6228c2ecf20Sopenharmony_ci int i; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci for (i = 0; i < info->nmaps && info->mtds[i]; i++) 6258c2ecf20Sopenharmony_ci if (mtd_suspend(info->mtds[i]) == 0) 6268c2ecf20Sopenharmony_ci mtd_resume(info->mtds[i]); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci#else 6298c2ecf20Sopenharmony_ci#define physmap_flash_shutdown NULL 6308c2ecf20Sopenharmony_ci#endif 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic struct platform_driver physmap_flash_driver = { 6338c2ecf20Sopenharmony_ci .probe = physmap_flash_probe, 6348c2ecf20Sopenharmony_ci .remove = physmap_flash_remove, 6358c2ecf20Sopenharmony_ci .shutdown = physmap_flash_shutdown, 6368c2ecf20Sopenharmony_ci .driver = { 6378c2ecf20Sopenharmony_ci .name = "physmap-flash", 6388c2ecf20Sopenharmony_ci .of_match_table = of_flash_match, 6398c2ecf20Sopenharmony_ci }, 6408c2ecf20Sopenharmony_ci}; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_PHYSMAP_COMPAT 6438c2ecf20Sopenharmony_cistatic struct physmap_flash_data physmap_flash_data = { 6448c2ecf20Sopenharmony_ci .width = CONFIG_MTD_PHYSMAP_BANKWIDTH, 6458c2ecf20Sopenharmony_ci}; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic struct resource physmap_flash_resource = { 6488c2ecf20Sopenharmony_ci .start = CONFIG_MTD_PHYSMAP_START, 6498c2ecf20Sopenharmony_ci .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1, 6508c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 6518c2ecf20Sopenharmony_ci}; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic struct platform_device physmap_flash = { 6548c2ecf20Sopenharmony_ci .name = "physmap-flash", 6558c2ecf20Sopenharmony_ci .id = 0, 6568c2ecf20Sopenharmony_ci .dev = { 6578c2ecf20Sopenharmony_ci .platform_data = &physmap_flash_data, 6588c2ecf20Sopenharmony_ci }, 6598c2ecf20Sopenharmony_ci .num_resources = 1, 6608c2ecf20Sopenharmony_ci .resource = &physmap_flash_resource, 6618c2ecf20Sopenharmony_ci}; 6628c2ecf20Sopenharmony_ci#endif 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic int __init physmap_init(void) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci int err; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci err = platform_driver_register(&physmap_flash_driver); 6698c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_PHYSMAP_COMPAT 6708c2ecf20Sopenharmony_ci if (err == 0) { 6718c2ecf20Sopenharmony_ci err = platform_device_register(&physmap_flash); 6728c2ecf20Sopenharmony_ci if (err) 6738c2ecf20Sopenharmony_ci platform_driver_unregister(&physmap_flash_driver); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci#endif 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return err; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic void __exit physmap_exit(void) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_PHYSMAP_COMPAT 6838c2ecf20Sopenharmony_ci platform_device_unregister(&physmap_flash); 6848c2ecf20Sopenharmony_ci#endif 6858c2ecf20Sopenharmony_ci platform_driver_unregister(&physmap_flash_driver); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cimodule_init(physmap_init); 6898c2ecf20Sopenharmony_cimodule_exit(physmap_exit); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6928c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 6938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); 6948c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); 6958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Generic configurable MTD map driver"); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci/* legacy platform drivers can't hotplug or coldplg */ 6988c2ecf20Sopenharmony_ci#ifndef CONFIG_MTD_PHYSMAP_COMPAT 6998c2ecf20Sopenharmony_ci/* work with hotplug and coldplug */ 7008c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:physmap-flash"); 7018c2ecf20Sopenharmony_ci#endif 702