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.9 2002/10/14 12:22:10 rmk Exp $
9 */
10 #include <linux/config.h>
11 #include <linux/module.h>
12 #include <linux/types.h>
13 #include <linux/kernel.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
22
23 static struct mtd_info *mymtd;
24
dc21285_read8(struct map_info * map,unsigned long ofs)25 __u8 dc21285_read8(struct map_info *map, unsigned long ofs)
26 {
27 return *(__u8*)(map->map_priv_1 + ofs);
28 }
29
dc21285_read16(struct map_info * map,unsigned long ofs)30 __u16 dc21285_read16(struct map_info *map, unsigned long ofs)
31 {
32 return *(__u16*)(map->map_priv_1 + ofs);
33 }
34
dc21285_read32(struct map_info * map,unsigned long ofs)35 __u32 dc21285_read32(struct map_info *map, unsigned long ofs)
36 {
37 return *(__u32*)(map->map_priv_1 + ofs);
38 }
39
dc21285_copy_from(struct map_info * map,void * to,unsigned long from,ssize_t len)40 void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
41 {
42 memcpy(to, (void*)(map->map_priv_1 + from), len);
43 }
44
dc21285_write8(struct map_info * map,__u8 d,unsigned long adr)45 void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
46 {
47 *CSR_ROMWRITEREG = adr & 3;
48 adr &= ~3;
49 *(__u8*)(map->map_priv_1 + adr) = d;
50 }
51
dc21285_write16(struct map_info * map,__u16 d,unsigned long adr)52 void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
53 {
54 *CSR_ROMWRITEREG = adr & 3;
55 adr &= ~3;
56 *(__u16*)(map->map_priv_1 + adr) = d;
57 }
58
dc21285_write32(struct map_info * map,__u32 d,unsigned long adr)59 void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr)
60 {
61 *(__u32*)(map->map_priv_1 + adr) = d;
62 }
63
dc21285_copy_to(struct map_info * map,unsigned long to,const void * from,ssize_t len)64 void dc21285_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
65 {
66 switch (map->buswidth) {
67 case 4:
68 while (len > 0) {
69 __u32 d = *((__u32*)from)++;
70 dc21285_write32(map, d, to);
71 to += 4;
72 len -= 4;
73 }
74 break;
75 case 2:
76 while (len > 0) {
77 __u16 d = *((__u16*)from)++;
78 dc21285_write16(map, d, to);
79 to += 2;
80 len -= 2;
81 }
82 break;
83 case 1:
84 while (len > 0) {
85 __u8 d = *((__u8*)from)++;
86 dc21285_write8(map, d, to);
87 to++;
88 len--;
89 }
90 break;
91 }
92 }
93
94 struct map_info dc21285_map = {
95 name: "DC21285 flash",
96 size: 16*1024*1024,
97 read8: dc21285_read8,
98 read16: dc21285_read16,
99 read32: dc21285_read32,
100 copy_from: dc21285_copy_from,
101 write8: dc21285_write8,
102 write16: dc21285_write16,
103 write32: dc21285_write32,
104 copy_to: dc21285_copy_to
105 };
106
107
108 /* Partition stuff */
109 static struct mtd_partition *dc21285_parts;
110
111 extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
112
init_dc21285(void)113 int __init init_dc21285(void)
114 {
115 /* Determine buswidth */
116 switch (*CSR_SA110_CNTL & (3<<14)) {
117 case SA110_CNTL_ROMWIDTH_8:
118 dc21285_map.buswidth = 1;
119 break;
120 case SA110_CNTL_ROMWIDTH_16:
121 dc21285_map.buswidth = 2;
122 break;
123 case SA110_CNTL_ROMWIDTH_32:
124 dc21285_map.buswidth = 4;
125 break;
126 default:
127 printk (KERN_ERR "DC21285 flash: undefined buswidth\n");
128 return -ENXIO;
129 }
130 printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n",
131 dc21285_map.buswidth*8);
132
133 /* Let's map the flash area */
134 dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
135 if (!dc21285_map.map_priv_1) {
136 printk("Failed to ioremap\n");
137 return -EIO;
138 }
139
140 mymtd = do_map_probe("cfi_probe", &dc21285_map);
141 if (mymtd) {
142 int nrparts = 0;
143
144 mymtd->module = THIS_MODULE;
145
146 /* partition fixup */
147
148 #ifdef CONFIG_MTD_REDBOOT_PARTS
149 nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
150 #endif
151 if (nrparts > 0) {
152 add_mtd_partitions(mymtd, dc21285_parts, nrparts);
153 } else if (nrparts == 0) {
154 printk(KERN_NOTICE "RedBoot partition table failed\n");
155 add_mtd_device(mymtd);
156 }
157
158 /*
159 * Flash timing is determined with bits 19-16 of the
160 * CSR_SA110_CNTL. The value is the number of wait cycles, or
161 * 0 for 16 cycles (the default). Cycles are 20 ns.
162 * Here we use 7 for 140 ns flash chips.
163 */
164 /* access time */
165 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
166 /* burst time */
167 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
168 /* tristate time */
169 *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
170
171 return 0;
172 }
173
174 iounmap((void *)dc21285_map.map_priv_1);
175 return -ENXIO;
176 }
177
cleanup_dc21285(void)178 static void __exit cleanup_dc21285(void)
179 {
180 if (mymtd) {
181 del_mtd_device(mymtd);
182 map_destroy(mymtd);
183 mymtd = NULL;
184 }
185 if (dc21285_map.map_priv_1) {
186 iounmap((void *)dc21285_map.map_priv_1);
187 dc21285_map.map_priv_1 = 0;
188 }
189 if(dc21285_parts)
190 kfree(dc21285_parts);
191 }
192
193 module_init(init_dc21285);
194 module_exit(cleanup_dc21285);
195
196
197 MODULE_LICENSE("GPL");
198 MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
199 MODULE_DESCRIPTION("MTD map driver for DC21285 boards");
200