~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/mtd/octagon-5066.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.