Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ecfe57b7 authored by Rafał Miłecki's avatar Rafał Miłecki Committed by Artem Bityutskiy
Browse files

mtd: bcm47xxnflash: writing support

parent d8b1e34e
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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"
+77 −0
Original line number Diff line number Diff line
@@ -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 */