]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/mtd/maps/octagon-5066.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mv-sheeva.git] / drivers / mtd / maps / octagon-5066.c
1 /* ######################################################################
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
26 #include <linux/module.h>
27 #include <linux/ioport.h>
28 #include <linux/init.h>
29 #include <asm/io.h>
30
31 #include <linux/mtd/map.h>
32 #include <linux/mtd/mtd.h>
33
34 #define WINDOW_START 0xe8000
35 #define WINDOW_LENGTH 0x8000
36 #define WINDOW_SHIFT 27
37 #define WINDOW_MASK 0x7FFF
38 #define PAGE_IO 0x208
39
40 static volatile char page_n_dev = 0;
41 static unsigned long iomapadr;
42 static DEFINE_SPINLOCK(oct5066_spin);
43
44 /*
45  * We use map_priv_1 to identify which device we are.
46  */
47
48 static void __oct5066_page(struct map_info *map, __u8 byte)
49 {
50         outb(byte,PAGE_IO);
51         page_n_dev = byte;
52 }
53
54 static inline void oct5066_page(struct map_info *map, unsigned long ofs)
55 {
56         __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
57
58         if (page_n_dev != byte)
59                 __oct5066_page(map, byte);
60 }
61
62
63 static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
64 {
65         map_word ret;
66         spin_lock(&oct5066_spin);
67         oct5066_page(map, ofs);
68         ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
69         spin_unlock(&oct5066_spin);
70         return ret;
71 }
72
73 static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
74 {
75         while(len) {
76                 unsigned long thislen = len;
77                 if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
78                         thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
79
80                 spin_lock(&oct5066_spin);
81                 oct5066_page(map, from);
82                 memcpy_fromio(to, iomapadr + from, thislen);
83                 spin_unlock(&oct5066_spin);
84                 to += thislen;
85                 from += thislen;
86                 len -= thislen;
87         }
88 }
89
90 static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
91 {
92         spin_lock(&oct5066_spin);
93         oct5066_page(map, adr);
94         writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
95         spin_unlock(&oct5066_spin);
96 }
97
98 static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
99 {
100         while(len) {
101                 unsigned long thislen = len;
102                 if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
103                         thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
104
105                 spin_lock(&oct5066_spin);
106                 oct5066_page(map, to);
107                 memcpy_toio(iomapadr + to, from, thislen);
108                 spin_unlock(&oct5066_spin);
109                 to += thislen;
110                 from += thislen;
111                 len -= thislen;
112         }
113 }
114
115 static struct map_info oct5066_map[2] = {
116         {
117                 .name = "Octagon 5066 Socket",
118                 .phys = NO_XIP,
119                 .size = 512 * 1024,
120                 .bankwidth = 1,
121                 .read = oct5066_read8,
122                 .copy_from = oct5066_copy_from,
123                 .write = oct5066_write8,
124                 .copy_to = oct5066_copy_to,
125                 .map_priv_1 = 1<<6
126         },
127         {
128                 .name = "Octagon 5066 Internal Flash",
129                 .phys = NO_XIP,
130                 .size = 2 * 1024 * 1024,
131                 .bankwidth = 1,
132                 .read = oct5066_read8,
133                 .copy_from = oct5066_copy_from,
134                 .write = oct5066_write8,
135                 .copy_to = oct5066_copy_to,
136                 .map_priv_1 = 2<<6
137         }
138 };
139
140 static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
141
142 // OctProbe - Sense if this is an octagon card
143 // ---------------------------------------------------------------------
144 /* Perform a simple validity test, we map the window select SSD0 and
145    change pages while monitoring the window. A change in the window,
146    controlled by the PAGE_IO port is a functioning 5066 board. This will
147    fail if the thing in the socket is set to a uniform value. */
148 static int __init OctProbe(void)
149 {
150    unsigned int Base = (1 << 6);
151    unsigned long I;
152    unsigned long Values[10];
153    for (I = 0; I != 20; I++)
154    {
155       outb(Base + (I%10),PAGE_IO);
156       if (I < 10)
157       {
158          // Record the value and check for uniqueness
159          Values[I%10] = readl(iomapadr);
160          if (I > 0 && Values[I%10] == Values[0])
161             return -EAGAIN;
162       }
163       else
164       {
165          // Make sure we get the same values on the second pass
166          if (Values[I%10] != readl(iomapadr))
167             return -EAGAIN;
168       }
169    }
170    return 0;
171 }
172
173 void cleanup_oct5066(void)
174 {
175         int i;
176         for (i=0; i<2; i++) {
177                 if (oct5066_mtd[i]) {
178                         del_mtd_device(oct5066_mtd[i]);
179                         map_destroy(oct5066_mtd[i]);
180                 }
181         }
182         iounmap((void *)iomapadr);
183         release_region(PAGE_IO, 1);
184 }
185
186 static int __init init_oct5066(void)
187 {
188         int i;
189         int ret = 0;
190
191         // Do an autoprobe sequence
192         if (!request_region(PAGE_IO,1,"Octagon SSD")) {
193                 printk(KERN_NOTICE "5066: Page Register in Use\n");
194                 return -EAGAIN;
195         }
196         iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
197         if (!iomapadr) {
198                 printk(KERN_NOTICE "Failed to ioremap memory region\n");
199                 ret = -EIO;
200                 goto out_rel;
201         }
202         if (OctProbe() != 0) {
203                 printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
204                 iounmap((void *)iomapadr);
205                 ret = -EAGAIN;
206                 goto out_unmap;
207         }
208
209         // Print out our little header..
210         printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
211                WINDOW_START+WINDOW_LENGTH);
212
213         for (i=0; i<2; i++) {
214                 oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
215                 if (!oct5066_mtd[i])
216                         oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
217                 if (!oct5066_mtd[i])
218                         oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
219                 if (!oct5066_mtd[i])
220                         oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
221                 if (oct5066_mtd[i]) {
222                         oct5066_mtd[i]->owner = THIS_MODULE;
223                         add_mtd_device(oct5066_mtd[i]);
224                 }
225         }
226
227         if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
228                 cleanup_oct5066();
229                 return -ENXIO;
230         }
231
232         return 0;
233
234  out_unmap:
235         iounmap((void *)iomapadr);
236  out_rel:
237         release_region(PAGE_IO, 1);
238         return ret;
239 }
240
241 module_init(init_oct5066);
242 module_exit(cleanup_oct5066);
243
244 MODULE_LICENSE("GPL");
245 MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
246 MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");