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

Md Sadre Alam quic_mdalam at quicinc.com
Tue Feb 20 04:30:29 PST 2024



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 at quicinc.com>
>> Signed-off-by: Sricharan Ramabadhran <quic_srichara at quicinc.com>
>> Co-developed-by: Varadarajan Narayanan <quic_varada at quicinc.com>
>> Signed-off-by: Varadarajan Narayanan <quic_varada at quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam at quicinc.com>
>> ---
>>   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 at quicinc.com>
>> + *        Sricharan R             <quic_srichara at quicinc.com>
>> + *        Varadarajan Narayanan    <quic_varada at quicinc.com>
>> + *
>> + */
>> +
>> +#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 at quicinc.com>
>> + *        Sricharan R             <quic_srichara at quicinc.com>
>> + *        Varadarajan Narayanan   <quic_varada at quicinc.com>
>> + *
>> + */
>> +#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



More information about the linux-mtd mailing list