ich2rom.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * ich2rom.c
  3.  *
  4.  * Normal mappings of chips in physical memory
  5.  * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $
  6.  */
  7. #include <linux/module.h>
  8. #include <linux/types.h>
  9. #include <linux/kernel.h>
  10. #include <asm/io.h>
  11. #include <linux/mtd/mtd.h>
  12. #include <linux/mtd/map.h>
  13. #include <linux/config.h>
  14. #include <linux/pci.h>
  15. #include <linux/pci_ids.h>
  16. #define RESERVE_MEM_REGION 0
  17. #define ICH2_FWH_REGION_START 0xFF000000UL
  18. #define ICH2_FWH_REGION_SIZE 0x01000000UL
  19. #define BIOS_CNTL 0x4e
  20. #define FWH_DEC_EN1 0xE3
  21. #define FWH_DEC_EN2 0xF0
  22. #define FWH_SEL1 0xE8
  23. #define FWH_SEL2 0xEE
  24. struct ich2rom_map_info {
  25. struct map_info map;
  26. struct mtd_info *mtd;
  27. unsigned long window_addr;
  28. };
  29. static inline unsigned long addr(struct map_info *map, unsigned long ofs)
  30. {
  31. unsigned long offset;
  32. offset = ((8*1024*1024) - map->size) + ofs;
  33. if (offset >= (4*1024*1024)) {
  34. offset += 0x400000;
  35. }
  36. return map->map_priv_1 + 0x400000 + offset;
  37. }
  38. static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
  39. {
  40. return addr - map->map_priv_1 + ICH2_FWH_REGION_START;
  41. }
  42. static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs)
  43. {
  44. return __raw_readb(addr(map, ofs));
  45. }
  46. static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs)
  47. {
  48. return __raw_readw(addr(map, ofs));
  49. }
  50. static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs)
  51. {
  52. return __raw_readl(addr(map, ofs));
  53. }
  54. static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
  55. {
  56. memcpy_fromio(to, addr(map, from), len);
  57. }
  58. static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs)
  59. {
  60. __raw_writeb(d, addr(map,ofs));
  61. mb();
  62. }
  63. static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs)
  64. {
  65. __raw_writew(d, addr(map, ofs));
  66. mb();
  67. }
  68. static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs)
  69. {
  70. __raw_writel(d, addr(map, ofs));
  71. mb();
  72. }
  73. static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
  74. {
  75. memcpy_toio(addr(map, to), from, len);
  76. }
  77. static struct ich2rom_map_info ich2rom_map = {
  78. map: {
  79. name: "ICH2 rom",
  80. size: 0,
  81. buswidth: 1,
  82. read8: ich2rom_read8,
  83. read16: ich2rom_read16,
  84. read32: ich2rom_read32,
  85. copy_from: ich2rom_copy_from,
  86. write8: ich2rom_write8,
  87. write16: ich2rom_write16,
  88. write32: ich2rom_write32,
  89. copy_to: ich2rom_copy_to,
  90. /* Firmware hubs only use vpp when being programmed
  91.  * in a factory setting.  So in place programming
  92.  * needs to use a different method.
  93.  */
  94. },
  95. mtd: 0,
  96. window_addr: 0,
  97. };
  98. enum fwh_lock_state {
  99. FWH_DENY_WRITE = 1,
  100. FWH_IMMUTABLE  = 2,
  101. FWH_DENY_READ  = 4,
  102. };
  103. static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
  104. enum fwh_lock_state state)
  105. {
  106. struct map_info *map = mtd->priv;
  107. unsigned long start = ofs;
  108. unsigned long end = start + len -1;
  109. /* FIXME do I need to guard against concurrency here? */
  110. /* round down to 64K boundaries */
  111. start = start & ~0xFFFF;
  112. end = end & ~0xFFFF;
  113. while (start <= end) {
  114. unsigned long ctrl_addr;
  115. ctrl_addr = addr(map, start) - 0x400000 + 2;
  116. writeb(state, ctrl_addr);
  117. start = start + 0x10000;
  118. }
  119. return 0;
  120. }
  121. static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
  122. {
  123. return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
  124. }
  125. static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
  126. {
  127. return ich2rom_set_lock_state(mtd, ofs, len, 0);
  128. }
  129. static int __devinit ich2rom_init_one (struct pci_dev *pdev,
  130. const struct pci_device_id *ent)
  131. {
  132. u16 word;
  133. struct ich2rom_map_info *info = &ich2rom_map;
  134. unsigned long map_size;
  135. /* For now I just handle the ich2 and I assume there
  136.  * are not a lot of resources up at the top of the address
  137.  * space.  It is possible to handle other devices in the
  138.  * top 16MB but it is very painful.  Also since
  139.  * you can only really attach a FWH to an ICH2 there
  140.  * a number of simplifications you can make.
  141.  *
  142.  * Also you can page firmware hubs if an 8MB window isn't enough 
  143.  * but don't currently handle that case either.
  144.  */
  145. #if RESERVE_MEM_REGION
  146. /* Some boards have this reserved and I haven't found a good work
  147.  * around to say I know what I'm doing!
  148.  */
  149. if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) {
  150. printk(KERN_ERR "ich2rom: cannot reserve rom windown");
  151. goto err_out_none;
  152. }
  153. #endif /* RESERVE_MEM_REGION */
  154. /* Enable writes through the rom window */
  155. pci_read_config_word(pdev, BIOS_CNTL, &word);
  156. if (!(word & 1)  && (word & (1<<1))) {
  157. /* The BIOS will generate an error if I enable
  158.  * this device, so don't even try.
  159.  */
  160. printk(KERN_ERR "ich2rom: firmware access control, I can't enable writesn");
  161. goto err_out_none;
  162. }
  163. pci_write_config_word(pdev, BIOS_CNTL, word | 1);
  164. /* Map the firmware hub into my address space. */
  165. /* Does this use to much virtual address space? */
  166. info->window_addr = (unsigned long)ioremap(
  167. ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
  168. if (!info->window_addr) {
  169. printk(KERN_ERR "Failed to ioremapn");
  170. goto err_out_free_mmio_region;
  171. }
  172. /* For now assume the firmware has setup all relavent firmware
  173.  * windows.  We don't have enough information to handle this case
  174.  * intelligently.
  175.  */
  176. /* FIXME select the firmware hub and enable a window to it. */
  177. info->mtd = 0;
  178. info->map.map_priv_1 =  info->window_addr;
  179. map_size = ICH2_FWH_REGION_SIZE;
  180. while(!info->mtd && (map_size > 0)) {
  181. info->map.size = map_size;
  182. info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map);
  183. map_size -= 512*1024;
  184. }
  185. if (!info->mtd) {
  186. goto err_out_iounmap;
  187. }
  188. /* I know I can only be a firmware hub here so put
  189.  * in the special lock and unlock routines.
  190.  */
  191. info->mtd->lock = ich2rom_lock;
  192. info->mtd->unlock = ich2rom_unlock;
  193. info->mtd->module = THIS_MODULE;
  194. add_mtd_device(info->mtd);
  195. return 0;
  196. err_out_iounmap:
  197. iounmap((void *)(info->window_addr));
  198. err_out_free_mmio_region:
  199. #if RESERVE_MEM_REGION
  200. release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
  201. #endif
  202. err_out_none:
  203. return -ENODEV;
  204. }
  205. static void __devexit ich2rom_remove_one (struct pci_dev *pdev)
  206. {
  207. struct ich2rom_map_info *info = &ich2rom_map;
  208. u16 word;
  209. del_mtd_device(info->mtd);
  210. map_destroy(info->mtd);
  211. info->mtd = 0;
  212. info->map.map_priv_1 = 0;
  213. iounmap((void *)(info->window_addr));
  214. info->window_addr = 0;
  215. /* Disable writes through the rom window */
  216. pci_read_config_word(pdev, BIOS_CNTL, &word);
  217. pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
  218. #if RESERVE_MEM_REGION
  219. release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
  220. #endif
  221. }
  222. static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = {
  223. { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
  224.   PCI_ANY_ID, PCI_ANY_ID, },
  225. };
  226. MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl);
  227. #if 0
  228. static struct pci_driver ich2rom_driver = {
  229. name:   "ich2rom",
  230. id_table: ich2rom_pci_tbl,
  231. probe:    ich2rom_init_one,
  232. remove:   ich2rom_remove_one,
  233. };
  234. #endif
  235. static struct pci_dev *mydev;
  236. int __init init_ich2rom(void)
  237. {
  238. struct pci_dev *pdev;
  239. pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0);
  240. if (pdev) {
  241. mydev = pdev;
  242. return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]);
  243. }
  244. return -ENXIO;
  245. #if 0
  246. return pci_module_init(&ich2rom_driver);
  247. #endif
  248. }
  249. static void __exit cleanup_ich2rom(void)
  250. {
  251. ich2rom_remove_one(mydev);
  252. }
  253. module_init(init_ich2rom);
  254. module_exit(cleanup_ich2rom);
  255. MODULE_LICENSE("GPL");
  256. MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
  257. MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge");