Version:  2.0.40 2.2.26 2.4.37 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17

Linux/drivers/mtd/devices/bcm47xxsflash.c

  1 #include <linux/kernel.h>
  2 #include <linux/module.h>
  3 #include <linux/slab.h>
  4 #include <linux/delay.h>
  5 #include <linux/mtd/mtd.h>
  6 #include <linux/platform_device.h>
  7 #include <linux/bcma/bcma.h>
  8 
  9 #include "bcm47xxsflash.h"
 10 
 11 MODULE_LICENSE("GPL");
 12 MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
 13 
 14 static const char * const probes[] = { "bcm47xxpart", NULL };
 15 
 16 /**************************************************
 17  * Various helpers
 18  **************************************************/
 19 
 20 static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
 21 {
 22         int i;
 23 
 24         b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
 25         for (i = 0; i < 1000; i++) {
 26                 if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
 27                       BCMA_CC_FLASHCTL_BUSY))
 28                         return;
 29                 cpu_relax();
 30         }
 31         pr_err("Control command failed (timeout)!\n");
 32 }
 33 
 34 static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
 35 {
 36         unsigned long deadline = jiffies + timeout;
 37 
 38         do {
 39                 switch (b47s->type) {
 40                 case BCM47XXSFLASH_TYPE_ST:
 41                         bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
 42                         if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
 43                               SR_ST_WIP))
 44                                 return 0;
 45                         break;
 46                 case BCM47XXSFLASH_TYPE_ATMEL:
 47                         bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
 48                         if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
 49                             SR_AT_READY)
 50                                 return 0;
 51                         break;
 52                 }
 53 
 54                 cpu_relax();
 55                 udelay(1);
 56         } while (!time_after_eq(jiffies, deadline));
 57 
 58         pr_err("Timeout waiting for flash to be ready!\n");
 59 
 60         return -EBUSY;
 61 }
 62 
 63 /**************************************************
 64  * MTD ops
 65  **************************************************/
 66 
 67 static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
 68 {
 69         struct bcm47xxsflash *b47s = mtd->priv;
 70         int err;
 71 
 72         switch (b47s->type) {
 73         case BCM47XXSFLASH_TYPE_ST:
 74                 bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
 75                 b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
 76                 /* Newer flashes have "sub-sectors" which can be erased
 77                  * independently with a new command: ST_SSE. The ST_SE command
 78                  * erases 64KB just as before.
 79                  */
 80                 if (b47s->blocksize < (64 * 1024))
 81                         bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
 82                 else
 83                         bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
 84                 break;
 85         case BCM47XXSFLASH_TYPE_ATMEL:
 86                 b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
 87                 bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
 88                 break;
 89         }
 90 
 91         err = bcm47xxsflash_poll(b47s, HZ);
 92         if (err)
 93                 erase->state = MTD_ERASE_FAILED;
 94         else
 95                 erase->state = MTD_ERASE_DONE;
 96 
 97         if (erase->callback)
 98                 erase->callback(erase);
 99 
100         return err;
101 }
102 
103 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
104                               size_t *retlen, u_char *buf)
105 {
106         struct bcm47xxsflash *b47s = mtd->priv;
107 
108         /* Check address range */
109         if ((from + len) > mtd->size)
110                 return -EINVAL;
111 
112         memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
113                       len);
114         *retlen = len;
115 
116         return len;
117 }
118 
119 static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
120                                   const u_char *buf)
121 {
122         struct bcm47xxsflash *b47s = mtd->priv;
123         int written = 0;
124 
125         /* Enable writes */
126         bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
127 
128         /* Write first byte */
129         b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
130         b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
131 
132         /* Program page */
133         if (b47s->bcma_cc->core->id.rev < 20) {
134                 bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
135                 return 1; /* 1B written */
136         }
137 
138         /* Program page and set CSA (on newer chips we can continue writing) */
139         bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
140         offset++;
141         len--;
142         written++;
143 
144         while (len > 0) {
145                 /* Page boundary, another function call is needed */
146                 if ((offset & 0xFF) == 0)
147                         break;
148 
149                 bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
150                 offset++;
151                 len--;
152                 written++;
153         }
154 
155         /* All done, drop CSA & poll */
156         b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
157         udelay(1);
158         if (bcm47xxsflash_poll(b47s, HZ / 10))
159                 pr_err("Flash rejected dropping CSA\n");
160 
161         return written;
162 }
163 
164 static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
165                                   const u_char *buf)
166 {
167         struct bcm47xxsflash *b47s = mtd->priv;
168         u32 mask = b47s->blocksize - 1;
169         u32 page = (offset & ~mask) << 1;
170         u32 byte = offset & mask;
171         int written = 0;
172 
173         /* If we don't overwrite whole page, read it to the buffer first */
174         if (byte || (len < b47s->blocksize)) {
175                 int err;
176 
177                 b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
178                 bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
179                 /* 250 us for AT45DB321B */
180                 err = bcm47xxsflash_poll(b47s, HZ / 1000);
181                 if (err) {
182                         pr_err("Timeout reading page 0x%X info buffer\n", page);
183                         return err;
184                 }
185         }
186 
187         /* Change buffer content with our data */
188         while (len > 0) {
189                 /* Page boundary, another function call is needed */
190                 if (byte == b47s->blocksize)
191                         break;
192 
193                 b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
194                 b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
195                 bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
196                 len--;
197                 written++;
198         }
199 
200         /* Program page with the buffer content */
201         b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
202         bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
203 
204         return written;
205 }
206 
207 static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
208                                size_t *retlen, const u_char *buf)
209 {
210         struct bcm47xxsflash *b47s = mtd->priv;
211         int written;
212 
213         /* Writing functions can return without writing all passed data, for
214          * example when the hardware is too old or when we git page boundary.
215          */
216         while (len > 0) {
217                 switch (b47s->type) {
218                 case BCM47XXSFLASH_TYPE_ST:
219                         written = bcm47xxsflash_write_st(mtd, to, len, buf);
220                         break;
221                 case BCM47XXSFLASH_TYPE_ATMEL:
222                         written = bcm47xxsflash_write_at(mtd, to, len, buf);
223                         break;
224                 default:
225                         BUG_ON(1);
226                 }
227                 if (written < 0) {
228                         pr_err("Error writing at offset 0x%llX\n", to);
229                         return written;
230                 }
231                 to += (loff_t)written;
232                 len -= written;
233                 *retlen += written;
234                 buf += written;
235         }
236 
237         return 0;
238 }
239 
240 static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
241 {
242         struct mtd_info *mtd = &b47s->mtd;
243 
244         mtd->priv = b47s;
245         mtd->name = "bcm47xxsflash";
246         mtd->owner = THIS_MODULE;
247 
248         mtd->type = MTD_NORFLASH;
249         mtd->flags = MTD_CAP_NORFLASH;
250         mtd->size = b47s->size;
251         mtd->erasesize = b47s->blocksize;
252         mtd->writesize = 1;
253         mtd->writebufsize = 1;
254 
255         mtd->_erase = bcm47xxsflash_erase;
256         mtd->_read = bcm47xxsflash_read;
257         mtd->_write = bcm47xxsflash_write;
258 }
259 
260 /**************************************************
261  * BCMA
262  **************************************************/
263 
264 static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
265 {
266         return bcma_cc_read32(b47s->bcma_cc, offset);
267 }
268 
269 static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
270                                         u32 value)
271 {
272         bcma_cc_write32(b47s->bcma_cc, offset, value);
273 }
274 
275 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
276 {
277         struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
278         struct bcm47xxsflash *b47s;
279         int err;
280 
281         b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
282         if (!b47s)
283                 return -ENOMEM;
284         sflash->priv = b47s;
285 
286         b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
287         b47s->cc_read = bcm47xxsflash_bcma_cc_read;
288         b47s->cc_write = bcm47xxsflash_bcma_cc_write;
289 
290         switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
291         case BCMA_CC_FLASHT_STSER:
292                 b47s->type = BCM47XXSFLASH_TYPE_ST;
293                 break;
294         case BCMA_CC_FLASHT_ATSER:
295                 b47s->type = BCM47XXSFLASH_TYPE_ATMEL;
296                 break;
297         }
298 
299         b47s->window = sflash->window;
300         b47s->blocksize = sflash->blocksize;
301         b47s->numblocks = sflash->numblocks;
302         b47s->size = sflash->size;
303         bcm47xxsflash_fill_mtd(b47s);
304 
305         err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
306         if (err) {
307                 pr_err("Failed to register MTD device: %d\n", err);
308                 return err;
309         }
310 
311         if (bcm47xxsflash_poll(b47s, HZ / 10))
312                 pr_warn("Serial flash busy\n");
313 
314         return 0;
315 }
316 
317 static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
318 {
319         struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
320         struct bcm47xxsflash *b47s = sflash->priv;
321 
322         mtd_device_unregister(&b47s->mtd);
323 
324         return 0;
325 }
326 
327 static struct platform_driver bcma_sflash_driver = {
328         .probe  = bcm47xxsflash_bcma_probe,
329         .remove = bcm47xxsflash_bcma_remove,
330         .driver = {
331                 .name = "bcma_sflash",
332                 .owner = THIS_MODULE,
333         },
334 };
335 
336 /**************************************************
337  * Init
338  **************************************************/
339 
340 module_platform_driver(bcma_sflash_driver);
341 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us