Added support to read/write oob during EDU transfers.

Signed-off-by: Kamal Dasu <kdasu.k...@gmail.com>
---
 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 59 +++++++++++++++++++++---
 1 file changed, 52 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c 
b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 659eaa6f0980..1c95b21aa63b 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -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;
-- 
2.17.1

Reply via email to