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