mtd: bcm47xxnflash: writing support

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
This commit is contained in:
Rafał Miłecki 2012-12-03 10:22:35 +01:00 committed by Artem Bityutskiy
parent d8b1e34e24
commit ecfe57b796
2 changed files with 79 additions and 3 deletions

View File

@ -461,13 +461,12 @@ config MTD_NAND_GPMI_NAND
the GPMI.
config MTD_NAND_BCM47XXNFLASH
tristate "R/O support for NAND flash on BCMA bus"
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only read mode for BCM4706 is
implemented.
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"

View File

@ -25,6 +25,7 @@
#define NCTL_CMD0 0x00010000
#define NCTL_CMD1W 0x00080000
#define NCTL_READ 0x00100000
#define NCTL_WRITE 0x00200000
#define NCTL_SPECADDR 0x01000000
#define NCTL_READY 0x04000000
#define NCTL_ERR 0x08000000
@ -132,6 +133,36 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
}
}
static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
const u32 *data = (u32 *)buf;
int i;
BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
/* Don't validate column using nand_chip->page_shift, it may be bigger
* when accessing OOB */
for (i = 0; i < len; i += 4, data++) {
bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
if (i == len - 4) /* Last read goes without that */
ctlcode &= ~NCTL_CSA;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
pr_err("%s ctl_cmd didn't work!\n", __func__);
return;
}
}
b47n->curr_column += len;
}
/**************************************************
* NAND chip ops
**************************************************/
@ -208,6 +239,36 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
if (page_addr != -1)
b47n->curr_column += mtd->writesize;
break;
case NAND_CMD_ERASE1:
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr);
ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 |
NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("ERASE1 failed\n");
break;
case NAND_CMD_ERASE2:
break;
case NAND_CMD_SEQIN:
/* Set page and column */
bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
b47n->curr_column);
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr);
/* Prepare to write */
ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000;
ctlcode |= NAND_CMD_SEQIN;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("SEQIN failed\n");
break;
case NAND_CMD_PAGEPROG:
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 |
NAND_CMD_PAGEPROG))
pr_err("PAGEPROG failed\n");
if (bcm47xxnflash_ops_bcm4706_poll(cc))
pr_err("PAGEPROG not ready\n");
break;
default:
pr_err("Command 0x%X unsupported\n", command);
break;
@ -259,6 +320,21 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
}
static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
switch (b47n->curr_command) {
case NAND_CMD_SEQIN:
bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
return;
}
pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
}
/**************************************************
* Init
**************************************************/
@ -278,6 +354,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */