ixp4xx: add support for linux 3.3.1
[openwrt.git] / target / linux / brcm47xx / patches-3.0 / 0013-bcma-add-serial-flash-support-to-bcma.patch
1 From a62940e988526c881966a8c72cc28c95fca89f3c Mon Sep 17 00:00:00 2001
2 From: Hauke Mehrtens <hauke@hauke-m.de>
3 Date: Sun, 17 Jul 2011 14:53:07 +0200
4 Subject: [PATCH 13/26] bcma: add serial flash support to bcma
5
6
7 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
8 ---
9  drivers/bcma/Kconfig                        |    5 +
10  drivers/bcma/Makefile                       |    1 +
11  drivers/bcma/bcma_private.h                 |    5 +
12  drivers/bcma/driver_chipcommon_sflash.c     |  555 +++++++++++++++++++++++++++
13  drivers/bcma/driver_mips.c                  |    8 +-
14  include/linux/bcma/bcma_driver_chipcommon.h |   24 ++
15  6 files changed, 597 insertions(+), 1 deletions(-)
16  create mode 100644 drivers/bcma/driver_chipcommon_sflash.c
17
18 --- a/drivers/bcma/Kconfig
19 +++ b/drivers/bcma/Kconfig
20 @@ -38,6 +38,11 @@ config BCMA_HOST_SOC
21         bool
22         depends on BCMA_DRIVER_MIPS
23  
24 +config BCMA_SFLASH
25 +       bool
26 +       depends on BCMA_DRIVER_MIPS
27 +       default y
28 +
29  config BCMA_DRIVER_MIPS
30         bool "BCMA Broadcom MIPS core driver"
31         depends on BCMA && MIPS
32 --- a/drivers/bcma/Makefile
33 +++ b/drivers/bcma/Makefile
34 @@ -1,5 +1,6 @@
35  bcma-y                                 += main.o scan.o core.o sprom.o
36  bcma-y                                 += driver_chipcommon.o driver_chipcommon_pmu.o
37 +bcma-$(CONFIG_BCMA_SFLASH)             += driver_chipcommon_sflash.o
38  bcma-y                                 += driver_pci.o
39  bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)        += driver_pci_host.o
40  bcma-$(CONFIG_BCMA_DRIVER_MIPS)                += driver_mips.o
41 --- a/drivers/bcma/bcma_private.h
42 +++ b/drivers/bcma/bcma_private.h
43 @@ -41,6 +41,11 @@ void bcma_chipco_serial_init(struct bcma
44  u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
45  u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
46  
47 +#ifdef CONFIG_BCMA_SFLASH
48 +/* driver_chipcommon_sflash.c */
49 +int bcma_sflash_init(struct bcma_drv_cc *cc);
50 +#endif /* CONFIG_BCMA_SFLASH */
51 +
52  #ifdef CONFIG_BCMA_HOST_PCI
53  /* host_pci.c */
54  extern int __init bcma_host_pci_init(void);
55 --- /dev/null
56 +++ b/drivers/bcma/driver_chipcommon_sflash.c
57 @@ -0,0 +1,555 @@
58 +/*
59 + * Broadcom SiliconBackplane chipcommon serial flash interface
60 + *
61 + * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
62 + * Copyright 2010, Broadcom Corporation
63 + *
64 + * Licensed under the GNU/GPL. See COPYING for details.
65 + */
66 +
67 +#include <linux/bcma/bcma.h>
68 +#include <linux/bcma/bcma_driver_chipcommon.h>
69 +#include <linux/delay.h>
70 +
71 +#include "bcma_private.h"
72 +
73 +#define NUM_RETRIES    3
74 +
75 +
76 +/* Issue a serial flash command */
77 +static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
78 +{
79 +       bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
80 +                       BCMA_CC_FLASHCTL_START | opcode);
81 +       while (bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & BCMA_CC_FLASHCTL_BUSY)
82 +               ;
83 +}
84 +
85 +
86 +static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
87 +                                             u32 offset, u8 byte)
88 +{
89 +       bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
90 +       bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
91 +}
92 +
93 +/* Initialize serial flash access */
94 +int bcma_sflash_init(struct bcma_drv_cc *cc)
95 +{
96 +       u32 id, id2;
97 +
98 +       memset(&cc->sflash, 0, sizeof(struct bcma_sflash));
99 +
100 +       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
101 +       case BCMA_CC_FLASHT_STSER:
102 +               /* Probe for ST chips */
103 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
104 +               bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
105 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
106 +               id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
107 +               cc->sflash.blocksize = 64 * 1024;
108 +               switch (id) {
109 +               case 0x11:
110 +                       /* ST M25P20 2 Mbit Serial Flash */
111 +                       cc->sflash.numblocks = 4;
112 +                       break;
113 +               case 0x12:
114 +                       /* ST M25P40 4 Mbit Serial Flash */
115 +                       cc->sflash.numblocks = 8;
116 +                       break;
117 +               case 0x13:
118 +                       /* ST M25P80 8 Mbit Serial Flash */
119 +                       cc->sflash.numblocks = 16;
120 +                       break;
121 +               case 0x14:
122 +                       /* ST M25P16 16 Mbit Serial Flash */
123 +                       cc->sflash.numblocks = 32;
124 +                       break;
125 +               case 0x15:
126 +                       /* ST M25P32 32 Mbit Serial Flash */
127 +                       cc->sflash.numblocks = 64;
128 +                       break;
129 +               case 0x16:
130 +                       /* ST M25P64 64 Mbit Serial Flash */
131 +                       cc->sflash.numblocks = 128;
132 +                       break;
133 +               case 0x17:
134 +                       /* ST M25FL128 128 Mbit Serial Flash */
135 +                       cc->sflash.numblocks = 256;
136 +                       break;
137 +               case 0xbf:
138 +                       /* All of the following flashes are SST with
139 +                        * 4KB subsectors. Others should be added but
140 +                        * We'll have to revamp the way we identify them
141 +                        * since RES is not eough to disambiguate them.
142 +                        */
143 +                       cc->sflash.blocksize = 4 * 1024;
144 +                       bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
145 +                       bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
146 +                       id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
147 +                       switch (id2) {
148 +                       case 1:
149 +                               /* SST25WF512 512 Kbit Serial Flash */
150 +                       case 0x48:
151 +                               /* SST25VF512 512 Kbit Serial Flash */
152 +                               cc->sflash.numblocks = 16;
153 +                               break;
154 +                       case 2:
155 +                               /* SST25WF010 1 Mbit Serial Flash */
156 +                       case 0x49:
157 +                               /* SST25VF010 1 Mbit Serial Flash */
158 +                               cc->sflash.numblocks = 32;
159 +                               break;
160 +                       case 3:
161 +                               /* SST25WF020 2 Mbit Serial Flash */
162 +                       case 0x43:
163 +                               /* SST25VF020 2 Mbit Serial Flash */
164 +                               cc->sflash.numblocks = 64;
165 +                               break;
166 +                       case 4:
167 +                               /* SST25WF040 4 Mbit Serial Flash */
168 +                       case 0x44:
169 +                               /* SST25VF040 4 Mbit Serial Flash */
170 +                       case 0x8d:
171 +                               /* SST25VF040B 4 Mbit Serial Flash */
172 +                               cc->sflash.numblocks = 128;
173 +                               break;
174 +                       case 5:
175 +                               /* SST25WF080 8 Mbit Serial Flash */
176 +                       case 0x8e:
177 +                               /* SST25VF080B 8 Mbit Serial Flash */
178 +                               cc->sflash.numblocks = 256;
179 +                               break;
180 +                       case 0x41:
181 +                               /* SST25VF016 16 Mbit Serial Flash */
182 +                               cc->sflash.numblocks = 512;
183 +                               break;
184 +                       case 0x4a:
185 +                               /* SST25VF032 32 Mbit Serial Flash */
186 +                               cc->sflash.numblocks = 1024;
187 +                               break;
188 +                       case 0x4b:
189 +                               /* SST25VF064 64 Mbit Serial Flash */
190 +                               cc->sflash.numblocks = 2048;
191 +                               break;
192 +                       }
193 +                       break;
194 +               }
195 +               break;
196 +
197 +       case BCMA_CC_FLASHT_ATSER:
198 +               /* Probe for Atmel chips */
199 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
200 +               id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
201 +               switch (id) {
202 +               case 0xc:
203 +                       /* Atmel AT45DB011 1Mbit Serial Flash */
204 +                       cc->sflash.blocksize = 256;
205 +                       cc->sflash.numblocks = 512;
206 +                       break;
207 +               case 0x14:
208 +                       /* Atmel AT45DB021 2Mbit Serial Flash */
209 +                       cc->sflash.blocksize = 256;
210 +                       cc->sflash.numblocks = 1024;
211 +                       break;
212 +               case 0x1c:
213 +                       /* Atmel AT45DB041 4Mbit Serial Flash */
214 +                       cc->sflash.blocksize = 256;
215 +                       cc->sflash.numblocks = 2048;
216 +                       break;
217 +               case 0x24:
218 +                       /* Atmel AT45DB081 8Mbit Serial Flash */
219 +                       cc->sflash.blocksize = 256;
220 +                       cc->sflash.numblocks = 4096;
221 +                       break;
222 +               case 0x2c:
223 +                       /* Atmel AT45DB161 16Mbit Serial Flash */
224 +                       cc->sflash.blocksize = 512;
225 +                       cc->sflash.numblocks = 4096;
226 +                       break;
227 +               case 0x34:
228 +                       /* Atmel AT45DB321 32Mbit Serial Flash */
229 +                       cc->sflash.blocksize = 512;
230 +                       cc->sflash.numblocks = 8192;
231 +                       break;
232 +               case 0x3c:
233 +                       /* Atmel AT45DB642 64Mbit Serial Flash */
234 +                       cc->sflash.blocksize = 1024;
235 +                       cc->sflash.numblocks = 8192;
236 +                       break;
237 +               }
238 +               break;
239 +       }
240 +
241 +       cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
242 +
243 +       return cc->sflash.size ? 0 : -ENODEV;
244 +}
245 +
246 +/* Read len bytes starting at offset into buf. Returns number of bytes read. */
247 +int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
248 +                          u8 *buf)
249 +{
250 +       u8 *from, *to;
251 +       u32 cnt, i;
252 +
253 +       if (!len)
254 +               return 0;
255 +
256 +       if ((offset + len) > cc->sflash.size)
257 +               return -EINVAL;
258 +
259 +       if ((len >= 4) && (offset & 3))
260 +               cnt = 4 - (offset & 3);
261 +       else if ((len >= 4) && ((u32)buf & 3))
262 +               cnt = 4 - ((u32)buf & 3);
263 +       else
264 +               cnt = len;
265 +
266 +
267 +       if (cc->core->id.rev == 12)
268 +               from = (u8 *)KSEG1ADDR(BCMA_FLASH2 + offset);
269 +       else
270 +               from = (u8 *)KSEG0ADDR(BCMA_FLASH2 + offset);
271 +
272 +       to = (u8 *)buf;
273 +
274 +       if (cnt < 4) {
275 +               for (i = 0; i < cnt; i++) {
276 +                       *to = readb(from);
277 +                       from++;
278 +                       to++;
279 +               }
280 +               return cnt;
281 +       }
282 +
283 +       while (cnt >= 4) {
284 +               *(u32 *)to = readl(from);
285 +               from += 4;
286 +               to += 4;
287 +               cnt -= 4;
288 +       }
289 +
290 +       return len - cnt;
291 +}
292 +
293 +/* Poll for command completion. Returns zero when complete. */
294 +int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset)
295 +{
296 +       if (offset >= cc->sflash.size)
297 +               return -22;
298 +
299 +       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
300 +       case BCMA_CC_FLASHT_STSER:
301 +               /* Check for ST Write In Progress bit */
302 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
303 +               return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
304 +                               & BCMA_CC_FLASHDATA_ST_WIP;
305 +       case BCMA_CC_FLASHT_ATSER:
306 +               /* Check for Atmel Ready bit */
307 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
308 +               return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
309 +                               & BCMA_CC_FLASHDATA_AT_READY);
310 +       }
311 +
312 +       return 0;
313 +}
314 +
315 +
316 +static int sflash_st_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
317 +                          const u8 *buf)
318 +{
319 +       struct bcma_bus *bus = cc->core->bus;
320 +       int ret = 0;
321 +       bool is4712b0 = (bus->chipinfo.id == 0x4712) && (bus->chipinfo.rev == 3);
322 +       u32 mask;
323 +
324 +
325 +       /* Enable writes */
326 +       bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
327 +       if (is4712b0) {
328 +               mask = 1 << 14;
329 +               bcma_sflash_write_u8(cc, offset, *buf++);
330 +               /* Set chip select */
331 +               bcma_cc_set32(cc, BCMA_CC_GPIOOUT, mask);
332 +               /* Issue a page program with the first byte */
333 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
334 +               ret = 1;
335 +               offset++;
336 +               len--;
337 +               while (len > 0) {
338 +                       if ((offset & 255) == 0) {
339 +                               /* Page boundary, drop cs and return */
340 +                               bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
341 +                               udelay(1);
342 +                               if (!bcma_sflash_poll(cc, offset)) {
343 +                                       /* Flash rejected command */
344 +                                       return -EAGAIN;
345 +                               }
346 +                               return ret;
347 +                       } else {
348 +                               /* Write single byte */
349 +                               bcma_sflash_cmd(cc, *buf++);
350 +                       }
351 +                       ret++;
352 +                       offset++;
353 +                       len--;
354 +               }
355 +               /* All done, drop cs */
356 +               bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
357 +               udelay(1);
358 +               if (!bcma_sflash_poll(cc, offset)) {
359 +                       /* Flash rejected command */
360 +                       return -EAGAIN;
361 +               }
362 +       } else if (cc->core->id.rev >= 20) {
363 +               bcma_sflash_write_u8(cc, offset, *buf++);
364 +               /* Issue a page program with CSA bit set */
365 +               bcma_sflash_cmd(cc,
366 +                               BCMA_CC_FLASHCTL_ST_CSA |
367 +                               BCMA_CC_FLASHCTL_ST_PP);
368 +               ret = 1;
369 +               offset++;
370 +               len--;
371 +               while (len > 0) {
372 +                       if ((offset & 255) == 0) {
373 +                               /* Page boundary, poll droping cs and return */
374 +                               bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
375 +                               udelay(1);
376 +                               if (!bcma_sflash_poll(cc, offset)) {
377 +                                       /* Flash rejected command */
378 +                                       return -EAGAIN;
379 +                               }
380 +                               return ret;
381 +                       } else {
382 +                               /* Write single byte */
383 +                               bcma_sflash_cmd(cc,
384 +                                               BCMA_CC_FLASHCTL_ST_CSA |
385 +                                               *buf++);
386 +                       }
387 +                       ret++;
388 +                       offset++;
389 +                       len--;
390 +               }
391 +               /* All done, drop cs & poll */
392 +               bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
393 +               udelay(1);
394 +               if (!bcma_sflash_poll(cc, offset)) {
395 +                       /* Flash rejected command */
396 +                       return -EAGAIN;
397 +               }
398 +       } else {
399 +               ret = 1;
400 +               bcma_sflash_write_u8(cc, offset, *buf);
401 +               /* Page program */
402 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
403 +       }
404 +       return ret;
405 +}
406 +
407 +static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
408 +                          const u8 *buf)
409 +{
410 +       struct bcma_sflash *sfl = &cc->sflash;
411 +       u32 page, byte, mask;
412 +       int ret = 0;
413 +       mask = sfl->blocksize - 1;
414 +       page = (offset & ~mask) << 1;
415 +       byte = offset & mask;
416 +       /* Read main memory page into buffer 1 */
417 +       if (byte || (len < sfl->blocksize)) {
418 +               int i = 100;
419 +               bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
420 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
421 +               /* 250 us for AT45DB321B */
422 +               while (i > 0 && bcma_sflash_poll(cc, offset)) {
423 +                       udelay(10);
424 +                       i--;
425 +               }
426 +               BUG_ON(!bcma_sflash_poll(cc, offset));
427 +       }
428 +       /* Write into buffer 1 */
429 +       for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
430 +               bcma_sflash_write_u8(cc, byte++, *buf++);
431 +               bcma_sflash_cmd(cc,
432 +                               BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
433 +       }
434 +       /* Write buffer 1 into main memory page */
435 +       bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
436 +       bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
437 +
438 +       return ret;
439 +}
440 +
441 +/* Write len bytes starting at offset into buf. Returns number of bytes
442 + * written. Caller should poll for completion.
443 + */
444 +int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
445 +                           const u8 *buf)
446 +{
447 +       struct bcma_sflash *sfl;
448 +       int ret = 0, tries = NUM_RETRIES;
449 +
450 +       if (!len)
451 +               return 0;
452 +
453 +       if ((offset + len) > cc->sflash.size)
454 +               return -EINVAL;
455 +
456 +       sfl = &cc->sflash;
457 +       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
458 +       case BCMA_CC_FLASHT_STSER:
459 +               do {
460 +                       ret = sflash_st_write(cc, offset, len, buf);
461 +                       tries--;
462 +               } while (ret == -EAGAIN && tries > 0);
463 +
464 +               if (ret == -EAGAIN && tries == 0) {
465 +                       pr_info("ST Flash rejected write\n");
466 +                       ret = -EIO;
467 +               }
468 +               break;
469 +       case BCMA_CC_FLASHT_ATSER:
470 +               ret = sflash_at_write(cc, offset, len, buf);
471 +               break;
472 +       }
473 +
474 +       return ret;
475 +}
476 +
477 +/* Erase a region. Returns number of bytes scheduled for erasure.
478 + * Caller should poll for completion.
479 + */
480 +int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset)
481 +{
482 +       struct bcma_sflash *sfl;
483 +
484 +       if (offset >= cc->sflash.size)
485 +               return -EINVAL;
486 +
487 +       sfl = &cc->sflash;
488 +       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
489 +       case BCMA_CC_FLASHT_STSER:
490 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
491 +               bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
492 +               /* Newer flashes have "sub-sectors" which can be erased independently
493 +                * with a new command: ST_SSE. The ST_SE command erases 64KB just as
494 +                * before.
495 +                */
496 +               bcma_sflash_cmd(cc, (sfl->blocksize < (64 * 1024)) ? BCMA_CC_FLASHCTL_ST_SSE : BCMA_CC_FLASHCTL_ST_SE);
497 +               return sfl->blocksize;
498 +       case BCMA_CC_FLASHT_ATSER:
499 +               bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
500 +               bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
501 +               return sfl->blocksize;
502 +       }
503 +
504 +       return 0;
505 +}
506 +
507 +/*
508 + * writes the appropriate range of flash, a NULL buf simply erases
509 + * the region of flash
510 + */
511 +int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
512 +                            const u8 *buf)
513 +{
514 +       struct bcma_sflash *sfl;
515 +       u8 *block = NULL, *cur_ptr, *blk_ptr;
516 +       u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
517 +       u32 blk_offset, blk_len, copied;
518 +       int bytes, ret = 0;
519 +
520 +       /* Check address range */
521 +       if (len <= 0)
522 +               return 0;
523 +
524 +       sfl = &cc->sflash;
525 +       if ((offset + len) > sfl->size)
526 +               return -EINVAL;
527 +
528 +       blocksize = sfl->blocksize;
529 +       mask = blocksize - 1;
530 +
531 +       /* Allocate a block of mem */
532 +       block = kmalloc(blocksize, GFP_KERNEL);
533 +       if (!block)
534 +               return -ENOMEM;
535 +
536 +       while (len) {
537 +               /* Align offset */
538 +               cur_offset = offset & ~mask;
539 +               cur_length = blocksize;
540 +               cur_ptr = block;
541 +
542 +               remainder = blocksize - (offset & mask);
543 +               if (len < remainder)
544 +                       cur_retlen = len;
545 +               else
546 +                       cur_retlen = remainder;
547 +
548 +               /* buf == NULL means erase only */
549 +               if (buf) {
550 +                       /* Copy existing data into holding block if necessary */
551 +                       if ((offset & mask) || (len < blocksize)) {
552 +                               blk_offset = cur_offset;
553 +                               blk_len = cur_length;
554 +                               blk_ptr = cur_ptr;
555 +
556 +                               /* Copy entire block */
557 +                               while (blk_len) {
558 +                                       copied = bcma_sflash_read(cc,
559 +                                                       blk_offset,
560 +                                                       blk_len, blk_ptr);
561 +                                       blk_offset += copied;
562 +                                       blk_len -= copied;
563 +                                       blk_ptr += copied;
564 +                               }
565 +                       }
566 +
567 +                       /* Copy input data into holding block */
568 +                       memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
569 +               }
570 +
571 +               /* Erase block */
572 +               ret = bcma_sflash_erase(cc, cur_offset);
573 +               if (ret < 0)
574 +                       goto done;
575 +
576 +               while (bcma_sflash_poll(cc, cur_offset));
577 +
578 +               /* buf == NULL means erase only */
579 +               if (!buf) {
580 +                       offset += cur_retlen;
581 +                       len -= cur_retlen;
582 +                       continue;
583 +               }
584 +
585 +               /* Write holding block */
586 +               while (cur_length > 0) {
587 +                       bytes = bcma_sflash_write(cc, cur_offset,
588 +                                       cur_length, cur_ptr);
589 +
590 +                       if (bytes < 0) {
591 +                               ret = bytes;
592 +                               goto done;
593 +                       }
594 +
595 +                       while (bcma_sflash_poll(cc, cur_offset))
596 +                               ;
597 +
598 +                       cur_offset += bytes;
599 +                       cur_length -= bytes;
600 +                       cur_ptr += bytes;
601 +               }
602 +
603 +               offset += cur_retlen;
604 +               len -= cur_retlen;
605 +               buf += cur_retlen;
606 +       }
607 +
608 +       ret = len;
609 +done:
610 +       kfree(block);
611 +       return ret;
612 +}
613 --- a/drivers/bcma/driver_mips.c
614 +++ b/drivers/bcma/driver_mips.c
615 @@ -185,7 +185,13 @@ static void bcma_core_mips_flash_detect(
616         switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
617         case BCMA_CC_FLASHT_STSER:
618         case BCMA_CC_FLASHT_ATSER:
619 -               pr_err("Serial flash not supported.\n");
620 +#ifdef CONFIG_BCMA_SFLASH
621 +               pr_info("found serial flash.\n");
622 +               bus->drv_cc.flash_type = BCMA_SFLASH;
623 +               bcma_sflash_init(&bus->drv_cc);
624 +#else
625 +               pr_info("serial flash not supported.\n");
626 +#endif /* CONFIG_BCMA_SFLASH */
627                 break;
628         case BCMA_CC_FLASHT_PARA:
629                 pr_info("found parallel flash.\n");
630 --- a/include/linux/bcma/bcma_driver_chipcommon.h
631 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
632 @@ -375,6 +375,7 @@ struct bcma_chipcommon_pmu {
633  #ifdef CONFIG_BCMA_DRIVER_MIPS
634  enum bcma_flash_type {
635         BCMA_PFLASH,
636 +       BCMA_SFLASH,
637  };
638  
639  struct bcma_pflash {
640 @@ -383,6 +384,14 @@ struct bcma_pflash {
641         u32 window_size;
642  };
643  
644 +#ifdef CONFIG_BCMA_SFLASH
645 +struct bcma_sflash {
646 +       u32 blocksize;          /* Block size */
647 +       u32 numblocks;          /* Number of blocks */
648 +       u32 size;               /* Total size in bytes */
649 +};
650 +#endif /* CONFIG_BCMA_SFLASH */
651 +
652  struct bcma_serial_port {
653         void *regs;
654         unsigned long clockspeed;
655 @@ -405,6 +414,9 @@ struct bcma_drv_cc {
656         enum bcma_flash_type flash_type;
657         union {
658                 struct bcma_pflash pflash;
659 +#ifdef CONFIG_BCMA_SFLASH
660 +               struct bcma_sflash sflash;
661 +#endif /* CONFIG_BCMA_SFLASH */
662         };
663  
664         int nr_serial_ports;
665 @@ -459,4 +471,16 @@ extern void bcma_chipco_chipctl_maskset(
666  extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
667                                        u32 offset, u32 mask, u32 set);
668  
669 +#ifdef CONFIG_BCMA_SFLASH
670 +/* Chipcommon sflash support. */
671 +int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
672 +                          u8 *buf);
673 +int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset);
674 +int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
675 +                           const u8 *buf);
676 +int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
677 +int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
678 +                            const u8 *buf);
679 +#endif /* CONFIG_BCMA_SFLASH */
680 +
681  #endif /* LINUX_BCMA_DRIVER_CC_H_ */