Re: [PATCH 2/5] drivers: mtd: nand: Add qpic_common API file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 2/16/2024 8:59 PM, Kathiravan Thirumoorthy wrote:


On 2/15/2024 7:18 PM, Md Sadre Alam wrote:
Add qpic_common.c file which hold all the common
qpic APIs which will be used by both qpic raw nand
driver and qpic spi nand driver.

Co-developed-by: Sricharan Ramabadhran <quic_srichara@xxxxxxxxxxx>
Signed-off-by: Sricharan Ramabadhran <quic_srichara@xxxxxxxxxxx>
Co-developed-by: Varadarajan Narayanan <quic_varada@xxxxxxxxxxx>
Signed-off-by: Varadarajan Narayanan <quic_varada@xxxxxxxxxxx>
Signed-off-by: Md Sadre Alam <quic_mdalam@xxxxxxxxxxx>
---
  drivers/mtd/nand/Makefile            |    1 +
  drivers/mtd/nand/qpic_common.c       |  786 +++++++++++++++++
  drivers/mtd/nand/raw/qcom_nandc.c    | 1226 +-------------------------
  include/linux/mtd/nand-qpic-common.h |  488 ++++++++++
  4 files changed, 1291 insertions(+), 1210 deletions(-)
  create mode 100644 drivers/mtd/nand/qpic_common.c
  create mode 100644 include/linux/mtd/nand-qpic-common.h

diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 19e1291ac4d5..131707a41293 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -12,3 +12,4 @@ nandcore-$(CONFIG_MTD_NAND_ECC) += ecc.o
  nandcore-$(CONFIG_MTD_NAND_ECC_SW_HAMMING) += ecc-sw-hamming.o
  nandcore-$(CONFIG_MTD_NAND_ECC_SW_BCH) += ecc-sw-bch.o
  nandcore-$(CONFIG_MTD_NAND_ECC_MXIC) += ecc-mxic.o
+obj-y += qpic_common.o
diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c
new file mode 100644
index 000000000000..4d74ba888028
--- /dev/null
+++ b/drivers/mtd/nand/qpic_common.c
@@ -0,0 +1,786 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * QPIC Controller common API file.
+ * Copyright (C) 2023  Qualcomm Inc.


Copyright should be repharsed?

 Will fix in next patch.


+ * Authors:    Md sadre Alam           <quic_mdalam@xxxxxxxxxxx>
+ *        Sricharan R             <quic_srichara@xxxxxxxxxxx>
+ *        Varadarajan Narayanan    <quic_varada@xxxxxxxxxxx>
+ *
+ */
+
+#include <linux/mtd/nand-qpic-common.h>
+
+struct qcom_nand_controller *
+get_qcom_nand_controller(struct nand_chip *chip)
+{
+    return container_of(chip->controller, struct qcom_nand_controller,
+                controller);
+}
+EXPORT_SYMBOL(get_qcom_nand_controller);
+
+/*
+ * Helper to prepare DMA descriptors for configuring registers
+ * before reading a NAND page.
+ */
+void config_nand_page_read(struct nand_chip *chip)
+{
+    struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+    write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+    write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+    if (!nandc->props->qpic_v2)
+        write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+    write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
+    write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
+              NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+}
+EXPORT_SYMBOL(config_nand_page_read);
+
+/* Frees the BAM transaction memory */
+void free_bam_transaction(struct qcom_nand_controller *nandc)
+{
+    struct bam_transaction *bam_txn = nandc->bam_txn;
+
+    devm_kfree(nandc->dev, bam_txn);
+}
+EXPORT_SYMBOL(free_bam_transaction);
+
+/* Callback for DMA descriptor completion */
+void qpic_bam_dma_done(void *data)
+{
+    struct bam_transaction *bam_txn = data;
+
+    /*
+     * In case of data transfer with NAND, 2 callbacks will be generated.
+     * One for command channel and another one for data channel.
+     * If current transaction has data descriptors
+     * (i.e. wait_second_completion is true), then set this to false
+     * and wait for second DMA descriptor completion.
+     */
+    if (bam_txn->wait_second_completion)
+        bam_txn->wait_second_completion = false;
+    else
+        complete(&bam_txn->txn_done);
+}
+EXPORT_SYMBOL(qpic_bam_dma_done);
+
+void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
+                bool is_cpu)
+{
+    if (!nandc->props->is_bam)
+        return;
+
+    if (is_cpu)
+        dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
+                    MAX_REG_RD *
+                    sizeof(*nandc->reg_read_buf),
+                    DMA_FROM_DEVICE);
+    else
+        dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
+                       MAX_REG_RD *
+                       sizeof(*nandc->reg_read_buf),
+                       DMA_FROM_DEVICE);
+}
+EXPORT_SYMBOL(nandc_read_buffer_sync);
+
+__le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
+{
+    switch (offset) {
+    case NAND_FLASH_CMD:
+        return &regs->cmd;
+    case NAND_ADDR0:
+        return &regs->addr0;
+    case NAND_ADDR1:
+        return &regs->addr1;
+    case NAND_FLASH_CHIP_SELECT:
+        return &regs->chip_sel;
+    case NAND_EXEC_CMD:
+        return &regs->exec;
+    case NAND_FLASH_STATUS:
+        return &regs->clrflashstatus;
+    case NAND_DEV0_CFG0:
+        return &regs->cfg0;
+    case NAND_DEV0_CFG1:
+        return &regs->cfg1;
+    case NAND_DEV0_ECC_CFG:
+        return &regs->ecc_bch_cfg;
+    case NAND_READ_STATUS:
+        return &regs->clrreadstatus;
+    case NAND_DEV_CMD1:
+        return &regs->cmd1;
+    case NAND_DEV_CMD1_RESTORE:
+        return &regs->orig_cmd1;
+    case NAND_DEV_CMD_VLD:
+        return &regs->vld;
+    case NAND_DEV_CMD_VLD_RESTORE:
+        return &regs->orig_vld;
+    case NAND_EBI2_ECC_BUF_CFG:
+        return &regs->ecc_buf_cfg;
+    case NAND_READ_LOCATION_0:
+        return &regs->read_location0;
+    case NAND_READ_LOCATION_1:
+        return &regs->read_location1;
+    case NAND_READ_LOCATION_2:
+        return &regs->read_location2;
+    case NAND_READ_LOCATION_3:
+        return &regs->read_location3;
+    case NAND_READ_LOCATION_LAST_CW_0:
+        return &regs->read_location_last0;
+    case NAND_READ_LOCATION_LAST_CW_1:
+        return &regs->read_location_last1;
+    case NAND_READ_LOCATION_LAST_CW_2:
+        return &regs->read_location_last2;
+    case NAND_READ_LOCATION_LAST_CW_3:
+        return &regs->read_location_last3;
+    default:
+        return NULL;
+    }
+}
+EXPORT_SYMBOL(offset_to_nandc_reg);
+
+/* reset the register read buffer for next NAND operation */
+void clear_read_regs(struct qcom_nand_controller *nandc)
+{
+    nandc->reg_read_pos = 0;
+    nandc_read_buffer_sync(nandc, false);
+}
+EXPORT_SYMBOL(clear_read_regs);
+
+int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+              int reg_off, const void *vaddr, int size,
+                 bool flow_control)
+{
+    struct desc_info *desc;
+    struct dma_async_tx_descriptor *dma_desc;
+    struct scatterlist *sgl;
+    struct dma_slave_config slave_conf;
+    struct qcom_adm_peripheral_config periph_conf = {};
+    enum dma_transfer_direction dir_eng;
+    int ret;
+
+    desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+    if (!desc)
+        return -ENOMEM;
+
+    sgl = &desc->adm_sgl;
+
+    sg_init_one(sgl, vaddr, size);
+
+    if (read) {
+        dir_eng = DMA_DEV_TO_MEM;
+        desc->dir = DMA_FROM_DEVICE;
+    } else {
+        dir_eng = DMA_MEM_TO_DEV;
+        desc->dir = DMA_TO_DEVICE;
+    }
+
+    ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
+    if (ret == 0) {
+        ret = -ENOMEM;
+        goto err;
+    }
+
+    memset(&slave_conf, 0x00, sizeof(slave_conf));
+
+    slave_conf.device_fc = flow_control;
+    if (read) {
+        slave_conf.src_maxburst = 16;
+        slave_conf.src_addr = nandc->base_dma + reg_off;
+        if (nandc->data_crci) {
+            periph_conf.crci = nandc->data_crci;
+            slave_conf.peripheral_config = &periph_conf;
+            slave_conf.peripheral_size = sizeof(periph_conf);
+        }
+    } else {
+        slave_conf.dst_maxburst = 16;
+        slave_conf.dst_addr = nandc->base_dma + reg_off;
+        if (nandc->cmd_crci) {
+            periph_conf.crci = nandc->cmd_crci;
+            slave_conf.peripheral_config = &periph_conf;
+            slave_conf.peripheral_size = sizeof(periph_conf);
+        }
+    }
+
+    ret = dmaengine_slave_config(nandc->chan, &slave_conf);
+    if (ret) {
+        dev_err(nandc->dev, "failed to configure dma channel\n");
+        goto err;
+    }
+
+    dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
+    if (!dma_desc) {
+        dev_err(nandc->dev, "failed to prepare desc\n");
+        ret = -EINVAL;
+        goto err;
+    }
+
+    desc->dma_desc = dma_desc;
+
+    list_add_tail(&desc->node, &nandc->desc_list);
+
+    return 0;
+err:
+    kfree(desc);
+
+    return ret;
+}
+EXPORT_SYMBOL(prep_adm_dma_desc);
+
+/* helpers to submit/free our list of dma descriptors */
+int submit_descs(struct qcom_nand_controller *nandc)
+{
+    struct desc_info *desc, *n;
+    dma_cookie_t cookie = 0;
+    struct bam_transaction *bam_txn = nandc->bam_txn;
+    int ret = 0;
+
+    if (nandc->props->is_bam) {
+        if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+            ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+            if (ret)
+                goto err_unmap_free_desc;
+        }
+
+        if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
+            ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
+                             DMA_PREP_INTERRUPT);
+            if (ret)
+                goto err_unmap_free_desc;
+        }
+
+        if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
+            ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+                             DMA_PREP_CMD);
+            if (ret)
+                goto err_unmap_free_desc;
+        }
+    }
+
+    list_for_each_entry(desc, &nandc->desc_list, node)
+        cookie = dmaengine_submit(desc->dma_desc);
+
+    if (nandc->props->is_bam) {
+        bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
+        bam_txn->last_cmd_desc->callback_param = bam_txn;
+        if (bam_txn->last_data_desc) {
+            bam_txn->last_data_desc->callback = qpic_bam_dma_done;
+            bam_txn->last_data_desc->callback_param = bam_txn;
+            bam_txn->wait_second_completion = true;
+        }
+
+        dma_async_issue_pending(nandc->tx_chan);
+        dma_async_issue_pending(nandc->rx_chan);
+        dma_async_issue_pending(nandc->cmd_chan);
+
+        if (!wait_for_completion_timeout(&bam_txn->txn_done,
+                         QPIC_NAND_COMPLETION_TIMEOUT))
+            ret = -ETIMEDOUT;
+    } else {
+        if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
+            ret = -ETIMEDOUT;
+    }
+
+err_unmap_free_desc:
+    /*
+     * Unmap the dma sg_list and free the desc allocated by both
+     * prepare_bam_async_desc() and prep_adm_dma_desc() functions.
+     */
+    list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+        list_del(&desc->node);
+
+        if (nandc->props->is_bam)
+            dma_unmap_sg(nandc->dev, desc->bam_sgl,
+                     desc->sgl_cnt, desc->dir);
+        else
+            dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
+                     desc->dir);
+
+        kfree(desc);
+    }
+
+    return ret;
+}
+EXPORT_SYMBOL(submit_descs);
+
+/*
+ * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
+ * for BAM. This descriptor will be added in the NAND DMA descriptor queue
+ * which will be submitted to DMA engine.
+ */
+int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+               struct dma_chan *chan,
+                  unsigned long flags)
+{
+    struct desc_info *desc;
+    struct scatterlist *sgl;
+    unsigned int sgl_cnt;
+    int ret;
+    struct bam_transaction *bam_txn = nandc->bam_txn;
+    enum dma_transfer_direction dir_eng;
+    struct dma_async_tx_descriptor *dma_desc;
+
+    desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+    if (!desc)
+        return -ENOMEM;
+
+    if (chan == nandc->cmd_chan) {
+        sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
+        sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
+        bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
+        dir_eng = DMA_MEM_TO_DEV;
+        desc->dir = DMA_TO_DEVICE;
+    } else if (chan == nandc->tx_chan) {
+        sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
+        sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
+        bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
+        dir_eng = DMA_MEM_TO_DEV;
+        desc->dir = DMA_TO_DEVICE;
+    } else {
+        sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
+        sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
+        bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
+        dir_eng = DMA_DEV_TO_MEM;
+        desc->dir = DMA_FROM_DEVICE;
+    }
+
+    sg_mark_end(sgl + sgl_cnt - 1);
+    ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+    if (ret == 0) {
+        dev_err(nandc->dev, "failure in mapping desc\n");
+        kfree(desc);
+        return -ENOMEM;
+    }
+
+    desc->sgl_cnt = sgl_cnt;
+    desc->bam_sgl = sgl;
+
+    dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
+                       flags);
+
+    if (!dma_desc) {
+        dev_err(nandc->dev, "failure in prep desc\n");
+        dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+        kfree(desc);
+        return -EINVAL;
+    }
+
+    desc->dma_desc = dma_desc;
+
+    /* update last data/command descriptor */
+    if (chan == nandc->cmd_chan)
+        bam_txn->last_cmd_desc = dma_desc;
+    else
+        bam_txn->last_data_desc = dma_desc;
+
+    list_add_tail(&desc->node, &nandc->desc_list);
+
+    return 0;
+}
+EXPORT_SYMBOL(prepare_bam_async_desc);
+
+/*
+ * Prepares the command descriptor for BAM DMA which will be used for NAND
+ * register reads and writes. The command descriptor requires the command
+ * to be formed in command element type so this function uses the command
+ * element from bam transaction ce array and fills the same with required
+ * data. A single SGL can contain multiple command elements so
+ * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
+ * after the current command element.
+ */
+int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+              int reg_off, const void *vaddr,
+                 int size, unsigned int flags)
+{
+    int bam_ce_size;
+    int i, ret;
+    struct bam_cmd_element *bam_ce_buffer;
+    struct bam_transaction *bam_txn = nandc->bam_txn;
+
+    bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
+
+    /* fill the command desc */
+    for (i = 0; i < size; i++) {
+        if (read)
+            bam_prep_ce(&bam_ce_buffer[i],
+                    nandc_reg_phys(nandc, reg_off + 4 * i),
+                    BAM_READ_COMMAND,
+                    reg_buf_dma_addr(nandc,
+                             (__le32 *)vaddr + i));
+        else
+            bam_prep_ce_le32(&bam_ce_buffer[i],
+                     nandc_reg_phys(nandc, reg_off + 4 * i),
+                     BAM_WRITE_COMMAND,
+                     *((__le32 *)vaddr + i));
+    }
+
+    bam_txn->bam_ce_pos += size;
+
+    /* use the separate sgl after this command */
+    if (flags & NAND_BAM_NEXT_SGL) {
+        bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
+        bam_ce_size = (bam_txn->bam_ce_pos -
+                bam_txn->bam_ce_start) *
+                sizeof(struct bam_cmd_element);
+        sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
+               bam_ce_buffer, bam_ce_size);
+        bam_txn->cmd_sgl_pos++;
+        bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
+
+        if (flags & NAND_BAM_NWD) {
+            ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+                             DMA_PREP_FENCE |
+                             DMA_PREP_CMD);
+            if (ret)
+                return ret;
+        }
+    }
+
+    return 0;
+}
+EXPORT_SYMBOL(prep_bam_dma_desc_cmd);
+
+/*
+ * Prepares the data descriptor for BAM DMA which will be used for NAND
+ * data reads and writes.
+ */
+int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+               const void *vaddr,
+                  int size, unsigned int flags)
+{
+    int ret;
+    struct bam_transaction *bam_txn = nandc->bam_txn;
+
+    if (read) {
+        sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
+               vaddr, size);
+        bam_txn->rx_sgl_pos++;
+    } else {
+        sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
+               vaddr, size);
+        bam_txn->tx_sgl_pos++;
+
+        /*
+         * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
+         * is not set, form the DMA descriptor
+         */
+        if (!(flags & NAND_BAM_NO_EOT)) {
+            ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
+                             DMA_PREP_INTERRUPT);
+            if (ret)
+                return ret;
+        }
+    }
+
+    return 0;
+}
+EXPORT_SYMBOL(prep_bam_dma_desc_data);
+
+/*
+ * read_reg_dma:    prepares a descriptor to read a given number of
+ *            contiguous registers to the reg_read_buf pointer
+ *
+ * @first:        offset of the first register in the contiguous block
+ * @num_regs:        number of registers to read
+ * @flags:        flags to control DMA descriptor preparation
+ */
+int read_reg_dma(struct qcom_nand_controller *nandc, int first,
+         int num_regs, unsigned int flags)
+{
+    bool flow_control = false;
+    void *vaddr;
+
+    vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+    nandc->reg_read_pos += num_regs;
+
+    if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
+        first = dev_cmd_reg_addr(nandc, first);
+
+    if (nandc->props->is_bam)
+        return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+                         num_regs, flags);
+
+    if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+        flow_control = true;
+
+    return prep_adm_dma_desc(nandc, true, first, vaddr,
+                 num_regs * sizeof(u32), flow_control);
+}
+EXPORT_SYMBOL(read_reg_dma);
+
+/*
+ * write_reg_dma:    prepares a descriptor to write a given number of
+ *            contiguous registers
+ *
+ * @first:        offset of the first register in the contiguous block
+ * @num_regs:        number of registers to write
+ * @flags:        flags to control DMA descriptor preparation
+ */
+int write_reg_dma(struct qcom_nand_controller *nandc, int first,
+          int num_regs, unsigned int flags)
+{
+    bool flow_control = false;
+    struct nandc_regs *regs = nandc->regs;
+    void *vaddr;
+
+    vaddr = offset_to_nandc_reg(regs, first);
+
+    if (first == NAND_ERASED_CW_DETECT_CFG) {
+        if (flags & NAND_ERASED_CW_SET)
+            vaddr = &regs->erased_cw_detect_cfg_set;
+        else
+            vaddr = &regs->erased_cw_detect_cfg_clr;
+    }
+
+    if (first == NAND_EXEC_CMD)
+        flags |= NAND_BAM_NWD;
+
+    if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
+        first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
+
+    if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
+        first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+
+    if (nandc->props->is_bam)
+        return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+                         num_regs, flags);
+
+    if (first == NAND_FLASH_CMD)
+        flow_control = true;
+
+    return prep_adm_dma_desc(nandc, false, first, vaddr,
+                 num_regs * sizeof(u32), flow_control);
+}
+EXPORT_SYMBOL(write_reg_dma);
+
+/*
+ * read_data_dma:    prepares a DMA descriptor to transfer data from the
+ *            controller's internal buffer to the buffer 'vaddr'
+ *
+ * @reg_off:        offset within the controller's data buffer
+ * @vaddr:        virtual address of the buffer we want to write to
+ * @size:        DMA transaction size in bytes
+ * @flags:        flags to control DMA descriptor preparation
+ */
+int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+          const u8 *vaddr, int size, unsigned int flags)
+{
+    if (nandc->props->is_bam)
+        return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+
+    return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+}
+EXPORT_SYMBOL(read_data_dma);
+
+/*
+ * write_data_dma:    prepares a DMA descriptor to transfer data from
+ *            'vaddr' to the controller's internal buffer
+ *
+ * @reg_off:        offset within the controller's data buffer
+ * @vaddr:        virtual address of the buffer we want to read from
+ * @size:        DMA transaction size in bytes
+ * @flags:        flags to control DMA descriptor preparation
+ */
+int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+           const u8 *vaddr, int size, unsigned int flags)
+{
+    if (nandc->props->is_bam)
+        return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+
+    return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+}
+EXPORT_SYMBOL(write_data_dma);
+
+/* Allocates and Initializes the BAM transaction */
+struct bam_transaction *
+alloc_bam_transaction(struct qcom_nand_controller *nandc)
+{
+    struct bam_transaction *bam_txn;
+    size_t bam_txn_size;
+    unsigned int num_cw = nandc->max_cwperpage;
+    void *bam_txn_buf;
+
+    bam_txn_size =
+        sizeof(*bam_txn) + num_cw *
+        ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
+        (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
+        (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
+
+    bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
+    if (!bam_txn_buf)
+        return NULL;
+
+    bam_txn = bam_txn_buf;
+    bam_txn_buf += sizeof(*bam_txn);
+
+    bam_txn->bam_ce = bam_txn_buf;
+    bam_txn_buf +=
+        sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
+
+    bam_txn->cmd_sgl = bam_txn_buf;
+    bam_txn_buf +=
+        sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
+
+    bam_txn->data_sgl = bam_txn_buf;
+
+    init_completion(&bam_txn->txn_done);
+
+    return bam_txn;
+}
+EXPORT_SYMBOL(alloc_bam_transaction);
+
+/* Clears the BAM transaction indexes */
+void clear_bam_transaction(struct qcom_nand_controller *nandc)
+{
+    struct bam_transaction *bam_txn = nandc->bam_txn;
+
+    if (!nandc->props->is_bam)
+        return;
+
+    bam_txn->bam_ce_pos = 0;
+    bam_txn->bam_ce_start = 0;
+    bam_txn->cmd_sgl_pos = 0;
+    bam_txn->cmd_sgl_start = 0;
+    bam_txn->tx_sgl_pos = 0;
+    bam_txn->tx_sgl_start = 0;
+    bam_txn->rx_sgl_pos = 0;
+    bam_txn->rx_sgl_start = 0;
+    bam_txn->last_data_desc = NULL;
+    bam_txn->wait_second_completion = false;
+
+    sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+              QPIC_PER_CW_CMD_SGL);
+    sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
+              QPIC_PER_CW_DATA_SGL);
+
+    reinit_completion(&bam_txn->txn_done);
+}
+EXPORT_SYMBOL(clear_bam_transaction);
+
+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+{
+    if (nandc->props->is_bam) {
+        if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
+            dma_unmap_single(nandc->dev, nandc->reg_read_dma,
+                     MAX_REG_RD *
+                     sizeof(*nandc->reg_read_buf),
+                     DMA_FROM_DEVICE);
+
+        if (nandc->tx_chan)
+            dma_release_channel(nandc->tx_chan);
+
+        if (nandc->rx_chan)
+            dma_release_channel(nandc->rx_chan);
+
+        if (nandc->cmd_chan)
+            dma_release_channel(nandc->cmd_chan);
+    } else {
+        if (nandc->chan)
+            dma_release_channel(nandc->chan);
+    }
+}
+EXPORT_SYMBOL(qcom_nandc_unalloc);
+
+int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
+{
+    int ret;
+
+    ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
+    if (ret) {
+        dev_err(nandc->dev, "failed to set DMA mask\n");
+        return ret;
+    }
+
+    /*
+     * we use the internal buffer for reading ONFI params, reading small
+     * data like ID and status, and preforming read-copy-write operations
+     * when writing to a codeword partially. 532 is the maximum possible
+     * size of a codeword for our nand controller
+     */
+    nandc->buf_size = 532;
+
+    nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
+    if (!nandc->data_buffer)
+        return -ENOMEM;
+
+    nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
+    if (!nandc->regs)
+        return -ENOMEM;
+
+    nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
+                       sizeof(*nandc->reg_read_buf),
+                       GFP_KERNEL);
+    if (!nandc->reg_read_buf)
+        return -ENOMEM;
+
+    if (nandc->props->is_bam) {
+        nandc->reg_read_dma =
+            dma_map_single(nandc->dev, nandc->reg_read_buf,
+                       MAX_REG_RD *
+                       sizeof(*nandc->reg_read_buf),
+                       DMA_FROM_DEVICE);
+        if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
+            dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
+            return -EIO;
+        }
+
+        nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
+        if (IS_ERR(nandc->tx_chan)) {
+            ret = PTR_ERR(nandc->tx_chan);
+            nandc->tx_chan = NULL;
+            dev_err_probe(nandc->dev, ret,
+                      "tx DMA channel request failed\n");
+            goto unalloc;
+        }
+
+        nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
+        if (IS_ERR(nandc->rx_chan)) {
+            ret = PTR_ERR(nandc->rx_chan);
+            nandc->rx_chan = NULL;
+            dev_err_probe(nandc->dev, ret,
+                      "rx DMA channel request failed\n");
+            goto unalloc;
+        }
+
+        nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
+        if (IS_ERR(nandc->cmd_chan)) {
+            ret = PTR_ERR(nandc->cmd_chan);
+            nandc->cmd_chan = NULL;
+            dev_err_probe(nandc->dev, ret,
+                      "cmd DMA channel request failed\n");
+            goto unalloc;
+        }
+
+        /*
+         * Initially allocate BAM transaction to read ONFI param page.
+         * After detecting all the devices, this BAM transaction will
+         * be freed and the next BAM transaction will be allocated with
+         * maximum codeword size
+         */
+        nandc->max_cwperpage = 1;
+        nandc->bam_txn = alloc_bam_transaction(nandc);
+        if (!nandc->bam_txn) {
+            dev_err(nandc->dev,
+                "failed to allocate bam transaction\n");
+            ret = -ENOMEM;
+            goto unalloc;
+        }
+    } else {
+        nandc->chan = dma_request_chan(nandc->dev, "rxtx");
+        if (IS_ERR(nandc->chan)) {
+            ret = PTR_ERR(nandc->chan);
+            nandc->chan = NULL;
+            dev_err_probe(nandc->dev, ret,
+                      "rxtx DMA channel request failed\n");
+            return ret;
+        }
+    }
+
+    INIT_LIST_HEAD(&nandc->desc_list);
+    INIT_LIST_HEAD(&nandc->host_list);
+
+    return 0;
+unalloc:
+    qcom_nandc_unalloc(nandc);
+    return ret;
+}
+EXPORT_SYMBOL(qcom_nandc_alloc);
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index b079605c84d3..75c6ca698c85 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2,186 +2,7 @@
  /*
   * Copyright (c) 2016, The Linux Foundation. All rights reserved.
   */
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/dma/qcom_adm.h>
-#include <linux/dma/qcom_bam_dma.h>
-#include <linux/module.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-/* NANDc reg offsets */
-#define    NAND_FLASH_CMD            0x00
-#define    NAND_ADDR0            0x04
-#define    NAND_ADDR1            0x08
-#define    NAND_FLASH_CHIP_SELECT        0x0c
-#define    NAND_EXEC_CMD            0x10
-#define    NAND_FLASH_STATUS        0x14
-#define    NAND_BUFFER_STATUS        0x18
-#define    NAND_DEV0_CFG0            0x20
-#define    NAND_DEV0_CFG1            0x24
-#define    NAND_DEV0_ECC_CFG        0x28
-#define    NAND_AUTO_STATUS_EN        0x2c
-#define    NAND_DEV1_CFG0            0x30
-#define    NAND_DEV1_CFG1            0x34
-#define    NAND_READ_ID            0x40
-#define    NAND_READ_STATUS        0x44
-#define    NAND_DEV_CMD0            0xa0
-#define    NAND_DEV_CMD1            0xa4
-#define    NAND_DEV_CMD2            0xa8
-#define    NAND_DEV_CMD_VLD        0xac
-#define    SFLASHC_BURST_CFG        0xe0
-#define    NAND_ERASED_CW_DETECT_CFG    0xe8
-#define    NAND_ERASED_CW_DETECT_STATUS    0xec
-#define    NAND_EBI2_ECC_BUF_CFG        0xf0
-#define    FLASH_BUF_ACC            0x100
-
-#define    NAND_CTRL            0xf00
-#define    NAND_VERSION            0xf08
-#define    NAND_READ_LOCATION_0        0xf20
-#define    NAND_READ_LOCATION_1        0xf24
-#define    NAND_READ_LOCATION_2        0xf28
-#define    NAND_READ_LOCATION_3        0xf2c
-#define    NAND_READ_LOCATION_LAST_CW_0    0xf40
-#define    NAND_READ_LOCATION_LAST_CW_1    0xf44
-#define    NAND_READ_LOCATION_LAST_CW_2    0xf48
-#define    NAND_READ_LOCATION_LAST_CW_3    0xf4c
-
-/* dummy register offsets, used by write_reg_dma */
-#define    NAND_DEV_CMD1_RESTORE        0xdead
-#define    NAND_DEV_CMD_VLD_RESTORE    0xbeef
-
-/* NAND_FLASH_CMD bits */
-#define    PAGE_ACC            BIT(4)
-#define    LAST_PAGE            BIT(5)
-
-/* NAND_FLASH_CHIP_SELECT bits */
-#define    NAND_DEV_SEL            0
-#define    DM_EN                BIT(2)
-
-/* NAND_FLASH_STATUS bits */
-#define    FS_OP_ERR            BIT(4)
-#define    FS_READY_BSY_N            BIT(5)
-#define    FS_MPU_ERR            BIT(8)
-#define    FS_DEVICE_STS_ERR        BIT(16)
-#define    FS_DEVICE_WP            BIT(23)
-
-/* NAND_BUFFER_STATUS bits */
-#define    BS_UNCORRECTABLE_BIT        BIT(8)
-#define    BS_CORRECTABLE_ERR_MSK        0x1f
-
-/* NAND_DEVn_CFG0 bits */
-#define    DISABLE_STATUS_AFTER_WRITE    4
-#define    CW_PER_PAGE            6
-#define    UD_SIZE_BYTES            9
-#define    UD_SIZE_BYTES_MASK        GENMASK(18, 9)
-#define    ECC_PARITY_SIZE_BYTES_RS    19
-#define    SPARE_SIZE_BYTES        23
-#define    SPARE_SIZE_BYTES_MASK        GENMASK(26, 23)
-#define    NUM_ADDR_CYCLES            27
-#define    STATUS_BFR_READ            30
-#define    SET_RD_MODE_AFTER_STATUS    31
-
-/* NAND_DEVn_CFG0 bits */
-#define    DEV0_CFG1_ECC_DISABLE        0
-#define    WIDE_FLASH            1
-#define    NAND_RECOVERY_CYCLES        2
-#define    CS_ACTIVE_BSY            5
-#define    BAD_BLOCK_BYTE_NUM        6
-#define    BAD_BLOCK_IN_SPARE_AREA        16
-#define    WR_RD_BSY_GAP            17
-#define    ENABLE_BCH_ECC            27
-
-/* NAND_DEV0_ECC_CFG bits */
-#define    ECC_CFG_ECC_DISABLE        0
-#define    ECC_SW_RESET            1
-#define    ECC_MODE            4
-#define    ECC_PARITY_SIZE_BYTES_BCH    8
-#define    ECC_NUM_DATA_BYTES        16
-#define    ECC_NUM_DATA_BYTES_MASK        GENMASK(25, 16)
-#define    ECC_FORCE_CLK_OPEN        30
-
-/* NAND_DEV_CMD1 bits */
-#define    READ_ADDR            0
-
-/* NAND_DEV_CMD_VLD bits */
-#define    READ_START_VLD            BIT(0)
-#define    READ_STOP_VLD            BIT(1)
-#define    WRITE_START_VLD            BIT(2)
-#define    ERASE_START_VLD            BIT(3)
-#define    SEQ_READ_START_VLD        BIT(4)
-
-/* NAND_EBI2_ECC_BUF_CFG bits */
-#define    NUM_STEPS            0
-
-/* NAND_ERASED_CW_DETECT_CFG bits */
-#define    ERASED_CW_ECC_MASK        1
-#define    AUTO_DETECT_RES            0
-#define    MASK_ECC            BIT(ERASED_CW_ECC_MASK)
-#define    RESET_ERASED_DET        BIT(AUTO_DETECT_RES)
-#define    ACTIVE_ERASED_DET        (0 << AUTO_DETECT_RES)
-#define    CLR_ERASED_PAGE_DET        (RESET_ERASED_DET | MASK_ECC)
-#define    SET_ERASED_PAGE_DET        (ACTIVE_ERASED_DET | MASK_ECC)
-
-/* NAND_ERASED_CW_DETECT_STATUS bits */
-#define    PAGE_ALL_ERASED            BIT(7)
-#define    CODEWORD_ALL_ERASED        BIT(6)
-#define    PAGE_ERASED            BIT(5)
-#define    CODEWORD_ERASED            BIT(4)
-#define    ERASED_PAGE            (PAGE_ALL_ERASED | PAGE_ERASED)
-#define    ERASED_CW            (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
-
-/* NAND_READ_LOCATION_n bits */
-#define READ_LOCATION_OFFSET        0
-#define READ_LOCATION_SIZE        16
-#define READ_LOCATION_LAST        31
-
-/* Version Mask */
-#define    NAND_VERSION_MAJOR_MASK        0xf0000000
-#define    NAND_VERSION_MAJOR_SHIFT    28
-#define    NAND_VERSION_MINOR_MASK        0x0fff0000
-#define    NAND_VERSION_MINOR_SHIFT    16
-
-/* NAND OP_CMDs */
-#define    OP_PAGE_READ            0x2
-#define    OP_PAGE_READ_WITH_ECC        0x3
-#define    OP_PAGE_READ_WITH_ECC_SPARE    0x4
-#define    OP_PAGE_READ_ONFI_READ        0x5
-#define    OP_PROGRAM_PAGE            0x6
-#define    OP_PAGE_PROGRAM_WITH_ECC    0x7
-#define    OP_PROGRAM_PAGE_SPARE        0x9
-#define    OP_BLOCK_ERASE            0xa
-#define    OP_CHECK_STATUS            0xc
-#define    OP_FETCH_ID            0xb
-#define    OP_RESET_DEVICE            0xd
-
-/* Default Value for NAND_DEV_CMD_VLD */
-#define NAND_DEV_CMD_VLD_VAL        (READ_START_VLD | WRITE_START_VLD | \
-                     ERASE_START_VLD | SEQ_READ_START_VLD)
-
-/* NAND_CTRL bits */
-#define    BAM_MODE_EN            BIT(0)
-
-/*
- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
- * the driver calls the chunks 'step' or 'codeword' interchangeably
- */
-#define    NANDC_STEP_SIZE            512
-
-/*
- * the largest page size we support is 8K, this will have 16 steps/codewords
- * of 512 bytes each
- */
-#define    MAX_NUM_STEPS            (SZ_8K / NANDC_STEP_SIZE)
-
-/* we read at most 3 registers per codeword scan */
-#define    MAX_REG_RD            (3 * MAX_NUM_STEPS)
+#include <linux/mtd/nand-qpic-common.h>
  /* ECC modes supported by the controller */
  #define    ECC_NONE    BIT(0)
@@ -200,247 +21,6 @@ nandc_set_reg(chip, reg,            \
            ((cw_offset) << READ_LOCATION_OFFSET) |        \
            ((read_size) << READ_LOCATION_SIZE) |            \
            ((is_last_read_loc) << READ_LOCATION_LAST))
-/*
- * Returns the actual register address for all NAND_DEV_ registers
- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
- */
-#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
-
-/* Returns the NAND register physical address */
-#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
-
-/* Returns the dma address for reg read buffer */
-#define reg_buf_dma_addr(chip, vaddr) \
-    ((chip)->reg_read_dma + \
-    ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
-
-#define QPIC_PER_CW_CMD_ELEMENTS    32
-#define QPIC_PER_CW_CMD_SGL        32
-#define QPIC_PER_CW_DATA_SGL        8
-
-#define QPIC_NAND_COMPLETION_TIMEOUT    msecs_to_jiffies(2000)
-
-/*
- * Flags used in DMA descriptor preparation helper functions
- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
- */
-/* Don't set the EOT in current tx BAM sgl */
-#define NAND_BAM_NO_EOT            BIT(0)
-/* Set the NWD flag in current BAM sgl */
-#define NAND_BAM_NWD            BIT(1)
-/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
-#define NAND_BAM_NEXT_SGL        BIT(2)
-/*
- * Erased codeword status is being used two times in single transfer so this
- * flag will determine the current value of erased codeword status register
- */
-#define NAND_ERASED_CW_SET        BIT(4)
-
-#define MAX_ADDRESS_CYCLE        5
-
-/*
- * This data type corresponds to the BAM transaction which will be used for all
- * NAND transfers.
- * @bam_ce - the array of BAM command elements
- * @cmd_sgl - sgl for NAND BAM command pipe
- * @data_sgl - sgl for NAND BAM consumer/producer pipe
- * @last_data_desc - last DMA desc in data channel (tx/rx).
- * @last_cmd_desc - last DMA desc in command channel.
- * @txn_done - completion for NAND transfer.
- * @bam_ce_pos - the index in bam_ce which is available for next sgl
- * @bam_ce_start - the index in bam_ce which marks the start position ce
- *           for current sgl. It will be used for size calculation
- *           for current sgl
- * @cmd_sgl_pos - current index in command sgl.
- * @cmd_sgl_start - start index in command sgl.
- * @tx_sgl_pos - current index in data sgl for tx.
- * @tx_sgl_start - start index in data sgl for tx.
- * @rx_sgl_pos - current index in data sgl for rx.
- * @rx_sgl_start - start index in data sgl for rx.
- * @wait_second_completion - wait for second DMA desc completion before making
- *                 the NAND transfer completion.
- */
-struct bam_transaction {
-    struct bam_cmd_element *bam_ce;
-    struct scatterlist *cmd_sgl;
-    struct scatterlist *data_sgl;
-    struct dma_async_tx_descriptor *last_data_desc;
-    struct dma_async_tx_descriptor *last_cmd_desc;
-    struct completion txn_done;
-    u32 bam_ce_pos;
-    u32 bam_ce_start;
-    u32 cmd_sgl_pos;
-    u32 cmd_sgl_start;
-    u32 tx_sgl_pos;
-    u32 tx_sgl_start;
-    u32 rx_sgl_pos;
-    u32 rx_sgl_start;
-    bool wait_second_completion;
-};
-
-/*
- * This data type corresponds to the nand dma descriptor
- * @dma_desc - low level DMA engine descriptor
- * @list - list for desc_info
- *
- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
- *          ADM
- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
- * @dir - DMA transfer direction
- */
-struct desc_info {
-    struct dma_async_tx_descriptor *dma_desc;
-    struct list_head node;
-
-    union {
-        struct scatterlist adm_sgl;
-        struct {
-            struct scatterlist *bam_sgl;
-            int sgl_cnt;
-        };
-    };
-    enum dma_data_direction dir;
-};
-
-/*
- * holds the current register values that we want to write. acts as a contiguous
- * chunk of memory which we use to write the controller registers through DMA.
- */
-struct nandc_regs {
-    __le32 cmd;
-    __le32 addr0;
-    __le32 addr1;
-    __le32 chip_sel;
-    __le32 exec;
-
-    __le32 cfg0;
-    __le32 cfg1;
-    __le32 ecc_bch_cfg;
-
-    __le32 clrflashstatus;
-    __le32 clrreadstatus;
-
-    __le32 cmd1;
-    __le32 vld;
-
-    __le32 orig_cmd1;
-    __le32 orig_vld;
-
-    __le32 ecc_buf_cfg;
-    __le32 read_location0;
-    __le32 read_location1;
-    __le32 read_location2;
-    __le32 read_location3;
-    __le32 read_location_last0;
-    __le32 read_location_last1;
-    __le32 read_location_last2;
-    __le32 read_location_last3;
-
-    __le32 erased_cw_detect_cfg_clr;
-    __le32 erased_cw_detect_cfg_set;
-};
-
-/*
- * NAND controller data struct
- *
- * @dev:            parent device
- *
- * @base:            MMIO base
- *
- * @core_clk:            controller clock
- * @aon_clk:            another controller clock
- *
- * @regs:            a contiguous chunk of memory for DMA register
- *                writes. contains the register values to be
- *                written to controller
- *
- * @props:            properties of current NAND controller,
- *                initialized via DT match data
- *
- * @controller:            base controller structure
- * @host_list:            list containing all the chips attached to the
- *                controller
- *
- * @chan:            dma channel
- * @cmd_crci:            ADM DMA CRCI for command flow control
- * @data_crci:            ADM DMA CRCI for data flow control
- *
- * @desc_list:            DMA descriptor list (list of desc_infos)
- *
- * @data_buffer:        our local DMA buffer for page read/writes,
- *                used when we can't use the buffer provided
- *                by upper layers directly
- * @reg_read_buf:        local buffer for reading back registers via DMA
- *
- * @base_phys:            physical base address of controller registers
- * @base_dma:            dma base address of controller registers
- * @reg_read_dma:        contains dma address for register read buffer
- *
- * @buf_size/count/start:    markers for chip->legacy.read_buf/write_buf
- *                functions
- * @max_cwperpage:        maximum QPIC codewords required. calculated
- *                from all connected NAND devices pagesize
- *
- * @reg_read_pos:        marker for data read in reg_read_buf
- *
- * @cmd1/vld:            some fixed controller register values
- *
- * @exec_opwrite:        flag to select correct number of code word
- *                while reading status
- */
-struct qcom_nand_controller {
-    struct device *dev;
-
-    void __iomem *base;
-
-    struct clk *core_clk;
-    struct clk *aon_clk;
-
-    struct nandc_regs *regs;
-    struct bam_transaction *bam_txn;
-
-    const struct qcom_nandc_props *props;
-
-    struct nand_controller controller;
-    struct list_head host_list;
-
-    union {
-        /* will be used only by QPIC for BAM DMA */
-        struct {
-            struct dma_chan *tx_chan;
-            struct dma_chan *rx_chan;
-            struct dma_chan *cmd_chan;
-        };
-
-        /* will be used only by EBI2 for ADM DMA */
-        struct {
-            struct dma_chan *chan;
-            unsigned int cmd_crci;
-            unsigned int data_crci;
-        };
-    };
-
-    struct list_head desc_list;
-
-    u8        *data_buffer;
-    __le32        *reg_read_buf;
-
-    phys_addr_t base_phys;
-    dma_addr_t base_dma;
-    dma_addr_t reg_read_dma;
-
-    int        buf_size;
-    int        buf_count;
-    int        buf_start;
-    unsigned int    max_cwperpage;
-
-    int reg_read_pos;
-
-    u32 cmd1, vld;
-    bool exec_opwrite;
-};
-
  /*
   * NAND special boot partitions
   *
@@ -544,113 +124,17 @@ struct qcom_nand_host {
      bool bch_enabled;
  };
-/*
- * This data type corresponds to the NAND controller properties which varies
- * among different NAND controllers.
- * @ecc_modes - ecc mode for NAND
- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
- * @is_bam - whether NAND controller is using BAM
- * @is_qpic - whether NAND CTRL is part of qpic IP
- * @qpic_v2 - flag to indicate QPIC IP version 2
- * @use_codeword_fixup - whether NAND has different layout for boot partitions
- */
-struct qcom_nandc_props {
-    u32 ecc_modes;
-    u32 dev_cmd_reg_start;
-    bool is_bam;
-    bool is_qpic;
-    bool qpic_v2;
-    bool use_codeword_fixup;
-};
-
-/* Frees the BAM transaction memory */
-static void free_bam_transaction(struct qcom_nand_controller *nandc)
-{
-    struct bam_transaction *bam_txn = nandc->bam_txn;
-
-    devm_kfree(nandc->dev, bam_txn);
-}
-
-/* Allocates and Initializes the BAM transaction */
-static struct bam_transaction *
-alloc_bam_transaction(struct qcom_nand_controller *nandc)
-{
-    struct bam_transaction *bam_txn;
-    size_t bam_txn_size;
-    unsigned int num_cw = nandc->max_cwperpage;
-    void *bam_txn_buf;
-
-    bam_txn_size =
-        sizeof(*bam_txn) + num_cw *
-        ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-        (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-        (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
-
-    bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
-    if (!bam_txn_buf)
-        return NULL;
-
-    bam_txn = bam_txn_buf;
-    bam_txn_buf += sizeof(*bam_txn);
-
-    bam_txn->bam_ce = bam_txn_buf;
-    bam_txn_buf +=
-        sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
-
-    bam_txn->cmd_sgl = bam_txn_buf;
-    bam_txn_buf +=
-        sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
-
-    bam_txn->data_sgl = bam_txn_buf;
-
-    init_completion(&bam_txn->txn_done);
-
-    return bam_txn;
-}
-
-/* Clears the BAM transaction indexes */
-static void clear_bam_transaction(struct qcom_nand_controller *nandc)
+static void nandc_set_reg(struct nand_chip *chip, int offset,
+              u32 val)
  {
-    struct bam_transaction *bam_txn = nandc->bam_txn;
-
-    if (!nandc->props->is_bam)
-        return;
-
-    bam_txn->bam_ce_pos = 0;
-    bam_txn->bam_ce_start = 0;
-    bam_txn->cmd_sgl_pos = 0;
-    bam_txn->cmd_sgl_start = 0;
-    bam_txn->tx_sgl_pos = 0;
-    bam_txn->tx_sgl_start = 0;
-    bam_txn->rx_sgl_pos = 0;
-    bam_txn->rx_sgl_start = 0;
-    bam_txn->last_data_desc = NULL;
-    bam_txn->wait_second_completion = false;
-
-    sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-              QPIC_PER_CW_CMD_SGL);
-    sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-              QPIC_PER_CW_DATA_SGL);
-
-    reinit_completion(&bam_txn->txn_done);
-}
+    struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+    struct nandc_regs *regs = nandc->regs;
+    __le32 *reg;
-/* Callback for DMA descriptor completion */
-static void qpic_bam_dma_done(void *data)
-{
-    struct bam_transaction *bam_txn = data;
+    reg = offset_to_nandc_reg(regs, offset);
-    /*
-     * In case of data transfer with NAND, 2 callbacks will be generated.
-     * One for command channel and another one for data channel.
-     * If current transaction has data descriptors
-     * (i.e. wait_second_completion is true), then set this to false
-     * and wait for second DMA descriptor completion.
-     */
-    if (bam_txn->wait_second_completion)
-        bam_txn->wait_second_completion = false;
-    else
-        complete(&bam_txn->txn_done);
+    if (reg)
+        *reg = cpu_to_le32(val);
  }
  static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
@@ -658,13 +142,6 @@ static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
      return container_of(chip, struct qcom_nand_host, chip);
  }
-static inline struct qcom_nand_controller *
-get_qcom_nand_controller(struct nand_chip *chip)
-{
-    return container_of(chip->controller, struct qcom_nand_controller,
-                controller);
-}
-
  static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
  {
      return ioread32(nandc->base + offset);
@@ -676,91 +153,6 @@ static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
      iowrite32(val, nandc->base + offset);
  }
-static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
-                      bool is_cpu)
-{
-    if (!nandc->props->is_bam)
-        return;
-
-    if (is_cpu)
-        dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-                    MAX_REG_RD *
-                    sizeof(*nandc->reg_read_buf),
-                    DMA_FROM_DEVICE);
-    else
-        dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-                       MAX_REG_RD *
-                       sizeof(*nandc->reg_read_buf),
-                       DMA_FROM_DEVICE);
-}
-
-static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
-{
-    switch (offset) {
-    case NAND_FLASH_CMD:
-        return &regs->cmd;
-    case NAND_ADDR0:
-        return &regs->addr0;
-    case NAND_ADDR1:
-        return &regs->addr1;
-    case NAND_FLASH_CHIP_SELECT:
-        return &regs->chip_sel;
-    case NAND_EXEC_CMD:
-        return &regs->exec;
-    case NAND_FLASH_STATUS:
-        return &regs->clrflashstatus;
-    case NAND_DEV0_CFG0:
-        return &regs->cfg0;
-    case NAND_DEV0_CFG1:
-        return &regs->cfg1;
-    case NAND_DEV0_ECC_CFG:
-        return &regs->ecc_bch_cfg;
-    case NAND_READ_STATUS:
-        return &regs->clrreadstatus;
-    case NAND_DEV_CMD1:
-        return &regs->cmd1;
-    case NAND_DEV_CMD1_RESTORE:
-        return &regs->orig_cmd1;
-    case NAND_DEV_CMD_VLD:
-        return &regs->vld;
-    case NAND_DEV_CMD_VLD_RESTORE:
-        return &regs->orig_vld;
-    case NAND_EBI2_ECC_BUF_CFG:
-        return &regs->ecc_buf_cfg;
-    case NAND_READ_LOCATION_0:
-        return &regs->read_location0;
-    case NAND_READ_LOCATION_1:
-        return &regs->read_location1;
-    case NAND_READ_LOCATION_2:
-        return &regs->read_location2;
-    case NAND_READ_LOCATION_3:
-        return &regs->read_location3;
-    case NAND_READ_LOCATION_LAST_CW_0:
-        return &regs->read_location_last0;
-    case NAND_READ_LOCATION_LAST_CW_1:
-        return &regs->read_location_last1;
-    case NAND_READ_LOCATION_LAST_CW_2:
-        return &regs->read_location_last2;
-    case NAND_READ_LOCATION_LAST_CW_3:
-        return &regs->read_location_last3;
-    default:
-        return NULL;
-    }
-}
-
-static void nandc_set_reg(struct nand_chip *chip, int offset,
-              u32 val)
-{
-    struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-    struct nandc_regs *regs = nandc->regs;
-    __le32 *reg;
-
-    reg = offset_to_nandc_reg(regs, offset);
-
-    if (reg)
-        *reg = cpu_to_le32(val);
-}
-
  /* Helper to check the code word, whether it is last cw or not */
  static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
  {
@@ -852,383 +244,6 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i
                     host->cw_data : host->cw_size, 1);
  }
-/*
- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
- * which will be submitted to DMA engine.
- */
-static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-                  struct dma_chan *chan,
-                  unsigned long flags)
-{
-    struct desc_info *desc;
-    struct scatterlist *sgl;
-    unsigned int sgl_cnt;
-    int ret;
-    struct bam_transaction *bam_txn = nandc->bam_txn;
-    enum dma_transfer_direction dir_eng;
-    struct dma_async_tx_descriptor *dma_desc;
-
-    desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-    if (!desc)
-        return -ENOMEM;
-
-    if (chan == nandc->cmd_chan) {
-        sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-        sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-        bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-        dir_eng = DMA_MEM_TO_DEV;
-        desc->dir = DMA_TO_DEVICE;
-    } else if (chan == nandc->tx_chan) {
-        sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-        sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-        bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-        dir_eng = DMA_MEM_TO_DEV;
-        desc->dir = DMA_TO_DEVICE;
-    } else {
-        sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-        sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-        bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-        dir_eng = DMA_DEV_TO_MEM;
-        desc->dir = DMA_FROM_DEVICE;
-    }
-
-    sg_mark_end(sgl + sgl_cnt - 1);
-    ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-    if (ret == 0) {
-        dev_err(nandc->dev, "failure in mapping desc\n");
-        kfree(desc);
-        return -ENOMEM;
-    }
-
-    desc->sgl_cnt = sgl_cnt;
-    desc->bam_sgl = sgl;
-
-    dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-                       flags);
-
-    if (!dma_desc) {
-        dev_err(nandc->dev, "failure in prep desc\n");
-        dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-        kfree(desc);
-        return -EINVAL;
-    }
-
-    desc->dma_desc = dma_desc;
-
-    /* update last data/command descriptor */
-    if (chan == nandc->cmd_chan)
-        bam_txn->last_cmd_desc = dma_desc;
-    else
-        bam_txn->last_data_desc = dma_desc;
-
-    list_add_tail(&desc->node, &nandc->desc_list);
-
-    return 0;
-}
-
-/*
- * Prepares the command descriptor for BAM DMA which will be used for NAND
- * register reads and writes. The command descriptor requires the command
- * to be formed in command element type so this function uses the command
- * element from bam transaction ce array and fills the same with required
- * data. A single SGL can contain multiple command elements so
- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
- * after the current command element.
- */
-static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-                 int reg_off, const void *vaddr,
-                 int size, unsigned int flags)
-{
-    int bam_ce_size;
-    int i, ret;
-    struct bam_cmd_element *bam_ce_buffer;
-    struct bam_transaction *bam_txn = nandc->bam_txn;
-
-    bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
-
-    /* fill the command desc */
-    for (i = 0; i < size; i++) {
-        if (read)
-            bam_prep_ce(&bam_ce_buffer[i],
-                    nandc_reg_phys(nandc, reg_off + 4 * i),
-                    BAM_READ_COMMAND,
-                    reg_buf_dma_addr(nandc,
-                             (__le32 *)vaddr + i));
-        else
-            bam_prep_ce_le32(&bam_ce_buffer[i],
-                     nandc_reg_phys(nandc, reg_off + 4 * i),
-                     BAM_WRITE_COMMAND,
-                     *((__le32 *)vaddr + i));
-    }
-
-    bam_txn->bam_ce_pos += size;
-
-    /* use the separate sgl after this command */
-    if (flags & NAND_BAM_NEXT_SGL) {
-        bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-        bam_ce_size = (bam_txn->bam_ce_pos -
-                bam_txn->bam_ce_start) *
-                sizeof(struct bam_cmd_element);
-        sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-               bam_ce_buffer, bam_ce_size);
-        bam_txn->cmd_sgl_pos++;
-        bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-
-        if (flags & NAND_BAM_NWD) {
-            ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-                             DMA_PREP_FENCE |
-                             DMA_PREP_CMD);
-            if (ret)
-                return ret;
-        }
-    }
-
-    return 0;
-}
-
-/*
- * Prepares the data descriptor for BAM DMA which will be used for NAND
- * data reads and writes.
- */
-static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-                  const void *vaddr,
-                  int size, unsigned int flags)
-{
-    int ret;
-    struct bam_transaction *bam_txn = nandc->bam_txn;
-
-    if (read) {
-        sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-               vaddr, size);
-        bam_txn->rx_sgl_pos++;
-    } else {
-        sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-               vaddr, size);
-        bam_txn->tx_sgl_pos++;
-
-        /*
-         * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-         * is not set, form the DMA descriptor
-         */
-        if (!(flags & NAND_BAM_NO_EOT)) {
-            ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-                             DMA_PREP_INTERRUPT);
-            if (ret)
-                return ret;
-        }
-    }
-
-    return 0;
-}
-
-static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-                 int reg_off, const void *vaddr, int size,
-                 bool flow_control)
-{
-    struct desc_info *desc;
-    struct dma_async_tx_descriptor *dma_desc;
-    struct scatterlist *sgl;
-    struct dma_slave_config slave_conf;
-    struct qcom_adm_peripheral_config periph_conf = {};
-    enum dma_transfer_direction dir_eng;
-    int ret;
-
-    desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-    if (!desc)
-        return -ENOMEM;
-
-    sgl = &desc->adm_sgl;
-
-    sg_init_one(sgl, vaddr, size);
-
-    if (read) {
-        dir_eng = DMA_DEV_TO_MEM;
-        desc->dir = DMA_FROM_DEVICE;
-    } else {
-        dir_eng = DMA_MEM_TO_DEV;
-        desc->dir = DMA_TO_DEVICE;
-    }
-
-    ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-    if (ret == 0) {
-        ret = -ENOMEM;
-        goto err;
-    }
-
-    memset(&slave_conf, 0x00, sizeof(slave_conf));
-
-    slave_conf.device_fc = flow_control;
-    if (read) {
-        slave_conf.src_maxburst = 16;
-        slave_conf.src_addr = nandc->base_dma + reg_off;
-        if (nandc->data_crci) {
-            periph_conf.crci = nandc->data_crci;
-            slave_conf.peripheral_config = &periph_conf;
-            slave_conf.peripheral_size = sizeof(periph_conf);
-        }
-    } else {
-        slave_conf.dst_maxburst = 16;
-        slave_conf.dst_addr = nandc->base_dma + reg_off;
-        if (nandc->cmd_crci) {
-            periph_conf.crci = nandc->cmd_crci;
-            slave_conf.peripheral_config = &periph_conf;
-            slave_conf.peripheral_size = sizeof(periph_conf);
-        }
-    }
-
-    ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-    if (ret) {
-        dev_err(nandc->dev, "failed to configure dma channel\n");
-        goto err;
-    }
-
-    dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-    if (!dma_desc) {
-        dev_err(nandc->dev, "failed to prepare desc\n");
-        ret = -EINVAL;
-        goto err;
-    }
-
-    desc->dma_desc = dma_desc;
-
-    list_add_tail(&desc->node, &nandc->desc_list);
-
-    return 0;
-err:
-    kfree(desc);
-
-    return ret;
-}
-
-/*
- * read_reg_dma:    prepares a descriptor to read a given number of
- *            contiguous registers to the reg_read_buf pointer
- *
- * @first:        offset of the first register in the contiguous block
- * @num_regs:        number of registers to read
- * @flags:        flags to control DMA descriptor preparation
- */
-static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
-            int num_regs, unsigned int flags)
-{
-    bool flow_control = false;
-    void *vaddr;
-
-    vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-    nandc->reg_read_pos += num_regs;
-
-    if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-        first = dev_cmd_reg_addr(nandc, first);
-
-    if (nandc->props->is_bam)
-        return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-                         num_regs, flags);
-
-    if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-        flow_control = true;
-
-    return prep_adm_dma_desc(nandc, true, first, vaddr,
-                 num_regs * sizeof(u32), flow_control);
-}
-
-/*
- * write_reg_dma:    prepares a descriptor to write a given number of
- *            contiguous registers
- *
- * @first:        offset of the first register in the contiguous block
- * @num_regs:        number of registers to write
- * @flags:        flags to control DMA descriptor preparation
- */
-static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
-             int num_regs, unsigned int flags)
-{
-    bool flow_control = false;
-    struct nandc_regs *regs = nandc->regs;
-    void *vaddr;
-
-    vaddr = offset_to_nandc_reg(regs, first);
-
-    if (first == NAND_ERASED_CW_DETECT_CFG) {
-        if (flags & NAND_ERASED_CW_SET)
-            vaddr = &regs->erased_cw_detect_cfg_set;
-        else
-            vaddr = &regs->erased_cw_detect_cfg_clr;
-    }
-
-    if (first == NAND_EXEC_CMD)
-        flags |= NAND_BAM_NWD;
-
-    if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-        first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
-
-    if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-        first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-
-    if (nandc->props->is_bam)
-        return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-                         num_regs, flags);
-
-    if (first == NAND_FLASH_CMD)
-        flow_control = true;
-
-    return prep_adm_dma_desc(nandc, false, first, vaddr,
-                 num_regs * sizeof(u32), flow_control);
-}
-
-/*
- * read_data_dma:    prepares a DMA descriptor to transfer data from the
- *            controller's internal buffer to the buffer 'vaddr'
- *
- * @reg_off:        offset within the controller's data buffer
- * @vaddr:        virtual address of the buffer we want to write to
- * @size:        DMA transaction size in bytes
- * @flags:        flags to control DMA descriptor preparation
- */
-static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-             const u8 *vaddr, int size, unsigned int flags)
-{
-    if (nandc->props->is_bam)
-        return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-
-    return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-}
-
-/*
- * write_data_dma:    prepares a DMA descriptor to transfer data from
- *            'vaddr' to the controller's internal buffer
- *
- * @reg_off:        offset within the controller's data buffer
- * @vaddr:        virtual address of the buffer we want to read from
- * @size:        DMA transaction size in bytes
- * @flags:        flags to control DMA descriptor preparation
- */
-static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-              const u8 *vaddr, int size, unsigned int flags)
-{
-    if (nandc->props->is_bam)
-        return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-
-    return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-}
-
-/*
- * Helper to prepare DMA descriptors for configuring registers
- * before reading a NAND page.
- */
-static void config_nand_page_read(struct nand_chip *chip)
-{
-    struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-    write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-    write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-    if (!nandc->props->qpic_v2)
-        write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-    write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
-    write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
-              NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-}
-
  /*
   * Helper to prepare DMA descriptors for configuring registers
   * before reading each codeword in NAND page.
@@ -1303,88 +318,6 @@ static void config_nand_cw_write(struct nand_chip *chip)
      write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
  }
-/* helpers to submit/free our list of dma descriptors */
-static int submit_descs(struct qcom_nand_controller *nandc)
-{
-    struct desc_info *desc, *n;
-    dma_cookie_t cookie = 0;
-    struct bam_transaction *bam_txn = nandc->bam_txn;
-    int ret = 0;
-
-    if (nandc->props->is_bam) {
-        if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-            ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-            if (ret)
-                goto err_unmap_free_desc;
-        }
-
-        if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-            ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-                           DMA_PREP_INTERRUPT);
-            if (ret)
-                goto err_unmap_free_desc;
-        }
-
-        if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-            ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-                           DMA_PREP_CMD);
-            if (ret)
-                goto err_unmap_free_desc;
-        }
-    }
-
-    list_for_each_entry(desc, &nandc->desc_list, node)
-        cookie = dmaengine_submit(desc->dma_desc);
-
-    if (nandc->props->is_bam) {
-        bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
-        bam_txn->last_cmd_desc->callback_param = bam_txn;
-        if (bam_txn->last_data_desc) {
-            bam_txn->last_data_desc->callback = qpic_bam_dma_done;
-            bam_txn->last_data_desc->callback_param = bam_txn;
-            bam_txn->wait_second_completion = true;
-        }
-
-        dma_async_issue_pending(nandc->tx_chan);
-        dma_async_issue_pending(nandc->rx_chan);
-        dma_async_issue_pending(nandc->cmd_chan);
-
-        if (!wait_for_completion_timeout(&bam_txn->txn_done,
-                         QPIC_NAND_COMPLETION_TIMEOUT))
-            ret = -ETIMEDOUT;
-    } else {
-        if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-            ret = -ETIMEDOUT;
-    }
-
-err_unmap_free_desc:
-    /*
-     * Unmap the dma sg_list and free the desc allocated by both
-     * prepare_bam_async_desc() and prep_adm_dma_desc() functions.
-     */
-    list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-        list_del(&desc->node);
-
-        if (nandc->props->is_bam)
-            dma_unmap_sg(nandc->dev, desc->bam_sgl,
-                     desc->sgl_cnt, desc->dir);
-        else
-            dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-                     desc->dir);
-
-        kfree(desc);
-    }
-
-    return ret;
-}
-
-/* reset the register read buffer for next NAND operation */
-static void clear_read_regs(struct qcom_nand_controller *nandc)
-{
-    nandc->reg_read_pos = 0;
-    nandc_read_buffer_sync(nandc, false);
-}
-
  /*
   * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
   * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
@@ -3016,136 +1949,6 @@ static const struct nand_controller_ops qcom_nandc_ops = {
      .exec_op = qcom_nand_exec_op,
  };
-static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
-{
-    if (nandc->props->is_bam) {
-        if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-            dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-                     MAX_REG_RD *
-                     sizeof(*nandc->reg_read_buf),
-                     DMA_FROM_DEVICE);
-
-        if (nandc->tx_chan)
-            dma_release_channel(nandc->tx_chan);
-
-        if (nandc->rx_chan)
-            dma_release_channel(nandc->rx_chan);
-
-        if (nandc->cmd_chan)
-            dma_release_channel(nandc->cmd_chan);
-    } else {
-        if (nandc->chan)
-            dma_release_channel(nandc->chan);
-    }
-}
-
-static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
-{
-    int ret;
-
-    ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-    if (ret) {
-        dev_err(nandc->dev, "failed to set DMA mask\n");
-        return ret;
-    }
-
-    /*
-     * we use the internal buffer for reading ONFI params, reading small
-     * data like ID and status, and preforming read-copy-write operations
-     * when writing to a codeword partially. 532 is the maximum possible
-     * size of a codeword for our nand controller
-     */
-    nandc->buf_size = 532;
-
-    nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
-    if (!nandc->data_buffer)
-        return -ENOMEM;
-
-    nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
-    if (!nandc->regs)
-        return -ENOMEM;
-
-    nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
-                       sizeof(*nandc->reg_read_buf),
-                       GFP_KERNEL);
-    if (!nandc->reg_read_buf)
-        return -ENOMEM;
-
-    if (nandc->props->is_bam) {
-        nandc->reg_read_dma =
-            dma_map_single(nandc->dev, nandc->reg_read_buf,
-                       MAX_REG_RD *
-                       sizeof(*nandc->reg_read_buf),
-                       DMA_FROM_DEVICE);
-        if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-            dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-            return -EIO;
-        }
-
-        nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
-        if (IS_ERR(nandc->tx_chan)) {
-            ret = PTR_ERR(nandc->tx_chan);
-            nandc->tx_chan = NULL;
-            dev_err_probe(nandc->dev, ret,
-                      "tx DMA channel request failed\n");
-            goto unalloc;
-        }
-
-        nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
-        if (IS_ERR(nandc->rx_chan)) {
-            ret = PTR_ERR(nandc->rx_chan);
-            nandc->rx_chan = NULL;
-            dev_err_probe(nandc->dev, ret,
-                      "rx DMA channel request failed\n");
-            goto unalloc;
-        }
-
-        nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
-        if (IS_ERR(nandc->cmd_chan)) {
-            ret = PTR_ERR(nandc->cmd_chan);
-            nandc->cmd_chan = NULL;
-            dev_err_probe(nandc->dev, ret,
-                      "cmd DMA channel request failed\n");
-            goto unalloc;
-        }
-
-        /*
-         * Initially allocate BAM transaction to read ONFI param page.
-         * After detecting all the devices, this BAM transaction will
-         * be freed and the next BAM transaction will be allocated with
-         * maximum codeword size
-         */
-        nandc->max_cwperpage = 1;
-        nandc->bam_txn = alloc_bam_transaction(nandc);
-        if (!nandc->bam_txn) {
-            dev_err(nandc->dev,
-                "failed to allocate bam transaction\n");
-            ret = -ENOMEM;
-            goto unalloc;
-        }
-    } else {
-        nandc->chan = dma_request_chan(nandc->dev, "rxtx");
-        if (IS_ERR(nandc->chan)) {
-            ret = PTR_ERR(nandc->chan);
-            nandc->chan = NULL;
-            dev_err_probe(nandc->dev, ret,
-                      "rxtx DMA channel request failed\n");
-            return ret;
-        }
-    }
-
-    INIT_LIST_HEAD(&nandc->desc_list);
-    INIT_LIST_HEAD(&nandc->host_list);
-
-    nand_controller_init(&nandc->controller);
-    nandc->controller.ops = &qcom_nandc_ops;
-
-    return 0;
-unalloc:
-    qcom_nandc_unalloc(nandc);
-    return ret;
-}
-
  /* one time setup of a few nand controller registers */
  static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
  {
@@ -3427,6 +2230,9 @@ static int qcom_nandc_probe(struct platform_device *pdev)
      if (ret)
          goto err_nandc_alloc;
+    nand_controller_init(&nandc->controller);
+    nandc->controller.ops = &qcom_nandc_ops;
+
      ret = qcom_nandc_setup(nandc);
      if (ret)
          goto err_setup;
@@ -3473,28 +2279,28 @@ static void qcom_nandc_remove(struct platform_device *pdev)
                 DMA_BIDIRECTIONAL, 0);
  }
-static const struct qcom_nandc_props ipq806x_nandc_props = {
+static struct qcom_nandc_props ipq806x_nandc_props = {
      .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
      .is_bam = false,
      .use_codeword_fixup = true,
      .dev_cmd_reg_start = 0x0,
  };
-static const struct qcom_nandc_props ipq4019_nandc_props = {
+static struct qcom_nandc_props ipq4019_nandc_props = {
      .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
      .is_bam = true,
      .is_qpic = true,
      .dev_cmd_reg_start = 0x0,
  };
-static const struct qcom_nandc_props ipq8074_nandc_props = {
+static struct qcom_nandc_props ipq8074_nandc_props = {
      .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
      .is_bam = true,
      .is_qpic = true,
      .dev_cmd_reg_start = 0x7000,
  };
-static const struct qcom_nandc_props sdx55_nandc_props = {
+static struct qcom_nandc_props sdx55_nandc_props = {
      .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
      .is_bam = true,
      .is_qpic = true,
diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h
new file mode 100644
index 000000000000..891f975ca173
--- /dev/null
+++ b/include/linux/mtd/nand-qpic-common.h
@@ -0,0 +1,488 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * QCOM QPIC common APIs header file
+ *
+ * Copyright (c) 2023 Qualcomm Inc.
+ * Authors:     Md sadre Alam           <quic_mdalam@xxxxxxxxxxx>
+ *        Sricharan R             <quic_srichara@xxxxxxxxxxx>
+ *        Varadarajan Narayanan   <quic_varada@xxxxxxxxxxx>
+ *
+ */
+#ifndef __MTD_NAND_QPIC_COMMON_H__
+#define __MTD_NAND_QPIC_COMMON_H__
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/qcom_adm.h>
+#include <linux/dma/qcom_bam_dma.h>
+#include <linux/module.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* NANDc reg offsets */
+#define    NAND_FLASH_CMD            0x00
+#define    NAND_ADDR0            0x04
+#define    NAND_ADDR1            0x08
+#define    NAND_FLASH_CHIP_SELECT        0x0c
+#define    NAND_EXEC_CMD            0x10
+#define    NAND_FLASH_STATUS        0x14
+#define    NAND_BUFFER_STATUS        0x18
+#define    NAND_DEV0_CFG0            0x20
+#define    NAND_DEV0_CFG1            0x24
+#define    NAND_DEV0_ECC_CFG        0x28
+#define    NAND_AUTO_STATUS_EN        0x2c
+#define    NAND_DEV1_CFG0            0x30
+#define    NAND_DEV1_CFG1            0x34
+#define    NAND_READ_ID            0x40
+#define    NAND_READ_STATUS        0x44
+#define    NAND_DEV_CMD0            0xa0
+#define    NAND_DEV_CMD1            0xa4
+#define    NAND_DEV_CMD2            0xa8
+#define    NAND_DEV_CMD_VLD        0xac
+#define    SFLASHC_BURST_CFG        0xe0
+#define    NAND_ERASED_CW_DETECT_CFG    0xe8
+#define    NAND_ERASED_CW_DETECT_STATUS    0xec
+#define    NAND_EBI2_ECC_BUF_CFG        0xf0
+#define    FLASH_BUF_ACC            0x100
+
+#define    NAND_CTRL            0xf00
+#define    NAND_VERSION            0xf08
+#define    NAND_READ_LOCATION_0        0xf20
+#define    NAND_READ_LOCATION_1        0xf24
+#define    NAND_READ_LOCATION_2        0xf28
+#define    NAND_READ_LOCATION_3        0xf2c
+#define    NAND_READ_LOCATION_LAST_CW_0    0xf40
+#define    NAND_READ_LOCATION_LAST_CW_1    0xf44
+#define    NAND_READ_LOCATION_LAST_CW_2    0xf48
+#define    NAND_READ_LOCATION_LAST_CW_3    0xf4c
+
+/* dummy register offsets, used by write_reg_dma */
+#define    NAND_DEV_CMD1_RESTORE        0xdead
+#define    NAND_DEV_CMD_VLD_RESTORE    0xbeef
+
+/* NAND_FLASH_CMD bits */
+#define    PAGE_ACC            BIT(4)
+#define    LAST_PAGE            BIT(5)
+
+/* NAND_FLASH_CHIP_SELECT bits */
+#define    NAND_DEV_SEL            0
+#define    DM_EN                BIT(2)
+
+/* NAND_FLASH_STATUS bits */
+#define    FS_OP_ERR            BIT(4)
+#define    FS_READY_BSY_N            BIT(5)
+#define    FS_MPU_ERR            BIT(8)
+#define    FS_DEVICE_STS_ERR        BIT(16)
+#define    FS_DEVICE_WP            BIT(23)
+
+/* NAND_BUFFER_STATUS bits */
+#define    BS_UNCORRECTABLE_BIT        BIT(8)
+#define    BS_CORRECTABLE_ERR_MSK        0x1f
+
+/* NAND_DEVn_CFG0 bits */
+#define    DISABLE_STATUS_AFTER_WRITE    4
+#define    CW_PER_PAGE            6
+#define    UD_SIZE_BYTES            9
+#define    UD_SIZE_BYTES_MASK        GENMASK(18, 9)
+#define    ECC_PARITY_SIZE_BYTES_RS    19
+#define    SPARE_SIZE_BYTES        23
+#define    SPARE_SIZE_BYTES_MASK        GENMASK(26, 23)
+#define    NUM_ADDR_CYCLES            27
+#define    STATUS_BFR_READ            30
+#define    SET_RD_MODE_AFTER_STATUS    31
+
+/* NAND_DEVn_CFG0 bits */
+#define    DEV0_CFG1_ECC_DISABLE        0
+#define    WIDE_FLASH            1
+#define    NAND_RECOVERY_CYCLES        2
+#define    CS_ACTIVE_BSY            5
+#define    BAD_BLOCK_BYTE_NUM        6
+#define    BAD_BLOCK_IN_SPARE_AREA        16
+#define    WR_RD_BSY_GAP            17
+#define    ENABLE_BCH_ECC            27
+
+/* NAND_DEV0_ECC_CFG bits */
+#define    ECC_CFG_ECC_DISABLE        0
+#define    ECC_SW_RESET            1
+#define    ECC_MODE            4
+#define    ECC_PARITY_SIZE_BYTES_BCH    8
+#define    ECC_NUM_DATA_BYTES        16
+#define    ECC_NUM_DATA_BYTES_MASK        GENMASK(25, 16)
+#define    ECC_FORCE_CLK_OPEN        30
+
+/* NAND_DEV_CMD1 bits */
+#define    READ_ADDR            0
+
+/* NAND_DEV_CMD_VLD bits */
+#define    READ_START_VLD            BIT(0)
+#define    READ_STOP_VLD            BIT(1)
+#define    WRITE_START_VLD            BIT(2)
+#define    ERASE_START_VLD            BIT(3)
+#define    SEQ_READ_START_VLD        BIT(4)
+
+/* NAND_EBI2_ECC_BUF_CFG bits */
+#define    NUM_STEPS            0
+
+/* NAND_ERASED_CW_DETECT_CFG bits */
+#define    ERASED_CW_ECC_MASK        1
+#define    AUTO_DETECT_RES            0
+#define    MASK_ECC            BIT(ERASED_CW_ECC_MASK)
+#define    RESET_ERASED_DET        BIT(AUTO_DETECT_RES)
+#define    ACTIVE_ERASED_DET        (0 << AUTO_DETECT_RES)
+#define    CLR_ERASED_PAGE_DET        (RESET_ERASED_DET | MASK_ECC)
+#define    SET_ERASED_PAGE_DET        (ACTIVE_ERASED_DET | MASK_ECC)
+
+/* NAND_ERASED_CW_DETECT_STATUS bits */
+#define    PAGE_ALL_ERASED            BIT(7)
+#define    CODEWORD_ALL_ERASED        BIT(6)
+#define    PAGE_ERASED            BIT(5)
+#define    CODEWORD_ERASED            BIT(4)
+#define    ERASED_PAGE            (PAGE_ALL_ERASED | PAGE_ERASED)
+#define    ERASED_CW            (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+
+/* NAND_READ_LOCATION_n bits */
+#define READ_LOCATION_OFFSET        0
+#define READ_LOCATION_SIZE        16
+#define READ_LOCATION_LAST        31
+
+/* Version Mask */
+#define    NAND_VERSION_MAJOR_MASK        0xf0000000
+#define    NAND_VERSION_MAJOR_SHIFT    28
+#define    NAND_VERSION_MINOR_MASK        0x0fff0000
+#define    NAND_VERSION_MINOR_SHIFT    16
+
+/* NAND OP_CMDs */
+#define    OP_PAGE_READ            0x2
+#define    OP_PAGE_READ_WITH_ECC        0x3
+#define    OP_PAGE_READ_WITH_ECC_SPARE    0x4
+#define    OP_PAGE_READ_ONFI_READ        0x5
+#define    OP_PROGRAM_PAGE            0x6
+#define    OP_PAGE_PROGRAM_WITH_ECC    0x7
+#define    OP_PROGRAM_PAGE_SPARE        0x9
+#define    OP_BLOCK_ERASE            0xa
+#define    OP_CHECK_STATUS            0xc
+#define    OP_FETCH_ID            0xb
+#define    OP_RESET_DEVICE            0xd
+
+/* Default Value for NAND_DEV_CMD_VLD */
+#define NAND_DEV_CMD_VLD_VAL        (READ_START_VLD | WRITE_START_VLD | \
+                     ERASE_START_VLD | SEQ_READ_START_VLD)
+
+/* NAND_CTRL bits */
+#define    BAM_MODE_EN            BIT(0)
+
+/*
+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+ * the driver calls the chunks 'step' or 'codeword' interchangeably
+ */
+#define    NANDC_STEP_SIZE            512
+
+/*
+ * the largest page size we support is 8K, this will have 16 steps/codewords
+ * of 512 bytes each
+ */
+#define    MAX_NUM_STEPS            (SZ_8K / NANDC_STEP_SIZE)
+
+/* we read at most 3 registers per codeword scan */
+#define    MAX_REG_RD            (3 * MAX_NUM_STEPS)
+
+#define QPIC_PER_CW_CMD_ELEMENTS    32
+#define QPIC_PER_CW_CMD_SGL        32
+#define QPIC_PER_CW_DATA_SGL        8
+
+#define QPIC_NAND_COMPLETION_TIMEOUT    msecs_to_jiffies(2000)
+
+/*
+ * Flags used in DMA descriptor preparation helper functions
+ * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
+ */
+/* Don't set the EOT in current tx BAM sgl */
+#define NAND_BAM_NO_EOT            BIT(0)
+/* Set the NWD flag in current BAM sgl */
+#define NAND_BAM_NWD            BIT(1)
+/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
+#define NAND_BAM_NEXT_SGL        BIT(2)
+
+/*
+ * Returns the actual register address for all NAND_DEV_ registers
+ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
+ */
+#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
+
+/* Returns the NAND register physical address */
+#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
+
+/* Returns the dma address for reg read buffer */
+#define reg_buf_dma_addr(chip, vaddr) \
+    ((chip)->reg_read_dma + \
+    ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
+
+/*
+ * Erased codeword status is being used two times in single transfer so this
+ * flag will determine the current value of erased codeword status register
+ */
+#define NAND_ERASED_CW_SET        BIT(4)
+
+#define MAX_ADDRESS_CYCLE        5
+
+/*
+ * This data type corresponds to the BAM transaction which will be used for all
+ * NAND transfers.
+ * @bam_ce - the array of BAM command elements
+ * @cmd_sgl - sgl for NAND BAM command pipe
+ * @data_sgl - sgl for NAND BAM consumer/producer pipe
+ * @last_data_desc - last DMA desc in data channel (tx/rx).
+ * @last_cmd_desc - last DMA desc in command channel.
+ * @txn_done - completion for NAND transfer.
+ * @bam_ce_pos - the index in bam_ce which is available for next sgl
+ * @bam_ce_start - the index in bam_ce which marks the start position ce
+ *           for current sgl. It will be used for size calculation
+ *           for current sgl
+ * @cmd_sgl_pos - current index in command sgl.
+ * @cmd_sgl_start - start index in command sgl.
+ * @tx_sgl_pos - current index in data sgl for tx.
+ * @tx_sgl_start - start index in data sgl for tx.
+ * @rx_sgl_pos - current index in data sgl for rx.
+ * @rx_sgl_start - start index in data sgl for rx.
+ * @wait_second_completion - wait for second DMA desc completion before making
+ *                 the NAND transfer completion.
+ */
+struct bam_transaction {
+    struct bam_cmd_element *bam_ce;
+    struct scatterlist *cmd_sgl;
+    struct scatterlist *data_sgl;
+    struct dma_async_tx_descriptor *last_data_desc;
+    struct dma_async_tx_descriptor *last_cmd_desc;
+    struct completion txn_done;
+    u32 bam_ce_pos;
+    u32 bam_ce_start;
+    u32 cmd_sgl_pos;
+    u32 cmd_sgl_start;
+    u32 tx_sgl_pos;
+    u32 tx_sgl_start;
+    u32 rx_sgl_pos;
+    u32 rx_sgl_start;
+    bool wait_second_completion;
+};
+
+/*
+ * This data type corresponds to the nand dma descriptor
+ * @dma_desc - low level DMA engine descriptor
+ * @list - list for desc_info
+ *
+ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
+ *          ADM
+ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
+ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
+ * @dir - DMA transfer direction
+ */
+struct desc_info {
+    struct dma_async_tx_descriptor *dma_desc;
+    struct list_head node;
+
+    union {
+        struct scatterlist adm_sgl;
+        struct {
+            struct scatterlist *bam_sgl;
+            int sgl_cnt;
+        };
+    };
+    enum dma_data_direction dir;
+};
+
+/*
+ * holds the current register values that we want to write. acts as a contiguous
+ * chunk of memory which we use to write the controller registers through DMA.
+ */
+struct nandc_regs {
+    __le32 cmd;
+    __le32 addr0;
+    __le32 addr1;
+    __le32 chip_sel;
+    __le32 exec;
+
+    __le32 cfg0;
+    __le32 cfg1;
+    __le32 ecc_bch_cfg;
+
+    __le32 clrflashstatus;
+    __le32 clrreadstatus;
+
+    __le32 cmd1;
+    __le32 vld;
+
+    __le32 orig_cmd1;
+    __le32 orig_vld;
+
+    __le32 ecc_buf_cfg;
+    __le32 read_location0;
+    __le32 read_location1;
+    __le32 read_location2;
+    __le32 read_location3;
+    __le32 read_location_last0;
+    __le32 read_location_last1;
+    __le32 read_location_last2;
+    __le32 read_location_last3;
+
+    __le32 erased_cw_detect_cfg_clr;
+    __le32 erased_cw_detect_cfg_set;
+};
+
+/*
+ * NAND controller data struct
+ *
+ * @dev:            parent device
+ *
+ * @base:            MMIO base
+ *
+ * @core_clk:            controller clock
+ * @aon_clk:            another controller clock
+ *
+ * @regs:            a contiguous chunk of memory for DMA register
+ *                writes. contains the register values to be
+ *                written to controller
+ *
+ * @props:            properties of current NAND controller,
+ *                initialized via DT match data
+ *
+ * @controller:            base controller structure
+ * @host_list:            list containing all the chips attached to the
+ *                controller
+ *
+ * @chan:            dma channel
+ * @cmd_crci:            ADM DMA CRCI for command flow control
+ * @data_crci:            ADM DMA CRCI for data flow control
+ *
+ * @desc_list:            DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:        our local DMA buffer for page read/writes,
+ *                used when we can't use the buffer provided
+ *                by upper layers directly
+ * @reg_read_buf:        local buffer for reading back registers via DMA
+ *
+ * @base_phys:            physical base address of controller registers
+ * @base_dma:            dma base address of controller registers
+ * @reg_read_dma:        contains dma address for register read buffer
+ *
+ * @buf_size/count/start:    markers for chip->legacy.read_buf/write_buf
+ *                functions
+ * @max_cwperpage:        maximum QPIC codewords required. calculated
+ *                from all connected NAND devices pagesize
+ *
+ * @reg_read_pos:        marker for data read in reg_read_buf
+ *
+ * @cmd1/vld:            some fixed controller register values
+ *
+ * @exec_opwrite:        flag to select correct number of code word
+ *                while reading status
+ */
+struct qcom_nand_controller {
+    struct device *dev;
+
+    void __iomem *base;
+
+    struct clk *core_clk;
+    struct clk *aon_clk;
+
+    struct nandc_regs *regs;
+    struct bam_transaction *bam_txn;
+
+    const struct qcom_nandc_props *props;
+
+    struct nand_controller controller;
+    struct list_head host_list;
+
+    union {
+        /* will be used only by QPIC for BAM DMA */
+        struct {
+            struct dma_chan *tx_chan;
+            struct dma_chan *rx_chan;
+            struct dma_chan *cmd_chan;
+        };
+
+        /* will be used only by EBI2 for ADM DMA */
+        struct {
+            struct dma_chan *chan;
+            unsigned int cmd_crci;
+            unsigned int data_crci;
+        };
+    };
+
+    struct list_head desc_list;
+
+    u8        *data_buffer;
+    __le32        *reg_read_buf;
+
+    phys_addr_t base_phys;
+    dma_addr_t base_dma;
+    dma_addr_t reg_read_dma;
+
+    int        buf_size;
+    int        buf_count;
+    int        buf_start;
+    unsigned int    max_cwperpage;
+
+    int reg_read_pos;
+
+    u32 cmd1, vld;
+    bool exec_opwrite;
+};
+
+/*
+ * This data type corresponds to the NAND controller properties which varies
+ * among different NAND controllers.
+ * @ecc_modes - ecc mode for NAND
+ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+ * @is_bam - whether NAND controller is using BAM
+ * @is_qpic - whether NAND CTRL is part of qpic IP
+ * @qpic_v2 - flag to indicate QPIC IP version 2
+ * @use_codeword_fixup - whether NAND has different layout for boot partitions
+ */
+struct qcom_nandc_props {
+    u32 ecc_modes;
+    u32 dev_cmd_reg_start;
+    bool is_bam;
+    bool is_qpic;
+    bool qpic_v2;
+    bool use_codeword_fixup;
+};
+
+void config_nand_page_read(struct nand_chip *chip);
+void free_bam_transaction(struct qcom_nand_controller *nandc);
+void qpic_bam_dma_done(void *data);
+void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, bool is_cpu);
+__le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset);
+void clear_read_regs(struct qcom_nand_controller *nandc);
+int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+              int reg_off, const void *vaddr, int size,
+            bool flow_control);
+int submit_descs(struct qcom_nand_controller *nandc);
+int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+               struct dma_chan *chan, unsigned long flags);
+int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+              int reg_off, const void *vaddr,
+            int size, unsigned int flags);
+int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+               const void *vaddr,
+            int size, unsigned int flags);
+int read_reg_dma(struct qcom_nand_controller *nandc, int first,
+         int num_regs, unsigned int flags);
+int write_reg_dma(struct qcom_nand_controller *nandc, int first,
+          int num_regs, unsigned int flags);
+int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+          const u8 *vaddr, int size, unsigned int flags);
+int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+           const u8 *vaddr, int size, unsigned int flags);
+struct bam_transaction *alloc_bam_transaction(struct qcom_nand_controller *nandc);
+void clear_bam_transaction(struct qcom_nand_controller *nandc);
+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc);
+int qcom_nandc_alloc(struct qcom_nand_controller *nandc);
+struct qcom_nand_controller *get_qcom_nand_controller(struct nand_chip *chip);
+
+#endif




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux