kernel: update bcma and ssb to master-2012-12-11-2 from wireless-testing
[openwrt/openwrt.git] / target / linux / brcm47xx / patches-3.3 / 071-bcma-add-functions-to-write-to-nand-flash.patch
1 --- a/drivers/bcma/driver_chipcommon_nflash.c
2 +++ b/drivers/bcma/driver_chipcommon_nflash.c
3 @@ -2,16 +2,23 @@
4 * Broadcom specific AMBA
5 * ChipCommon NAND flash interface
6 *
7 + * Copyright 2011, Tathagata Das <tathagata@alumnux.com>
8 + * Copyright 2010, Broadcom Corporation
9 + *
10 * Licensed under the GNU/GPL. See COPYING for details.
11 */
12
13 +#include <linux/delay.h>
14 +#include <linux/mtd/bcm47xx_nand.h>
15 +#include <linux/mtd/nand.h>
16 #include <linux/platform_device.h>
17 #include <linux/bcma/bcma.h>
18 +#include <linux/bcma/bcma_driver_chipcommon.h>
19
20 #include "bcma_private.h"
21
22 struct platform_device bcma_nflash_dev = {
23 - .name = "bcma_nflash",
24 + .name = "bcm47xx-nflash",
25 .num_resources = 0,
26 };
27
28 @@ -31,6 +38,11 @@ int bcma_nflash_init(struct bcma_drv_cc
29 return -ENODEV;
30 }
31
32 + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
33 + bcma_err(bus, "NAND flash support for BCM4706 not implemented\n");
34 + return -ENOTSUPP;
35 + }
36 +
37 cc->nflash.present = true;
38 if (cc->core->id.rev == 38 &&
39 (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
40 @@ -42,3 +54,141 @@ int bcma_nflash_init(struct bcma_drv_cc
41
42 return 0;
43 }
44 +
45 +/* Issue a nand flash command */
46 +static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
47 +{
48 + bcma_cc_write32(cc, NAND_CMD_START, opcode);
49 + bcma_cc_read32(cc, NAND_CMD_START);
50 +}
51 +
52 +/* Check offset and length */
53 +static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, u32 len, u32 mask)
54 +{
55 + if ((offset & mask) != 0 || (len & mask) != 0) {
56 + pr_err("%s(): Address is not aligned. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
57 + return 1;
58 + }
59 +
60 + if ((((offset + len) >> 20) >= cc->nflash.size) &&
61 + (((offset + len) & ((1 << 20) - 1)) != 0)) {
62 + pr_err("%s(): Address is outside Flash memory region. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
63 + return 1;
64 + }
65 +
66 + return 0;
67 +}
68 +
69 +#define NF_RETRIES 1000000
70 +
71 +/* Poll for command completion. Returns zero when complete. */
72 +int bcma_nflash_poll(struct bcma_drv_cc *cc)
73 +{
74 + u32 retries = NF_RETRIES;
75 + u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY;
76 + u32 mask;
77 +
78 + while (retries--) {
79 + mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask;
80 + if (mask == pollmask)
81 + return 0;
82 + cpu_relax();
83 + }
84 +
85 + if (!retries) {
86 + pr_err("bcma_nflash_poll: not ready\n");
87 + return -1;
88 + }
89 +
90 + return 0;
91 +}
92 +
93 +/* Read len bytes starting at offset into buf. Returns number of bytes read. */
94 +int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf)
95 +{
96 + u32 mask;
97 + int i;
98 + u32 *to, val, res;
99 +
100 + mask = NFL_SECTOR_SIZE - 1;
101 + if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
102 + return 0;
103 +
104 + to = (u32 *)buf;
105 + res = len;
106 + while (res > 0) {
107 + bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
108 + bcma_nflash_cmd(cc, NCMD_PAGE_RD);
109 + if (bcma_nflash_poll(cc) < 0)
110 + break;
111 + val = bcma_cc_read32(cc, NAND_INTFC_STATUS);
112 + if ((val & NIST_CACHE_VALID) == 0)
113 + break;
114 + bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
115 + for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
116 + *to = bcma_cc_read32(cc, NAND_CACHE_DATA);
117 + }
118 + res -= NFL_SECTOR_SIZE;
119 + offset += NFL_SECTOR_SIZE;
120 + }
121 + return (len - res);
122 +}
123 +
124 +/* Write len bytes starting at offset into buf. Returns success (0) or failure (!0).
125 + * Should poll for completion.
126 + */
127 +int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
128 + const u8 *buf)
129 +{
130 + u32 mask;
131 + int i;
132 + u32 *from, res, reg;
133 +
134 + mask = cc->nflash.pagesize - 1;
135 + if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
136 + return 1;
137 +
138 + /* disable partial page enable */
139 + reg = bcma_cc_read32(cc, NAND_ACC_CONTROL);
140 + reg &= ~NAC_PARTIAL_PAGE_EN;
141 + bcma_cc_write32(cc, NAND_ACC_CONTROL, reg);
142 +
143 + from = (u32 *)buf;
144 + res = len;
145 + while (res > 0) {
146 + bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
147 + for (i = 0; i < cc->nflash.pagesize; i += 4, from++) {
148 + if (i % 512 == 0)
149 + bcma_cc_write32(cc, NAND_CMD_ADDR, i);
150 + bcma_cc_write32(cc, NAND_CACHE_DATA, *from);
151 + }
152 + bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize - 512);
153 + bcma_nflash_cmd(cc, NCMD_PAGE_PROG);
154 + if (bcma_nflash_poll(cc) < 0)
155 + break;
156 + res -= cc->nflash.pagesize;
157 + offset += cc->nflash.pagesize;
158 + }
159 +
160 + if (res <= 0)
161 + return 0;
162 + else
163 + return (len - res);
164 +}
165 +
166 +/* Erase a region. Returns success (0) or failure (-1).
167 + * Poll for completion.
168 + */
169 +int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset)
170 +{
171 + if ((offset >> 20) >= cc->nflash.size)
172 + return -1;
173 + if ((offset & (cc->nflash.blocksize - 1)) != 0)
174 + return -1;
175 +
176 + bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
177 + bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE);
178 + if (bcma_nflash_poll(cc) < 0)
179 + return -1;
180 + return 0;
181 +}
182 --- a/include/linux/bcma/bcma_driver_chipcommon.h
183 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
184 @@ -4,6 +4,7 @@
185 #include <linux/platform_device.h>
186
187 #include <linux/mtd/bcm47xx_sflash.h>
188 +#include <linux/mtd/bcm47xx_nand.h>
189
190 /** ChipCommon core registers. **/
191 #define BCMA_CC_ID 0x0000
192 @@ -521,17 +522,6 @@ struct bcma_pflash {
193 };
194
195
196 -#ifdef CONFIG_BCMA_NFLASH
197 -struct mtd_info;
198 -
199 -struct bcma_nflash {
200 - bool present;
201 - bool boot; /* This is the flash the SoC boots from */
202 -
203 - struct mtd_info *mtd;
204 -};
205 -#endif
206 -
207 struct bcma_serial_port {
208 void *regs;
209 unsigned long clockspeed;
210 @@ -557,7 +547,7 @@ struct bcma_drv_cc {
211 struct bcm47xx_sflash sflash;
212 #endif
213 #ifdef CONFIG_BCMA_NFLASH
214 - struct bcma_nflash nflash;
215 + struct bcm47xx_nflash nflash;
216 #endif
217
218 int nr_serial_ports;
219 @@ -616,4 +606,13 @@ extern void bcma_chipco_regctl_maskset(s
220 u32 offset, u32 mask, u32 set);
221 extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
222
223 +#ifdef CONFIG_BCMA_NFLASH
224 +/* Chipcommon nflash support. */
225 +int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf);
226 +int bcma_nflash_poll(struct bcma_drv_cc *cc);
227 +int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
228 +int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset);
229 +int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
230 +#endif
231 +
232 #endif /* LINUX_BCMA_DRIVER_CC_H_ */