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

嵌入式Linux

开发平台:

Unix_Linux

  1. // $Id: octagon-5066.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $
  2. /* ######################################################################
  3.    Octagon 5066 MTD Driver. 
  4.   
  5.    The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
  6.    comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
  7.    is replacable by flash. Both units are mapped through a multiplexer
  8.    into a 32k memory window at 0xe8000. The control register for the 
  9.    multiplexing unit is located at IO 0x208 with a bit map of
  10.      0-5 Page Selection in 32k increments
  11.      6-7 Device selection:
  12.         00 SSD off
  13.         01 SSD 0 (Socket)
  14.         10 SSD 1 (Flash chip)
  15.         11 undefined
  16.   
  17.    On each SSD, the first 128k is reserved for use by the bios
  18.    (actually it IS the bios..) This only matters if you are booting off the 
  19.    flash, you must not put a file system starting there.
  20.    
  21.    The driver tries to do a detection algorithm to guess what sort of devices
  22.    are plugged into the sockets.
  23.    
  24.    ##################################################################### */
  25. #include <linux/module.h>
  26. #include <linux/slab.h>
  27. #include <linux/ioport.h>
  28. #include <linux/init.h>
  29. #include <asm/io.h>
  30. #include <linux/mtd/map.h>
  31. #define WINDOW_START 0xe8000
  32. #define WINDOW_LENGTH 0x8000
  33. #define WINDOW_SHIFT 27
  34. #define WINDOW_MASK 0x7FFF
  35. #define PAGE_IO 0x208
  36. static volatile char page_n_dev = 0;
  37. static unsigned long iomapadr;
  38. static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
  39. /*
  40.  * We use map_priv_1 to identify which device we are.
  41.  */
  42. static void __oct5066_page(struct map_info *map, __u8 byte)
  43. {
  44. outb(byte,PAGE_IO);
  45. page_n_dev = byte;
  46. }
  47. static inline void oct5066_page(struct map_info *map, unsigned long ofs)
  48. {
  49. __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
  50. if (page_n_dev != byte)
  51. __oct5066_page(map, byte);
  52. }
  53. static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
  54. {
  55. __u8 ret;
  56. spin_lock(&oct5066_spin);
  57. oct5066_page(map, ofs);
  58. ret = readb(iomapadr + (ofs & WINDOW_MASK));
  59. spin_unlock(&oct5066_spin);
  60. return ret;
  61. }
  62. static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
  63. {
  64. __u16 ret;
  65. spin_lock(&oct5066_spin);
  66. oct5066_page(map, ofs);
  67. ret = readw(iomapadr + (ofs & WINDOW_MASK));
  68. spin_unlock(&oct5066_spin);
  69. return ret;
  70. }
  71. static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
  72. {
  73. __u32 ret;
  74. spin_lock(&oct5066_spin);
  75. oct5066_page(map, ofs);
  76. ret = readl(iomapadr + (ofs & WINDOW_MASK));
  77. spin_unlock(&oct5066_spin);
  78. return ret;
  79. }
  80. static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
  81. {
  82. while(len) {
  83. unsigned long thislen = len;
  84. if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
  85. thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
  86. spin_lock(&oct5066_spin);
  87. oct5066_page(map, from);
  88. memcpy_fromio(to, iomapadr + from, thislen);
  89. spin_unlock(&oct5066_spin);
  90. to += thislen;
  91. from += thislen;
  92. len -= thislen;
  93. }
  94. }
  95. static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
  96. {
  97. spin_lock(&oct5066_spin);
  98. oct5066_page(map, adr);
  99. writeb(d, iomapadr + (adr & WINDOW_MASK));
  100. spin_unlock(&oct5066_spin);
  101. }
  102. static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
  103. {
  104. spin_lock(&oct5066_spin);
  105. oct5066_page(map, adr);
  106. writew(d, iomapadr + (adr & WINDOW_MASK));
  107. spin_unlock(&oct5066_spin);
  108. }
  109. static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
  110. {
  111. spin_lock(&oct5066_spin);
  112. oct5066_page(map, adr);
  113. writel(d, iomapadr + (adr & WINDOW_MASK));
  114. spin_unlock(&oct5066_spin);
  115. }
  116. static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
  117. {
  118. while(len) {
  119. unsigned long thislen = len;
  120. if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
  121. thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
  122. spin_lock(&oct5066_spin);
  123. oct5066_page(map, to);
  124. memcpy_toio(iomapadr + to, from, thislen);
  125. spin_unlock(&oct5066_spin);
  126. to += thislen;
  127. from += thislen;
  128. len -= thislen;
  129. }
  130. }
  131. static struct map_info oct5066_map[2] = {
  132. {
  133. name: "Octagon 5066 Socket",
  134. size: 512 * 1024,
  135. buswidth: 1,
  136. read8: oct5066_read8,
  137. read16: oct5066_read16,
  138. read32: oct5066_read32,
  139. copy_from: oct5066_copy_from,
  140. write8: oct5066_write8,
  141. write16: oct5066_write16,
  142. write32: oct5066_write32,
  143. copy_to: oct5066_copy_to,
  144. map_priv_1: 1<<6
  145. },
  146. {
  147. name: "Octagon 5066 Internal Flash",
  148. size: 2 * 1024 * 1024,
  149. buswidth: 1,
  150. read8: oct5066_read8,
  151. read16: oct5066_read16,
  152. read32: oct5066_read32,
  153. copy_from: oct5066_copy_from,
  154. write8: oct5066_write8,
  155. write16: oct5066_write16,
  156. write32: oct5066_write32,
  157. copy_to: oct5066_copy_to,
  158. map_priv_1: 2<<6
  159. }
  160. };
  161. static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
  162. // OctProbe - Sense if this is an octagon card
  163. // ---------------------------------------------------------------------
  164. /* Perform a simple validity test, we map the window select SSD0 and
  165.    change pages while monitoring the window. A change in the window, 
  166.    controlled by the PAGE_IO port is a functioning 5066 board. This will
  167.    fail if the thing in the socket is set to a uniform value. */
  168. static int __init OctProbe(void)
  169. {
  170.    unsigned int Base = (1 << 6);
  171.    unsigned long I;
  172.    unsigned long Values[10];
  173.    for (I = 0; I != 20; I++)
  174.    {
  175.       outb(Base + (I%10),PAGE_IO);
  176.       if (I < 10)
  177.       {
  178.  // Record the value and check for uniqueness
  179.  Values[I%10] = readl(iomapadr);
  180.  if (I > 0 && Values[I%10] == Values[0])
  181.     return -EAGAIN;
  182.       }      
  183.       else
  184.       {
  185.  // Make sure we get the same values on the second pass
  186.  if (Values[I%10] != readl(iomapadr))
  187.     return -EAGAIN;
  188.       }      
  189.    }
  190.    return 0;
  191. }
  192. void cleanup_oct5066(void)
  193. {
  194. int i;
  195. for (i=0; i<2; i++) {
  196. if (oct5066_mtd[i]) {
  197. del_mtd_device(oct5066_mtd[i]);
  198. map_destroy(oct5066_mtd[i]);
  199. }
  200. }
  201. iounmap((void *)iomapadr);
  202. release_region(PAGE_IO,1);
  203. }
  204. int __init init_oct5066(void)
  205. {
  206. int i;
  207. // Do an autoprobe sequence
  208. if (check_region(PAGE_IO,1) != 0)
  209. {
  210. printk("5066: Page Register in Usen");
  211. return -EAGAIN;
  212. }
  213. iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
  214. if (!iomapadr) {
  215. printk("Failed to ioremap memory regionn");
  216. return -EIO;
  217. }
  218. if (OctProbe() != 0)
  219. {
  220. printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?n");
  221. iounmap((void *)iomapadr);
  222. return -EAGAIN;
  223. }
  224. request_region(PAGE_IO,1,"Octagon SSD");
  225. // Print out our little header..
  226. printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%xn",PAGE_IO,WINDOW_START,
  227.        WINDOW_START+WINDOW_LENGTH);
  228. for (i=0; i<2; i++) {
  229. oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
  230. if (!oct5066_mtd[i])
  231. oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
  232. if (!oct5066_mtd[i])
  233. oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
  234. if (!oct5066_mtd[i])
  235. oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
  236. if (oct5066_mtd[i]) {
  237. oct5066_mtd[i]->module = THIS_MODULE;
  238. add_mtd_device(oct5066_mtd[i]);
  239. }
  240. }
  241. if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
  242. cleanup_oct5066();
  243. return -ENXIO;
  244. }   
  245. return 0;
  246. }
  247. module_init(init_oct5066);
  248. module_exit(cleanup_oct5066);
  249. MODULE_LICENSE("GPL");
  250. MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
  251. MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");