convert brcm-2.4 to the new target structure
[openwrt.git] / target / linux / brcm-2.4 / files / drivers / mtd / devices / sflash.c
1 /*
2 * Broadcom SiliconBackplane chipcommon serial flash interface
3 *
4 * Copyright 2001-2003, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: sflash.c,v 1.1.1.3 2003/11/10 17:43:38 hyin Exp $
13 */
14
15 #include <linux/config.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/ioport.h>
19 #include <linux/mtd/compatmac.h>
20 #include <linux/mtd/mtd.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/errno.h>
23 #include <linux/pci.h>
24 #include <linux/delay.h>
25 #include <asm/io.h>
26
27 #ifdef CONFIG_MTD_PARTITIONS
28 #include <linux/mtd/mtd.h>
29 #include <linux/mtd/partitions.h>
30 #include <linux/minix_fs.h>
31 #include <linux/ext2_fs.h>
32 #include <linux/romfs_fs.h>
33 #include <linux/cramfs_fs.h>
34 #include <linux/jffs2.h>
35 #endif
36
37 #include <typedefs.h>
38 #include <bcmdevs.h>
39 #include <bcmutils.h>
40 #include <osl.h>
41 #include <bcmutils.h>
42 #include <bcmnvram.h>
43 #include <sbconfig.h>
44 #include <sbchipc.h>
45 #include <sflash.h>
46 #include <trxhdr.h>
47
48 #ifdef CONFIG_MTD_PARTITIONS
49 extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
50 #endif
51
52 struct sflash_mtd {
53 chipcregs_t *cc;
54 struct semaphore lock;
55 struct mtd_info mtd;
56 struct mtd_erase_region_info regions[1];
57 };
58
59 /* Private global state */
60 static struct sflash_mtd sflash;
61
62 static int
63 sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
64 {
65 int now = jiffies;
66 int ret = 0;
67
68 for (;;) {
69 if (!sflash_poll(sflash->cc, offset)) {
70 ret = 0;
71 break;
72 }
73 if (time_after(jiffies, now + timeout)) {
74 printk(KERN_ERR "sflash: timeout\n");
75 ret = -ETIMEDOUT;
76 break;
77 }
78 if (current->need_resched) {
79 set_current_state(TASK_UNINTERRUPTIBLE);
80 schedule_timeout(timeout / 10);
81 } else
82 udelay(1);
83 }
84
85 return ret;
86 }
87
88 static int
89 sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
90 {
91 struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
92 int bytes, ret = 0;
93
94 /* Check address range */
95 if (!len)
96 return 0;
97 if ((from + len) > mtd->size)
98 return -EINVAL;
99
100 down(&sflash->lock);
101
102 *retlen = 0;
103 while (len) {
104 if ((bytes = sflash_read(sflash->cc, (uint) from, len, buf)) < 0) {
105 ret = bytes;
106 break;
107 }
108 from += (loff_t) bytes;
109 len -= bytes;
110 buf += bytes;
111 *retlen += bytes;
112 }
113
114 up(&sflash->lock);
115
116 return ret;
117 }
118
119 static int
120 sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
121 {
122 struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
123 int bytes, ret = 0;
124
125 /* Check address range */
126 if (!len)
127 return 0;
128 if ((to + len) > mtd->size)
129 return -EINVAL;
130
131 down(&sflash->lock);
132
133 *retlen = 0;
134 while (len) {
135 if ((bytes = sflash_write(sflash->cc, (uint) to, len, buf)) < 0) {
136 ret = bytes;
137 break;
138 }
139 if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10)))
140 break;
141 to += (loff_t) bytes;
142 len -= bytes;
143 buf += bytes;
144 *retlen += bytes;
145 }
146
147 up(&sflash->lock);
148
149 return ret;
150 }
151
152 static int
153 sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
154 {
155 struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
156 int i, j, ret = 0;
157 unsigned int addr, len;
158
159 /* Check address range */
160 if (!erase->len)
161 return 0;
162 if ((erase->addr + erase->len) > mtd->size)
163 return -EINVAL;
164
165 addr = erase->addr;
166 len = erase->len;
167
168 down(&sflash->lock);
169
170 /* Ensure that requested region is aligned */
171 for (i = 0; i < mtd->numeraseregions; i++) {
172 for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
173 if (addr == mtd->eraseregions[i].offset + mtd->eraseregions[i].erasesize * j &&
174 len >= mtd->eraseregions[i].erasesize) {
175 if ((ret = sflash_erase(sflash->cc, addr)) < 0)
176 break;
177 if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ)))
178 break;
179 addr += mtd->eraseregions[i].erasesize;
180 len -= mtd->eraseregions[i].erasesize;
181 }
182 }
183 if (ret)
184 break;
185 }
186
187 up(&sflash->lock);
188
189 /* Set erase status */
190 if (ret)
191 erase->state = MTD_ERASE_FAILED;
192 else
193 erase->state = MTD_ERASE_DONE;
194
195 /* Call erase callback */
196 if (erase->callback)
197 erase->callback(erase);
198
199 return ret;
200 }
201
202 #if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
203 #define sflash_mtd_init init_module
204 #define sflash_mtd_exit cleanup_module
205 #endif
206
207 mod_init_t
208 sflash_mtd_init(void)
209 {
210 struct pci_dev *pdev;
211 int ret = 0;
212 struct sflash *info;
213 uint bank, i;
214 #ifdef CONFIG_MTD_PARTITIONS
215 struct mtd_partition *parts;
216 #endif
217
218 if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) {
219 printk(KERN_ERR "sflash: chipcommon not found\n");
220 return -ENODEV;
221 }
222
223 memset(&sflash, 0, sizeof(struct sflash_mtd));
224 init_MUTEX(&sflash.lock);
225
226 /* Map registers and flash base */
227 if (!(sflash.cc = ioremap_nocache(pci_resource_start(pdev, 0),
228 pci_resource_len(pdev, 0)))) {
229 printk(KERN_ERR "sflash: error mapping registers\n");
230 ret = -EIO;
231 goto fail;
232 }
233
234 /* Initialize serial flash access */
235 info = sflash_init(sflash.cc);
236
237 if (!info) {
238 printk(KERN_ERR "sflash: found no supported devices\n");
239 ret = -ENODEV;
240 goto fail;
241 }
242
243 /* Setup banks */
244 sflash.regions[0].offset = 0;
245 sflash.regions[0].erasesize = info->blocksize;
246 sflash.regions[0].numblocks = info->numblocks;
247 if (sflash.regions[0].erasesize > sflash.mtd.erasesize)
248 sflash.mtd.erasesize = sflash.regions[0].erasesize;
249 if (sflash.regions[0].erasesize * sflash.regions[0].numblocks) {
250 sflash.mtd.size += sflash.regions[0].erasesize * sflash.regions[0].numblocks;
251 }
252 sflash.mtd.numeraseregions = 1;
253 ASSERT(sflash.mtd.size == info->size);
254
255 /* Register with MTD */
256 sflash.mtd.name = "sflash";
257 sflash.mtd.type = MTD_NORFLASH;
258 sflash.mtd.flags = MTD_CAP_NORFLASH;
259 sflash.mtd.eraseregions = sflash.regions;
260 sflash.mtd.module = THIS_MODULE;
261 sflash.mtd.erase = sflash_mtd_erase;
262 sflash.mtd.read = sflash_mtd_read;
263 sflash.mtd.write = sflash_mtd_write;
264 sflash.mtd.priv = &sflash;
265
266 #ifdef CONFIG_MTD_PARTITIONS
267 parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size);
268 for (i = 0; parts[i].name; i++);
269 ret = add_mtd_partitions(&sflash.mtd, parts, i);
270 #else
271 ret = add_mtd_device(&sflash.mtd);
272 #endif
273 if (ret) {
274 printk(KERN_ERR "sflash: add_mtd failed\n");
275 goto fail;
276 }
277
278 return 0;
279
280 fail:
281 if (sflash.cc)
282 iounmap((void *) sflash.cc);
283 return ret;
284 }
285
286 mod_exit_t
287 sflash_mtd_exit(void)
288 {
289 #ifdef CONFIG_MTD_PARTITIONS
290 del_mtd_partitions(&sflash.mtd);
291 #else
292 del_mtd_device(&sflash.mtd);
293 #endif
294 iounmap((void *) sflash.cc);
295 }
296
297 module_init(sflash_mtd_init);
298 module_exit(sflash_mtd_exit);
This page took 0.065775 seconds and 5 git commands to generate.