pci.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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