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