more debug output
[linux-2.4.git] / drivers / mtd / maps / octagon-5066.c
1 // $Id: octagon-5066.c,v 1.20 2003/01/07 17:21:55 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/slab.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(void)
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 void cleanup_oct5066(void)
217 {
218         int i;
219         for (i=0; i<2; i++) {
220                 if (oct5066_mtd[i]) {
221                         del_mtd_device(oct5066_mtd[i]);
222                         map_destroy(oct5066_mtd[i]);
223                 }
224         }
225         iounmap((void *)iomapadr);
226         release_region(PAGE_IO, 1);
227 }
228
229 int __init init_oct5066(void)
230 {
231         int i;
232         int ret = 0;
233
234         // Do an autoprobe sequence
235         if (!request_region(PAGE_IO,1,"Octagon SSD")) {
236                 printk(KERN_NOTICE "5066: Page Register in Use\n");
237                 return -EAGAIN;
238         }
239         iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
240         if (!iomapadr) {
241                 printk(KERN_NOTICE "Failed to ioremap memory region\n");
242                 ret = -EIO;
243                 goto out_rel;
244         }
245         if (OctProbe() != 0) {
246                 printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
247                 ret = -EAGAIN;
248                 goto out_unmap;
249         }
250         
251         // Print out our little header..
252         printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
253                WINDOW_START+WINDOW_LENGTH);
254         
255         for (i=0; i<2; i++) {
256                 oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
257                 if (!oct5066_mtd[i])
258                         oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
259                 if (!oct5066_mtd[i])
260                         oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
261                 if (!oct5066_mtd[i])
262                         oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
263                 if (oct5066_mtd[i]) {
264                         oct5066_mtd[i]->module = THIS_MODULE;
265                         add_mtd_device(oct5066_mtd[i]);
266                 }
267         }
268         
269         if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
270                 cleanup_oct5066();
271                 return -ENXIO;
272         }         
273
274         return 0;
275
276  out_unmap:
277         iounmap((void *)iomapadr);
278  out_rel:
279         release_region(PAGE_IO, 1);
280         return ret;
281 }
282
283 module_init(init_oct5066);
284 module_exit(cleanup_oct5066);
285
286 MODULE_LICENSE("GPL");
287 MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
288 MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");