diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2013-05-22 08:39:02 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2013-08-30 16:52:20 -0400 |
commit | 13134f48c8a7a9daaef74118d19f2d2ef29cd33a (patch) | |
tree | 2c7af124f82de753a52acfe799e698ec56639e52 /drivers/mtd | |
parent | c0fcbc56d93220c772a524e49ed2612fe5787a98 (diff) |
mtd: bcm47xxsflash: writing support
Tested with BCM4706.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/devices/bcm47xxsflash.c | 130 |
1 files changed, 126 insertions, 4 deletions
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 534cb741b107..77de29bc02ba 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c | |||
@@ -116,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
116 | return len; | 116 | return len; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, | ||
120 | const u_char *buf) | ||
121 | { | ||
122 | struct bcm47xxsflash *b47s = mtd->priv; | ||
123 | int written = 0; | ||
124 | |||
125 | /* Enable writes */ | ||
126 | bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); | ||
127 | |||
128 | /* Write first byte */ | ||
129 | b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset); | ||
130 | b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); | ||
131 | |||
132 | /* Program page */ | ||
133 | if (b47s->bcma_cc->core->id.rev < 20) { | ||
134 | bcm47xxsflash_cmd(b47s, OPCODE_ST_PP); | ||
135 | return 1; /* 1B written */ | ||
136 | } | ||
137 | |||
138 | /* Program page and set CSA (on newer chips we can continue writing) */ | ||
139 | bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP); | ||
140 | offset++; | ||
141 | len--; | ||
142 | written++; | ||
143 | |||
144 | while (len > 0) { | ||
145 | /* Page boundary, another function call is needed */ | ||
146 | if ((offset & 0xFF) == 0) | ||
147 | break; | ||
148 | |||
149 | bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++); | ||
150 | offset++; | ||
151 | len--; | ||
152 | written++; | ||
153 | } | ||
154 | |||
155 | /* All done, drop CSA & poll */ | ||
156 | b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0); | ||
157 | udelay(1); | ||
158 | if (bcm47xxsflash_poll(b47s, HZ / 10)) | ||
159 | pr_err("Flash rejected dropping CSA\n"); | ||
160 | |||
161 | return written; | ||
162 | } | ||
163 | |||
164 | static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len, | ||
165 | const u_char *buf) | ||
166 | { | ||
167 | struct bcm47xxsflash *b47s = mtd->priv; | ||
168 | u32 mask = b47s->blocksize - 1; | ||
169 | u32 page = (offset & ~mask) << 1; | ||
170 | u32 byte = offset & mask; | ||
171 | int written = 0; | ||
172 | |||
173 | /* If we don't overwrite whole page, read it to the buffer first */ | ||
174 | if (byte || (len < b47s->blocksize)) { | ||
175 | int err; | ||
176 | |||
177 | b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); | ||
178 | bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD); | ||
179 | /* 250 us for AT45DB321B */ | ||
180 | err = bcm47xxsflash_poll(b47s, HZ / 1000); | ||
181 | if (err) { | ||
182 | pr_err("Timeout reading page 0x%X info buffer\n", page); | ||
183 | return err; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /* Change buffer content with our data */ | ||
188 | while (len > 0) { | ||
189 | /* Page boundary, another function call is needed */ | ||
190 | if (byte == b47s->blocksize) | ||
191 | break; | ||
192 | |||
193 | b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++); | ||
194 | b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); | ||
195 | bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE); | ||
196 | len--; | ||
197 | written++; | ||
198 | } | ||
199 | |||
200 | /* Program page with the buffer content */ | ||
201 | b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); | ||
202 | bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM); | ||
203 | |||
204 | return written; | ||
205 | } | ||
206 | |||
207 | static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
208 | size_t *retlen, const u_char *buf) | ||
209 | { | ||
210 | struct bcm47xxsflash *b47s = mtd->priv; | ||
211 | int written; | ||
212 | |||
213 | /* Writing functions can return without writing all passed data, for | ||
214 | * example when the hardware is too old or when we git page boundary. | ||
215 | */ | ||
216 | while (len > 0) { | ||
217 | switch (b47s->type) { | ||
218 | case BCM47XXSFLASH_TYPE_ST: | ||
219 | written = bcm47xxsflash_write_st(mtd, to, len, buf); | ||
220 | break; | ||
221 | case BCM47XXSFLASH_TYPE_ATMEL: | ||
222 | written = bcm47xxsflash_write_at(mtd, to, len, buf); | ||
223 | break; | ||
224 | default: | ||
225 | BUG_ON(1); | ||
226 | } | ||
227 | if (written < 0) { | ||
228 | pr_err("Error writing at offset 0x%llX\n", to); | ||
229 | return written; | ||
230 | } | ||
231 | to += (loff_t)written; | ||
232 | len -= written; | ||
233 | *retlen += written; | ||
234 | buf += written; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
119 | static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) | 240 | static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) |
120 | { | 241 | { |
121 | struct mtd_info *mtd = &b47s->mtd; | 242 | struct mtd_info *mtd = &b47s->mtd; |
@@ -123,16 +244,17 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) | |||
123 | mtd->priv = b47s; | 244 | mtd->priv = b47s; |
124 | mtd->name = "bcm47xxsflash"; | 245 | mtd->name = "bcm47xxsflash"; |
125 | mtd->owner = THIS_MODULE; | 246 | mtd->owner = THIS_MODULE; |
126 | mtd->type = MTD_ROM; | ||
127 | 247 | ||
128 | /* TODO: implement writing support and verify/change following code */ | 248 | mtd->type = MTD_NORFLASH; |
129 | mtd->flags = MTD_CAP_ROM; | 249 | mtd->flags = MTD_CAP_NORFLASH; |
130 | mtd->size = b47s->size; | 250 | mtd->size = b47s->size; |
131 | mtd->erasesize = b47s->blocksize; | 251 | mtd->erasesize = b47s->blocksize; |
132 | mtd->writebufsize = mtd->writesize = 1; | 252 | mtd->writesize = 1; |
253 | mtd->writebufsize = 1; | ||
133 | 254 | ||
134 | mtd->_erase = bcm47xxsflash_erase; | 255 | mtd->_erase = bcm47xxsflash_erase; |
135 | mtd->_read = bcm47xxsflash_read; | 256 | mtd->_read = bcm47xxsflash_read; |
257 | mtd->_write = bcm47xxsflash_write; | ||
136 | } | 258 | } |
137 | 259 | ||
138 | /************************************************** | 260 | /************************************************** |