Commit ecfe57b796d4ccec7ea53783ca18a0ad48ad880b
Committed by
Artem Bityutskiy
1 parent
d8b1e34e24
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
mtd: bcm47xxnflash: writing support
Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Showing 2 changed files with 79 additions and 3 deletions Side-by-side Diff
drivers/mtd/nand/Kconfig
... | ... | @@ -461,13 +461,12 @@ |
461 | 461 | the GPMI. |
462 | 462 | |
463 | 463 | config MTD_NAND_BCM47XXNFLASH |
464 | - tristate "R/O support for NAND flash on BCMA bus" | |
464 | + tristate "Support for NAND flash on BCM4706 BCMA bus" | |
465 | 465 | depends on BCMA_NFLASH |
466 | 466 | help |
467 | 467 | BCMA bus can have various flash memories attached, they are |
468 | 468 | registered by bcma as platform devices. This enables driver for |
469 | - NAND flash memories. For now only read mode for BCM4706 is | |
470 | - implemented. | |
469 | + NAND flash memories. For now only BCM4706 is supported. | |
471 | 470 | |
472 | 471 | config MTD_NAND_PLATFORM |
473 | 472 | tristate "Support for generic platform NAND driver" |
drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | #define NCTL_CMD0 0x00010000 |
26 | 26 | #define NCTL_CMD1W 0x00080000 |
27 | 27 | #define NCTL_READ 0x00100000 |
28 | +#define NCTL_WRITE 0x00200000 | |
28 | 29 | #define NCTL_SPECADDR 0x01000000 |
29 | 30 | #define NCTL_READY 0x04000000 |
30 | 31 | #define NCTL_ERR 0x08000000 |
... | ... | @@ -132,6 +133,36 @@ |
132 | 133 | } |
133 | 134 | } |
134 | 135 | |
136 | +static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, | |
137 | + const uint8_t *buf, int len) | |
138 | +{ | |
139 | + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | |
140 | + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | |
141 | + struct bcma_drv_cc *cc = b47n->cc; | |
142 | + | |
143 | + u32 ctlcode; | |
144 | + const u32 *data = (u32 *)buf; | |
145 | + int i; | |
146 | + | |
147 | + BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); | |
148 | + /* Don't validate column using nand_chip->page_shift, it may be bigger | |
149 | + * when accessing OOB */ | |
150 | + | |
151 | + for (i = 0; i < len; i += 4, data++) { | |
152 | + bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data); | |
153 | + | |
154 | + ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE; | |
155 | + if (i == len - 4) /* Last read goes without that */ | |
156 | + ctlcode &= ~NCTL_CSA; | |
157 | + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) { | |
158 | + pr_err("%s ctl_cmd didn't work!\n", __func__); | |
159 | + return; | |
160 | + } | |
161 | + } | |
162 | + | |
163 | + b47n->curr_column += len; | |
164 | +} | |
165 | + | |
135 | 166 | /************************************************** |
136 | 167 | * NAND chip ops |
137 | 168 | **************************************************/ |
... | ... | @@ -208,6 +239,36 @@ |
208 | 239 | if (page_addr != -1) |
209 | 240 | b47n->curr_column += mtd->writesize; |
210 | 241 | break; |
242 | + case NAND_CMD_ERASE1: | |
243 | + bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, | |
244 | + b47n->curr_page_addr); | |
245 | + ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | | |
246 | + NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); | |
247 | + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) | |
248 | + pr_err("ERASE1 failed\n"); | |
249 | + break; | |
250 | + case NAND_CMD_ERASE2: | |
251 | + break; | |
252 | + case NAND_CMD_SEQIN: | |
253 | + /* Set page and column */ | |
254 | + bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR, | |
255 | + b47n->curr_column); | |
256 | + bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, | |
257 | + b47n->curr_page_addr); | |
258 | + | |
259 | + /* Prepare to write */ | |
260 | + ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; | |
261 | + ctlcode |= NAND_CMD_SEQIN; | |
262 | + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) | |
263 | + pr_err("SEQIN failed\n"); | |
264 | + break; | |
265 | + case NAND_CMD_PAGEPROG: | |
266 | + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | | |
267 | + NAND_CMD_PAGEPROG)) | |
268 | + pr_err("PAGEPROG failed\n"); | |
269 | + if (bcm47xxnflash_ops_bcm4706_poll(cc)) | |
270 | + pr_err("PAGEPROG not ready\n"); | |
271 | + break; | |
211 | 272 | default: |
212 | 273 | pr_err("Command 0x%X unsupported\n", command); |
213 | 274 | break; |
... | ... | @@ -259,6 +320,21 @@ |
259 | 320 | pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); |
260 | 321 | } |
261 | 322 | |
323 | +static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, | |
324 | + const uint8_t *buf, int len) | |
325 | +{ | |
326 | + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | |
327 | + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | |
328 | + | |
329 | + switch (b47n->curr_command) { | |
330 | + case NAND_CMD_SEQIN: | |
331 | + bcm47xxnflash_ops_bcm4706_write(mtd, buf, len); | |
332 | + return; | |
333 | + } | |
334 | + | |
335 | + pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command); | |
336 | +} | |
337 | + | |
262 | 338 | /************************************************** |
263 | 339 | * Init |
264 | 340 | **************************************************/ |
... | ... | @@ -278,6 +354,7 @@ |
278 | 354 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; |
279 | 355 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; |
280 | 356 | b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; |
357 | + b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; | |
281 | 358 | b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; |
282 | 359 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ |
283 | 360 |