brcm47xx: add new usb driver for bcma bus and replace ssb usb driver.
[openwrt/svn-archive/archive.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_ */