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