cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

physmap-core.c (16683B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Normal mappings of chips in physical memory
      4 *
      5 * Copyright (C) 2003 MontaVista Software Inc.
      6 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
      7 *
      8 * 031022 - [jsun] add run-time configure and partition setup
      9 *
     10 * Device tree support:
     11 *    Copyright (C) 2006 MontaVista Software Inc.
     12 *    Author: Vitaly Wool <vwool@ru.mvista.com>
     13 *
     14 *    Revised to handle newer style flash binding by:
     15 *    Copyright (C) 2007 David Gibson, IBM Corporation.
     16 *
     17 * GPIO address extension:
     18 *    Handle the case where a flash device is mostly addressed using physical
     19 *    line and supplemented by GPIOs.  This way you can hook up say a 8MiB flash
     20 *    to a 2MiB memory range and use the GPIOs to select a particular range.
     21 *
     22 *    Copyright © 2000 Nicolas Pitre <nico@cam.org>
     23 *    Copyright © 2005-2009 Analog Devices Inc.
     24 */
     25
     26#include <linux/module.h>
     27#include <linux/types.h>
     28#include <linux/kernel.h>
     29#include <linux/init.h>
     30#include <linux/slab.h>
     31#include <linux/device.h>
     32#include <linux/platform_device.h>
     33#include <linux/mtd/mtd.h>
     34#include <linux/mtd/map.h>
     35#include <linux/mtd/partitions.h>
     36#include <linux/mtd/physmap.h>
     37#include <linux/mtd/concat.h>
     38#include <linux/mtd/cfi_endian.h>
     39#include <linux/io.h>
     40#include <linux/of_device.h>
     41#include <linux/pm_runtime.h>
     42#include <linux/gpio/consumer.h>
     43
     44#include "physmap-bt1-rom.h"
     45#include "physmap-gemini.h"
     46#include "physmap-ixp4xx.h"
     47#include "physmap-versatile.h"
     48
     49struct physmap_flash_info {
     50	unsigned int		nmaps;
     51	struct mtd_info		**mtds;
     52	struct mtd_info		*cmtd;
     53	struct map_info		*maps;
     54	spinlock_t		vpp_lock;
     55	int			vpp_refcnt;
     56	const char		*probe_type;
     57	const char * const	*part_types;
     58	unsigned int		nparts;
     59	const struct mtd_partition *parts;
     60	struct gpio_descs	*gpios;
     61	unsigned int		gpio_values;
     62	unsigned int		win_order;
     63};
     64
     65static int physmap_flash_remove(struct platform_device *dev)
     66{
     67	struct physmap_flash_info *info;
     68	struct physmap_flash_data *physmap_data;
     69	int i, err = 0;
     70
     71	info = platform_get_drvdata(dev);
     72	if (!info) {
     73		err = -EINVAL;
     74		goto out;
     75	}
     76
     77	if (info->cmtd) {
     78		err = mtd_device_unregister(info->cmtd);
     79		if (err)
     80			goto out;
     81
     82		if (info->cmtd != info->mtds[0])
     83			mtd_concat_destroy(info->cmtd);
     84	}
     85
     86	for (i = 0; i < info->nmaps; i++) {
     87		if (info->mtds[i])
     88			map_destroy(info->mtds[i]);
     89	}
     90
     91	physmap_data = dev_get_platdata(&dev->dev);
     92	if (physmap_data && physmap_data->exit)
     93		physmap_data->exit(dev);
     94
     95out:
     96	pm_runtime_put(&dev->dev);
     97	pm_runtime_disable(&dev->dev);
     98	return err;
     99}
    100
    101static void physmap_set_vpp(struct map_info *map, int state)
    102{
    103	struct platform_device *pdev;
    104	struct physmap_flash_data *physmap_data;
    105	struct physmap_flash_info *info;
    106	unsigned long flags;
    107
    108	pdev = (struct platform_device *)map->map_priv_1;
    109	physmap_data = dev_get_platdata(&pdev->dev);
    110
    111	if (!physmap_data->set_vpp)
    112		return;
    113
    114	info = platform_get_drvdata(pdev);
    115
    116	spin_lock_irqsave(&info->vpp_lock, flags);
    117	if (state) {
    118		if (++info->vpp_refcnt == 1)    /* first nested 'on' */
    119			physmap_data->set_vpp(pdev, 1);
    120	} else {
    121		if (--info->vpp_refcnt == 0)    /* last nested 'off' */
    122			physmap_data->set_vpp(pdev, 0);
    123	}
    124	spin_unlock_irqrestore(&info->vpp_lock, flags);
    125}
    126
    127#if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR)
    128static void physmap_set_addr_gpios(struct physmap_flash_info *info,
    129				   unsigned long ofs)
    130{
    131	unsigned int i;
    132
    133	ofs >>= info->win_order;
    134	if (info->gpio_values == ofs)
    135		return;
    136
    137	for (i = 0; i < info->gpios->ndescs; i++) {
    138		if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values))
    139			continue;
    140
    141		gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
    142	}
    143
    144	info->gpio_values = ofs;
    145}
    146
    147#define win_mask(order)		(BIT(order) - 1)
    148
    149static map_word physmap_addr_gpios_read(struct map_info *map,
    150					unsigned long ofs)
    151{
    152	struct platform_device *pdev;
    153	struct physmap_flash_info *info;
    154	map_word mw;
    155	u16 word;
    156
    157	pdev = (struct platform_device *)map->map_priv_1;
    158	info = platform_get_drvdata(pdev);
    159	physmap_set_addr_gpios(info, ofs);
    160
    161	word = readw(map->virt + (ofs & win_mask(info->win_order)));
    162	mw.x[0] = word;
    163	return mw;
    164}
    165
    166static void physmap_addr_gpios_copy_from(struct map_info *map, void *buf,
    167					 unsigned long ofs, ssize_t len)
    168{
    169	struct platform_device *pdev;
    170	struct physmap_flash_info *info;
    171
    172	pdev = (struct platform_device *)map->map_priv_1;
    173	info = platform_get_drvdata(pdev);
    174
    175	while (len) {
    176		unsigned int winofs = ofs & win_mask(info->win_order);
    177		unsigned int chunklen = min_t(unsigned int, len,
    178					      BIT(info->win_order) - winofs);
    179
    180		physmap_set_addr_gpios(info, ofs);
    181		memcpy_fromio(buf, map->virt + winofs, chunklen);
    182		len -= chunklen;
    183		buf += chunklen;
    184		ofs += chunklen;
    185	}
    186}
    187
    188static void physmap_addr_gpios_write(struct map_info *map, map_word mw,
    189				     unsigned long ofs)
    190{
    191	struct platform_device *pdev;
    192	struct physmap_flash_info *info;
    193	u16 word;
    194
    195	pdev = (struct platform_device *)map->map_priv_1;
    196	info = platform_get_drvdata(pdev);
    197	physmap_set_addr_gpios(info, ofs);
    198
    199	word = mw.x[0];
    200	writew(word, map->virt + (ofs & win_mask(info->win_order)));
    201}
    202
    203static void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs,
    204				       const void *buf, ssize_t len)
    205{
    206	struct platform_device *pdev;
    207	struct physmap_flash_info *info;
    208
    209	pdev = (struct platform_device *)map->map_priv_1;
    210	info = platform_get_drvdata(pdev);
    211
    212	while (len) {
    213		unsigned int winofs = ofs & win_mask(info->win_order);
    214		unsigned int chunklen = min_t(unsigned int, len,
    215					      BIT(info->win_order) - winofs);
    216
    217		physmap_set_addr_gpios(info, ofs);
    218		memcpy_toio(map->virt + winofs, buf, chunklen);
    219		len -= chunklen;
    220		buf += chunklen;
    221		ofs += chunklen;
    222	}
    223}
    224
    225static int physmap_addr_gpios_map_init(struct map_info *map)
    226{
    227	map->phys = NO_XIP;
    228	map->read = physmap_addr_gpios_read;
    229	map->copy_from = physmap_addr_gpios_copy_from;
    230	map->write = physmap_addr_gpios_write;
    231	map->copy_to = physmap_addr_gpios_copy_to;
    232
    233	return 0;
    234}
    235#else
    236static int physmap_addr_gpios_map_init(struct map_info *map)
    237{
    238	return -ENOTSUPP;
    239}
    240#endif
    241
    242#if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF)
    243static const struct of_device_id of_flash_match[] = {
    244	{
    245		.compatible = "cfi-flash",
    246		.data = "cfi_probe",
    247	},
    248	{
    249		/*
    250		 * FIXME: JEDEC chips can't be safely and reliably
    251		 * probed, although the mtd code gets it right in
    252		 * practice most of the time.  We should use the
    253		 * vendor and device ids specified by the binding to
    254		 * bypass the heuristic probe code, but the mtd layer
    255		 * provides, at present, no interface for doing so
    256		 * :(.
    257		 */
    258		.compatible = "jedec-flash",
    259		.data = "jedec_probe",
    260	},
    261	{
    262		.compatible = "mtd-ram",
    263		.data = "map_ram",
    264	},
    265	{
    266		.compatible = "mtd-rom",
    267		.data = "map_rom",
    268	},
    269	{
    270		.type = "rom",
    271		.compatible = "direct-mapped"
    272	},
    273	{ /* sentinel */ },
    274};
    275MODULE_DEVICE_TABLE(of, of_flash_match);
    276
    277static const char * const of_default_part_probes[] = {
    278	"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL
    279};
    280
    281static const char * const *of_get_part_probes(struct platform_device *dev)
    282{
    283	struct device_node *dp = dev->dev.of_node;
    284	const char **res;
    285	int count;
    286
    287	count = of_property_count_strings(dp, "linux,part-probe");
    288	if (count < 0)
    289		return of_default_part_probes;
    290
    291	res = devm_kcalloc(&dev->dev, count + 1, sizeof(*res), GFP_KERNEL);
    292	if (!res)
    293		return NULL;
    294
    295	count = of_property_read_string_array(dp, "linux,part-probe", res,
    296					      count);
    297	if (count < 0)
    298		return NULL;
    299
    300	return res;
    301}
    302
    303static const char *of_select_probe_type(struct platform_device *dev)
    304{
    305	struct device_node *dp = dev->dev.of_node;
    306	const struct of_device_id *match;
    307	const char *probe_type;
    308
    309	match = of_match_device(of_flash_match, &dev->dev);
    310	probe_type = match->data;
    311	if (probe_type)
    312		return probe_type;
    313
    314	dev_warn(&dev->dev,
    315		 "Device tree uses obsolete \"direct-mapped\" flash binding\n");
    316
    317	of_property_read_string(dp, "probe-type", &probe_type);
    318	if (!probe_type)
    319		return NULL;
    320
    321	if (!strcmp(probe_type, "CFI")) {
    322		probe_type = "cfi_probe";
    323	} else if (!strcmp(probe_type, "JEDEC")) {
    324		probe_type = "jedec_probe";
    325	} else if (!strcmp(probe_type, "ROM")) {
    326		probe_type = "map_rom";
    327	} else {
    328		dev_warn(&dev->dev,
    329			 "obsolete_probe: don't know probe type '%s', mapping as rom\n",
    330			 probe_type);
    331		probe_type = "map_rom";
    332	}
    333
    334	return probe_type;
    335}
    336
    337static int physmap_flash_of_init(struct platform_device *dev)
    338{
    339	struct physmap_flash_info *info = platform_get_drvdata(dev);
    340	struct device_node *dp = dev->dev.of_node;
    341	const char *mtd_name = NULL;
    342	int err, swap = 0;
    343	bool map_indirect;
    344	unsigned int i;
    345	u32 bankwidth;
    346
    347	if (!dp)
    348		return -EINVAL;
    349
    350	info->probe_type = of_select_probe_type(dev);
    351
    352	info->part_types = of_get_part_probes(dev);
    353	if (!info->part_types)
    354		return -ENOMEM;
    355
    356	of_property_read_string(dp, "linux,mtd-name", &mtd_name);
    357
    358	map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
    359
    360	err = of_property_read_u32(dp, "bank-width", &bankwidth);
    361	if (err) {
    362		dev_err(&dev->dev, "Can't get bank width from device tree\n");
    363		return err;
    364	}
    365
    366	if (of_property_read_bool(dp, "big-endian"))
    367		swap = CFI_BIG_ENDIAN;
    368	else if (of_property_read_bool(dp, "little-endian"))
    369		swap = CFI_LITTLE_ENDIAN;
    370
    371	for (i = 0; i < info->nmaps; i++) {
    372		info->maps[i].name = mtd_name;
    373		info->maps[i].swap = swap;
    374		info->maps[i].bankwidth = bankwidth;
    375		info->maps[i].device_node = dp;
    376
    377		err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]);
    378		if (err)
    379			return err;
    380
    381		err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
    382		if (err)
    383			return err;
    384
    385		err = of_flash_probe_ixp4xx(dev, dp, &info->maps[i]);
    386		if (err)
    387			return err;
    388
    389		err = of_flash_probe_versatile(dev, dp, &info->maps[i]);
    390		if (err)
    391			return err;
    392
    393		/*
    394		 * On some platforms (e.g. MPC5200) a direct 1:1 mapping
    395		 * may cause problems with JFFS2 usage, as the local bus (LPB)
    396		 * doesn't support unaligned accesses as implemented in the
    397		 * JFFS2 code via memcpy(). By setting NO_XIP, the
    398		 * flash will not be exposed directly to the MTD users
    399		 * (e.g. JFFS2) any more.
    400		 */
    401		if (map_indirect)
    402			info->maps[i].phys = NO_XIP;
    403	}
    404
    405	return 0;
    406}
    407#else /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
    408#define of_flash_match NULL
    409
    410static int physmap_flash_of_init(struct platform_device *dev)
    411{
    412	return -ENOTSUPP;
    413}
    414#endif /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
    415
    416static const char * const rom_probe_types[] = {
    417	"cfi_probe", "jedec_probe", "qinfo_probe", "map_rom",
    418};
    419
    420static const char * const part_probe_types[] = {
    421	"cmdlinepart", "RedBoot", "afs", NULL
    422};
    423
    424static int physmap_flash_pdata_init(struct platform_device *dev)
    425{
    426	struct physmap_flash_info *info = platform_get_drvdata(dev);
    427	struct physmap_flash_data *physmap_data;
    428	unsigned int i;
    429	int err;
    430
    431	physmap_data = dev_get_platdata(&dev->dev);
    432	if (!physmap_data)
    433		return -EINVAL;
    434
    435	info->probe_type = physmap_data->probe_type;
    436	info->part_types = physmap_data->part_probe_types ? : part_probe_types;
    437	info->parts = physmap_data->parts;
    438	info->nparts = physmap_data->nr_parts;
    439
    440	if (physmap_data->init) {
    441		err = physmap_data->init(dev);
    442		if (err)
    443			return err;
    444	}
    445
    446	for (i = 0; i < info->nmaps; i++) {
    447		info->maps[i].bankwidth = physmap_data->width;
    448		info->maps[i].pfow_base = physmap_data->pfow_base;
    449		info->maps[i].set_vpp = physmap_set_vpp;
    450	}
    451
    452	return 0;
    453}
    454
    455static int physmap_flash_probe(struct platform_device *dev)
    456{
    457	struct physmap_flash_info *info;
    458	int err = 0;
    459	int i;
    460
    461	if (!dev->dev.of_node && !dev_get_platdata(&dev->dev))
    462		return -EINVAL;
    463
    464	info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
    465	if (!info)
    466		return -ENOMEM;
    467
    468	while (platform_get_resource(dev, IORESOURCE_MEM, info->nmaps))
    469		info->nmaps++;
    470
    471	if (!info->nmaps)
    472		return -ENODEV;
    473
    474	info->maps = devm_kzalloc(&dev->dev,
    475				  sizeof(*info->maps) * info->nmaps,
    476				  GFP_KERNEL);
    477	if (!info->maps)
    478		return -ENOMEM;
    479
    480	info->mtds = devm_kzalloc(&dev->dev,
    481				  sizeof(*info->mtds) * info->nmaps,
    482				  GFP_KERNEL);
    483	if (!info->mtds)
    484		return -ENOMEM;
    485
    486	platform_set_drvdata(dev, info);
    487
    488	info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr",
    489						    GPIOD_OUT_LOW);
    490	if (IS_ERR(info->gpios))
    491		return PTR_ERR(info->gpios);
    492
    493	if (info->gpios && info->nmaps > 1) {
    494		dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n");
    495		return -EINVAL;
    496	}
    497
    498	pm_runtime_enable(&dev->dev);
    499	pm_runtime_get_sync(&dev->dev);
    500
    501	if (dev->dev.of_node)
    502		err = physmap_flash_of_init(dev);
    503	else
    504		err = physmap_flash_pdata_init(dev);
    505
    506	if (err) {
    507		pm_runtime_put(&dev->dev);
    508		pm_runtime_disable(&dev->dev);
    509		return err;
    510	}
    511
    512	for (i = 0; i < info->nmaps; i++) {
    513		struct resource *res;
    514
    515		res = platform_get_resource(dev, IORESOURCE_MEM, i);
    516		info->maps[i].virt = devm_ioremap_resource(&dev->dev, res);
    517		if (IS_ERR(info->maps[i].virt)) {
    518			err = PTR_ERR(info->maps[i].virt);
    519			goto err_out;
    520		}
    521
    522		dev_notice(&dev->dev, "physmap platform flash device: %pR\n",
    523			   res);
    524
    525		if (!info->maps[i].name)
    526			info->maps[i].name = dev_name(&dev->dev);
    527
    528		if (!info->maps[i].phys)
    529			info->maps[i].phys = res->start;
    530
    531		info->win_order = get_bitmask_order(resource_size(res)) - 1;
    532		info->maps[i].size = BIT(info->win_order +
    533					 (info->gpios ?
    534					  info->gpios->ndescs : 0));
    535
    536		info->maps[i].map_priv_1 = (unsigned long)dev;
    537
    538		if (info->gpios) {
    539			err = physmap_addr_gpios_map_init(&info->maps[i]);
    540			if (err)
    541				goto err_out;
    542		}
    543
    544#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
    545		/*
    546		 * Only use the simple_map implementation if map hooks are not
    547		 * implemented. Since map->read() is mandatory checking for its
    548		 * presence is enough.
    549		 */
    550		if (!info->maps[i].read)
    551			simple_map_init(&info->maps[i]);
    552#else
    553		simple_map_init(&info->maps[i]);
    554#endif
    555
    556		if (info->probe_type) {
    557			info->mtds[i] = do_map_probe(info->probe_type,
    558						     &info->maps[i]);
    559		} else {
    560			int j;
    561
    562			for (j = 0; j < ARRAY_SIZE(rom_probe_types); j++) {
    563				info->mtds[i] = do_map_probe(rom_probe_types[j],
    564							     &info->maps[i]);
    565				if (info->mtds[i])
    566					break;
    567			}
    568		}
    569
    570		if (!info->mtds[i]) {
    571			dev_err(&dev->dev, "map_probe failed\n");
    572			err = -ENXIO;
    573			goto err_out;
    574		}
    575		info->mtds[i]->dev.parent = &dev->dev;
    576	}
    577
    578	if (info->nmaps == 1) {
    579		info->cmtd = info->mtds[0];
    580	} else {
    581		/*
    582		 * We detected multiple devices. Concatenate them together.
    583		 */
    584		info->cmtd = mtd_concat_create(info->mtds, info->nmaps,
    585					       dev_name(&dev->dev));
    586		if (!info->cmtd)
    587			err = -ENXIO;
    588	}
    589	if (err)
    590		goto err_out;
    591
    592	spin_lock_init(&info->vpp_lock);
    593
    594	mtd_set_of_node(info->cmtd, dev->dev.of_node);
    595	err = mtd_device_parse_register(info->cmtd, info->part_types, NULL,
    596					info->parts, info->nparts);
    597	if (err)
    598		goto err_out;
    599
    600	return 0;
    601
    602err_out:
    603	physmap_flash_remove(dev);
    604	return err;
    605}
    606
    607#ifdef CONFIG_PM
    608static void physmap_flash_shutdown(struct platform_device *dev)
    609{
    610	struct physmap_flash_info *info = platform_get_drvdata(dev);
    611	int i;
    612
    613	for (i = 0; i < info->nmaps && info->mtds[i]; i++)
    614		if (mtd_suspend(info->mtds[i]) == 0)
    615			mtd_resume(info->mtds[i]);
    616}
    617#else
    618#define physmap_flash_shutdown NULL
    619#endif
    620
    621static struct platform_driver physmap_flash_driver = {
    622	.probe		= physmap_flash_probe,
    623	.remove		= physmap_flash_remove,
    624	.shutdown	= physmap_flash_shutdown,
    625	.driver		= {
    626		.name	= "physmap-flash",
    627		.of_match_table = of_flash_match,
    628	},
    629};
    630
    631#ifdef CONFIG_MTD_PHYSMAP_COMPAT
    632static struct physmap_flash_data physmap_flash_data = {
    633	.width		= CONFIG_MTD_PHYSMAP_BANKWIDTH,
    634};
    635
    636static struct resource physmap_flash_resource = {
    637	.start		= CONFIG_MTD_PHYSMAP_START,
    638	.end		= CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
    639	.flags		= IORESOURCE_MEM,
    640};
    641
    642static struct platform_device physmap_flash = {
    643	.name		= "physmap-flash",
    644	.id		= 0,
    645	.dev		= {
    646		.platform_data	= &physmap_flash_data,
    647	},
    648	.num_resources	= 1,
    649	.resource	= &physmap_flash_resource,
    650};
    651#endif
    652
    653static int __init physmap_init(void)
    654{
    655	int err;
    656
    657	err = platform_driver_register(&physmap_flash_driver);
    658#ifdef CONFIG_MTD_PHYSMAP_COMPAT
    659	if (err == 0) {
    660		err = platform_device_register(&physmap_flash);
    661		if (err)
    662			platform_driver_unregister(&physmap_flash_driver);
    663	}
    664#endif
    665
    666	return err;
    667}
    668
    669static void __exit physmap_exit(void)
    670{
    671#ifdef CONFIG_MTD_PHYSMAP_COMPAT
    672	platform_device_unregister(&physmap_flash);
    673#endif
    674	platform_driver_unregister(&physmap_flash_driver);
    675}
    676
    677module_init(physmap_init);
    678module_exit(physmap_exit);
    679
    680MODULE_LICENSE("GPL");
    681MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
    682MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
    683MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
    684MODULE_DESCRIPTION("Generic configurable MTD map driver");
    685
    686/* legacy platform drivers can't hotplug or coldplg */
    687#ifndef CONFIG_MTD_PHYSMAP_COMPAT
    688/* work with hotplug and coldplug */
    689MODULE_ALIAS("platform:physmap-flash");
    690#endif