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
7 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
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
18 --- a/drivers/bcma/Kconfig
19 +++ b/drivers/bcma/Kconfig
20 @@ -38,6 +38,11 @@ config BCMA_HOST_SOC
22 depends on BCMA_DRIVER_MIPS
26 + depends on BCMA_DRIVER_MIPS
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
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);
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 */
52 #ifdef CONFIG_BCMA_HOST_PCI
54 extern int __init bcma_host_pci_init(void);
56 +++ b/drivers/bcma/driver_chipcommon_sflash.c
59 + * Broadcom SiliconBackplane chipcommon serial flash interface
61 + * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
62 + * Copyright 2010, Broadcom Corporation
64 + * Licensed under the GNU/GPL. See COPYING for details.
67 +#include <linux/bcma/bcma.h>
68 +#include <linux/bcma/bcma_driver_chipcommon.h>
69 +#include <linux/delay.h>
71 +#include "bcma_private.h"
73 +#define NUM_RETRIES 3
76 +/* Issue a serial flash command */
77 +static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
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)
86 +static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
87 + u32 offset, u8 byte)
89 + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
90 + bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
93 +/* Initialize serial flash access */
94 +int bcma_sflash_init(struct bcma_drv_cc *cc)
98 + memset(&cc->sflash, 0, sizeof(struct bcma_sflash));
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;
110 + /* ST M25P20 2 Mbit Serial Flash */
111 + cc->sflash.numblocks = 4;
114 + /* ST M25P40 4 Mbit Serial Flash */
115 + cc->sflash.numblocks = 8;
118 + /* ST M25P80 8 Mbit Serial Flash */
119 + cc->sflash.numblocks = 16;
122 + /* ST M25P16 16 Mbit Serial Flash */
123 + cc->sflash.numblocks = 32;
126 + /* ST M25P32 32 Mbit Serial Flash */
127 + cc->sflash.numblocks = 64;
130 + /* ST M25P64 64 Mbit Serial Flash */
131 + cc->sflash.numblocks = 128;
134 + /* ST M25FL128 128 Mbit Serial Flash */
135 + cc->sflash.numblocks = 256;
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.
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);
149 + /* SST25WF512 512 Kbit Serial Flash */
151 + /* SST25VF512 512 Kbit Serial Flash */
152 + cc->sflash.numblocks = 16;
155 + /* SST25WF010 1 Mbit Serial Flash */
157 + /* SST25VF010 1 Mbit Serial Flash */
158 + cc->sflash.numblocks = 32;
161 + /* SST25WF020 2 Mbit Serial Flash */
163 + /* SST25VF020 2 Mbit Serial Flash */
164 + cc->sflash.numblocks = 64;
167 + /* SST25WF040 4 Mbit Serial Flash */
169 + /* SST25VF040 4 Mbit Serial Flash */
171 + /* SST25VF040B 4 Mbit Serial Flash */
172 + cc->sflash.numblocks = 128;
175 + /* SST25WF080 8 Mbit Serial Flash */
177 + /* SST25VF080B 8 Mbit Serial Flash */
178 + cc->sflash.numblocks = 256;
181 + /* SST25VF016 16 Mbit Serial Flash */
182 + cc->sflash.numblocks = 512;
185 + /* SST25VF032 32 Mbit Serial Flash */
186 + cc->sflash.numblocks = 1024;
189 + /* SST25VF064 64 Mbit Serial Flash */
190 + cc->sflash.numblocks = 2048;
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;
203 + /* Atmel AT45DB011 1Mbit Serial Flash */
204 + cc->sflash.blocksize = 256;
205 + cc->sflash.numblocks = 512;
208 + /* Atmel AT45DB021 2Mbit Serial Flash */
209 + cc->sflash.blocksize = 256;
210 + cc->sflash.numblocks = 1024;
213 + /* Atmel AT45DB041 4Mbit Serial Flash */
214 + cc->sflash.blocksize = 256;
215 + cc->sflash.numblocks = 2048;
218 + /* Atmel AT45DB081 8Mbit Serial Flash */
219 + cc->sflash.blocksize = 256;
220 + cc->sflash.numblocks = 4096;
223 + /* Atmel AT45DB161 16Mbit Serial Flash */
224 + cc->sflash.blocksize = 512;
225 + cc->sflash.numblocks = 4096;
228 + /* Atmel AT45DB321 32Mbit Serial Flash */
229 + cc->sflash.blocksize = 512;
230 + cc->sflash.numblocks = 8192;
233 + /* Atmel AT45DB642 64Mbit Serial Flash */
234 + cc->sflash.blocksize = 1024;
235 + cc->sflash.numblocks = 8192;
241 + cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
243 + return cc->sflash.size ? 0 : -ENODEV;
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,
256 + if ((offset + len) > cc->sflash.size)
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);
267 + if (cc->core->id.rev == 12)
268 + from = (u8 *)KSEG1ADDR(BCMA_FLASH2 + offset);
270 + from = (u8 *)KSEG0ADDR(BCMA_FLASH2 + offset);
275 + for (i = 0; i < cnt; i++) {
284 + *(u32 *)to = readl(from);
293 +/* Poll for command completion. Returns zero when complete. */
294 +int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset)
296 + if (offset >= cc->sflash.size)
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);
316 +static int sflash_st_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
319 + struct bcma_bus *bus = cc->core->bus;
321 + bool is4712b0 = (bus->chipinfo.id == 0x4712) && (bus->chipinfo.rev == 3);
325 + /* Enable writes */
326 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
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);
338 + if ((offset & 255) == 0) {
339 + /* Page boundary, drop cs and return */
340 + bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
342 + if (!bcma_sflash_poll(cc, offset)) {
343 + /* Flash rejected command */
348 + /* Write single byte */
349 + bcma_sflash_cmd(cc, *buf++);
355 + /* All done, drop cs */
356 + bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
358 + if (!bcma_sflash_poll(cc, offset)) {
359 + /* Flash rejected command */
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);
372 + if ((offset & 255) == 0) {
373 + /* Page boundary, poll droping cs and return */
374 + bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
376 + if (!bcma_sflash_poll(cc, offset)) {
377 + /* Flash rejected command */
382 + /* Write single byte */
383 + bcma_sflash_cmd(cc,
384 + BCMA_CC_FLASHCTL_ST_CSA |
391 + /* All done, drop cs & poll */
392 + bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
394 + if (!bcma_sflash_poll(cc, offset)) {
395 + /* Flash rejected command */
400 + bcma_sflash_write_u8(cc, offset, *buf);
402 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
407 +static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
410 + struct bcma_sflash *sfl = &cc->sflash;
411 + u32 page, byte, mask;
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)) {
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)) {
426 + BUG_ON(!bcma_sflash_poll(cc, offset));
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);
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);
441 +/* Write len bytes starting at offset into buf. Returns number of bytes
442 + * written. Caller should poll for completion.
444 +int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
447 + struct bcma_sflash *sfl;
448 + int ret = 0, tries = NUM_RETRIES;
453 + if ((offset + len) > cc->sflash.size)
457 + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
458 + case BCMA_CC_FLASHT_STSER:
460 + ret = sflash_st_write(cc, offset, len, buf);
462 + } while (ret == -EAGAIN && tries > 0);
464 + if (ret == -EAGAIN && tries == 0) {
465 + pr_info("ST Flash rejected write\n");
469 + case BCMA_CC_FLASHT_ATSER:
470 + ret = sflash_at_write(cc, offset, len, buf);
477 +/* Erase a region. Returns number of bytes scheduled for erasure.
478 + * Caller should poll for completion.
480 +int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset)
482 + struct bcma_sflash *sfl;
484 + if (offset >= cc->sflash.size)
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
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;
508 + * writes the appropriate range of flash, a NULL buf simply erases
509 + * the region of flash
511 +int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
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;
520 + /* Check address range */
525 + if ((offset + len) > sfl->size)
528 + blocksize = sfl->blocksize;
529 + mask = blocksize - 1;
531 + /* Allocate a block of mem */
532 + block = kmalloc(blocksize, GFP_KERNEL);
538 + cur_offset = offset & ~mask;
539 + cur_length = blocksize;
542 + remainder = blocksize - (offset & mask);
543 + if (len < remainder)
546 + cur_retlen = remainder;
548 + /* buf == NULL means erase only */
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;
556 + /* Copy entire block */
558 + copied = bcma_sflash_read(cc,
561 + blk_offset += copied;
567 + /* Copy input data into holding block */
568 + memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
572 + ret = bcma_sflash_erase(cc, cur_offset);
576 + while (bcma_sflash_poll(cc, cur_offset));
578 + /* buf == NULL means erase only */
580 + offset += cur_retlen;
585 + /* Write holding block */
586 + while (cur_length > 0) {
587 + bytes = bcma_sflash_write(cc, cur_offset,
588 + cur_length, cur_ptr);
595 + while (bcma_sflash_poll(cc, cur_offset))
598 + cur_offset += bytes;
599 + cur_length -= bytes;
603 + offset += cur_retlen;
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);
625 + pr_info("serial flash not supported.\n");
626 +#endif /* CONFIG_BCMA_SFLASH */
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 {
640 @@ -383,6 +384,14 @@ struct bcma_pflash {
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 */
650 +#endif /* CONFIG_BCMA_SFLASH */
652 struct bcma_serial_port {
654 unsigned long clockspeed;
655 @@ -405,6 +414,9 @@ struct bcma_drv_cc {
656 enum bcma_flash_type flash_type;
658 struct bcma_pflash pflash;
659 +#ifdef CONFIG_BCMA_SFLASH
660 + struct bcma_sflash sflash;
661 +#endif /* CONFIG_BCMA_SFLASH */
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);
669 +#ifdef CONFIG_BCMA_SFLASH
670 +/* Chipcommon sflash support. */
671 +int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
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,
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,
679 +#endif /* CONFIG_BCMA_SFLASH */
681 #endif /* LINUX_BCMA_DRIVER_CC_H_ */