mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
mtd: rawnand: brcmnand: read/write oob during EDU transfer
Added support to read/write oob during EDU transfers. Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20210311170909.9031-1-kdasu.kdev@gmail.com
This commit is contained in:
parent
55fbb9ba4f
commit
a071912636
1 changed files with 52 additions and 7 deletions
|
@ -242,6 +242,9 @@ struct brcmnand_controller {
|
|||
u32 edu_ext_addr;
|
||||
u32 edu_cmd;
|
||||
u32 edu_config;
|
||||
int sas; /* spare area size, per flash cache */
|
||||
int sector_size_1k;
|
||||
u8 *oob;
|
||||
|
||||
/* flash_dma reg */
|
||||
const u16 *flash_dma_offsets;
|
||||
|
@ -249,7 +252,7 @@ struct brcmnand_controller {
|
|||
dma_addr_t dma_pa;
|
||||
|
||||
int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf,
|
||||
u32 len, u8 dma_cmd);
|
||||
u8 *oob, u32 len, u8 dma_cmd);
|
||||
|
||||
/* in-memory cache of the FLASH_CACHE, used only for some commands */
|
||||
u8 flash_cache[FC_BYTES];
|
||||
|
@ -1479,6 +1482,23 @@ static irqreturn_t brcmnand_edu_irq(int irq, void *data)
|
|||
edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr);
|
||||
edu_readl(ctrl, EDU_EXT_ADDR);
|
||||
|
||||
if (ctrl->oob) {
|
||||
if (ctrl->edu_cmd == EDU_CMD_READ) {
|
||||
ctrl->oob += read_oob_from_regs(ctrl,
|
||||
ctrl->edu_count + 1,
|
||||
ctrl->oob, ctrl->sas,
|
||||
ctrl->sector_size_1k);
|
||||
} else {
|
||||
brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
|
||||
ctrl->edu_ext_addr);
|
||||
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
|
||||
ctrl->oob += write_oob_to_regs(ctrl,
|
||||
ctrl->edu_count,
|
||||
ctrl->oob, ctrl->sas,
|
||||
ctrl->sector_size_1k);
|
||||
}
|
||||
}
|
||||
|
||||
mb(); /* flush previous writes */
|
||||
edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
|
||||
edu_readl(ctrl, EDU_CMD);
|
||||
|
@ -1850,9 +1870,10 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
|
|||
* Kick EDU engine
|
||||
*/
|
||||
static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
||||
u32 len, u8 cmd)
|
||||
u8 *oob, u32 len, u8 cmd)
|
||||
{
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
struct brcmnand_cfg *cfg = &host->hwcfg;
|
||||
unsigned long timeo = msecs_to_jiffies(200);
|
||||
int ret = 0;
|
||||
int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
|
@ -1860,6 +1881,9 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
|||
unsigned int trans = len >> FC_SHIFT;
|
||||
dma_addr_t pa;
|
||||
|
||||
dev_dbg(ctrl->dev, "EDU %s %p:%p\n", ((edu_cmd == EDU_CMD_READ) ?
|
||||
"read" : "write"), buf, oob);
|
||||
|
||||
pa = dma_map_single(ctrl->dev, buf, len, dir);
|
||||
if (dma_mapping_error(ctrl->dev, pa)) {
|
||||
dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n");
|
||||
|
@ -1871,6 +1895,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
|||
ctrl->edu_ext_addr = addr;
|
||||
ctrl->edu_cmd = edu_cmd;
|
||||
ctrl->edu_count = trans;
|
||||
ctrl->sas = cfg->spare_area_size;
|
||||
ctrl->oob = oob;
|
||||
|
||||
edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr);
|
||||
edu_readl(ctrl, EDU_DRAM_ADDR);
|
||||
|
@ -1879,6 +1905,16 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
|||
edu_writel(ctrl, EDU_LENGTH, FC_BYTES);
|
||||
edu_readl(ctrl, EDU_LENGTH);
|
||||
|
||||
if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_WRITE)) {
|
||||
brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
|
||||
ctrl->edu_ext_addr);
|
||||
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
|
||||
ctrl->oob += write_oob_to_regs(ctrl,
|
||||
1,
|
||||
ctrl->oob, ctrl->sas,
|
||||
ctrl->sector_size_1k);
|
||||
}
|
||||
|
||||
/* Start edu engine */
|
||||
mb(); /* flush previous writes */
|
||||
edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
|
||||
|
@ -1893,6 +1929,14 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
|||
|
||||
dma_unmap_single(ctrl->dev, pa, len, dir);
|
||||
|
||||
/* read last subpage oob */
|
||||
if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_READ)) {
|
||||
ctrl->oob += read_oob_from_regs(ctrl,
|
||||
1,
|
||||
ctrl->oob, ctrl->sas,
|
||||
ctrl->sector_size_1k);
|
||||
}
|
||||
|
||||
/* for program page check NAND status */
|
||||
if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
|
||||
INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) &&
|
||||
|
@ -2002,7 +2046,7 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
|
|||
}
|
||||
|
||||
static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
||||
u32 len, u8 dma_cmd)
|
||||
u8 *oob, u32 len, u8 dma_cmd)
|
||||
{
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
dma_addr_t buf_pa;
|
||||
|
@ -2147,8 +2191,9 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
try_dmaread:
|
||||
brcmnand_clear_ecc_addr(ctrl);
|
||||
|
||||
if (ctrl->dma_trans && !oob && flash_dma_buf_ok(buf)) {
|
||||
err = ctrl->dma_trans(host, addr, buf,
|
||||
if (ctrl->dma_trans && (has_edu(ctrl) || !oob) &&
|
||||
flash_dma_buf_ok(buf)) {
|
||||
err = ctrl->dma_trans(host, addr, buf, oob,
|
||||
trans * FC_BYTES,
|
||||
CMD_PAGE_READ);
|
||||
|
||||
|
@ -2296,8 +2341,8 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
for (i = 0; i < ctrl->max_oob; i += 4)
|
||||
oob_reg_write(ctrl, i, 0xffffffff);
|
||||
|
||||
if (use_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
|
||||
if (ctrl->dma_trans(host, addr, (u32 *)buf, mtd->writesize,
|
||||
if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
|
||||
if (ctrl->dma_trans(host, addr, (u32 *)buf, oob, mtd->writesize,
|
||||
CMD_PROGRAM_PAGE))
|
||||
|
||||
ret = -EIO;
|
||||
|
|
Loading…
Reference in a new issue