kernel: b53: add support for GPIO reset
[openwrt/svn-archive/archive.git] / target / linux / brcm47xx / patches-3.9 / 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,6 +1,9 @@
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 @@ -8,7 +11,11 @@
14 #include "bcma_private.h"
15
16 #include <linux/platform_device.h>
17 +#include <linux/delay.h>
18 #include <linux/bcma/bcma.h>
19 +#include <linux/bcma/bcma_driver_chipcommon.h>
20 +
21 +#define NUM_RETRIES 3
22
23 static struct resource bcma_sflash_resource = {
24 .name = "bcma_sflash",
25 @@ -18,7 +25,7 @@ static struct resource bcma_sflash_resou
26 };
27
28 struct platform_device bcma_sflash_dev = {
29 - .name = "bcma_sflash",
30 + .name = "bcm47xx-sflash",
31 .resource = &bcma_sflash_resource,
32 .num_resources = 1,
33 };
34 @@ -84,11 +91,185 @@ static void bcma_sflash_cmd(struct bcma_
35 bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
36 }
37
38 +static void bcma_sflash_write_u8(struct bcma_drv_cc *cc, u32 offset, u8 byte)
39 +{
40 + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
41 + bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
42 +}
43 +
44 +/* Poll for command completion. Returns zero when complete. */
45 +static int bcma_sflash_poll(struct bcm47xxsflash *dev, u32 offset)
46 +{
47 + struct bcma_drv_cc *cc = dev->bcc;
48 +
49 + if (offset >= cc->sflash.size)
50 + return -22;
51 +
52 + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
53 + case BCMA_CC_FLASHT_STSER:
54 + /* Check for ST Write In Progress bit */
55 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
56 + return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
57 + & BCMA_CC_FLASHDATA_ST_WIP;
58 + case BCMA_CC_FLASHT_ATSER:
59 + /* Check for Atmel Ready bit */
60 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
61 + return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
62 + & BCMA_CC_FLASHDATA_AT_READY);
63 + }
64 +
65 + return 0;
66 +}
67 +
68 +static int sflash_st_write(struct bcm47xxsflash *dev, u32 offset, u32 len,
69 + const u8 *buf)
70 +{
71 + int written = 1;
72 + struct bcma_drv_cc *cc = dev->bcc;
73 +
74 + /* Enable writes */
75 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
76 + bcma_sflash_write_u8(cc, offset, *buf++);
77 + /* Issue a page program with CSA bit set */
78 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_CSA | BCMA_CC_FLASHCTL_ST_PP);
79 + offset++;
80 + len--;
81 + while (len > 0) {
82 + if ((offset & 255) == 0) {
83 + /* Page boundary, poll droping cs and return */
84 + bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
85 + udelay(1);
86 + if (!bcma_sflash_poll(dev, offset)) {
87 + /* Flash rejected command */
88 + return -EAGAIN;
89 + }
90 + return written;
91 + } else {
92 + /* Write single byte */
93 + bcma_sflash_cmd(cc,
94 + BCMA_CC_FLASHCTL_ST_CSA |
95 + *buf++);
96 + }
97 + written++;
98 + offset++;
99 + len--;
100 + }
101 + /* All done, drop cs & poll */
102 + bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
103 + udelay(1);
104 + if (!bcma_sflash_poll(dev, offset)) {
105 + /* Flash rejected command */
106 + return -EAGAIN;
107 + }
108 + return written;
109 +}
110 +
111 +static int sflash_at_write(struct bcm47xxsflash *dev, u32 offset, u32 len,
112 + const u8 *buf)
113 +{
114 + struct bcma_drv_cc *cc = dev->bcc;
115 + u32 page, byte, mask;
116 + int ret = 0;
117 +
118 + mask = dev->blocksize - 1;
119 + page = (offset & ~mask) << 1;
120 + byte = offset & mask;
121 + /* Read main memory page into buffer 1 */
122 + if (byte || (len < dev->blocksize)) {
123 + int i = 100;
124 + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
125 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
126 + /* 250 us for AT45DB321B */
127 + while (i > 0 && bcma_sflash_poll(dev, offset)) {
128 + udelay(10);
129 + i--;
130 + }
131 + BUG_ON(!bcma_sflash_poll(dev, offset));
132 + }
133 + /* Write into buffer 1 */
134 + for (ret = 0; (ret < (int)len) && (byte < dev->blocksize); ret++) {
135 + bcma_sflash_write_u8(cc, byte++, *buf++);
136 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
137 + }
138 + /* Write buffer 1 into main memory page */
139 + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
140 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
141 +
142 + return ret;
143 +}
144 +
145 +/* Write len bytes starting at offset into buf. Returns number of bytes
146 + * written. Caller should poll for completion.
147 + */
148 +static int bcma_sflash_write(struct bcm47xxsflash *dev, u32 offset, u32 len,
149 + const u8 *buf)
150 +{
151 + int ret = 0, tries = NUM_RETRIES;
152 + struct bcma_drv_cc *cc = dev->bcc;
153 +
154 + if (!len)
155 + return 0;
156 +
157 + if ((offset + len) > cc->sflash.size)
158 + return -EINVAL;
159 +
160 + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
161 + case BCMA_CC_FLASHT_STSER:
162 + do {
163 + ret = sflash_st_write(dev, offset, len, buf);
164 + tries--;
165 + } while (ret == -EAGAIN && tries > 0);
166 +
167 + if (ret == -EAGAIN && tries == 0) {
168 + bcma_info(cc->core->bus, "ST Flash rejected write\n");
169 + ret = -EIO;
170 + }
171 + break;
172 + case BCMA_CC_FLASHT_ATSER:
173 + ret = sflash_at_write(dev, offset, len, buf);
174 + break;
175 + }
176 +
177 + return ret;
178 +}
179 +
180 +/* Erase a region. Returns number of bytes scheduled for erasure.
181 + * Caller should poll for completion.
182 + */
183 +static int bcma_sflash_erase(struct bcm47xxsflash *dev, u32 offset)
184 +{
185 + struct bcma_drv_cc *cc = dev->bcc;
186 +
187 + if (offset >= cc->sflash.size)
188 + return -EINVAL;
189 +
190 + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
191 + case BCMA_CC_FLASHT_STSER:
192 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
193 + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
194 + /* Newer flashes have "sub-sectors" which can be erased independently
195 + * with a new command: ST_SSE. The ST_SE command erases 64KB just as
196 + * before.
197 + */
198 + if (dev->blocksize < (64 * 1024))
199 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SSE);
200 + else
201 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SE);
202 + return dev->blocksize;
203 + case BCMA_CC_FLASHT_ATSER:
204 + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
205 + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
206 + return dev->blocksize;
207 + }
208 +
209 + return 0;
210 +}
211 +
212 /* Initialize serial flash access */
213 int bcma_sflash_init(struct bcma_drv_cc *cc)
214 {
215 struct bcma_bus *bus = cc->core->bus;
216 - struct bcma_sflash *sflash = &cc->sflash;
217 + struct bcm47xxsflash *sflash = &cc->sflash;
218 const struct bcma_sflash_tbl_e *e;
219 u32 id, id2;
220
221 @@ -150,6 +331,11 @@ int bcma_sflash_init(struct bcma_drv_cc
222 sflash->numblocks = e->numblocks;
223 sflash->size = sflash->blocksize * sflash->numblocks;
224 sflash->present = true;
225 + sflash->poll = bcma_sflash_poll;
226 + sflash->write = bcma_sflash_write;
227 + sflash->erase = bcma_sflash_erase;
228 + sflash->type = BCM47XX_SFLASH_BCMA;
229 + sflash->bcc = cc;
230
231 bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
232 e->name, sflash->size / 1024, sflash->blocksize,
233 --- a/include/linux/bcma/bcma_driver_chipcommon.h
234 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
235 @@ -3,6 +3,7 @@
236
237 #include <linux/platform_device.h>
238 #include <linux/gpio.h>
239 +#include <linux/mtd/bcm47xxsflash.h>
240
241 /** ChipCommon core registers. **/
242 #define BCMA_CC_ID 0x0000
243 @@ -578,19 +579,6 @@ struct bcma_pflash {
244 u32 window_size;
245 };
246
247 -#ifdef CONFIG_BCMA_SFLASH
248 -struct bcma_sflash {
249 - bool present;
250 - u32 window;
251 - u32 blocksize;
252 - u16 numblocks;
253 - u32 size;
254 -
255 - struct mtd_info *mtd;
256 - void *priv;
257 -};
258 -#endif
259 -
260 #ifdef CONFIG_BCMA_NFLASH
261 struct mtd_info;
262
263 @@ -624,7 +612,7 @@ struct bcma_drv_cc {
264 #ifdef CONFIG_BCMA_DRIVER_MIPS
265 struct bcma_pflash pflash;
266 #ifdef CONFIG_BCMA_SFLASH
267 - struct bcma_sflash sflash;
268 + struct bcm47xxsflash sflash;
269 #endif
270 #ifdef CONFIG_BCMA_NFLASH
271 struct bcma_nflash nflash;