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);