1 // $Id: octagon-5066.c,v 1.20 2003/01/07 17:21:55 dwmw2 Exp $
2 /* ######################################################################
4 Octagon 5066 MTD Driver.
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
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.
22 The driver tries to do a detection algorithm to guess what sort of devices
23 are plugged into the sockets.
25 ##################################################################### */
27 #include <linux/module.h>
28 #include <linux/slab.h>
29 #include <linux/ioport.h>
30 #include <linux/init.h>
33 #include <linux/mtd/map.h>
35 #define WINDOW_START 0xe8000
36 #define WINDOW_LENGTH 0x8000
37 #define WINDOW_SHIFT 27
38 #define WINDOW_MASK 0x7FFF
41 static volatile char page_n_dev = 0;
42 static unsigned long iomapadr;
43 static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
46 * We use map_priv_1 to identify which device we are.
49 static void __oct5066_page(struct map_info *map, __u8 byte)
55 static inline void oct5066_page(struct map_info *map, unsigned long ofs)
57 __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
59 if (page_n_dev != byte)
60 __oct5066_page(map, byte);
64 static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
67 spin_lock(&oct5066_spin);
68 oct5066_page(map, ofs);
69 ret = readb(iomapadr + (ofs & WINDOW_MASK));
70 spin_unlock(&oct5066_spin);
74 static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
77 spin_lock(&oct5066_spin);
78 oct5066_page(map, ofs);
79 ret = readw(iomapadr + (ofs & WINDOW_MASK));
80 spin_unlock(&oct5066_spin);
84 static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
87 spin_lock(&oct5066_spin);
88 oct5066_page(map, ofs);
89 ret = readl(iomapadr + (ofs & WINDOW_MASK));
90 spin_unlock(&oct5066_spin);
94 static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
97 unsigned long thislen = len;
98 if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
99 thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
101 spin_lock(&oct5066_spin);
102 oct5066_page(map, from);
103 memcpy_fromio(to, iomapadr + from, thislen);
104 spin_unlock(&oct5066_spin);
111 static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
113 spin_lock(&oct5066_spin);
114 oct5066_page(map, adr);
115 writeb(d, iomapadr + (adr & WINDOW_MASK));
116 spin_unlock(&oct5066_spin);
119 static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
121 spin_lock(&oct5066_spin);
122 oct5066_page(map, adr);
123 writew(d, iomapadr + (adr & WINDOW_MASK));
124 spin_unlock(&oct5066_spin);
127 static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
129 spin_lock(&oct5066_spin);
130 oct5066_page(map, adr);
131 writel(d, iomapadr + (adr & WINDOW_MASK));
132 spin_unlock(&oct5066_spin);
135 static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
138 unsigned long thislen = len;
139 if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
140 thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
142 spin_lock(&oct5066_spin);
143 oct5066_page(map, to);
144 memcpy_toio(iomapadr + to, from, thislen);
145 spin_unlock(&oct5066_spin);
152 static struct map_info oct5066_map[2] = {
154 name: "Octagon 5066 Socket",
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,
168 name: "Octagon 5066 Internal Flash",
169 size: 2 * 1024 * 1024,
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,
183 static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
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)
193 unsigned int Base = (1 << 6);
195 unsigned long Values[10];
196 for (I = 0; I != 20; I++)
198 outb(Base + (I%10),PAGE_IO);
201 // Record the value and check for uniqueness
202 Values[I%10] = readl(iomapadr);
203 if (I > 0 && Values[I%10] == Values[0])
208 // Make sure we get the same values on the second pass
209 if (Values[I%10] != readl(iomapadr))
216 void cleanup_oct5066(void)
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]);
225 iounmap((void *)iomapadr);
226 release_region(PAGE_IO, 1);
229 int __init init_oct5066(void)
234 // Do an autoprobe sequence
235 if (!request_region(PAGE_IO,1,"Octagon SSD")) {
236 printk(KERN_NOTICE "5066: Page Register in Use\n");
239 iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
241 printk(KERN_NOTICE "Failed to ioremap memory region\n");
245 if (OctProbe() != 0) {
246 printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
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);
255 for (i=0; i<2; i++) {
256 oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
258 oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
260 oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[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]);
269 if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
277 iounmap((void *)iomapadr);
279 release_region(PAGE_IO, 1);
283 module_init(init_oct5066);
284 module_exit(cleanup_oct5066);
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");