1 /* ######################################################################
3 Octagon 5066 MTD Driver.
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
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.
21 The driver tries to do a detection algorithm to guess what sort of devices
22 are plugged into the sockets.
24 ##################################################################### */
26 #include <linux/module.h>
27 #include <linux/ioport.h>
28 #include <linux/init.h>
31 #include <linux/mtd/map.h>
32 #include <linux/mtd/mtd.h>
34 #define WINDOW_START 0xe8000
35 #define WINDOW_LENGTH 0x8000
36 #define WINDOW_SHIFT 27
37 #define WINDOW_MASK 0x7FFF
40 static volatile char page_n_dev
= 0;
41 static unsigned long iomapadr
;
42 static DEFINE_SPINLOCK(oct5066_spin
);
45 * We use map_priv_1 to identify which device we are.
48 static void __oct5066_page(struct map_info
*map
, __u8 byte
)
54 static inline void oct5066_page(struct map_info
*map
, unsigned long ofs
)
56 __u8 byte
= map
->map_priv_1
| (ofs
>> WINDOW_SHIFT
);
58 if (page_n_dev
!= byte
)
59 __oct5066_page(map
, byte
);
63 static map_word
oct5066_read8(struct map_info
*map
, unsigned long ofs
)
66 spin_lock(&oct5066_spin
);
67 oct5066_page(map
, ofs
);
68 ret
.x
[0] = readb(iomapadr
+ (ofs
& WINDOW_MASK
));
69 spin_unlock(&oct5066_spin
);
73 static void oct5066_copy_from(struct map_info
*map
, void *to
, unsigned long from
, ssize_t len
)
76 unsigned long thislen
= len
;
77 if (len
> (WINDOW_LENGTH
- (from
& WINDOW_MASK
)))
78 thislen
= WINDOW_LENGTH
-(from
& WINDOW_MASK
);
80 spin_lock(&oct5066_spin
);
81 oct5066_page(map
, from
);
82 memcpy_fromio(to
, iomapadr
+ from
, thislen
);
83 spin_unlock(&oct5066_spin
);
90 static void oct5066_write8(struct map_info
*map
, map_word d
, unsigned long adr
)
92 spin_lock(&oct5066_spin
);
93 oct5066_page(map
, adr
);
94 writeb(d
.x
[0], iomapadr
+ (adr
& WINDOW_MASK
));
95 spin_unlock(&oct5066_spin
);
98 static void oct5066_copy_to(struct map_info
*map
, unsigned long to
, const void *from
, ssize_t len
)
101 unsigned long thislen
= len
;
102 if (len
> (WINDOW_LENGTH
- (to
& WINDOW_MASK
)))
103 thislen
= WINDOW_LENGTH
-(to
& WINDOW_MASK
);
105 spin_lock(&oct5066_spin
);
106 oct5066_page(map
, to
);
107 memcpy_toio(iomapadr
+ to
, from
, thislen
);
108 spin_unlock(&oct5066_spin
);
115 static struct map_info oct5066_map
[2] = {
117 .name
= "Octagon 5066 Socket",
121 .read
= oct5066_read8
,
122 .copy_from
= oct5066_copy_from
,
123 .write
= oct5066_write8
,
124 .copy_to
= oct5066_copy_to
,
128 .name
= "Octagon 5066 Internal Flash",
130 .size
= 2 * 1024 * 1024,
132 .read
= oct5066_read8
,
133 .copy_from
= oct5066_copy_from
,
134 .write
= oct5066_write8
,
135 .copy_to
= oct5066_copy_to
,
140 static struct mtd_info
*oct5066_mtd
[2] = {NULL
, NULL
};
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)
150 unsigned int Base
= (1 << 6);
152 unsigned long Values
[10];
153 for (I
= 0; I
!= 20; I
++)
155 outb(Base
+ (I
%10),PAGE_IO
);
158 // Record the value and check for uniqueness
159 Values
[I
%10] = readl(iomapadr
);
160 if (I
> 0 && Values
[I
%10] == Values
[0])
165 // Make sure we get the same values on the second pass
166 if (Values
[I
%10] != readl(iomapadr
))
173 void cleanup_oct5066(void)
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
]);
182 iounmap((void *)iomapadr
);
183 release_region(PAGE_IO
, 1);
186 static int __init
init_oct5066(void)
191 // Do an autoprobe sequence
192 if (!request_region(PAGE_IO
,1,"Octagon SSD")) {
193 printk(KERN_NOTICE
"5066: Page Register in Use\n");
196 iomapadr
= (unsigned long)ioremap(WINDOW_START
, WINDOW_LENGTH
);
198 printk(KERN_NOTICE
"Failed to ioremap memory region\n");
202 if (OctProbe() != 0) {
203 printk(KERN_NOTICE
"5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
204 iounmap((void *)iomapadr
);
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
);
213 for (i
=0; i
<2; i
++) {
214 oct5066_mtd
[i
] = do_map_probe("cfi_probe", &oct5066_map
[i
]);
216 oct5066_mtd
[i
] = do_map_probe("jedec", &oct5066_map
[i
]);
218 oct5066_mtd
[i
] = do_map_probe("map_ram", &oct5066_map
[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
]);
227 if (!oct5066_mtd
[0] && !oct5066_mtd
[1]) {
235 iounmap((void *)iomapadr
);
237 release_region(PAGE_IO
, 1);
241 module_init(init_oct5066
);
242 module_exit(cleanup_oct5066
);
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");