mtd: rawnand: sunxi: Migrate to ->exec_op()
authorBoris Brezillon <boris.brezillon@bootlin.com>
Sat, 15 Dec 2018 08:24:36 +0000 (09:24 +0100)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Tue, 5 Feb 2019 14:39:39 +0000 (15:39 +0100)
And get rif of all legacy hooks and unused fields.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nand/raw/sunxi_nand.c

index eea64bc3ff1e781bfcf2c78b5f89cc592aefb4f4..f52728f317ea667798163852061aca26db03e0bc 100644 (file)
@@ -183,7 +183,6 @@ struct sunxi_nand_hw_ecc {
  * @mtd:               base MTD structure
  * @clk_rate:          clk_rate required for this NAND chip
  * @timing_cfg         TIMING_CFG register value for this NAND chip
- * @selected:          current active CS
  * @nsels:             number of CS lines required by the NAND chip
  * @sels:              array of CS lines descriptions
  */
@@ -193,11 +192,6 @@ struct sunxi_nand_chip {
        unsigned long clk_rate;
        u32 timing_cfg;
        u32 timing_ctl;
-       int selected;
-       int addr_cycles;
-       u32 addr[2];
-       int cmd_cycles;
-       u8 cmd[2];
        int nsels;
        struct sunxi_nand_chip_sel sels[0];
 };
@@ -386,26 +380,7 @@ static void sunxi_nfc_dma_op_cleanup(struct sunxi_nfc *nfc,
               nfc->regs + NFC_REG_CTL);
 }
 
-static int sunxi_nfc_dev_ready(struct nand_chip *nand)
-{
-       struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-       struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-       u32 mask;
-
-       if (sunxi_nand->selected < 0)
-               return 0;
-
-       if (sunxi_nand->sels[sunxi_nand->selected].rb < 0) {
-               dev_err(nfc->dev, "cannot check R/B NAND status!\n");
-               return 0;
-       }
-
-       mask = NFC_RB_STATE(sunxi_nand->sels[sunxi_nand->selected].rb);
-
-       return !!(readl(nfc->regs + NFC_REG_ST) & mask);
-}
-
-static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip)
+static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
 {
        struct mtd_info *mtd = nand_to_mtd(nand);
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
@@ -413,40 +388,27 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip)
        struct sunxi_nand_chip_sel *sel;
        u32 ctl;
 
-       if (chip > 0 && chip >= sunxi_nand->nsels)
-               return;
-
-       if (chip == sunxi_nand->selected)
+       if (cs > 0 && cs >= sunxi_nand->nsels)
                return;
 
        ctl = readl(nfc->regs + NFC_REG_CTL) &
              ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
 
-       if (chip >= 0) {
-               sel = &sunxi_nand->sels[chip];
-
-               ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
-                      NFC_PAGE_SHIFT(nand->page_shift);
-               if (sel->rb < 0) {
-                       nand->legacy.dev_ready = NULL;
-               } else {
-                       nand->legacy.dev_ready = sunxi_nfc_dev_ready;
-                       ctl |= NFC_RB_SEL(sel->rb);
-               }
+       sel = &sunxi_nand->sels[cs];
+       ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | NFC_PAGE_SHIFT(nand->page_shift);
+       if (sel->rb >= 0)
+               ctl |= NFC_RB_SEL(sel->rb);
 
-               writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
+       writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
 
-               if (nfc->clk_rate != sunxi_nand->clk_rate) {
-                       clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
-                       nfc->clk_rate = sunxi_nand->clk_rate;
-               }
+       if (nfc->clk_rate != sunxi_nand->clk_rate) {
+               clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
+               nfc->clk_rate = sunxi_nand->clk_rate;
        }
 
        writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
        writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
        writel(ctl, nfc->regs + NFC_REG_CTL);
-
-       sunxi_nand->selected = chip;
 }
 
 static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
@@ -523,71 +485,6 @@ static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
        }
 }
 
-static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
-{
-       uint8_t ret = 0;
-
-       sunxi_nfc_read_buf(nand, &ret, 1);
-
-       return ret;
-}
-
-static void sunxi_nfc_cmd_ctrl(struct nand_chip *nand, int dat,
-                              unsigned int ctrl)
-{
-       struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-       struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-       int ret;
-
-       if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
-           !(ctrl & (NAND_CLE | NAND_ALE))) {
-               u32 cmd = 0;
-
-               if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
-                       return;
-
-               if (sunxi_nand->cmd_cycles--)
-                       cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
-
-               if (sunxi_nand->cmd_cycles--) {
-                       cmd |= NFC_SEND_CMD2;
-                       writel(sunxi_nand->cmd[1],
-                              nfc->regs + NFC_REG_RCMD_SET);
-               }
-
-               sunxi_nand->cmd_cycles = 0;
-
-               if (sunxi_nand->addr_cycles) {
-                       cmd |= NFC_SEND_ADR |
-                              NFC_ADR_NUM(sunxi_nand->addr_cycles);
-                       writel(sunxi_nand->addr[0],
-                              nfc->regs + NFC_REG_ADDR_LOW);
-               }
-
-               if (sunxi_nand->addr_cycles > 4)
-                       writel(sunxi_nand->addr[1],
-                              nfc->regs + NFC_REG_ADDR_HIGH);
-
-               ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-               if (ret)
-                       return;
-
-               writel(cmd, nfc->regs + NFC_REG_CMD);
-               sunxi_nand->addr[0] = 0;
-               sunxi_nand->addr[1] = 0;
-               sunxi_nand->addr_cycles = 0;
-               sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
-       }
-
-       if (ctrl & NAND_CLE) {
-               sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
-       } else if (ctrl & NAND_ALE) {
-               sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
-                               dat << ((sunxi_nand->addr_cycles % 4) * 8);
-               sunxi_nand->addr_cycles++;
-       }
-}
-
 /* These seed values have been extracted from Allwinner's BSP */
 static const u16 sunxi_nfc_randomizer_page_seeds[] = {
        0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
@@ -1174,6 +1071,8 @@ static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf,
        int ret, i, cur_off = 0;
        bool raw_mode = false;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        nand_read_page_op(nand, page, 0, NULL, 0);
 
        sunxi_nfc_hw_ecc_enable(nand);
@@ -1208,6 +1107,8 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf,
 {
        int ret;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        nand_read_page_op(nand, page, 0, NULL, 0);
 
        ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, oob_required, page,
@@ -1228,6 +1129,8 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *nand,
        int ret, i, cur_off = 0;
        unsigned int max_bitflips = 0;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        nand_read_page_op(nand, page, 0, NULL, 0);
 
        sunxi_nfc_hw_ecc_enable(nand);
@@ -1260,6 +1163,8 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *nand,
        int nchunks = DIV_ROUND_UP(data_offs + readlen, nand->ecc.size);
        int ret;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        nand_read_page_op(nand, page, 0, NULL, 0);
 
        ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, false, page, nchunks);
@@ -1279,6 +1184,8 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand,
        struct nand_ecc_ctrl *ecc = &nand->ecc;
        int ret, i, cur_off = 0;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        nand_prog_page_begin_op(nand, page, 0, NULL, 0);
 
        sunxi_nfc_hw_ecc_enable(nand);
@@ -1314,6 +1221,8 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *nand,
        struct nand_ecc_ctrl *ecc = &nand->ecc;
        int ret, i, cur_off = 0;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        nand_prog_page_begin_op(nand, page, 0, NULL, 0);
 
        sunxi_nfc_hw_ecc_enable(nand);
@@ -1347,6 +1256,8 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
        struct scatterlist sg;
        int ret, i;
 
+       sunxi_nfc_select_chip(nand, nand->cur_cs);
+
        ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
        if (ret)
                return ret;
@@ -1820,9 +1731,159 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand)
        return 0;
 }
 
+static int sunxi_nfc_exec_subop(struct nand_chip *nand,
+                               const struct nand_subop *subop)
+{
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       u32 cmd = 0, extcmd = 0, cnt = 0, addrs[2] = { };
+       unsigned int i, j, remaining, start;
+       void *inbuf = NULL;
+       int ret;
+
+       for (i = 0; i < subop->ninstrs; i++) {
+               const struct nand_op_instr *instr = &subop->instrs[i];
+
+               switch (instr->type) {
+               case NAND_OP_CMD_INSTR:
+                       if (cmd & NFC_SEND_CMD1) {
+                               if (WARN_ON(cmd & NFC_SEND_CMD2))
+                                       return -EINVAL;
+
+                               cmd |= NFC_SEND_CMD2;
+                               extcmd |= instr->ctx.cmd.opcode;
+                       } else {
+                               cmd |= NFC_SEND_CMD1 |
+                                      NFC_CMD(instr->ctx.cmd.opcode);
+                       }
+                       break;
+
+               case NAND_OP_ADDR_INSTR:
+                       remaining = nand_subop_get_num_addr_cyc(subop, i);
+                       start = nand_subop_get_addr_start_off(subop, i);
+                       for (j = 0; j < 8 && j + start < remaining; j++) {
+                               u32 addr = instr->ctx.addr.addrs[j + start];
+
+                               addrs[j / 4] |= addr << (j % 4) * 8;
+                       }
+
+                       if (j)
+                               cmd |= NFC_SEND_ADR | NFC_ADR_NUM(j);
+
+                       break;
+
+               case NAND_OP_DATA_IN_INSTR:
+               case NAND_OP_DATA_OUT_INSTR:
+                       start = nand_subop_get_data_start_off(subop, i);
+                       remaining = nand_subop_get_data_len(subop, i);
+                       cnt = min_t(u32, remaining, NFC_SRAM_SIZE);
+                       cmd |= NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
+
+                       if (instr->type == NAND_OP_DATA_OUT_INSTR) {
+                               cmd |= NFC_ACCESS_DIR;
+                               memcpy_toio(nfc->regs + NFC_RAM0_BASE,
+                                           instr->ctx.data.buf.out + start,
+                                           cnt);
+                       } else {
+                               inbuf = instr->ctx.data.buf.in + start;
+                       }
+
+                       break;
+
+               case NAND_OP_WAITRDY_INSTR:
+                       cmd |= NFC_WAIT_FLAG;
+                       break;
+               }
+       }
+
+       ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+       if (ret)
+               return ret;
+
+       if (cmd & NFC_SEND_ADR) {
+               writel(addrs[0], nfc->regs + NFC_REG_ADDR_LOW);
+               writel(addrs[1], nfc->regs + NFC_REG_ADDR_HIGH);
+       }
+
+       if (cmd & NFC_SEND_CMD2)
+               writel(extcmd,
+                      nfc->regs +
+                      (cmd & NFC_ACCESS_DIR ?
+                       NFC_REG_WCMD_SET : NFC_REG_RCMD_SET));
+
+       if (cmd & NFC_DATA_TRANS)
+               writel(cnt, nfc->regs + NFC_REG_CNT);
+
+       writel(cmd, nfc->regs + NFC_REG_CMD);
+
+       ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG,
+                                   !(cmd & NFC_WAIT_FLAG) && cnt < 64,
+                                   0);
+       if (ret)
+               return ret;
+
+       if (inbuf)
+               memcpy_fromio(inbuf, nfc->regs + NFC_RAM0_BASE, cnt);
+
+       return 0;
+}
+
+static int sunxi_nfc_soft_waitrdy(struct nand_chip *nand,
+                                 const struct nand_subop *subop)
+{
+       return nand_soft_waitrdy(nand,
+                                subop->instrs[0].ctx.waitrdy.timeout_ms);
+}
+
+static const struct nand_op_parser sunxi_nfc_op_parser = NAND_OP_PARSER(
+       NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
+                              NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 1024)),
+       NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
+                              NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, 1024),
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+);
+
+static const struct nand_op_parser sunxi_nfc_norb_op_parser = NAND_OP_PARSER(
+       NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 1024)),
+       NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true),
+                              NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
+                              NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, 1024),
+                              NAND_OP_PARSER_PAT_CMD_ELEM(true)),
+       NAND_OP_PARSER_PATTERN(sunxi_nfc_soft_waitrdy,
+                              NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+);
+
+static int sunxi_nfc_exec_op(struct nand_chip *nand,
+                            const struct nand_operation *op, bool check_only)
+{
+       struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+       const struct nand_op_parser *parser;
+
+       sunxi_nfc_select_chip(nand, op->cs);
+
+       if (sunxi_nand->sels[op->cs].rb >= 0)
+               parser = &sunxi_nfc_op_parser;
+       else
+               parser = &sunxi_nfc_norb_op_parser;
+
+       return nand_op_parser_exec_op(nand, parser, op, check_only);
+}
+
 static const struct nand_controller_ops sunxi_nand_controller_ops = {
        .attach_chip = sunxi_nand_attach_chip,
        .setup_data_interface = sunxi_nfc_setup_data_interface,
+       .exec_op = sunxi_nfc_exec_op,
 };
 
 static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
@@ -1853,7 +1914,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        }
 
        sunxi_nand->nsels = nsels;
-       sunxi_nand->selected = -1;
 
        for (i = 0; i < nsels; i++) {
                ret = of_property_read_u32_index(np, "reg", i, &tmp);
@@ -1886,7 +1946,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 
        nand = &sunxi_nand->nand;
        /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
-       nand->legacy.chip_delay = 200;
        nand->controller = &nfc->controller;
        nand->controller->ops = &sunxi_nand_controller_ops;
 
@@ -1896,11 +1955,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
         */
        nand->ecc.mode = NAND_ECC_HW;
        nand_set_flash_node(nand, np);
-       nand->legacy.select_chip = sunxi_nfc_select_chip;
-       nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl;
-       nand->legacy.read_buf = sunxi_nfc_read_buf;
-       nand->legacy.write_buf = sunxi_nfc_write_buf;
-       nand->legacy.read_byte = sunxi_nfc_read_byte;
 
        mtd = nand_to_mtd(nand);
        mtd->dev.parent = dev;