diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/mtd/maps/dc21285.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/mtd/maps/dc21285.c')
-rw-r--r-- | drivers/mtd/maps/dc21285.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c new file mode 100644 index 000000000000..938c41f2f056 --- /dev/null +++ b/drivers/mtd/maps/dc21285.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip) | ||
3 | * | ||
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | ||
5 | * | ||
6 | * This code is GPL | ||
7 | * | ||
8 | * $Id: dc21285.c,v 1.22 2004/11/01 13:39:21 rmk Exp $ | ||
9 | */ | ||
10 | #include <linux/config.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/delay.h> | ||
16 | |||
17 | #include <linux/mtd/mtd.h> | ||
18 | #include <linux/mtd/map.h> | ||
19 | #include <linux/mtd/partitions.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include <asm/hardware/dec21285.h> | ||
23 | #include <asm/mach-types.h> | ||
24 | |||
25 | |||
26 | static struct mtd_info *dc21285_mtd; | ||
27 | |||
28 | #ifdef CONFIG_ARCH_NETWINDER | ||
29 | /* | ||
30 | * This is really ugly, but it seams to be the only | ||
31 | * realiable way to do it, as the cpld state machine | ||
32 | * is unpredictible. So we have a 25us penalty per | ||
33 | * write access. | ||
34 | */ | ||
35 | static void nw_en_write(void) | ||
36 | { | ||
37 | extern spinlock_t gpio_lock; | ||
38 | unsigned long flags; | ||
39 | |||
40 | /* | ||
41 | * we want to write a bit pattern XXX1 to Xilinx to enable | ||
42 | * the write gate, which will be open for about the next 2ms. | ||
43 | */ | ||
44 | spin_lock_irqsave(&gpio_lock, flags); | ||
45 | cpld_modify(1, 1); | ||
46 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
47 | |||
48 | /* | ||
49 | * let the ISA bus to catch on... | ||
50 | */ | ||
51 | udelay(25); | ||
52 | } | ||
53 | #else | ||
54 | #define nw_en_write() do { } while (0) | ||
55 | #endif | ||
56 | |||
57 | static map_word dc21285_read8(struct map_info *map, unsigned long ofs) | ||
58 | { | ||
59 | map_word val; | ||
60 | val.x[0] = *(uint8_t*)(map->virt + ofs); | ||
61 | return val; | ||
62 | } | ||
63 | |||
64 | static map_word dc21285_read16(struct map_info *map, unsigned long ofs) | ||
65 | { | ||
66 | map_word val; | ||
67 | val.x[0] = *(uint16_t*)(map->virt + ofs); | ||
68 | return val; | ||
69 | } | ||
70 | |||
71 | static map_word dc21285_read32(struct map_info *map, unsigned long ofs) | ||
72 | { | ||
73 | map_word val; | ||
74 | val.x[0] = *(uint32_t*)(map->virt + ofs); | ||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) | ||
79 | { | ||
80 | memcpy(to, (void*)(map->virt + from), len); | ||
81 | } | ||
82 | |||
83 | static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr) | ||
84 | { | ||
85 | if (machine_is_netwinder()) | ||
86 | nw_en_write(); | ||
87 | *CSR_ROMWRITEREG = adr & 3; | ||
88 | adr &= ~3; | ||
89 | *(uint8_t*)(map->virt + adr) = d.x[0]; | ||
90 | } | ||
91 | |||
92 | static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr) | ||
93 | { | ||
94 | if (machine_is_netwinder()) | ||
95 | nw_en_write(); | ||
96 | *CSR_ROMWRITEREG = adr & 3; | ||
97 | adr &= ~3; | ||
98 | *(uint16_t*)(map->virt + adr) = d.x[0]; | ||
99 | } | ||
100 | |||
101 | static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr) | ||
102 | { | ||
103 | if (machine_is_netwinder()) | ||
104 | nw_en_write(); | ||
105 | *(uint32_t*)(map->virt + adr) = d.x[0]; | ||
106 | } | ||
107 | |||
108 | static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len) | ||
109 | { | ||
110 | while (len > 0) { | ||
111 | map_word d; | ||
112 | d.x[0] = *((uint32_t*)from)++; | ||
113 | dc21285_write32(map, d, to); | ||
114 | to += 4; | ||
115 | len -= 4; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len) | ||
120 | { | ||
121 | while (len > 0) { | ||
122 | map_word d; | ||
123 | d.x[0] = *((uint16_t*)from)++; | ||
124 | dc21285_write16(map, d, to); | ||
125 | to += 2; | ||
126 | len -= 2; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len) | ||
131 | { | ||
132 | map_word d; | ||
133 | d.x[0] = *((uint8_t*)from)++; | ||
134 | dc21285_write8(map, d, to); | ||
135 | to++; | ||
136 | len--; | ||
137 | } | ||
138 | |||
139 | static struct map_info dc21285_map = { | ||
140 | .name = "DC21285 flash", | ||
141 | .phys = NO_XIP, | ||
142 | .size = 16*1024*1024, | ||
143 | .copy_from = dc21285_copy_from, | ||
144 | }; | ||
145 | |||
146 | |||
147 | /* Partition stuff */ | ||
148 | #ifdef CONFIG_MTD_PARTITIONS | ||
149 | static struct mtd_partition *dc21285_parts; | ||
150 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; | ||
151 | #endif | ||
152 | |||
153 | static int __init init_dc21285(void) | ||
154 | { | ||
155 | |||
156 | #ifdef CONFIG_MTD_PARTITIONS | ||
157 | int nrparts; | ||
158 | #endif | ||
159 | |||
160 | /* Determine bankwidth */ | ||
161 | switch (*CSR_SA110_CNTL & (3<<14)) { | ||
162 | case SA110_CNTL_ROMWIDTH_8: | ||
163 | dc21285_map.bankwidth = 1; | ||
164 | dc21285_map.read = dc21285_read8; | ||
165 | dc21285_map.write = dc21285_write8; | ||
166 | dc21285_map.copy_to = dc21285_copy_to_8; | ||
167 | break; | ||
168 | case SA110_CNTL_ROMWIDTH_16: | ||
169 | dc21285_map.bankwidth = 2; | ||
170 | dc21285_map.read = dc21285_read16; | ||
171 | dc21285_map.write = dc21285_write16; | ||
172 | dc21285_map.copy_to = dc21285_copy_to_16; | ||
173 | break; | ||
174 | case SA110_CNTL_ROMWIDTH_32: | ||
175 | dc21285_map.bankwidth = 4; | ||
176 | dc21285_map.read = dc21285_read32; | ||
177 | dc21285_map.write = dc21285_write32; | ||
178 | dc21285_map.copy_to = dc21285_copy_to_32; | ||
179 | break; | ||
180 | default: | ||
181 | printk (KERN_ERR "DC21285 flash: undefined bankwidth\n"); | ||
182 | return -ENXIO; | ||
183 | } | ||
184 | printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n", | ||
185 | dc21285_map.bankwidth*8); | ||
186 | |||
187 | /* Let's map the flash area */ | ||
188 | dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024); | ||
189 | if (!dc21285_map.virt) { | ||
190 | printk("Failed to ioremap\n"); | ||
191 | return -EIO; | ||
192 | } | ||
193 | |||
194 | if (machine_is_ebsa285()) { | ||
195 | dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map); | ||
196 | } else { | ||
197 | dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map); | ||
198 | } | ||
199 | |||
200 | if (!dc21285_mtd) { | ||
201 | iounmap(dc21285_map.virt); | ||
202 | return -ENXIO; | ||
203 | } | ||
204 | |||
205 | dc21285_mtd->owner = THIS_MODULE; | ||
206 | |||
207 | #ifdef CONFIG_MTD_PARTITIONS | ||
208 | nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); | ||
209 | if (nrparts > 0) | ||
210 | add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts); | ||
211 | else | ||
212 | #endif | ||
213 | add_mtd_device(dc21285_mtd); | ||
214 | |||
215 | if(machine_is_ebsa285()) { | ||
216 | /* | ||
217 | * Flash timing is determined with bits 19-16 of the | ||
218 | * CSR_SA110_CNTL. The value is the number of wait cycles, or | ||
219 | * 0 for 16 cycles (the default). Cycles are 20 ns. | ||
220 | * Here we use 7 for 140 ns flash chips. | ||
221 | */ | ||
222 | /* access time */ | ||
223 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); | ||
224 | /* burst time */ | ||
225 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); | ||
226 | /* tristate time */ | ||
227 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void __exit cleanup_dc21285(void) | ||
234 | { | ||
235 | #ifdef CONFIG_MTD_PARTITIONS | ||
236 | if (dc21285_parts) { | ||
237 | del_mtd_partitions(dc21285_mtd); | ||
238 | kfree(dc21285_parts); | ||
239 | } else | ||
240 | #endif | ||
241 | del_mtd_device(dc21285_mtd); | ||
242 | |||
243 | map_destroy(dc21285_mtd); | ||
244 | iounmap(dc21285_map.virt); | ||
245 | } | ||
246 | |||
247 | module_init(init_dc21285); | ||
248 | module_exit(cleanup_dc21285); | ||
249 | |||
250 | |||
251 | MODULE_LICENSE("GPL"); | ||
252 | MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); | ||
253 | MODULE_DESCRIPTION("MTD map driver for DC21285 boards"); | ||