1 // $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 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>
34 #include <linux/mtd/mtd.h>
36 #define WINDOW_START 0xe8000
37 #define WINDOW_LENGTH 0x8000
38 #define WINDOW_SHIFT 27
39 #define WINDOW_MASK 0x7FFF
42 static volatile char page_n_dev = 0;
43 static unsigned long iomapadr;
44 static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
47 * We use map_priv_1 to identify which device we are.
50 static void __oct5066_page(struct map_info *map, __u8 byte)
56 static inline void oct5066_page(struct map_info *map, unsigned long ofs)
58 __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
60 if (page_n_dev != byte)
61 __oct5066_page(map, byte);
65 static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
68 spin_lock(&oct5066_spin);
69 oct5066_page(map, ofs);
70 ret = readb(iomapadr + (ofs & WINDOW_MASK));
71 spin_unlock(&oct5066_spin);
75 static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
78 spin_lock(&oct5066_spin);
79 oct5066_page(map, ofs);
80 ret = readw(iomapadr + (ofs & WINDOW_MASK));
81 spin_unlock(&oct5066_spin);
85 static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
88 spin_lock(&oct5066_spin);
89 oct5066_page(map, ofs);
90 ret = readl(iomapadr + (ofs & WINDOW_MASK));
91 spin_unlock(&oct5066_spin);
95 static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
98 unsigned long thislen = len;
99 if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
100 thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
102 spin_lock(&oct5066_spin);
103 oct5066_page(map, from);
104 memcpy_fromio(to, iomapadr + from, thislen);
105 spin_unlock(&oct5066_spin);
112 static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
114 spin_lock(&oct5066_spin);
115 oct5066_page(map, adr);
116 writeb(d, iomapadr + (adr & WINDOW_MASK));
117 spin_unlock(&oct5066_spin);
120 static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
122 spin_lock(&oct5066_spin);
123 oct5066_page(map, adr);
124 writew(d, iomapadr + (adr & WINDOW_MASK));
125 spin_unlock(&oct5066_spin);
128 static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
130 spin_lock(&oct5066_spin);
131 oct5066_page(map, adr);
132 writel(d, iomapadr + (adr & WINDOW_MASK));
133 spin_unlock(&oct5066_spin);
136 static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
139 unsigned long thislen = len;
140 if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
141 thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
143 spin_lock(&oct5066_spin);
144 oct5066_page(map, to);
145 memcpy_toio(iomapadr + to, from, thislen);
146 spin_unlock(&oct5066_spin);
153 static struct map_info oct5066_map[2] = {
155 .name = "Octagon 5066 Socket",
159 .read8 = oct5066_read8,
160 .read16 = oct5066_read16,
161 .read32 = oct5066_read32,
162 .copy_from = oct5066_copy_from,
163 .write8 = oct5066_write8,
164 .write16 = oct5066_write16,
165 .write32 = oct5066_write32,
166 .copy_to = oct5066_copy_to,
170 .name = "Octagon 5066 Internal Flash",
172 .size = 2 * 1024 * 1024,
174 .read8 = oct5066_read8,
175 .read16 = oct5066_read16,
176 .read32 = oct5066_read32,
177 .copy_from = oct5066_copy_from,
178 .write8 = oct5066_write8,
179 .write16 = oct5066_write16,
180 .write32 = oct5066_write32,
181 .copy_to = oct5066_copy_to,
186 static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
188 // OctProbe - Sense if this is an octagon card
189 // ---------------------------------------------------------------------
190 /* Perform a simple validity test, we map the window select SSD0 and
191 change pages while monitoring the window. A change in the window,
192 controlled by the PAGE_IO port is a functioning 5066 board. This will
193 fail if the thing in the socket is set to a uniform value. */
194 static int __init OctProbe(void)
196 unsigned int Base = (1 << 6);
198 unsigned long Values[10];
199 for (I = 0; I != 20; I++)
201 outb(Base + (I%10),PAGE_IO);
204 // Record the value and check for uniqueness
205 Values[I%10] = readl(iomapadr);
206 if (I > 0 && Values[I%10] == Values[0])
211 // Make sure we get the same values on the second pass
212 if (Values[I%10] != readl(iomapadr))
219 void cleanup_oct5066(void)
222 for (i=0; i<2; i++) {
223 if (oct5066_mtd[i]) {
224 del_mtd_device(oct5066_mtd[i]);
225 map_destroy(oct5066_mtd[i]);
228 iounmap((void *)iomapadr);
229 release_region(PAGE_IO, 1);
232 int __init init_oct5066(void)
237 // Do an autoprobe sequence
238 if (!request_region(PAGE_IO,1,"Octagon SSD")) {
239 printk(KERN_NOTICE "5066: Page Register in Use\n");
242 iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
244 printk(KERN_NOTICE "Failed to ioremap memory region\n");
248 if (OctProbe() != 0) {
249 printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
250 iounmap((void *)iomapadr);
255 // Print out our little header..
256 printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
257 WINDOW_START+WINDOW_LENGTH);
259 for (i=0; i<2; i++) {
260 oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
262 oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
264 oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
266 oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
267 if (oct5066_mtd[i]) {
268 oct5066_mtd[i]->owner = THIS_MODULE;
269 add_mtd_device(oct5066_mtd[i]);
273 if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
281 iounmap((void *)iomapadr);
283 release_region(PAGE_IO, 1);
287 module_init(init_oct5066);
288 module_exit(cleanup_oct5066);
290 MODULE_LICENSE("GPL");
291 MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
292 MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");