Message ID | 20240307041726.1648829-3-quic_mdalam@quicinc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add QPIC SPI NAND driver | expand |
On Thu, 7 Mar 2024 at 06:19, Md Sadre Alam <quic_mdalam@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@quicinc.com> > Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com> > Co-developed-by: Varadarajan Narayanan <quic_varada@quicinc.com> > Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com> > Signed-off-by: Md Sadre Alam <quic_mdalam@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. > 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. > +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@quicinc.com> > + * Sricharan R <quic_srichara@quicinc.com> > + * Varadarajan Narayanan <quic_varada@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.
On 3/7/2024 12:56 PM, Dmitry Baryshkov wrote: > On Thu, 7 Mar 2024 at 06:19, Md Sadre Alam <quic_mdalam@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@quicinc.com> >> Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com> >> Co-developed-by: Varadarajan Narayanan <quic_varada@quicinc.com> >> Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com> >> Signed-off-by: Md Sadre Alam <quic_mdalam@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@quicinc.com> >> + * Sricharan R <quic_srichara@quicinc.com> >> + * Varadarajan Narayanan <quic_varada@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. >
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 19e1291ac4d5..131707a41293 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -12,3 +12,4 @@ nandcore-$(CONFIG_MTD_NAND_ECC) += ecc.o nandcore-$(CONFIG_MTD_NAND_ECC_SW_HAMMING) += ecc-sw-hamming.o nandcore-$(CONFIG_MTD_NAND_ECC_SW_BCH) += ecc-sw-bch.o nandcore-$(CONFIG_MTD_NAND_ECC_MXIC) += ecc-mxic.o +obj-y += qpic_common.o diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c new file mode 100644 index 000000000000..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 + */ +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@quicinc.com> + * Sricharan R <quic_srichara@quicinc.com> + * Varadarajan Narayanan <quic_varada@quicinc.com> + * + */ +#ifndef __MTD_NAND_QPIC_COMMON_H__ +#define __MTD_NAND_QPIC_COMMON_H__ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/dma/qcom_adm.h> +#include <linux/dma/qcom_bam_dma.h> +#include <linux/module.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/rawnand.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* NANDc reg offsets */ +#define NAND_FLASH_CMD 0x00 +#define NAND_ADDR0 0x04 +#define NAND_ADDR1 0x08 +#define NAND_FLASH_CHIP_SELECT 0x0c +#define NAND_EXEC_CMD 0x10 +#define NAND_FLASH_STATUS 0x14 +#define NAND_BUFFER_STATUS 0x18 +#define NAND_DEV0_CFG0 0x20 +#define NAND_DEV0_CFG1 0x24 +#define NAND_DEV0_ECC_CFG 0x28 +#define NAND_AUTO_STATUS_EN 0x2c +#define NAND_DEV1_CFG0 0x30 +#define NAND_DEV1_CFG1 0x34 +#define NAND_READ_ID 0x40 +#define NAND_READ_STATUS 0x44 +#define NAND_DEV_CMD0 0xa0 +#define NAND_DEV_CMD1 0xa4 +#define NAND_DEV_CMD2 0xa8 +#define NAND_DEV_CMD_VLD 0xac +#define SFLASHC_BURST_CFG 0xe0 +#define NAND_ERASED_CW_DETECT_CFG 0xe8 +#define NAND_ERASED_CW_DETECT_STATUS 0xec +#define NAND_EBI2_ECC_BUF_CFG 0xf0 +#define FLASH_BUF_ACC 0x100 + +#define NAND_CTRL 0xf00 +#define NAND_VERSION 0xf08 +#define NAND_READ_LOCATION_0 0xf20 +#define NAND_READ_LOCATION_1 0xf24 +#define NAND_READ_LOCATION_2 0xf28 +#define NAND_READ_LOCATION_3 0xf2c +#define NAND_READ_LOCATION_LAST_CW_0 0xf40 +#define NAND_READ_LOCATION_LAST_CW_1 0xf44 +#define NAND_READ_LOCATION_LAST_CW_2 0xf48 +#define NAND_READ_LOCATION_LAST_CW_3 0xf4c + +/* dummy register offsets, used by write_reg_dma */ +#define NAND_DEV_CMD1_RESTORE 0xdead +#define NAND_DEV_CMD_VLD_RESTORE 0xbeef + +/* NAND_FLASH_CMD bits */ +#define PAGE_ACC BIT(4) +#define LAST_PAGE BIT(5) + +/* NAND_FLASH_CHIP_SELECT bits */ +#define NAND_DEV_SEL 0 +#define DM_EN BIT(2) + +/* NAND_FLASH_STATUS bits */ +#define FS_OP_ERR BIT(4) +#define FS_READY_BSY_N BIT(5) +#define FS_MPU_ERR BIT(8) +#define FS_DEVICE_STS_ERR BIT(16) +#define FS_DEVICE_WP BIT(23) + +/* NAND_BUFFER_STATUS bits */ +#define BS_UNCORRECTABLE_BIT BIT(8) +#define BS_CORRECTABLE_ERR_MSK 0x1f + +/* NAND_DEVn_CFG0 bits */ +#define DISABLE_STATUS_AFTER_WRITE 4 +#define CW_PER_PAGE 6 +#define UD_SIZE_BYTES 9 +#define UD_SIZE_BYTES_MASK GENMASK(18, 9) +#define ECC_PARITY_SIZE_BYTES_RS 19 +#define SPARE_SIZE_BYTES 23 +#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) +#define NUM_ADDR_CYCLES 27 +#define STATUS_BFR_READ 30 +#define SET_RD_MODE_AFTER_STATUS 31 + +/* NAND_DEVn_CFG0 bits */ +#define DEV0_CFG1_ECC_DISABLE 0 +#define WIDE_FLASH 1 +#define NAND_RECOVERY_CYCLES 2 +#define CS_ACTIVE_BSY 5 +#define BAD_BLOCK_BYTE_NUM 6 +#define BAD_BLOCK_IN_SPARE_AREA 16 +#define WR_RD_BSY_GAP 17 +#define ENABLE_BCH_ECC 27 + +/* NAND_DEV0_ECC_CFG bits */ +#define ECC_CFG_ECC_DISABLE 0 +#define ECC_SW_RESET 1 +#define ECC_MODE 4 +#define ECC_PARITY_SIZE_BYTES_BCH 8 +#define ECC_NUM_DATA_BYTES 16 +#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) +#define ECC_FORCE_CLK_OPEN 30 + +/* NAND_DEV_CMD1 bits */ +#define READ_ADDR 0 + +/* NAND_DEV_CMD_VLD bits */ +#define READ_START_VLD BIT(0) +#define READ_STOP_VLD BIT(1) +#define WRITE_START_VLD BIT(2) +#define ERASE_START_VLD BIT(3) +#define SEQ_READ_START_VLD BIT(4) + +/* NAND_EBI2_ECC_BUF_CFG bits */ +#define NUM_STEPS 0 + +/* NAND_ERASED_CW_DETECT_CFG bits */ +#define ERASED_CW_ECC_MASK 1 +#define AUTO_DETECT_RES 0 +#define MASK_ECC BIT(ERASED_CW_ECC_MASK) +#define RESET_ERASED_DET BIT(AUTO_DETECT_RES) +#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) +#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) +#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) + +/* NAND_ERASED_CW_DETECT_STATUS bits */ +#define PAGE_ALL_ERASED BIT(7) +#define CODEWORD_ALL_ERASED BIT(6) +#define PAGE_ERASED BIT(5) +#define CODEWORD_ERASED BIT(4) +#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) +#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) + +/* NAND_READ_LOCATION_n bits */ +#define READ_LOCATION_OFFSET 0 +#define READ_LOCATION_SIZE 16 +#define READ_LOCATION_LAST 31 + +/* Version Mask */ +#define NAND_VERSION_MAJOR_MASK 0xf0000000 +#define NAND_VERSION_MAJOR_SHIFT 28 +#define NAND_VERSION_MINOR_MASK 0x0fff0000 +#define NAND_VERSION_MINOR_SHIFT 16 + +/* NAND OP_CMDs */ +#define OP_PAGE_READ 0x2 +#define OP_PAGE_READ_WITH_ECC 0x3 +#define OP_PAGE_READ_WITH_ECC_SPARE 0x4 +#define OP_PAGE_READ_ONFI_READ 0x5 +#define OP_PROGRAM_PAGE 0x6 +#define OP_PAGE_PROGRAM_WITH_ECC 0x7 +#define OP_PROGRAM_PAGE_SPARE 0x9 +#define OP_BLOCK_ERASE 0xa +#define OP_CHECK_STATUS 0xc +#define OP_FETCH_ID 0xb +#define OP_RESET_DEVICE 0xd + +/* Default Value for NAND_DEV_CMD_VLD */ +#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ + ERASE_START_VLD | SEQ_READ_START_VLD) + +/* NAND_CTRL bits */ +#define BAM_MODE_EN BIT(0) + +/* + * the NAND controller performs reads/writes with ECC in 516 byte chunks. + * the driver calls the chunks 'step' or 'codeword' interchangeably + */ +#define NANDC_STEP_SIZE 512 + +/* + * the largest page size we support is 8K, this will have 16 steps/codewords + * of 512 bytes each + */ +#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE) + +/* we read at most 3 registers per codeword scan */ +#define MAX_REG_RD (3 * MAX_NUM_STEPS) + +#define QPIC_PER_CW_CMD_ELEMENTS 32 +#define QPIC_PER_CW_CMD_SGL 32 +#define QPIC_PER_CW_DATA_SGL 8 + +#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000) + +/* + * Flags used in DMA descriptor preparation helper functions + * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma) + */ +/* Don't set the EOT in current tx BAM sgl */ +#define NAND_BAM_NO_EOT BIT(0) +/* Set the NWD flag in current BAM sgl */ +#define NAND_BAM_NWD BIT(1) +/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ +#define NAND_BAM_NEXT_SGL BIT(2) + +/* + * Returns the actual register address for all NAND_DEV_ registers + * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) + */ +#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) + +/* Returns the NAND register physical address */ +#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset)) + +/* Returns the dma address for reg read buffer */ +#define reg_buf_dma_addr(chip, vaddr) \ + ((chip)->reg_read_dma + \ + ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf)) + +/* + * Erased codeword status is being used two times in single transfer so this + * flag will determine the current value of erased codeword status register + */ +#define NAND_ERASED_CW_SET BIT(4) + +#define MAX_ADDRESS_CYCLE 5 + +/* + * This data type corresponds to the BAM transaction which will be used for all + * NAND transfers. + * @bam_ce - the array of BAM command elements + * @cmd_sgl - sgl for NAND BAM command pipe + * @data_sgl - sgl for NAND BAM consumer/producer pipe + * @last_data_desc - last DMA desc in data channel (tx/rx). + * @last_cmd_desc - last DMA desc in command channel. + * @txn_done - completion for NAND transfer. + * @bam_ce_pos - the index in bam_ce which is available for next sgl + * @bam_ce_start - the index in bam_ce which marks the start position ce + * for current sgl. It will be used for size calculation + * for current sgl + * @cmd_sgl_pos - current index in command sgl. + * @cmd_sgl_start - start index in command sgl. + * @tx_sgl_pos - current index in data sgl for tx. + * @tx_sgl_start - start index in data sgl for tx. + * @rx_sgl_pos - current index in data sgl for rx. + * @rx_sgl_start - start index in data sgl for rx. + * @wait_second_completion - wait for second DMA desc completion before making + * the NAND transfer completion. + */ +struct bam_transaction { + struct bam_cmd_element *bam_ce; + struct scatterlist *cmd_sgl; + struct scatterlist *data_sgl; + struct dma_async_tx_descriptor *last_data_desc; + struct dma_async_tx_descriptor *last_cmd_desc; + struct completion txn_done; + u32 bam_ce_pos; + u32 bam_ce_start; + u32 cmd_sgl_pos; + u32 cmd_sgl_start; + u32 tx_sgl_pos; + u32 tx_sgl_start; + u32 rx_sgl_pos; + u32 rx_sgl_start; + bool wait_second_completion; +}; + +/* + * This data type corresponds to the nand dma descriptor + * @dma_desc - low level DMA engine descriptor + * @list - list for desc_info + * + * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by + * ADM + * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM + * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM + * @dir - DMA transfer direction + */ +struct desc_info { + struct dma_async_tx_descriptor *dma_desc; + struct list_head node; + + union { + struct scatterlist adm_sgl; + struct { + struct scatterlist *bam_sgl; + int sgl_cnt; + }; + }; + enum dma_data_direction dir; +}; + +/* + * holds the current register values that we want to write. acts as a contiguous + * chunk of memory which we use to write the controller registers through DMA. + */ +struct nandc_regs { + __le32 cmd; + __le32 addr0; + __le32 addr1; + __le32 chip_sel; + __le32 exec; + + __le32 cfg0; + __le32 cfg1; + __le32 ecc_bch_cfg; + + __le32 clrflashstatus; + __le32 clrreadstatus; + + __le32 cmd1; + __le32 vld; + + __le32 orig_cmd1; + __le32 orig_vld; + + __le32 ecc_buf_cfg; + __le32 read_location0; + __le32 read_location1; + __le32 read_location2; + __le32 read_location3; + __le32 read_location_last0; + __le32 read_location_last1; + __le32 read_location_last2; + __le32 read_location_last3; + + __le32 erased_cw_detect_cfg_clr; + __le32 erased_cw_detect_cfg_set; +}; + +/* + * NAND controller data struct + * + * @dev: parent device + * + * @base: MMIO base + * + * @core_clk: controller clock + * @aon_clk: another controller clock + * + * @regs: a contiguous chunk of memory for DMA register + * writes. contains the register values to be + * written to controller + * + * @props: properties of current NAND controller, + * initialized via DT match data + * + * @controller: base controller structure + * @host_list: list containing all the chips attached to the + * controller + * + * @chan: dma channel + * @cmd_crci: ADM DMA CRCI for command flow control + * @data_crci: ADM DMA CRCI for data flow control + * + * @desc_list: DMA descriptor list (list of desc_infos) + * + * @data_buffer: our local DMA buffer for page read/writes, + * used when we can't use the buffer provided + * by upper layers directly + * @reg_read_buf: local buffer for reading back registers via DMA + * + * @base_phys: physical base address of controller registers + * @base_dma: dma base address of controller registers + * @reg_read_dma: contains dma address for register read buffer + * + * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf + * functions + * @max_cwperpage: maximum QPIC codewords required. calculated + * from all connected NAND devices pagesize + * + * @reg_read_pos: marker for data read in reg_read_buf + * + * @cmd1/vld: some fixed controller register values + * + * @exec_opwrite: flag to select correct number of code word + * while reading status + */ +struct qcom_nand_controller { + struct device *dev; + + void __iomem *base; + + struct clk *core_clk; + struct clk *aon_clk; + + struct nandc_regs *regs; + struct bam_transaction *bam_txn; + + const struct qcom_nandc_props *props; + + struct nand_controller controller; + struct list_head host_list; + + union { + /* will be used only by QPIC for BAM DMA */ + struct { + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + struct dma_chan *cmd_chan; + }; + + /* will be used only by EBI2 for ADM DMA */ + struct { + struct dma_chan *chan; + unsigned int cmd_crci; + unsigned int data_crci; + }; + }; + + struct list_head desc_list; + + u8 *data_buffer; + __le32 *reg_read_buf; + + phys_addr_t base_phys; + dma_addr_t base_dma; + dma_addr_t reg_read_dma; + + int buf_size; + int buf_count; + int buf_start; + unsigned int max_cwperpage; + + int reg_read_pos; + + u32 cmd1, vld; + bool exec_opwrite; +}; + +/* + * This data type corresponds to the NAND controller properties which varies + * among different NAND controllers. + * @ecc_modes - ecc mode for NAND + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset + * @is_bam - whether NAND controller is using BAM + * @is_qpic - whether NAND CTRL is part of qpic IP + * @qpic_v2 - flag to indicate QPIC IP version 2 + * @use_codeword_fixup - whether NAND has different layout for boot partitions + */ +struct qcom_nandc_props { + u32 ecc_modes; + u32 dev_cmd_reg_start; + bool is_bam; + bool is_qpic; + bool qpic_v2; + bool use_codeword_fixup; +}; + +void config_nand_page_read(struct nand_chip *chip); +void qcom_qpic_bam_dma_done(void *data); +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