brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · ca00d21 Raw
331 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  linux/drivers/mtd/maps/pci.c4 *5 *  Copyright (C) 2001 Russell King, All rights reserved.6 *7 * Generic PCI memory map driver.  We support the following boards:8 *  - Intel IQ80310 ATU.9 *  - Intel EBSA285 (blank rom programming mode). Tested working 27/09/200110 */11#include <linux/module.h>12#include <linux/kernel.h>13#include <linux/pci.h>14#include <linux/slab.h>15 16#include <linux/mtd/mtd.h>17#include <linux/mtd/map.h>18#include <linux/mtd/partitions.h>19 20struct map_pci_info;21 22struct mtd_pci_info {23	int  (*init)(struct pci_dev *dev, struct map_pci_info *map);24	void (*exit)(struct pci_dev *dev, struct map_pci_info *map);25	unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);26	const char *map_name;27};28 29struct map_pci_info {30	struct map_info map;31	void __iomem *base;32	void (*exit)(struct pci_dev *dev, struct map_pci_info *map);33	unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);34	struct pci_dev *dev;35};36 37static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)38{39	struct map_pci_info *map = (struct map_pci_info *)_map;40	map_word val;41	val.x[0]= readb(map->base + map->translate(map, ofs));42	return val;43}44 45static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs)46{47	struct map_pci_info *map = (struct map_pci_info *)_map;48	map_word val;49	val.x[0] = readl(map->base + map->translate(map, ofs));50	return val;51}52 53static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)54{55	struct map_pci_info *map = (struct map_pci_info *)_map;56	memcpy_fromio(to, map->base + map->translate(map, from), len);57}58 59static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs)60{61	struct map_pci_info *map = (struct map_pci_info *)_map;62	writeb(val.x[0], map->base + map->translate(map, ofs));63}64 65static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs)66{67	struct map_pci_info *map = (struct map_pci_info *)_map;68	writel(val.x[0], map->base + map->translate(map, ofs));69}70 71static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)72{73	struct map_pci_info *map = (struct map_pci_info *)_map;74	memcpy_toio(map->base + map->translate(map, to), from, len);75}76 77static const struct map_info mtd_pci_map = {78	.phys =		NO_XIP,79	.copy_from =	mtd_pci_copyfrom,80	.copy_to =	mtd_pci_copyto,81};82 83/*84 * Intel IOP80310 Flash driver85 */86 87static int88intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)89{90	u32 win_base;91 92	map->map.bankwidth = 1;93	map->map.read = mtd_pci_read8;94	map->map.write = mtd_pci_write8;95 96	map->map.size     = 0x00800000;97	map->base         = ioremap(pci_resource_start(dev, 0),98					    pci_resource_len(dev, 0));99 100	if (!map->base)101		return -ENOMEM;102 103	/*104	 * We want to base the memory window at Xscale105	 * bus address 0, not 0x1000.106	 */107	pci_read_config_dword(dev, 0x44, &win_base);108	pci_write_config_dword(dev, 0x44, 0);109 110	map->map.map_priv_2 = win_base;111 112	return 0;113}114 115static void116intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)117{118	if (map->base)119		iounmap(map->base);120	pci_write_config_dword(dev, 0x44, map->map.map_priv_2);121}122 123static unsigned long124intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs)125{126	unsigned long page_addr = ofs & 0x00400000;127 128	/*129	 * This mundges the flash location so we avoid130	 * the first 80 bytes (they appear to read nonsense).131	 */132	if (page_addr) {133		writel(0x00000008, map->base + 0x1558);134		writel(0x00000000, map->base + 0x1550);135	} else {136		writel(0x00000007, map->base + 0x1558);137		writel(0x00800000, map->base + 0x1550);138		ofs += 0x00800000;139	}140 141	return ofs;142}143 144static struct mtd_pci_info intel_iq80310_info = {145	.init =		intel_iq80310_init,146	.exit =		intel_iq80310_exit,147	.translate =	intel_iq80310_translate,148	.map_name =	"cfi_probe",149};150 151/*152 * Intel DC21285 driver153 */154 155static int156intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)157{158	unsigned long base, len;159 160	base = pci_resource_start(dev, PCI_ROM_RESOURCE);161	len  = pci_resource_len(dev, PCI_ROM_RESOURCE);162 163	if (!len || !base) {164		/*165		 * No ROM resource166		 */167		base = pci_resource_start(dev, 2);168		len  = pci_resource_len(dev, 2);169 170		/*171		 * We need to re-allocate PCI BAR2 address range to the172		 * PCI ROM BAR, and disable PCI BAR2.173		 */174	} else {175		/*176		 * Hmm, if an address was allocated to the ROM resource, but177		 * not enabled, should we be allocating a new resource for it178		 * or simply enabling it?179		 */180		pci_enable_rom(dev);181		printk("%s: enabling expansion ROM\n", pci_name(dev));182	}183 184	if (!len || !base)185		return -ENXIO;186 187	map->map.bankwidth = 4;188	map->map.read = mtd_pci_read32;189	map->map.write = mtd_pci_write32;190	map->map.size     = len;191	map->base         = ioremap(base, len);192 193	if (!map->base)194		return -ENOMEM;195 196	return 0;197}198 199static void200intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)201{202	if (map->base)203		iounmap(map->base);204 205	/*206	 * We need to undo the PCI BAR2/PCI ROM BAR address alteration.207	 */208	pci_disable_rom(dev);209}210 211static unsigned long212intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs)213{214	return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5));215}216 217static struct mtd_pci_info intel_dc21285_info = {218	.init =		intel_dc21285_init,219	.exit =		intel_dc21285_exit,220	.translate =	intel_dc21285_translate,221	.map_name =	"jedec_probe",222};223 224/*225 * PCI device ID table226 */227 228static const struct pci_device_id mtd_pci_ids[] = {229	{230		.vendor =	PCI_VENDOR_ID_INTEL,231		.device =	0x530d,232		.subvendor =	PCI_ANY_ID,233		.subdevice =	PCI_ANY_ID,234		.class =	PCI_CLASS_MEMORY_OTHER << 8,235		.class_mask =	0xffff00,236		.driver_data =	(unsigned long)&intel_iq80310_info,237	},238	{239		.vendor =	PCI_VENDOR_ID_DEC,240		.device =	PCI_DEVICE_ID_DEC_21285,241		.subvendor =	0,	/* DC21285 defaults to 0 on reset */242		.subdevice =	0,	/* DC21285 defaults to 0 on reset */243		.driver_data =	(unsigned long)&intel_dc21285_info,244	},245	{ 0, }246};247 248/*249 * Generic code follows.250 */251 252static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)253{254	struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;255	struct map_pci_info *map = NULL;256	struct mtd_info *mtd = NULL;257	int err;258 259	err = pci_enable_device(dev);260	if (err)261		goto out;262 263	err = pci_request_regions(dev, "pci mtd");264	if (err)265		goto out;266 267	map = kmalloc(sizeof(*map), GFP_KERNEL);268	err = -ENOMEM;269	if (!map)270		goto release;271 272	map->map       = mtd_pci_map;273	map->map.name  = pci_name(dev);274	map->dev       = dev;275	map->exit      = info->exit;276	map->translate = info->translate;277 278	err = info->init(dev, map);279	if (err)280		goto release;281 282	mtd = do_map_probe(info->map_name, &map->map);283	err = -ENODEV;284	if (!mtd)285		goto release;286 287	mtd->owner = THIS_MODULE;288	mtd_device_register(mtd, NULL, 0);289 290	pci_set_drvdata(dev, mtd);291 292	return 0;293 294release:295	if (map) {296		map->exit(dev, map);297		kfree(map);298	}299 300	pci_release_regions(dev);301out:302	return err;303}304 305static void mtd_pci_remove(struct pci_dev *dev)306{307	struct mtd_info *mtd = pci_get_drvdata(dev);308	struct map_pci_info *map = mtd->priv;309 310	mtd_device_unregister(mtd);311	map_destroy(mtd);312	map->exit(dev, map);313	kfree(map);314 315	pci_release_regions(dev);316}317 318static struct pci_driver mtd_pci_driver = {319	.name =		"MTD PCI",320	.probe =	mtd_pci_probe,321	.remove =	mtd_pci_remove,322	.id_table =	mtd_pci_ids,323};324 325module_pci_driver(mtd_pci_driver);326 327MODULE_LICENSE("GPL");328MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");329MODULE_DESCRIPTION("Generic PCI map driver");330MODULE_DEVICE_TABLE(pci, mtd_pci_ids);331