VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / mtd / maps / dc21285.c
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.20 2004/07/12 22:38:29 dwmw2 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         extern spinlock_t gpio_lock;
37         unsigned long flags;
38
39         /*
40          * we want to write a bit pattern XXX1 to Xilinx to enable
41          * the write gate, which will be open for about the next 2ms.
42          */
43         spin_lock_irqsave(&gpio_lock, flags);
44         cpld_modify(1, 1);
45         spin_unlock_irqrestore(&gpio_lock, flags);
46
47         /*
48          * let the ISA bus to catch on...
49          */
50         udelay(25);
51 }
52 #else
53 #define nw_en_write() do { } while (0)
54 #endif
55
56 static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
57 {
58         return *(uint8_t*)(map->map_priv_1 + ofs);
59 }
60
61 static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
62 {
63         return *(uint16_t*)(map->map_priv_1 + ofs);
64 }
65
66 static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
67 {
68         return *(uint32_t*)(map->map_priv_1 + ofs);
69 }
70
71 static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
72 {
73         memcpy(to, (void*)(map->map_priv_1 + from), len);
74 }
75
76 static void dc21285_write(struct map_info *map, map_word d, unsigned long adr)
77 {
78         if (machine_is_netwinder())
79                 nw_en_write();
80         *CSR_ROMWRITEREG = adr & 3;
81         adr &= ~3;
82         *(uint8_t*)(map->map_priv_1 + adr) = d.x[0];
83 }
84
85 static void dc21285_write16(struct map_info *map, map_word d, unsigned long adr)
86 {
87         if (machine_is_netwinder())
88                 nw_en_write();
89         *CSR_ROMWRITEREG = adr & 3;
90         adr &= ~3;
91         *(uint16_t*)(map->map_priv_1 + adr) = d.x[0];
92 }
93
94 static void dc21285_write32(struct map_info *map, map_word d, unsigned long adr)
95 {
96         if (machine_is_netwinder())
97                 nw_en_write();
98         *(uint32_t*)(map->map_priv_1 + adr) = d.x[0];
99 }
100
101 static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
102 {
103         while (len > 0) {
104                 uint32_t d = *((uint32_t*)from)++;
105                 dc21285_write32(map, d, to);
106                 to += 4;
107                 len -= 4;
108         }
109 }
110
111 static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
112 {
113         while (len > 0) {
114                 uint16_t d = *((uint16_t*)from)++;
115                 dc21285_write16(map, d, to);
116                 to += 2;
117                 len -= 2;
118         }
119 }
120
121 static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
122 {
123         uint8_t d = *((uint8_t*)from)++;
124         dc21285_write8(map, d, to);
125         to++;
126         len--;
127 }
128
129 static struct map_info dc21285_map = {
130         .name = "DC21285 flash",
131         .phys = NO_XIP,
132         .size = 16*1024*1024,
133         .copy_from = dc21285_copy_from,
134 };
135
136
137 /* Partition stuff */
138 static struct mtd_partition *dc21285_parts;
139 #ifdef CONFIG_MTD_PARTITIONS
140 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
141 #endif
142   
143 static int __init init_dc21285(void)
144 {
145
146 #ifdef CONFIG_MTD_PARTITIONS
147         int nrparts;
148 #endif
149
150         /* Determine bankwidth */
151         switch (*CSR_SA110_CNTL & (3<<14)) {
152                 case SA110_CNTL_ROMWIDTH_8: 
153                         dc21285_map.bankwidth = 1;
154                         dc21285_map.read = dc21285_read8;
155                         dc21285_map.write = dc21285_write8;
156                         dc21285_map.copy_to = dc21285_copy_to_8;
157                         break;
158                 case SA110_CNTL_ROMWIDTH_16: 
159                         dc21285_map.bankwidth = 2; 
160                         dc21285_map.read = dc21285_read16;
161                         dc21285_map.write = dc21285_write16;
162                         dc21285_map.copy_to = dc21285_copy_to_16;
163                         break;
164                 case SA110_CNTL_ROMWIDTH_32: 
165                         dc21285_map.bankwidth = 4; 
166                         break;
167                         dc21285_map.read = dc21285_read32;
168                         dc21285_map.write = dc21285_write32;
169                         dc21285_map.copy_to = dc21285_copy_to_32;
170                 default:
171                         printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
172                         return -ENXIO;
173         }
174         printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
175                 dc21285_map.bankwidth*8);
176
177         /* Let's map the flash area */
178         dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
179         if (!dc21285_map.map_priv_1) {
180                 printk("Failed to ioremap\n");
181                 return -EIO;
182         }
183
184         if (machine_is_ebsa285()) {
185                 dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
186         } else {
187                 dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
188         }
189
190         if (!dc21285_mtd) {
191                 iounmap((void *)dc21285_map.map_priv_1);
192                 return -ENXIO;
193         }       
194         
195         dc21285_mtd->owner = THIS_MODULE;
196
197 #ifdef CONFIG_MTD_PARTITIONS
198         nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, (void *)0);
199         if (nrparts > 0)
200                 add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts);
201         else    
202 #endif  
203                 add_mtd_device(dc21285_mtd);
204                         
205         if(machine_is_ebsa285()) {
206                 /* 
207                  * Flash timing is determined with bits 19-16 of the
208                  * CSR_SA110_CNTL.  The value is the number of wait cycles, or
209                  * 0 for 16 cycles (the default).  Cycles are 20 ns.
210                  * Here we use 7 for 140 ns flash chips.
211                  */
212                 /* access time */
213                 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
214                 /* burst time */
215                 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
216                 /* tristate time */
217                 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
218         }
219         
220         return 0;
221 }
222
223 static void __exit cleanup_dc21285(void)
224 {
225 #ifdef CONFIG_MTD_PARTITIONS
226         if (dc21285_parts) {
227                 del_mtd_partitions(dc21285_mtd);
228                 kfree(dc21285_parts);
229         } else
230 #endif
231                 del_mtd_device(dc21285_mtd);
232
233         map_destroy(dc21285_mtd);
234         iounmap((void *)dc21285_map.map_priv_1);
235 }
236
237 module_init(init_dc21285);
238 module_exit(cleanup_dc21285);
239
240
241 MODULE_LICENSE("GPL");
242 MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
243 MODULE_DESCRIPTION("MTD map driver for DC21285 boards");