1 | /* |
2 | * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip) |
3 | * |
4 | * (C) 2000 Nicolas Pitre <nico@fluxnic.net> |
5 | * |
6 | * This code is GPL |
7 | */ |
8 | #include <linux/module.h> |
9 | #include <linux/types.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/slab.h> |
14 | |
15 | #include <linux/mtd/mtd.h> |
16 | #include <linux/mtd/map.h> |
17 | #include <linux/mtd/partitions.h> |
18 | |
19 | #include <asm/io.h> |
20 | #include <asm/hardware/dec21285.h> |
21 | #include <asm/mach-types.h> |
22 | |
23 | |
24 | static struct mtd_info *dc21285_mtd; |
25 | |
26 | #ifdef CONFIG_ARCH_NETWINDER |
27 | /* |
28 | * This is really ugly, but it seams to be the only |
29 | * realiable way to do it, as the cpld state machine |
30 | * is unpredictible. So we have a 25us penalty per |
31 | * write access. |
32 | */ |
33 | static void nw_en_write(void) |
34 | { |
35 | unsigned long flags; |
36 | |
37 | /* |
38 | * we want to write a bit pattern XXX1 to Xilinx to enable |
39 | * the write gate, which will be open for about the next 2ms. |
40 | */ |
41 | raw_spin_lock_irqsave(&nw_gpio_lock, flags); |
42 | nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); |
43 | raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); |
44 | |
45 | /* |
46 | * let the ISA bus to catch on... |
47 | */ |
48 | udelay(25); |
49 | } |
50 | #else |
51 | #define nw_en_write() do { } while (0) |
52 | #endif |
53 | |
54 | static map_word dc21285_read8(struct map_info *map, unsigned long ofs) |
55 | { |
56 | map_word val; |
57 | val.x[0] = *(uint8_t*)(map->virt + ofs); |
58 | return val; |
59 | } |
60 | |
61 | static map_word dc21285_read16(struct map_info *map, unsigned long ofs) |
62 | { |
63 | map_word val; |
64 | val.x[0] = *(uint16_t*)(map->virt + ofs); |
65 | return val; |
66 | } |
67 | |
68 | static map_word dc21285_read32(struct map_info *map, unsigned long ofs) |
69 | { |
70 | map_word val; |
71 | val.x[0] = *(uint32_t*)(map->virt + ofs); |
72 | return val; |
73 | } |
74 | |
75 | static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
76 | { |
77 | memcpy(to, (void*)(map->virt + from), len); |
78 | } |
79 | |
80 | static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr) |
81 | { |
82 | if (machine_is_netwinder()) |
83 | nw_en_write(); |
84 | *CSR_ROMWRITEREG = adr & 3; |
85 | adr &= ~3; |
86 | *(uint8_t*)(map->virt + adr) = d.x[0]; |
87 | } |
88 | |
89 | static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr) |
90 | { |
91 | if (machine_is_netwinder()) |
92 | nw_en_write(); |
93 | *CSR_ROMWRITEREG = adr & 3; |
94 | adr &= ~3; |
95 | *(uint16_t*)(map->virt + adr) = d.x[0]; |
96 | } |
97 | |
98 | static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr) |
99 | { |
100 | if (machine_is_netwinder()) |
101 | nw_en_write(); |
102 | *(uint32_t*)(map->virt + adr) = d.x[0]; |
103 | } |
104 | |
105 | static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len) |
106 | { |
107 | while (len > 0) { |
108 | map_word d; |
109 | d.x[0] = *((uint32_t*)from); |
110 | dc21285_write32(map, d, adr: to); |
111 | from += 4; |
112 | to += 4; |
113 | len -= 4; |
114 | } |
115 | } |
116 | |
117 | static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len) |
118 | { |
119 | while (len > 0) { |
120 | map_word d; |
121 | d.x[0] = *((uint16_t*)from); |
122 | dc21285_write16(map, d, adr: to); |
123 | from += 2; |
124 | to += 2; |
125 | len -= 2; |
126 | } |
127 | } |
128 | |
129 | static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len) |
130 | { |
131 | map_word d; |
132 | d.x[0] = *((uint8_t*)from); |
133 | dc21285_write8(map, d, adr: to); |
134 | from++; |
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 | /* Partition stuff */ |
147 | static const char * const probes[] = { "RedBoot" , "cmdlinepart" , NULL }; |
148 | |
149 | static int __init init_dc21285(void) |
150 | { |
151 | /* Determine bankwidth */ |
152 | switch (*CSR_SA110_CNTL & (3<<14)) { |
153 | case SA110_CNTL_ROMWIDTH_8: |
154 | dc21285_map.bankwidth = 1; |
155 | dc21285_map.read = dc21285_read8; |
156 | dc21285_map.write = dc21285_write8; |
157 | dc21285_map.copy_to = dc21285_copy_to_8; |
158 | break; |
159 | case SA110_CNTL_ROMWIDTH_16: |
160 | dc21285_map.bankwidth = 2; |
161 | dc21285_map.read = dc21285_read16; |
162 | dc21285_map.write = dc21285_write16; |
163 | dc21285_map.copy_to = dc21285_copy_to_16; |
164 | break; |
165 | case SA110_CNTL_ROMWIDTH_32: |
166 | dc21285_map.bankwidth = 4; |
167 | dc21285_map.read = dc21285_read32; |
168 | dc21285_map.write = dc21285_write32; |
169 | dc21285_map.copy_to = dc21285_copy_to_32; |
170 | break; |
171 | default: |
172 | printk (KERN_ERR "DC21285 flash: undefined bankwidth\n" ); |
173 | return -ENXIO; |
174 | } |
175 | printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n" , |
176 | dc21285_map.bankwidth*8); |
177 | |
178 | /* Let's map the flash area */ |
179 | dc21285_map.virt = ioremap(offset: DC21285_FLASH, size: 16*1024*1024); |
180 | if (!dc21285_map.virt) { |
181 | printk("Failed to ioremap\n" ); |
182 | return -EIO; |
183 | } |
184 | |
185 | if (machine_is_ebsa285()) { |
186 | dc21285_mtd = do_map_probe(name: "cfi_probe" , map: &dc21285_map); |
187 | } else { |
188 | dc21285_mtd = do_map_probe(name: "jedec_probe" , map: &dc21285_map); |
189 | } |
190 | |
191 | if (!dc21285_mtd) { |
192 | iounmap(addr: dc21285_map.virt); |
193 | return -ENXIO; |
194 | } |
195 | |
196 | dc21285_mtd->owner = THIS_MODULE; |
197 | |
198 | mtd_device_parse_register(mtd: dc21285_mtd, part_probe_types: probes, NULL, NULL, defnr_parts: 0); |
199 | |
200 | if(machine_is_ebsa285()) { |
201 | /* |
202 | * Flash timing is determined with bits 19-16 of the |
203 | * CSR_SA110_CNTL. The value is the number of wait cycles, or |
204 | * 0 for 16 cycles (the default). Cycles are 20 ns. |
205 | * Here we use 7 for 140 ns flash chips. |
206 | */ |
207 | /* access time */ |
208 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); |
209 | /* burst time */ |
210 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); |
211 | /* tristate time */ |
212 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); |
213 | } |
214 | |
215 | return 0; |
216 | } |
217 | |
218 | static void __exit cleanup_dc21285(void) |
219 | { |
220 | mtd_device_unregister(master: dc21285_mtd); |
221 | map_destroy(mtd: dc21285_mtd); |
222 | iounmap(addr: dc21285_map.virt); |
223 | } |
224 | |
225 | module_init(init_dc21285); |
226 | module_exit(cleanup_dc21285); |
227 | |
228 | |
229 | MODULE_LICENSE("GPL" ); |
230 | MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>" ); |
231 | MODULE_DESCRIPTION("MTD map driver for DC21285 boards" ); |
232 | |