Root/target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch

1--- a/drivers/bcma/Kconfig
2+++ b/drivers/bcma/Kconfig
3@@ -38,6 +38,11 @@ config BCMA_HOST_SOC
4     bool
5     depends on BCMA_DRIVER_MIPS
6 
7+config BCMA_SFLASH
8+ bool
9+ depends on BCMA_DRIVER_MIPS
10+ default y
11+
12 config BCMA_DRIVER_MIPS
13     bool "BCMA Broadcom MIPS core driver"
14     depends on BCMA && MIPS
15--- a/drivers/bcma/Makefile
16+++ b/drivers/bcma/Makefile
17@@ -1,5 +1,6 @@
18 bcma-y += main.o scan.o core.o sprom.o
19 bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
20+bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
21 bcma-y += driver_pci.o
22 bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
23 bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
24--- a/drivers/bcma/bcma_private.h
25+++ b/drivers/bcma/bcma_private.h
26@@ -51,6 +51,11 @@ void bcma_chipco_serial_init(struct bcma
27 u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
28 u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
29 
30+#ifdef CONFIG_BCMA_SFLASH
31+/* driver_chipcommon_sflash.c */
32+int bcma_sflash_init(struct bcma_drv_cc *cc);
33+#endif /* CONFIG_BCMA_SFLASH */
34+
35 #ifdef CONFIG_BCMA_HOST_PCI
36 /* host_pci.c */
37 extern int __init bcma_host_pci_init(void);
38--- /dev/null
39+++ b/drivers/bcma/driver_chipcommon_sflash.c
40@@ -0,0 +1,398 @@
41+/*
42+ * Broadcom SiliconBackplane chipcommon serial flash interface
43+ *
44+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
45+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
46+ * Copyright 2010, Broadcom Corporation
47+ *
48+ * Licensed under the GNU/GPL. See COPYING for details.
49+ */
50+
51+#include <linux/bcma/bcma.h>
52+#include <linux/bcma/bcma_driver_chipcommon.h>
53+#include <linux/delay.h>
54+
55+#include "bcma_private.h"
56+
57+#define NUM_RETRIES 3
58+
59+
60+/* Issue a serial flash command */
61+static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
62+{
63+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
64+ BCMA_CC_FLASHCTL_START | opcode);
65+ while (bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & BCMA_CC_FLASHCTL_BUSY)
66+ ;
67+}
68+
69+
70+static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
71+ u32 offset, u8 byte)
72+{
73+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
74+ bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
75+}
76+
77+/* Initialize serial flash access */
78+int bcma_sflash_init(struct bcma_drv_cc *cc)
79+{
80+ u32 id, id2;
81+
82+ memset(&cc->sflash, 0, sizeof(struct bcma_sflash));
83+
84+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
85+ case BCMA_CC_FLASHT_STSER:
86+ /* Probe for ST chips */
87+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
88+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
89+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
90+ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
91+ cc->sflash.blocksize = 64 * 1024;
92+ switch (id) {
93+ case 0x11:
94+ /* ST M25P20 2 Mbit Serial Flash */
95+ cc->sflash.numblocks = 4;
96+ break;
97+ case 0x12:
98+ /* ST M25P40 4 Mbit Serial Flash */
99+ cc->sflash.numblocks = 8;
100+ break;
101+ case 0x13:
102+ /* ST M25P80 8 Mbit Serial Flash */
103+ cc->sflash.numblocks = 16;
104+ break;
105+ case 0x14:
106+ /* ST M25P16 16 Mbit Serial Flash */
107+ cc->sflash.numblocks = 32;
108+ break;
109+ case 0x15:
110+ /* ST M25P32 32 Mbit Serial Flash */
111+ cc->sflash.numblocks = 64;
112+ break;
113+ case 0x16:
114+ /* ST M25P64 64 Mbit Serial Flash */
115+ cc->sflash.numblocks = 128;
116+ break;
117+ case 0x17:
118+ /* ST M25FL128 128 Mbit Serial Flash */
119+ cc->sflash.numblocks = 256;
120+ break;
121+ case 0xbf:
122+ /* All of the following flashes are SST with
123+ * 4KB subsectors. Others should be added but
124+ * We'll have to revamp the way we identify them
125+ * since RES is not eough to disambiguate them.
126+ */
127+ cc->sflash.blocksize = 4 * 1024;
128+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
129+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
130+ id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
131+ switch (id2) {
132+ case 1:
133+ /* SST25WF512 512 Kbit Serial Flash */
134+ case 0x48:
135+ /* SST25VF512 512 Kbit Serial Flash */
136+ cc->sflash.numblocks = 16;
137+ break;
138+ case 2:
139+ /* SST25WF010 1 Mbit Serial Flash */
140+ case 0x49:
141+ /* SST25VF010 1 Mbit Serial Flash */
142+ cc->sflash.numblocks = 32;
143+ break;
144+ case 3:
145+ /* SST25WF020 2 Mbit Serial Flash */
146+ case 0x43:
147+ /* SST25VF020 2 Mbit Serial Flash */
148+ cc->sflash.numblocks = 64;
149+ break;
150+ case 4:
151+ /* SST25WF040 4 Mbit Serial Flash */
152+ case 0x44:
153+ /* SST25VF040 4 Mbit Serial Flash */
154+ case 0x8d:
155+ /* SST25VF040B 4 Mbit Serial Flash */
156+ cc->sflash.numblocks = 128;
157+ break;
158+ case 5:
159+ /* SST25WF080 8 Mbit Serial Flash */
160+ case 0x8e:
161+ /* SST25VF080B 8 Mbit Serial Flash */
162+ cc->sflash.numblocks = 256;
163+ break;
164+ case 0x41:
165+ /* SST25VF016 16 Mbit Serial Flash */
166+ cc->sflash.numblocks = 512;
167+ break;
168+ case 0x4a:
169+ /* SST25VF032 32 Mbit Serial Flash */
170+ cc->sflash.numblocks = 1024;
171+ break;
172+ case 0x4b:
173+ /* SST25VF064 64 Mbit Serial Flash */
174+ cc->sflash.numblocks = 2048;
175+ break;
176+ }
177+ break;
178+ }
179+ break;
180+
181+ case BCMA_CC_FLASHT_ATSER:
182+ /* Probe for Atmel chips */
183+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
184+ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
185+ switch (id) {
186+ case 0xc:
187+ /* Atmel AT45DB011 1Mbit Serial Flash */
188+ cc->sflash.blocksize = 256;
189+ cc->sflash.numblocks = 512;
190+ break;
191+ case 0x14:
192+ /* Atmel AT45DB021 2Mbit Serial Flash */
193+ cc->sflash.blocksize = 256;
194+ cc->sflash.numblocks = 1024;
195+ break;
196+ case 0x1c:
197+ /* Atmel AT45DB041 4Mbit Serial Flash */
198+ cc->sflash.blocksize = 256;
199+ cc->sflash.numblocks = 2048;
200+ break;
201+ case 0x24:
202+ /* Atmel AT45DB081 8Mbit Serial Flash */
203+ cc->sflash.blocksize = 256;
204+ cc->sflash.numblocks = 4096;
205+ break;
206+ case 0x2c:
207+ /* Atmel AT45DB161 16Mbit Serial Flash */
208+ cc->sflash.blocksize = 512;
209+ cc->sflash.numblocks = 4096;
210+ break;
211+ case 0x34:
212+ /* Atmel AT45DB321 32Mbit Serial Flash */
213+ cc->sflash.blocksize = 512;
214+ cc->sflash.numblocks = 8192;
215+ break;
216+ case 0x3c:
217+ /* Atmel AT45DB642 64Mbit Serial Flash */
218+ cc->sflash.blocksize = 1024;
219+ cc->sflash.numblocks = 8192;
220+ break;
221+ }
222+ break;
223+ }
224+
225+ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
226+
227+ return cc->sflash.size ? 0 : -ENODEV;
228+}
229+
230+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
231+int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf)
232+{
233+ u8 *from, *to;
234+ u32 cnt, i;
235+
236+ if (!len)
237+ return 0;
238+
239+ if ((offset + len) > cc->sflash.size)
240+ return -EINVAL;
241+
242+ if ((len >= 4) && (offset & 3))
243+ cnt = 4 - (offset & 3);
244+ else if ((len >= 4) && ((u32)buf & 3))
245+ cnt = 4 - ((u32)buf & 3);
246+ else
247+ cnt = len;
248+
249+ from = (u8 *)KSEG0ADDR(BCMA_FLASH2 + offset);
250+
251+ to = (u8 *)buf;
252+
253+ if (cnt < 4) {
254+ for (i = 0; i < cnt; i++) {
255+ *to = readb(from);
256+ from++;
257+ to++;
258+ }
259+ return cnt;
260+ }
261+
262+ while (cnt >= 4) {
263+ *(u32 *)to = readl(from);
264+ from += 4;
265+ to += 4;
266+ cnt -= 4;
267+ }
268+
269+ return len - cnt;
270+}
271+
272+/* Poll for command completion. Returns zero when complete. */
273+int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset)
274+{
275+ if (offset >= cc->sflash.size)
276+ return -22;
277+
278+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
279+ case BCMA_CC_FLASHT_STSER:
280+ /* Check for ST Write In Progress bit */
281+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
282+ return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
283+ & BCMA_CC_FLASHDATA_ST_WIP;
284+ case BCMA_CC_FLASHT_ATSER:
285+ /* Check for Atmel Ready bit */
286+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
287+ return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
288+ & BCMA_CC_FLASHDATA_AT_READY);
289+ }
290+
291+ return 0;
292+}
293+
294+
295+static int sflash_st_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
296+ const u8 *buf)
297+{
298+ int written = 1;
299+
300+ /* Enable writes */
301+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
302+ bcma_sflash_write_u8(cc, offset, *buf++);
303+ /* Issue a page program with CSA bit set */
304+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_CSA | BCMA_CC_FLASHCTL_ST_PP);
305+ offset++;
306+ len--;
307+ while (len > 0) {
308+ if ((offset & 255) == 0) {
309+ /* Page boundary, poll droping cs and return */
310+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
311+ udelay(1);
312+ if (!bcma_sflash_poll(cc, offset)) {
313+ /* Flash rejected command */
314+ return -EAGAIN;
315+ }
316+ return written;
317+ } else {
318+ /* Write single byte */
319+ bcma_sflash_cmd(cc,
320+ BCMA_CC_FLASHCTL_ST_CSA |
321+ *buf++);
322+ }
323+ written++;
324+ offset++;
325+ len--;
326+ }
327+ /* All done, drop cs & poll */
328+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
329+ udelay(1);
330+ if (!bcma_sflash_poll(cc, offset)) {
331+ /* Flash rejected command */
332+ return -EAGAIN;
333+ }
334+ return written;
335+}
336+
337+static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
338+ const u8 *buf)
339+{
340+ struct bcma_sflash *sfl = &cc->sflash;
341+ u32 page, byte, mask;
342+ int ret = 0;
343+
344+ mask = sfl->blocksize - 1;
345+ page = (offset & ~mask) << 1;
346+ byte = offset & mask;
347+ /* Read main memory page into buffer 1 */
348+ if (byte || (len < sfl->blocksize)) {
349+ int i = 100;
350+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
351+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
352+ /* 250 us for AT45DB321B */
353+ while (i > 0 && bcma_sflash_poll(cc, offset)) {
354+ udelay(10);
355+ i--;
356+ }
357+ BUG_ON(!bcma_sflash_poll(cc, offset));
358+ }
359+ /* Write into buffer 1 */
360+ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
361+ bcma_sflash_write_u8(cc, byte++, *buf++);
362+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
363+ }
364+ /* Write buffer 1 into main memory page */
365+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
366+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
367+
368+ return ret;
369+}
370+
371+/* Write len bytes starting at offset into buf. Returns number of bytes
372+ * written. Caller should poll for completion.
373+ */
374+int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
375+ const u8 *buf)
376+{
377+ struct bcma_sflash *sfl;
378+ int ret = 0, tries = NUM_RETRIES;
379+
380+ if (!len)
381+ return 0;
382+
383+ if ((offset + len) > cc->sflash.size)
384+ return -EINVAL;
385+
386+ sfl = &cc->sflash;
387+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
388+ case BCMA_CC_FLASHT_STSER:
389+ do {
390+ ret = sflash_st_write(cc, offset, len, buf);
391+ tries--;
392+ } while (ret == -EAGAIN && tries > 0);
393+
394+ if (ret == -EAGAIN && tries == 0) {
395+ bcma_info(cc->core->bus, "ST Flash rejected write\n");
396+ ret = -EIO;
397+ }
398+ break;
399+ case BCMA_CC_FLASHT_ATSER:
400+ ret = sflash_at_write(cc, offset, len, buf);
401+ break;
402+ }
403+
404+ return ret;
405+}
406+
407+/* Erase a region. Returns number of bytes scheduled for erasure.
408+ * Caller should poll for completion.
409+ */
410+int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset)
411+{
412+ struct bcma_sflash *sfl;
413+
414+ if (offset >= cc->sflash.size)
415+ return -EINVAL;
416+
417+ sfl = &cc->sflash;
418+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
419+ case BCMA_CC_FLASHT_STSER:
420+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
421+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
422+ /* Newer flashes have "sub-sectors" which can be erased independently
423+ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
424+ * before.
425+ */
426+ if (sfl->blocksize < (64 * 1024))
427+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SSE);
428+ else
429+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SE);
430+ return sfl->blocksize;
431+ case BCMA_CC_FLASHT_ATSER:
432+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
433+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
434+ return sfl->blocksize;
435+ }
436+
437+ return 0;
438+}
439--- a/drivers/bcma/driver_mips.c
440+++ b/drivers/bcma/driver_mips.c
441@@ -185,7 +185,13 @@ static void bcma_core_mips_flash_detect(
442     switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
443     case BCMA_CC_FLASHT_STSER:
444     case BCMA_CC_FLASHT_ATSER:
445- bcma_err(bus, "Serial flash not supported.\n");
446+#ifdef CONFIG_BCMA_SFLASH
447+ bcma_info(bus, "found serial flash.\n");
448+ bus->drv_cc.flash_type = BCMA_SFLASH;
449+ bcma_sflash_init(&bus->drv_cc);
450+#else
451+ bcma_info(bus, "serial flash not supported.\n");
452+#endif /* CONFIG_BCMA_SFLASH */
453         break;
454     case BCMA_CC_FLASHT_PARA:
455         bcma_info(bus, "found parallel flash.\n");
456--- a/include/linux/bcma/bcma_driver_chipcommon.h
457+++ b/include/linux/bcma/bcma_driver_chipcommon.h
458@@ -435,6 +435,7 @@ struct bcma_chipcommon_pmu {
459 #ifdef CONFIG_BCMA_DRIVER_MIPS
460 enum bcma_flash_type {
461     BCMA_PFLASH,
462+ BCMA_SFLASH,
463 };
464 
465 struct bcma_pflash {
466@@ -443,6 +444,14 @@ struct bcma_pflash {
467     u32 window_size;
468 };
469 
470+#ifdef CONFIG_BCMA_SFLASH
471+struct bcma_sflash {
472+ u32 blocksize; /* Block size */
473+ u32 numblocks; /* Number of blocks */
474+ u32 size; /* Total size in bytes */
475+};
476+#endif /* CONFIG_BCMA_SFLASH */
477+
478 struct bcma_serial_port {
479     void *regs;
480     unsigned long clockspeed;
481@@ -465,6 +474,9 @@ struct bcma_drv_cc {
482     enum bcma_flash_type flash_type;
483     union {
484         struct bcma_pflash pflash;
485+#ifdef CONFIG_BCMA_SFLASH
486+ struct bcma_sflash sflash;
487+#endif /* CONFIG_BCMA_SFLASH */
488     };
489 
490     int nr_serial_ports;
491@@ -520,4 +532,14 @@ extern void bcma_chipco_regctl_maskset(s
492                        u32 offset, u32 mask, u32 set);
493 extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
494 
495+#ifdef CONFIG_BCMA_SFLASH
496+/* Chipcommon sflash support. */
497+int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
498+ u8 *buf);
499+int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset);
500+int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
501+ const u8 *buf);
502+int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
503+#endif /* CONFIG_BCMA_SFLASH */
504+
505 #endif /* LINUX_BCMA_DRIVER_CC_H_ */
506

Archive Download this file



interactive