Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pci.c
Go to the documentation of this file.
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 
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 __devinit
257 mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
258 {
259  struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
260  struct map_pci_info *map = NULL;
261  struct mtd_info *mtd = NULL;
262  int err;
263 
264  err = pci_enable_device(dev);
265  if (err)
266  goto out;
267 
268  err = pci_request_regions(dev, "pci mtd");
269  if (err)
270  goto out;
271 
272  map = kmalloc(sizeof(*map), GFP_KERNEL);
273  err = -ENOMEM;
274  if (!map)
275  goto release;
276 
277  map->map = mtd_pci_map;
278  map->map.name = pci_name(dev);
279  map->dev = dev;
280  map->exit = info->exit;
281  map->translate = info->translate;
282 
283  err = info->init(dev, map);
284  if (err)
285  goto release;
286 
287  /* tsk - do_map_probe should take const char * */
288  mtd = do_map_probe((char *)info->map_name, &map->map);
289  err = -ENODEV;
290  if (!mtd)
291  goto release;
292 
293  mtd->owner = THIS_MODULE;
294  mtd_device_register(mtd, NULL, 0);
295 
296  pci_set_drvdata(dev, mtd);
297 
298  return 0;
299 
300 release:
301  if (map) {
302  map->exit(dev, map);
303  kfree(map);
304  }
305 
306  pci_release_regions(dev);
307 out:
308  return err;
309 }
310 
311 static void __devexit
312 mtd_pci_remove(struct pci_dev *dev)
313 {
314  struct mtd_info *mtd = pci_get_drvdata(dev);
315  struct map_pci_info *map = mtd->priv;
316 
318  map_destroy(mtd);
319  map->exit(dev, map);
320  kfree(map);
321 
322  pci_set_drvdata(dev, NULL);
323  pci_release_regions(dev);
324 }
325 
326 static struct pci_driver mtd_pci_driver = {
327  .name = "MTD PCI",
328  .probe = mtd_pci_probe,
329  .remove = __devexit_p(mtd_pci_remove),
330  .id_table = mtd_pci_ids,
331 };
332 
333 module_pci_driver(mtd_pci_driver);
334 
335 MODULE_LICENSE("GPL");
336 MODULE_AUTHOR("Russell King <[email protected]>");
337 MODULE_DESCRIPTION("Generic PCI map driver");
338 MODULE_DEVICE_TABLE(pci, mtd_pci_ids);