]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/mtd/maps/octagon-5066.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[net-next-2.6.git] / drivers / mtd / maps / octagon-5066.c
CommitLineData
1da177e4
LT
1/* ######################################################################
2
69f34c98
TG
3 Octagon 5066 MTD Driver.
4
1da177e4
LT
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
69f34c98 8 into a 32k memory window at 0xe8000. The control register for the
1da177e4
LT
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
69f34c98 16
1da177e4 17 On each SSD, the first 128k is reserved for use by the bios
69f34c98 18 (actually it IS the bios..) This only matters if you are booting off the
1da177e4 19 flash, you must not put a file system starting there.
69f34c98 20
1da177e4
LT
21 The driver tries to do a detection algorithm to guess what sort of devices
22 are plugged into the sockets.
69f34c98 23
1da177e4
LT
24 ##################################################################### */
25
26#include <linux/module.h>
1da177e4
LT
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
40static volatile char page_n_dev = 0;
41static unsigned long iomapadr;
42static DEFINE_SPINLOCK(oct5066_spin);
43
44/*
45 * We use map_priv_1 to identify which device we are.
46 */
47
48static void __oct5066_page(struct map_info *map, __u8 byte)
49{
50 outb(byte,PAGE_IO);
51 page_n_dev = byte;
52}
53
54static inline void oct5066_page(struct map_info *map, unsigned long ofs)
55{
56 __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
69f34c98 57
1da177e4
LT
58 if (page_n_dev != byte)
59 __oct5066_page(map, byte);
60}
61
62
63static 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
73static 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);
69f34c98 79
1da177e4
LT
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
90static 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
98static 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);
69f34c98 104
1da177e4
LT
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
115static 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
140static 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
69f34c98 145 change pages while monitoring the window. A change in the window,
1da177e4
LT
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. */
148static 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;
69f34c98 162 }
1da177e4
LT
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;
69f34c98 168 }
1da177e4
LT
169 }
170 return 0;
171}
172
173void 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
d849257c 186static int __init init_oct5066(void)
1da177e4
LT
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 }
69f34c98 208
1da177e4
LT
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);
69f34c98 212
1da177e4
LT
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 }
69f34c98 226
1da177e4
LT
227 if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
228 cleanup_oct5066();
229 return -ENXIO;
69f34c98 230 }
1da177e4
LT
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
241module_init(init_oct5066);
242module_exit(cleanup_oct5066);
243
244MODULE_LICENSE("GPL");
245MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
246MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");