diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2012-12-03 04:22:35 -0500 |
---|---|---|
committer | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2012-12-10 07:09:49 -0500 |
commit | ecfe57b796d4ccec7ea53783ca18a0ad48ad880b (patch) | |
tree | fcf2967b23a721aa05fe89e2723ba502ddc6ca82 /drivers/mtd | |
parent | d8b1e34e248d89f43bab18704894d537dc0b497e (diff) |
mtd: bcm47xxnflash: writing support
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 5 | ||||
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | 77 |
2 files changed, 79 insertions, 3 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 3314e92120c9..37ffe56e74a4 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -461,13 +461,12 @@ config MTD_NAND_GPMI_NAND | |||
461 | the GPMI. | 461 | the GPMI. |
462 | 462 | ||
463 | config MTD_NAND_BCM47XXNFLASH | 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 | depends on BCMA_NFLASH | 465 | depends on BCMA_NFLASH |
466 | help | 466 | help |
467 | BCMA bus can have various flash memories attached, they are | 467 | BCMA bus can have various flash memories attached, they are |
468 | registered by bcma as platform devices. This enables driver for | 468 | registered by bcma as platform devices. This enables driver for |
469 | NAND flash memories. For now only read mode for BCM4706 is | 469 | NAND flash memories. For now only BCM4706 is supported. |
470 | implemented. | ||
471 | 470 | ||
472 | config MTD_NAND_PLATFORM | 471 | config MTD_NAND_PLATFORM |
473 | tristate "Support for generic platform NAND driver" | 472 | tristate "Support for generic platform NAND driver" |
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index ece343ccc1b0..86c9a79b89b3 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #define NCTL_CMD0 0x00010000 | 25 | #define NCTL_CMD0 0x00010000 |
26 | #define NCTL_CMD1W 0x00080000 | 26 | #define NCTL_CMD1W 0x00080000 |
27 | #define NCTL_READ 0x00100000 | 27 | #define NCTL_READ 0x00100000 |
28 | #define NCTL_WRITE 0x00200000 | ||
28 | #define NCTL_SPECADDR 0x01000000 | 29 | #define NCTL_SPECADDR 0x01000000 |
29 | #define NCTL_READY 0x04000000 | 30 | #define NCTL_READY 0x04000000 |
30 | #define NCTL_ERR 0x08000000 | 31 | #define NCTL_ERR 0x08000000 |
@@ -132,6 +133,36 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, | |||
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 | * NAND chip ops | 167 | * NAND chip ops |
137 | **************************************************/ | 168 | **************************************************/ |
@@ -208,6 +239,36 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, | |||
208 | if (page_addr != -1) | 239 | if (page_addr != -1) |
209 | b47n->curr_column += mtd->writesize; | 240 | b47n->curr_column += mtd->writesize; |
210 | break; | 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 | default: | 272 | default: |
212 | pr_err("Command 0x%X unsupported\n", command); | 273 | pr_err("Command 0x%X unsupported\n", command); |
213 | break; | 274 | break; |
@@ -259,6 +320,21 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, | |||
259 | pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); | 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 | * Init | 339 | * Init |
264 | **************************************************/ | 340 | **************************************************/ |
@@ -278,6 +354,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) | |||
278 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; | 354 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; |
279 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; | 355 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; |
280 | b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; | 356 | b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; |
357 | b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; | ||
281 | b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; | 358 | b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; |
282 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ | 359 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ |
283 | 360 | ||