[PATCH v3 2/5] drivers: mtd: nand: Add qpic_common API file
Md Sadre Alam
quic_mdalam at quicinc.com
Wed Mar 6 23:36:15 PST 2024
On 3/7/2024 12:56 PM, Dmitry Baryshkov wrote:
> On Thu, 7 Mar 2024 at 06:19, Md Sadre Alam <quic_mdalam at quicinc.com> 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>
>> ---
>> Change in [v3]
>>
>> * Added original copy right
>>
>> * Removed all EXPORT_SYMBOL()
>>
>> * Made this common api file more generic
>>
>> * Added qcom_ prefix to all api in this file
>>
>> * Removed devm_kfree and added kfree
>>
>> * Moved to_qcom_nand_controller() to raw nand driver
>> since it was only used by raw nand driver, so not needed
>> as common
>>
>> * Added kernel doc for all api
>>
>> * made reverse tree of variable declaration in
>> prep_adm_dma_desc() function
>>
>> * Added if(!ret) condition in prep_adm_dma_desc()
>> function
>>
>> * Initialized slave_conf as 0 while declaration
>>
>> Change in [v2]
>>
>> * Posted initial support for common api file
>>
>> Change in [v1]
>>
>> * Posted as RFC patch for design review
>>
>> drivers/mtd/nand/Makefile | 1 +
>> drivers/mtd/nand/qpic_common.c | 781 ++++++++++++++
>> drivers/mtd/nand/raw/qcom_nandc.c | 1440 +++-----------------------
>> include/linux/mtd/nand-qpic-common.h | 486 +++++++++
>> 4 files changed, 1403 insertions(+), 1305 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
>
> So, this object file will be built-in into all kernels that have NAND
> enabled? Clearly this is not a way to go.
Sorry its my mistake, will add config for this qpic_common API file.
>
>> diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c
>> new file mode 100644
>> index 000000000000..11e322fdd706
>> --- /dev/null
>> +++ b/drivers/mtd/nand/qpic_common.c
>> @@ -0,0 +1,781 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2016, The Linux Foundation. All rights reserved.
>> + */
>> +#include <linux/mtd/nand-qpic-common.h>
>> +
>> +/*
>> + * qcom_free_bam_transaction: Frees the BAM transaction memory
>> + */
>
> This is not a kerneldoc comment. Please take a look at the documentation first.
Ok
>
>> +void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
>> +{
>> + struct bam_transaction *bam_txn = nandc->bam_txn;
>> +
>> + kfree(bam_txn);
>> +}
>> +
>> +/*
>> + * qcom_clear_read_regs: reset the register read buffer
>> + * for next NAND operation
>> + */
>> +void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
>> +{
>> + nandc->reg_read_pos = 0;
>> + qcom_nandc_read_buffer_sync(nandc, false);
>> +}
>> +
>> +/*
>> + * qcom_qpic_bam_dma_done: Callback for DMA descriptor completion
>> + *
>> + * @data: data
>> + */
>> +void qcom_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);
>> +}
>> +
>> +/*
>> + * qcom_nandc_read_buffer_sync: Check for dma sync for cpu or device
>> + *
>> + * @is_cpu: cpu or Device
>> + */
>> +void qcom_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);
>> +}
>> +
>> +/*
>> + * qcom_offset_to_nandc_reg: Get the actual offset for qpic register
>> + * @ offset: register offset
>> + */
>> +__le32 *qcom_offset_to_nandc_reg(struct nandc_regs *regs, int offset)
>> +{
>> + switch (offset) {
>> + case NAND_FLASH_CMD:
>> + return ®s->cmd;
>> + case NAND_ADDR0:
>> + return ®s->addr0;
>> + case NAND_ADDR1:
>> + return ®s->addr1;
>> + case NAND_FLASH_CHIP_SELECT:
>> + return ®s->chip_sel;
>> + case NAND_EXEC_CMD:
>> + return ®s->exec;
>> + case NAND_FLASH_STATUS:
>> + return ®s->clrflashstatus;
>> + case NAND_DEV0_CFG0:
>> + return ®s->cfg0;
>> + case NAND_DEV0_CFG1:
>> + return ®s->cfg1;
>> + case NAND_DEV0_ECC_CFG:
>> + return ®s->ecc_bch_cfg;
>> + case NAND_READ_STATUS:
>> + return ®s->clrreadstatus;
>> + case NAND_DEV_CMD1:
>> + return ®s->cmd1;
>> + case NAND_DEV_CMD1_RESTORE:
>> + return ®s->orig_cmd1;
>> + case NAND_DEV_CMD_VLD:
>> + return ®s->vld;
>> + case NAND_DEV_CMD_VLD_RESTORE:
>> + return ®s->orig_vld;
>> + case NAND_EBI2_ECC_BUF_CFG:
>> + return ®s->ecc_buf_cfg;
>> + case NAND_READ_LOCATION_0:
>> + return ®s->read_location0;
>> + case NAND_READ_LOCATION_1:
>> + return ®s->read_location1;
>> + case NAND_READ_LOCATION_2:
>> + return ®s->read_location2;
>> + case NAND_READ_LOCATION_3:
>> + return ®s->read_location3;
>> + case NAND_READ_LOCATION_LAST_CW_0:
>> + return ®s->read_location_last0;
>> + case NAND_READ_LOCATION_LAST_CW_1:
>> + return ®s->read_location_last1;
>> + case NAND_READ_LOCATION_LAST_CW_2:
>> + return ®s->read_location_last2;
>> + case NAND_READ_LOCATION_LAST_CW_3:
>> + return ®s->read_location_last3;
>> + default:
>> + return NULL;
>> + }
>> +}
>> +
>> +/*
>> + * qcom_prep_adm_dma_desc: Prepare descriptor for adma
>> + * @read: read or write
>> + * @reg_off: offset within the controller's data buffer
>> + * @vaddr: virtual address of the buffer we want to write to
>> + * @size: adm dma transaction size in bytes
>> + * @flow_control: flow controller
>> + */
>> +int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
>> + int reg_off, const void *vaddr, int size,
>> + bool flow_control)
>> +{
>> + struct qcom_adm_peripheral_config periph_conf = {};
>> + struct dma_async_tx_descriptor *dma_desc;
>> + struct dma_slave_config slave_conf = {0};
>> + enum dma_transfer_direction dir_eng;
>> + struct scatterlist *sgl;
>> + struct desc_info *desc;
>> + 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) {
>> + ret = -ENOMEM;
>> + goto err;
>> + }
>> +
>> + 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;
>> +}
>> +
>> +/*
>> + * qcom_submit_descs: submit descriptor cmd/data
>> + */
>> +int qcom_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 = qcom_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 = qcom_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 = qcom_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 = qcom_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 = qcom_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;
>> +}
>> +
>> +/*
>> + * qcom_prepare_bam_async_desc: 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
>> + * @chan: dma channel
>> + * @flag: flags to control DMA descriptor preparation
>> + */
>> +int qcom_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;
>> +}
>> +
>> +/*
>> + * qcom_prep_bam_dma_desc_cmd: Prepares the command descriptor for BAM DMA
>> + * which will be used for NAND register reads and
>> + * writes.
>> + * @read: read/write type
>> + * @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: offset within the controller's data buffer
>> + */
>> +int qcom_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 = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
>> + DMA_PREP_FENCE |
>> + DMA_PREP_CMD);
>> + if (ret)
>> + return ret;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/*
>> + * qcom_prep_bam_dma_desc_data: Prepares the data descriptor for BAM DMA which
>> + * will be used for NAND data reads and writes.
>> + * @read: read/write type
>> + * @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 qcom_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 = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
>> + DMA_PREP_INTERRUPT);
>> + if (ret)
>> + return ret;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/*
>> + * qcom_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 qcom_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 qcom_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 qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
>> + num_regs * sizeof(u32), flow_control);
>> +}
>> +
>> +/*
>> + * qcom_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 qcom_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 = qcom_offset_to_nandc_reg(regs, first);
>> +
>> + if (first == NAND_ERASED_CW_DETECT_CFG) {
>> + if (flags & NAND_ERASED_CW_SET)
>> + vaddr = ®s->erased_cw_detect_cfg_set;
>> + else
>> + vaddr = ®s->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 qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
>> + num_regs, flags);
>> +
>> + if (first == NAND_FLASH_CMD)
>> + flow_control = true;
>> +
>> + return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
>> + num_regs * sizeof(u32), flow_control);
>> +}
>> +
>> +/*
>> + * qcom_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 qcom_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 qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
>> +
>> + return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
>> +}
>> +
>> +/*
>> + * qcom_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 qcom_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 qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
>> +
>> + return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
>> +}
>> +
>> +/*
>> + * qcom_alloc_bam_transaction: Allocates and Initializes the BAM transaction
>> + */
>> +struct bam_transaction *
>> +qcom_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 = kzalloc(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;
>> +}
>> +
>> +/*
>> + * qcom_clear_bam_transaction: Clears the BAM transaction indexes
>> + */
>> +void qcom_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);
>> +}
>> +
>> +/*
>> + * qcom_nandc_unalloc: unallocate memory allocated for controller
>> + */
>> +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);
>> + }
>> +}
>> +
>> +/*
>> + * qcom_nandc_alloc: Allocate memory for nand controller
>> + */
>> +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 = qcom_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;
>> +}
>> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
>> index b079605c84d3..d4faabc8244f 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,24 @@ 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 qcom_nand_controller *
>> +get_qcom_nand_controller(struct nand_chip *chip)
>> {
>> - 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;
>> + return container_of(chip->controller, struct qcom_nand_controller,
>> + controller);
>> }
>>
>> -/* 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 = qcom_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 +149,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 +160,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 ®s->cmd;
>> - case NAND_ADDR0:
>> - return ®s->addr0;
>> - case NAND_ADDR1:
>> - return ®s->addr1;
>> - case NAND_FLASH_CHIP_SELECT:
>> - return ®s->chip_sel;
>> - case NAND_EXEC_CMD:
>> - return ®s->exec;
>> - case NAND_FLASH_STATUS:
>> - return ®s->clrflashstatus;
>> - case NAND_DEV0_CFG0:
>> - return ®s->cfg0;
>> - case NAND_DEV0_CFG1:
>> - return ®s->cfg1;
>> - case NAND_DEV0_ECC_CFG:
>> - return ®s->ecc_bch_cfg;
>> - case NAND_READ_STATUS:
>> - return ®s->clrreadstatus;
>> - case NAND_DEV_CMD1:
>> - return ®s->cmd1;
>> - case NAND_DEV_CMD1_RESTORE:
>> - return ®s->orig_cmd1;
>> - case NAND_DEV_CMD_VLD:
>> - return ®s->vld;
>> - case NAND_DEV_CMD_VLD_RESTORE:
>> - return ®s->orig_vld;
>> - case NAND_EBI2_ECC_BUF_CFG:
>> - return ®s->ecc_buf_cfg;
>> - case NAND_READ_LOCATION_0:
>> - return ®s->read_location0;
>> - case NAND_READ_LOCATION_1:
>> - return ®s->read_location1;
>> - case NAND_READ_LOCATION_2:
>> - return ®s->read_location2;
>> - case NAND_READ_LOCATION_3:
>> - return ®s->read_location3;
>> - case NAND_READ_LOCATION_LAST_CW_0:
>> - return ®s->read_location_last0;
>> - case NAND_READ_LOCATION_LAST_CW_1:
>> - return ®s->read_location_last1;
>> - case NAND_READ_LOCATION_LAST_CW_2:
>> - return ®s->read_location_last2;
>> - case NAND_READ_LOCATION_LAST_CW_3:
>> - return ®s->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 +251,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 = ®s->erased_cw_detect_cfg_set;
>> - else
>> - vaddr = ®s->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.
>> @@ -1245,20 +267,37 @@ config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw)
>> reg = NAND_READ_LOCATION_LAST_CW_0;
>>
>> if (nandc->props->is_bam)
>> - write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
>>
>> - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>>
>> if (use_ecc) {
>> - read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
>> - read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
>> - NAND_BAM_NEXT_SGL);
>> + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
>> + qcom_read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
>> + NAND_BAM_NEXT_SGL);
>> } else {
>> - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> }
>> }
>>
>> +/*
>> + * 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);
>> +
>> + qcom_write_reg_dma(nandc, NAND_ADDR0, 2, 0);
>> + qcom_write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
>> + if (!nandc->props->qpic_v2)
>> + qcom_write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
>> + qcom_write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
>> + qcom_write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
>> + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
>> +}
>> +
>> /*
>> * Helper to prepare dma descriptors to configure registers needed for reading a
>> * single codeword in page
>> @@ -1279,11 +318,11 @@ static void config_nand_page_write(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);
>> + qcom_write_reg_dma(nandc, NAND_ADDR0, 2, 0);
>> + qcom_write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
>> if (!nandc->props->qpic_v2)
>> - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
>> - NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
>> + NAND_BAM_NEXT_SGL);
>> }
>>
>> /*
>> @@ -1294,95 +333,13 @@ static void config_nand_cw_write(struct nand_chip *chip)
>> {
>> struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>
>> - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>>
>> - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>>
>> - write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> - 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);
>> + qcom_write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> + qcom_write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>> }
>>
>> /*
>> @@ -1446,7 +403,7 @@ static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt)
>> struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> int i;
>>
>> - nandc_read_buffer_sync(nandc, true);
>> + qcom_nandc_read_buffer_sync(nandc, true);
>>
>> for (i = 0; i < cw_cnt; i++) {
>> u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
>> @@ -1473,13 +430,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
>> nand_read_page_op(chip, page, 0, NULL, 0);
>> nandc->buf_count = 0;
>> nandc->buf_start = 0;
>> - clear_read_regs(nandc);
>> + qcom_clear_read_regs(nandc);
>> host->use_ecc = false;
>>
>> if (nandc->props->qpic_v2)
>> raw_cw = ecc->steps - 1;
>>
>> - clear_bam_transaction(nandc);
>> + qcom_clear_bam_transaction(nandc);
>> set_address(host, host->cw_size * cw, page);
>> update_rw_regs(host, 1, true, raw_cw);
>> config_nand_page_read(chip);
>> @@ -1512,18 +469,18 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
>>
>> config_nand_cw_read(chip, false, raw_cw);
>>
>> - read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
>> + qcom_read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
>> reg_off += data_size1;
>>
>> - read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
>> + qcom_read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
>> reg_off += oob_size1;
>>
>> - read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
>> + qcom_read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
>> reg_off += data_size2;
>>
>> - read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
>> + qcom_read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
>> return ret;
>> @@ -1621,7 +578,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
>> u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
>>
>> buf = (struct read_stats *)nandc->reg_read_buf;
>> - nandc_read_buffer_sync(nandc, true);
>> + qcom_nandc_read_buffer_sync(nandc, true);
>>
>> for (i = 0; i < ecc->steps; i++, buf++) {
>> u32 flash, buffer, erased_cw;
>> @@ -1750,8 +707,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
>> config_nand_cw_read(chip, true, i);
>>
>> if (data_buf)
>> - read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
>> - data_size, 0);
>> + qcom_read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
>> + data_size, 0);
>>
>> /*
>> * when ecc is enabled, the controller doesn't read the real
>> @@ -1766,8 +723,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
>> for (j = 0; j < host->bbm_size; j++)
>> *oob_buf++ = 0xff;
>>
>> - read_data_dma(nandc, FLASH_BUF_ACC + data_size,
>> - oob_buf, oob_size, 0);
>> + qcom_read_data_dma(nandc, FLASH_BUF_ACC + data_size,
>> + oob_buf, oob_size, 0);
>> }
>>
>> if (data_buf)
>> @@ -1776,7 +733,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
>> oob_buf += oob_size;
>> }
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure to read page/oob\n");
>> return ret;
>> @@ -1797,7 +754,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
>> int size;
>> int ret;
>>
>> - clear_read_regs(nandc);
>> + qcom_clear_read_regs(nandc);
>>
>> size = host->use_ecc ? host->cw_data : host->cw_size;
>>
>> @@ -1809,9 +766,9 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
>>
>> config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1);
>>
>> - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
>> + qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret)
>> dev_err(nandc->dev, "failed to copy last codeword\n");
>>
>> @@ -1897,14 +854,14 @@ static int qcom_nandc_read_page(struct nand_chip *chip, u8 *buf,
>> nandc->buf_count = 0;
>> nandc->buf_start = 0;
>> host->use_ecc = true;
>> - clear_read_regs(nandc);
>> + qcom_clear_read_regs(nandc);
>> set_address(host, 0, page);
>> update_rw_regs(host, ecc->steps, true, 0);
>>
>> data_buf = buf;
>> oob_buf = oob_required ? chip->oob_poi : NULL;
>>
>> - clear_bam_transaction(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> return read_page_ecc(host, data_buf, oob_buf, page);
>> }
>> @@ -1945,8 +902,8 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
>> if (host->nr_boot_partitions)
>> qcom_nandc_codeword_fixup(host, page);
>>
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> host->use_ecc = true;
>> set_address(host, 0, page);
>> @@ -1973,8 +930,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf,
>> set_address(host, 0, page);
>> nandc->buf_count = 0;
>> nandc->buf_start = 0;
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> data_buf = (u8 *)buf;
>> oob_buf = chip->oob_poi;
>> @@ -1995,8 +952,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf,
>> oob_size = ecc->bytes;
>> }
>>
>> - write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
>> - i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
>> + qcom_write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
>> + i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
>>
>> /*
>> * when ECC is enabled, we don't really need to write anything
>> @@ -2008,8 +965,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf,
>> if (qcom_nandc_is_last_cw(ecc, i)) {
>> oob_buf += host->bbm_size;
>>
>> - write_data_dma(nandc, FLASH_BUF_ACC + data_size,
>> - oob_buf, oob_size, 0);
>> + qcom_write_data_dma(nandc, FLASH_BUF_ACC + data_size,
>> + oob_buf, oob_size, 0);
>> }
>>
>> config_nand_cw_write(chip);
>> @@ -2018,7 +975,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf,
>> oob_buf += oob_size;
>> }
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure to write page\n");
>> return ret;
>> @@ -2043,8 +1000,8 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
>> qcom_nandc_codeword_fixup(host, page);
>>
>> nand_prog_page_begin_op(chip, page, 0, NULL, 0);
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> data_buf = (u8 *)buf;
>> oob_buf = chip->oob_poi;
>> @@ -2070,28 +1027,28 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
>> oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
>> }
>>
>> - write_data_dma(nandc, reg_off, data_buf, data_size1,
>> - NAND_BAM_NO_EOT);
>> + qcom_write_data_dma(nandc, reg_off, data_buf, data_size1,
>> + NAND_BAM_NO_EOT);
>> reg_off += data_size1;
>> data_buf += data_size1;
>>
>> - write_data_dma(nandc, reg_off, oob_buf, oob_size1,
>> - NAND_BAM_NO_EOT);
>> + qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size1,
>> + NAND_BAM_NO_EOT);
>> reg_off += oob_size1;
>> oob_buf += oob_size1;
>>
>> - write_data_dma(nandc, reg_off, data_buf, data_size2,
>> - NAND_BAM_NO_EOT);
>> + qcom_write_data_dma(nandc, reg_off, data_buf, data_size2,
>> + NAND_BAM_NO_EOT);
>> reg_off += data_size2;
>> data_buf += data_size2;
>>
>> - write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
>> + qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
>> oob_buf += oob_size2;
>>
>> config_nand_cw_write(chip);
>> }
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure to write raw page\n");
>> return ret;
>> @@ -2121,7 +1078,7 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
>> qcom_nandc_codeword_fixup(host, page);
>>
>> host->use_ecc = true;
>> - clear_bam_transaction(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> /* calculate the data and oob size for the last codeword/step */
>> data_size = ecc->size - ((ecc->steps - 1) << 2);
>> @@ -2136,11 +1093,11 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
>> update_rw_regs(host, 1, false, 0);
>>
>> config_nand_page_write(chip);
>> - write_data_dma(nandc, FLASH_BUF_ACC,
>> - nandc->data_buffer, data_size + oob_size, 0);
>> + qcom_write_data_dma(nandc, FLASH_BUF_ACC,
>> + nandc->data_buffer, data_size + oob_size, 0);
>> config_nand_cw_write(chip);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure to write oob\n");
>> return ret;
>> @@ -2167,7 +1124,7 @@ static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
>> */
>> host->use_ecc = false;
>>
>> - clear_bam_transaction(nandc);
>> + qcom_clear_bam_transaction(nandc);
>> ret = copy_last_cw(host, page);
>> if (ret)
>> goto err;
>> @@ -2194,8 +1151,8 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>> struct nand_ecc_ctrl *ecc = &chip->ecc;
>> int page, ret;
>>
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> /*
>> * to mark the BBM as bad, we flash the entire last codeword with 0s.
>> @@ -2212,11 +1169,11 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>> update_rw_regs(host, 1, false, ecc->steps - 1);
>>
>> config_nand_page_write(chip);
>> - write_data_dma(nandc, FLASH_BUF_ACC,
>> - nandc->data_buffer, host->cw_size, 0);
>> + qcom_write_data_dma(nandc, FLASH_BUF_ACC,
>> + nandc->data_buffer, host->cw_size, 0);
>> config_nand_cw_write(chip);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure to update BBM\n");
>> return ret;
>> @@ -2456,14 +1413,14 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>> mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
>> /* Free the initially allocated BAM transaction for reading the ONFI params */
>> if (nandc->props->is_bam)
>> - free_bam_transaction(nandc);
>> + qcom_free_bam_transaction(nandc);
>>
>> nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
>> cwperpage);
>>
>> /* Now allocate the BAM transaction based on updated max_cwperpage */
>> if (nandc->props->is_bam) {
>> - nandc->bam_txn = alloc_bam_transaction(nandc);
>> + nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
>> if (!nandc->bam_txn) {
>> dev_err(nandc->dev,
>> "failed to allocate bam transaction\n");
>> @@ -2663,7 +1620,7 @@ static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms)
>> unsigned long start = jiffies + msecs_to_jiffies(time_ms);
>> u32 flash;
>>
>> - nandc_read_buffer_sync(nandc, true);
>> + qcom_nandc_read_buffer_sync(nandc, true);
>>
>> do {
>> flash = le32_to_cpu(nandc->reg_read_buf[0]);
>> @@ -2703,23 +1660,23 @@ static int qcom_read_status_exec(struct nand_chip *chip,
>> nandc->buf_start = 0;
>> host->use_ecc = false;
>>
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
>> nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>
>> - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure in submitting status descriptor\n");
>> goto err_out;
>> }
>>
>> - nandc_read_buffer_sync(nandc, true);
>> + qcom_nandc_read_buffer_sync(nandc, true);
>>
>> for (i = 0; i < num_cw; i++) {
>> flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
>> @@ -2760,8 +1717,8 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo
>> nandc->buf_start = 0;
>> host->use_ecc = false;
>>
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
>> nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
>> @@ -2771,12 +1728,12 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo
>>
>> nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>
>> - write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
>> - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>>
>> - read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> + qcom_read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure in submitting read id descriptor\n");
>> goto err_out;
>> @@ -2786,7 +1743,7 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo
>> op_id = q_op.data_instr_idx;
>> len = nand_subop_get_data_len(subop, op_id);
>>
>> - nandc_read_buffer_sync(nandc, true);
>> + qcom_nandc_read_buffer_sync(nandc, true);
>> memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
>>
>> err_out:
>> @@ -2823,21 +1780,21 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub
>> nandc->buf_start = 0;
>> host->use_ecc = false;
>>
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
>> nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>
>> - write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
>> - (q_op.cmd_reg == OP_BLOCK_ERASE) ? write_reg_dma(nandc, NAND_DEV0_CFG0,
>> - 2, NAND_BAM_NEXT_SGL) : read_reg_dma(nandc,
>> + qcom_write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
>> + (q_op.cmd_reg == OP_BLOCK_ERASE) ? qcom_write_reg_dma(nandc, NAND_DEV0_CFG0,
>> + 2, NAND_BAM_NEXT_SGL) : qcom_read_reg_dma(nandc,
>> NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>>
>> - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure in submitting misc descriptor\n");
>> goto err_out;
>> @@ -2870,8 +1827,8 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
>> nandc->buf_count = 0;
>> nandc->buf_start = 0;
>> host->use_ecc = false;
>> - clear_read_regs(nandc);
>> - clear_bam_transaction(nandc);
>> + qcom_clear_read_regs(nandc);
>> + qcom_clear_bam_transaction(nandc);
>>
>> nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
>>
>> @@ -2914,8 +1871,8 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
>> nandc_set_read_loc(chip, 0, 0, 0, len, 1);
>>
>> if (!nandc->props->qpic_v2) {
>> - write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
>> - write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
>> + qcom_write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
>> }
>>
>> nandc->buf_count = len;
>> @@ -2923,16 +1880,16 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
>>
>> config_nand_single_cw_page_read(chip, false, 0);
>>
>> - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
>> - nandc->buf_count, 0);
>> + qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
>> + nandc->buf_count, 0);
>>
>> /* restore CMD1 and VLD regs */
>> if (!nandc->props->qpic_v2) {
>> - write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
>> - write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
>> + qcom_write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
>> + qcom_write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
>> }
>>
>> - ret = submit_descs(nandc);
>> + ret = qcom_submit_descs(nandc);
>> if (ret) {
>> dev_err(nandc->dev, "failure in submitting param page descriptor\n");
>> goto err_out;
>> @@ -3016,136 +1973,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 +2254,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 +2303,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..aced15866627
>> --- /dev/null
>> +++ b/include/linux/mtd/nand-qpic-common.h
>> @@ -0,0 +1,486 @@
>> +/* 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>
>
> Oh, really?
>
>> + *
>> + */
>> +#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))
>
> Sensible prefixes are appreciated in the global headers too.
>
>> +
>> +/* 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;
>> +};
>
> Is there any reason to export both register offsets and a containing struct?
>
>> +
>> +/*
>> + * 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 {
>
> If you need to export data structures, this usually means that
> something is not that great with the design. Also, do you really need
> qcom_nand_controller::controller in the SPI NOR case?
>
>> + 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 qcom_qpic_bam_dma_done(void *data);
>
> So, what is the actual prefix? qcom_? Isn't that too broad? Not to
> mention that config_nand_page_read isn't following even that style.
>
>> +void qcom_nandc_read_buffer_sync(struct qcom_nand_controller *nandc, bool is_cpu);
>> +__le32 *qcom_offset_to_nandc_reg(struct nandc_regs *regs, int offset);
>> +int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
>> + int reg_off, const void *vaddr, int size,
>> + bool flow_control);
>> +int qcom_submit_descs(struct qcom_nand_controller *nandc);
>> +int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
>> + struct dma_chan *chan, unsigned long flags);
>> +int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
>> + int reg_off, const void *vaddr,
>> + int size, unsigned int flags);
>> +int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
>> + const void *vaddr,
>> + int size, unsigned int flags);
>> +int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
>> + int num_regs, unsigned int flags);
>> +int qcom_write_reg_dma(struct qcom_nand_controller *nandc, int first,
>> + int num_regs, unsigned int flags);
>> +int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
>> + const u8 *vaddr, int size, unsigned int flags);
>> +int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
>> + const u8 *vaddr, int size, unsigned int flags);
>> +struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc);
>> +void qcom_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);
>> +void qcom_clear_read_regs(struct qcom_nand_controller *nandc);
>> +void qcom_free_bam_transaction(struct qcom_nand_controller *nandc);
>> +#endif
>> --
>> 2.34.1
>>
>>
>
> General comment: Please take a pause. Start from the scratch by
> actually _designing_, what kind of API do you need for you common core
> and for NAND and SPI-NOR controllers. Then rework existing driver to
> use that API internally. Move the API functions to the common helper.
> Add the SPI-NOR driver on top of new _designed_ helper. Just
> continuing further on the path of "let's move this and that" will not
> lead you to acceptable solution.
>
More information about the linux-mtd
mailing list