2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: sflash.c,v 1.6 2011-02-10 10:55:57 Exp $
21 #include <linux/config.h>
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/ioport.h>
25 #include <linux/mtd/compatmac.h>
26 #include <linux/mtd/mtd.h>
27 #include <linux/mtd/partitions.h>
28 #include <linux/errno.h>
29 #include <linux/pci.h>
30 #include <linux/delay.h>
45 #ifdef CONFIG_MTD_PARTITIONS
46 extern struct mtd_partition
* init_mtd_partitions(struct mtd_info
*mtd
, size_t size
);
49 extern struct mutex
*partitions_mutex_init(void);
55 struct mtd_erase_region_info region
;
58 /* Private global state */
59 static struct sflash_mtd sflash
;
62 sflash_mtd_poll(struct sflash_mtd
*sflash
, unsigned int offset
, int timeout
)
68 if (!sflash_poll(sflash
->sih
, sflash
->cc
, offset
))
71 if (time_after((unsigned long)jiffies
, (unsigned long)now
+ timeout
)) {
72 if (!sflash_poll(sflash
->sih
, sflash
->cc
, offset
))
75 printk(KERN_ERR
"sflash: timeout\n");
86 sflash_mtd_read(struct mtd_info
*mtd
, loff_t from
, size_t len
, size_t *retlen
, u_char
*buf
)
88 struct sflash_mtd
*sflash
= (struct sflash_mtd
*) mtd
->priv
;
91 /* Check address range */
94 if ((from
+ len
) > mtd
->size
)
97 mutex_lock(mtd
->mutex
);
101 if ((bytes
= sflash_read(sflash
->sih
, sflash
->cc
, (uint
) from
, len
, buf
)) < 0) {
105 from
+= (loff_t
) bytes
;
111 mutex_unlock(mtd
->mutex
);
116 sflash_mtd_write(struct mtd_info
*mtd
, loff_t to
, size_t len
, size_t *retlen
, const u_char
*buf
)
118 struct sflash_mtd
*sflash
= (struct sflash_mtd
*) mtd
->priv
;
121 /* Check address range */
124 if ((to
+ len
) > mtd
->size
)
127 mutex_lock(mtd
->mutex
);
130 if ((bytes
= sflash_write(sflash
->sih
, sflash
->cc
, (uint
) to
, len
, buf
)) < 0) {
134 if ((ret
= sflash_mtd_poll(sflash
, (unsigned int) to
, HZ
)))
136 to
+= (loff_t
) bytes
;
142 mutex_unlock(mtd
->mutex
);
147 sflash_mtd_erase(struct mtd_info
*mtd
, struct erase_info
*erase
)
149 struct sflash_mtd
*sflash
= (struct sflash_mtd
*) mtd
->priv
;
151 unsigned int addr
, len
;
153 /* Check address range */
156 if ((erase
->addr
+ erase
->len
) > mtd
->size
)
159 mutex_lock(mtd
->mutex
);
163 /* Ensure that requested region is aligned */
164 for (i
= 0; i
< mtd
->numeraseregions
; i
++) {
165 for (j
= 0; j
< mtd
->eraseregions
[i
].numblocks
; j
++) {
166 if (addr
== mtd
->eraseregions
[i
].offset
+
167 mtd
->eraseregions
[i
].erasesize
* j
&&
168 len
>= mtd
->eraseregions
[i
].erasesize
) {
169 if ((ret
= sflash_erase(sflash
->sih
, sflash
->cc
, addr
)) < 0)
171 if ((ret
= sflash_mtd_poll(sflash
, addr
, 10 * HZ
)))
173 addr
+= mtd
->eraseregions
[i
].erasesize
;
174 len
-= mtd
->eraseregions
[i
].erasesize
;
181 /* Set erase status */
183 erase
->state
= MTD_ERASE_FAILED
;
185 erase
->state
= MTD_ERASE_DONE
;
187 mutex_unlock(mtd
->mutex
);
189 /* Call erase callback */
191 erase
->callback(erase
);
196 #if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
197 #define sflash_mtd_init init_module
198 #define sflash_mtd_exit cleanup_module
202 sflash_mtd_init(void)
206 struct pci_dev
*dev
= NULL
;
207 #ifdef CONFIG_MTD_PARTITIONS
208 struct mtd_partition
*parts
;
212 list_for_each_entry(dev
, &((pci_find_bus(0, 0))->devices
), bus_list
) {
213 if ((dev
!= NULL
) && (dev
->device
== CC_CORE_ID
))
218 printk(KERN_ERR
"sflash: chipcommon not found\n");
222 memset(&sflash
, 0, sizeof(struct sflash_mtd
));
224 /* attach to the backplane */
225 if (!(sflash
.sih
= si_kattach(SI_OSH
))) {
226 printk(KERN_ERR
"sflash: error attaching to backplane\n");
231 /* Map registers and flash base */
232 if (!(sflash
.cc
= ioremap_nocache(
233 pci_resource_start(dev
, 0),
234 pci_resource_len(dev
, 0)))) {
235 printk(KERN_ERR
"sflash: error mapping registers\n");
240 /* Initialize serial flash access */
241 if (!(info
= sflash_init(sflash
.sih
, sflash
.cc
))) {
242 printk(KERN_ERR
"sflash: found no supported devices\n");
247 /* Setup region info */
248 sflash
.region
.offset
= 0;
249 sflash
.region
.erasesize
= info
->blocksize
;
250 sflash
.region
.numblocks
= info
->numblocks
;
251 if (sflash
.region
.erasesize
> sflash
.mtd
.erasesize
)
252 sflash
.mtd
.erasesize
= sflash
.region
.erasesize
;
253 sflash
.mtd
.size
= info
->size
;
254 sflash
.mtd
.numeraseregions
= 1;
256 /* Register with MTD */
257 sflash
.mtd
.name
= "sflash";
258 sflash
.mtd
.type
= MTD_NORFLASH
;
259 sflash
.mtd
.flags
= MTD_CAP_NORFLASH
;
260 sflash
.mtd
.eraseregions
= &sflash
.region
;
261 sflash
.mtd
.erase
= sflash_mtd_erase
;
262 sflash
.mtd
.read
= sflash_mtd_read
;
263 sflash
.mtd
.write
= sflash_mtd_write
;
264 sflash
.mtd
.writesize
= 1;
265 sflash
.mtd
.priv
= &sflash
;
266 sflash
.mtd
.owner
= THIS_MODULE
;
267 sflash
.mtd
.mutex
= partitions_mutex_init();
268 if (!sflash
.mtd
.mutex
)
271 #ifdef CONFIG_MTD_PARTITIONS
272 parts
= init_mtd_partitions(&sflash
.mtd
, sflash
.mtd
.size
);
273 for (i
= 0; parts
[i
].name
; i
++);
274 ret
= add_mtd_partitions(&sflash
.mtd
, parts
, i
);
276 printk(KERN_ERR
"sflash: add_mtd failed\n");
285 iounmap((void *) sflash
.cc
);
287 si_detach(sflash
.sih
);
292 sflash_mtd_exit(void)
294 #ifdef CONFIG_MTD_PARTITIONS
295 del_mtd_partitions(&sflash
.mtd
);
297 del_mtd_device(&sflash
.mtd
);
299 iounmap((void *) sflash
.cc
);
300 si_detach(sflash
.sih
);
303 module_init(sflash_mtd_init
);
304 module_exit(sflash_mtd_exit
);