Root/target/linux/brcm47xx/patches-3.6/070-bcma-add-functions-to-write-to-serial-flash.patch

1--- a/drivers/bcma/driver_chipcommon_sflash.c
2+++ b/drivers/bcma/driver_chipcommon_sflash.c
3@@ -1,15 +1,22 @@
4 /*
5  * Broadcom specific AMBA
6  * ChipCommon serial flash interface
7+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
8+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
9+ * Copyright 2010, Broadcom Corporation
10  *
11  * Licensed under the GNU/GPL. See COPYING for details.
12  */
13 
14 #include <linux/platform_device.h>
15+#include <linux/delay.h>
16 #include <linux/bcma/bcma.h>
17+#include <linux/bcma/bcma_driver_chipcommon.h>
18 
19 #include "bcma_private.h"
20 
21+#define NUM_RETRIES 3
22+
23 static struct resource bcma_sflash_resource = {
24     .name = "bcma_sflash",
25     .start = BCMA_SOC_FLASH2,
26@@ -18,7 +25,7 @@ static struct resource bcma_sflash_resou
27 };
28 
29 struct platform_device bcma_sflash_dev = {
30- .name = "bcma_sflash",
31+ .name = "bcm47xx-sflash",
32     .resource = &bcma_sflash_resource,
33     .num_resources = 1,
34 };
35@@ -30,7 +37,7 @@ struct bcma_sflash_tbl_e {
36     u16 numblocks;
37 };
38 
39-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
40+static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
41     { "M25P20", 0x11, 0x10000, 4, },
42     { "M25P40", 0x12, 0x10000, 8, },
43 
44@@ -41,7 +48,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
45     { 0 },
46 };
47 
48-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
49+static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
50     { "SST25WF512", 1, 0x1000, 16, },
51     { "SST25VF512", 0x48, 0x1000, 16, },
52     { "SST25WF010", 2, 0x1000, 32, },
53@@ -59,7 +66,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
54     { 0 },
55 };
56 
57-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
58+static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
59     { "AT45DB011", 0xc, 256, 512, },
60     { "AT45DB021", 0x14, 256, 1024, },
61     { "AT45DB041", 0x1c, 256, 2048, },
62@@ -84,12 +91,230 @@ static void bcma_sflash_cmd(struct bcma_
63     bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
64 }
65 
66+static void bcma_sflash_write_u8(struct bcma_drv_cc *cc, u32 offset, u8 byte)
67+{
68+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
69+ bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
70+}
71+
72+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
73+static int bcma_sflash_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
74+{
75+ u8 *from, *to;
76+ u32 cnt, i;
77+ struct bcma_drv_cc *cc = dev->bcc;
78+
79+ if (!len)
80+ return 0;
81+
82+ if ((offset + len) > cc->sflash.size)
83+ return -EINVAL;
84+
85+ if ((len >= 4) && (offset & 3))
86+ cnt = 4 - (offset & 3);
87+ else if ((len >= 4) && ((u32)buf & 3))
88+ cnt = 4 - ((u32)buf & 3);
89+ else
90+ cnt = len;
91+
92+ from = (u8 *)KSEG0ADDR(BCMA_SOC_FLASH2 + offset);
93+
94+ to = (u8 *)buf;
95+
96+ if (cnt < 4) {
97+ for (i = 0; i < cnt; i++) {
98+ *to = readb(from);
99+ from++;
100+ to++;
101+ }
102+ return cnt;
103+ }
104+
105+ while (cnt >= 4) {
106+ *(u32 *)to = readl(from);
107+ from += 4;
108+ to += 4;
109+ cnt -= 4;
110+ }
111+
112+ return len - cnt;
113+}
114+
115+/* Poll for command completion. Returns zero when complete. */
116+static int bcma_sflash_poll(struct bcm47xx_sflash *dev, u32 offset)
117+{
118+ struct bcma_drv_cc *cc = dev->bcc;
119+
120+ if (offset >= cc->sflash.size)
121+ return -22;
122+
123+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
124+ case BCMA_CC_FLASHT_STSER:
125+ /* Check for ST Write In Progress bit */
126+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
127+ return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
128+ & BCMA_CC_FLASHDATA_ST_WIP;
129+ case BCMA_CC_FLASHT_ATSER:
130+ /* Check for Atmel Ready bit */
131+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
132+ return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
133+ & BCMA_CC_FLASHDATA_AT_READY);
134+ }
135+
136+ return 0;
137+}
138+
139+
140+static int sflash_st_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
141+ const u8 *buf)
142+{
143+ int written = 1;
144+ struct bcma_drv_cc *cc = dev->bcc;
145+
146+ /* Enable writes */
147+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
148+ bcma_sflash_write_u8(cc, offset, *buf++);
149+ /* Issue a page program with CSA bit set */
150+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_CSA | BCMA_CC_FLASHCTL_ST_PP);
151+ offset++;
152+ len--;
153+ while (len > 0) {
154+ if ((offset & 255) == 0) {
155+ /* Page boundary, poll droping cs and return */
156+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
157+ udelay(1);
158+ if (!bcma_sflash_poll(dev, offset)) {
159+ /* Flash rejected command */
160+ return -EAGAIN;
161+ }
162+ return written;
163+ } else {
164+ /* Write single byte */
165+ bcma_sflash_cmd(cc,
166+ BCMA_CC_FLASHCTL_ST_CSA |
167+ *buf++);
168+ }
169+ written++;
170+ offset++;
171+ len--;
172+ }
173+ /* All done, drop cs & poll */
174+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
175+ udelay(1);
176+ if (!bcma_sflash_poll(dev, offset)) {
177+ /* Flash rejected command */
178+ return -EAGAIN;
179+ }
180+ return written;
181+}
182+
183+static int sflash_at_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
184+ const u8 *buf)
185+{
186+ struct bcma_drv_cc *cc = dev->bcc;
187+ u32 page, byte, mask;
188+ int ret = 0;
189+
190+ mask = dev->blocksize - 1;
191+ page = (offset & ~mask) << 1;
192+ byte = offset & mask;
193+ /* Read main memory page into buffer 1 */
194+ if (byte || (len < dev->blocksize)) {
195+ int i = 100;
196+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
197+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
198+ /* 250 us for AT45DB321B */
199+ while (i > 0 && bcma_sflash_poll(dev, offset)) {
200+ udelay(10);
201+ i--;
202+ }
203+ BUG_ON(!bcma_sflash_poll(dev, offset));
204+ }
205+ /* Write into buffer 1 */
206+ for (ret = 0; (ret < (int)len) && (byte < dev->blocksize); ret++) {
207+ bcma_sflash_write_u8(cc, byte++, *buf++);
208+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
209+ }
210+ /* Write buffer 1 into main memory page */
211+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
212+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
213+
214+ return ret;
215+}
216+
217+/* Write len bytes starting at offset into buf. Returns number of bytes
218+ * written. Caller should poll for completion.
219+ */
220+static int bcma_sflash_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
221+ const u8 *buf)
222+{
223+ int ret = 0, tries = NUM_RETRIES;
224+ struct bcma_drv_cc *cc = dev->bcc;
225+
226+ if (!len)
227+ return 0;
228+
229+ if ((offset + len) > cc->sflash.size)
230+ return -EINVAL;
231+
232+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
233+ case BCMA_CC_FLASHT_STSER:
234+ do {
235+ ret = sflash_st_write(dev, offset, len, buf);
236+ tries--;
237+ } while (ret == -EAGAIN && tries > 0);
238+
239+ if (ret == -EAGAIN && tries == 0) {
240+ bcma_info(cc->core->bus, "ST Flash rejected write\n");
241+ ret = -EIO;
242+ }
243+ break;
244+ case BCMA_CC_FLASHT_ATSER:
245+ ret = sflash_at_write(dev, offset, len, buf);
246+ break;
247+ }
248+
249+ return ret;
250+}
251+
252+/* Erase a region. Returns number of bytes scheduled for erasure.
253+ * Caller should poll for completion.
254+ */
255+static int bcma_sflash_erase(struct bcm47xx_sflash *dev, u32 offset)
256+{
257+ struct bcma_drv_cc *cc = dev->bcc;
258+
259+ if (offset >= cc->sflash.size)
260+ return -EINVAL;
261+
262+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
263+ case BCMA_CC_FLASHT_STSER:
264+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
265+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
266+ /* Newer flashes have "sub-sectors" which can be erased independently
267+ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
268+ * before.
269+ */
270+ if (dev->blocksize < (64 * 1024))
271+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SSE);
272+ else
273+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SE);
274+ return dev->blocksize;
275+ case BCMA_CC_FLASHT_ATSER:
276+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
277+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
278+ return dev->blocksize;
279+ }
280+
281+ return 0;
282+}
283+
284 /* Initialize serial flash access */
285 int bcma_sflash_init(struct bcma_drv_cc *cc)
286 {
287     struct bcma_bus *bus = cc->core->bus;
288- struct bcma_sflash *sflash = &cc->sflash;
289- struct bcma_sflash_tbl_e *e;
290+ struct bcm47xx_sflash *sflash = &cc->sflash;
291+ const struct bcma_sflash_tbl_e *e;
292     u32 id, id2;
293 
294     switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
295@@ -150,6 +375,12 @@ int bcma_sflash_init(struct bcma_drv_cc
296     sflash->numblocks = e->numblocks;
297     sflash->size = sflash->blocksize * sflash->numblocks;
298     sflash->present = true;
299+ sflash->read = bcma_sflash_read;
300+ sflash->poll = bcma_sflash_poll;
301+ sflash->write = bcma_sflash_write;
302+ sflash->erase = bcma_sflash_erase;
303+ sflash->type = BCM47XX_SFLASH_BCMA;
304+ sflash->bcc = cc;
305 
306     bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
307           e->name, sflash->size / 1024, sflash->blocksize,
308--- a/include/linux/bcma/bcma_driver_chipcommon.h
309+++ b/include/linux/bcma/bcma_driver_chipcommon.h
310@@ -3,6 +3,8 @@
311 
312 #include <linux/platform_device.h>
313 
314+#include <linux/mtd/bcm47xx_sflash.h>
315+
316 /** ChipCommon core registers. **/
317 #define BCMA_CC_ID 0x0000
318 #define BCMA_CC_ID_ID 0x0000FFFF
319@@ -518,17 +520,6 @@ struct bcma_pflash {
320     u32 window_size;
321 };
322 
323-#ifdef CONFIG_BCMA_SFLASH
324-struct bcma_sflash {
325- bool present;
326- u32 window;
327- u32 blocksize;
328- u16 numblocks;
329- u32 size;
330-
331- struct mtd_info *mtd;
332-};
333-#endif
334 
335 #ifdef CONFIG_BCMA_NFLASH
336 struct mtd_info;
337@@ -563,7 +554,7 @@ struct bcma_drv_cc {
338 #ifdef CONFIG_BCMA_DRIVER_MIPS
339     struct bcma_pflash pflash;
340 #ifdef CONFIG_BCMA_SFLASH
341- struct bcma_sflash sflash;
342+ struct bcm47xx_sflash sflash;
343 #endif
344 #ifdef CONFIG_BCMA_NFLASH
345     struct bcma_nflash nflash;
346

Archive Download this file



interactive