2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright 2001-2003, Broadcom Corporation
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.
12 * $Id: sflash.c,v 1.1.1.3 2003/11/10 17:43:38 hyin Exp $
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>
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>
48 #ifdef CONFIG_MTD_PARTITIONS
49 extern struct mtd_partition
* init_mtd_partitions(struct mtd_info
*mtd
, size_t size
);
54 struct semaphore lock
;
56 struct mtd_erase_region_info regions
[1];
59 /* Private global state */
60 static struct sflash_mtd sflash
;
63 sflash_mtd_poll(struct sflash_mtd
*sflash
, unsigned int offset
, int timeout
)
69 if (!sflash_poll(sflash
->cc
, offset
)) {
73 if (time_after(jiffies
, now
+ timeout
)) {
74 printk(KERN_ERR
"sflash: timeout\n");
78 if (current
->need_resched
) {
79 set_current_state(TASK_UNINTERRUPTIBLE
);
80 schedule_timeout(timeout
/ 10);
89 sflash_mtd_read(struct mtd_info
*mtd
, loff_t from
, size_t len
, size_t *retlen
, u_char
*buf
)
91 struct sflash_mtd
*sflash
= (struct sflash_mtd
*) mtd
->priv
;
94 /* Check address range */
97 if ((from
+ len
) > mtd
->size
)
104 if ((bytes
= sflash_read(sflash
->cc
, (uint
) from
, len
, buf
)) < 0) {
108 from
+= (loff_t
) bytes
;
120 sflash_mtd_write(struct mtd_info
*mtd
, loff_t to
, size_t len
, size_t *retlen
, const u_char
*buf
)
122 struct sflash_mtd
*sflash
= (struct sflash_mtd
*) mtd
->priv
;
125 /* Check address range */
128 if ((to
+ len
) > mtd
->size
)
135 if ((bytes
= sflash_write(sflash
->cc
, (uint
) to
, len
, buf
)) < 0) {
139 if ((ret
= sflash_mtd_poll(sflash
, (unsigned int) to
, HZ
/ 10)))
141 to
+= (loff_t
) bytes
;
153 sflash_mtd_erase(struct mtd_info
*mtd
, struct erase_info
*erase
)
155 struct sflash_mtd
*sflash
= (struct sflash_mtd
*) mtd
->priv
;
157 unsigned int addr
, len
;
159 /* Check address range */
162 if ((erase
->addr
+ erase
->len
) > mtd
->size
)
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)
177 if ((ret
= sflash_mtd_poll(sflash
, addr
, 10 * HZ
)))
179 addr
+= mtd
->eraseregions
[i
].erasesize
;
180 len
-= mtd
->eraseregions
[i
].erasesize
;
189 /* Set erase status */
191 erase
->state
= MTD_ERASE_FAILED
;
193 erase
->state
= MTD_ERASE_DONE
;
195 /* Call erase callback */
197 erase
->callback(erase
);
202 #if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
203 #define sflash_mtd_init init_module
204 #define sflash_mtd_exit cleanup_module
208 sflash_mtd_init(void)
210 struct pci_dev
*pdev
;
214 #ifdef CONFIG_MTD_PARTITIONS
215 struct mtd_partition
*parts
;
218 if (!(pdev
= pci_find_device(VENDOR_BROADCOM
, SB_CC
, NULL
))) {
219 printk(KERN_ERR
"sflash: chipcommon not found\n");
223 memset(&sflash
, 0, sizeof(struct sflash_mtd
));
224 init_MUTEX(&sflash
.lock
);
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");
234 /* Initialize serial flash access */
235 info
= sflash_init(sflash
.cc
);
238 printk(KERN_ERR
"sflash: found no supported devices\n");
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
;
252 sflash
.mtd
.numeraseregions
= 1;
253 ASSERT(sflash
.mtd
.size
== info
->size
);
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
;
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
);
271 ret
= add_mtd_device(&sflash
.mtd
);
274 printk(KERN_ERR
"sflash: add_mtd failed\n");
282 iounmap((void *) sflash
.cc
);
287 sflash_mtd_exit(void)
289 #ifdef CONFIG_MTD_PARTITIONS
290 del_mtd_partitions(&sflash
.mtd
);
292 del_mtd_device(&sflash
.mtd
);
294 iounmap((void *) sflash
.cc
);
297 module_init(sflash_mtd_init
);
298 module_exit(sflash_mtd_exit
);