回信: [RFC PATCH 09/10] spi: mxic: Add support for direct mapping

jaimeliao at mxic.com.tw jaimeliao at mxic.com.tw
Tue Oct 12 00:14:56 PDT 2021


Hi Miquel

ZhengxunLi have patch new mxic spi host controller before.
The patch name as below
spi: mxic: patch for octal DTR mode support
Please patch mxic ECC engine base on latest version.

Thanks
Jaime

> [RFC PATCH 09/10] spi: mxic: Add support for direct mapping
> 
> Implement the ->dirmap_create() and ->dirmap_read/write() hooks to
> provide a fast path for read and write accesses.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
> ---
>  drivers/spi/spi-mxic.c | 171 ++++++++++++++++++++++++++++++++++-------
>  1 file changed, 144 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> index 4fb19e6f94b0..e10c55ee4d06 100644
> --- a/drivers/spi/spi-mxic.c
> +++ b/drivers/spi/spi-mxic.c
> @@ -172,6 +172,11 @@ struct mxic_spi {
>     struct clk *send_dly_clk;
>     void __iomem *regs;
>     u32 cur_speed_hz;
> +   struct {
> +      void __iomem *map;
> +      dma_addr_t dma;
> +      size_t size;
> +   } linear;
>  };
> 
>  static int mxic_spi_clk_enable(struct mxic_spi *mxic)
> @@ -280,6 +285,42 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
>            mxic->regs + HC_CFG);
>  }
> 
> +static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
> +{
> +   u32 cfg = OP_CMD_BYTES(1) | OP_CMD_BUSW(fls(op->cmd.buswidth) - 1);
> +
> +   if (op->addr.nbytes)
> +      cfg |= OP_ADDR_BYTES(op->addr.nbytes) |
> +             OP_ADDR_BUSW(fls(op->addr.buswidth) - 1);
> +
> +   if (op->dummy.nbytes)
> +      cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
> +
> +   if (op->data.dir != SPI_MEM_NO_DATA) {
> +      cfg |= OP_DATA_BUSW(fls(op->data.buswidth) - 1);
> +      if (op->data.dir == SPI_MEM_DATA_IN)
> +         cfg |= OP_READ;
> +   }
> +
> +   return cfg;
> +}
> +
> +static void mxic_spi_set_hc_cfg(struct spi_device *spi, u32 flags)
> +{
> +   struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
> +   int nio = 1;
> +
> +   if (spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
> +      nio = 4;
> +   else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
> +      nio = 2;
> +
> +   writel(flags | HC_CFG_NIO(nio) |
> +          HC_CFG_TYPE(spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
> +          HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1),
> +          mxic->regs + HC_CFG);
> +}
> +
>  static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
>                 void *rxbuf, unsigned int len)
>  {
> @@ -328,6 +369,77 @@ static int mxic_spi_data_xfer(struct mxic_spi 
> *mxic, const void *txbuf,
>     return 0;
>  }
> 
> +static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc 
*desc,
> +               u64 offs, size_t len, void *buf)
> +{
> +   struct mxic_spi *mxic = 
spi_master_get_devdata(desc->mem->spi->master);
> +   int ret;
> +   u32 sts;
> +
> +   if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
> +      return -EINVAL;
> +
> +   mxic_spi_set_hc_cfg(desc->mem->spi, 0);
> +
> +   writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) |
> +          LMODE_SLV_ACT(desc->mem->spi->chip_select) |
> +          LMODE_EN,
> +          mxic->regs + LRD_CTRL);
> +   writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl),
> +          mxic->regs + LRD_CFG);
> +   writel(desc->info.offset + offs, mxic->regs + LRD_ADDR);
> +   len = min_t(size_t, len, mxic->linear.size);
> +   writel(len, mxic->regs + LRD_RANGE);
> +
> +   memcpy_fromio(buf, mxic->linear.map, len);
> +
> +   writel(INT_LRD_DIS, mxic->regs + INT_STS);
> +   writel(0, mxic->regs + LRD_CTRL);
> +
> +   ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
> +             sts & INT_LRD_DIS, 0, USEC_PER_SEC);
> +   if (ret)
> +      return ret;
> +
> +   return len;
> +}
> +
> +static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc 
*desc,
> +                u64 offs, size_t len,
> +                const void *buf)
> +{
> +   struct mxic_spi *mxic = 
spi_master_get_devdata(desc->mem->spi->master);
> +   u32 sts;
> +   int ret;
> +
> +   if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
> +      return -EINVAL;
> +
> +   mxic_spi_set_hc_cfg(desc->mem->spi, 0);
> +
> +   writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) |
> +          LMODE_SLV_ACT(desc->mem->spi->chip_select) |
> +          LMODE_EN,
> +          mxic->regs + LWR_CTRL);
> +   writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl),
> +          mxic->regs + LWR_CFG);
> +   writel(desc->info.offset + offs, mxic->regs + LWR_ADDR);
> +   len = min_t(size_t, len, mxic->linear.size);
> +   writel(len, mxic->regs + LWR_RANGE);
> +
> +   memcpy_toio(mxic->linear.map, buf, len);
> +
> +   writel(INT_LWR_DIS, mxic->regs + INT_STS);
> +   writel(0, mxic->regs + LWR_CTRL);
> +
> +   ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
> +             sts & INT_LWR_DIS, 0, USEC_PER_SEC);
> +   if (ret)
> +      return ret;
> +
> +   return len;
> +}
> +
>  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>                   const struct spi_mem_op *op)
>  {
> @@ -345,12 +457,27 @@ static bool mxic_spi_mem_supports_op(struct 
> spi_mem *mem,
>     return spi_mem_default_supports_op(mem, op);
>  }
> 
> +static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
> +{
> +   struct mxic_spi *mxic = 
spi_master_get_devdata(desc->mem->spi->master);
> +
> +   if (!mxic->linear.map)
> +      return -ENOTSUPP;
> +
> +   if (desc->info.offset + desc->info.length > U32_MAX)
> +      return -ENOTSUPP;
> +
> +   if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
> +      return -ENOTSUPP;
> +
> +   return 0;
> +}
> +
>  static int mxic_spi_mem_exec_op(struct spi_mem *mem,
>              const struct spi_mem_op *op)
>  {
>     struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
> -   int nio = 1, i, ret;
> -   u32 ss_ctrl;
> +   int i, ret;
>     u8 addr[8];
>     u8 opcode = op->cmd.opcode;
> 
> @@ -358,34 +485,12 @@ static int mxic_spi_mem_exec_op(struct spi_mem 
*mem,
>     if (ret)
>        return ret;
> 
> -   if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
> -      nio = 4;
> -   else if (mem->spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
> -      nio = 2;
> +   mxic_spi_set_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN);
> 
> -   writel(HC_CFG_NIO(nio) |
> -          HC_CFG_TYPE(mem->spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
> -          HC_CFG_SLV_ACT(mem->spi->chip_select) | 
HC_CFG_IDLE_SIO_LVL(1) |
> -          HC_CFG_MAN_CS_EN,
> -          mxic->regs + HC_CFG);
>     writel(HC_EN_BIT, mxic->regs + HC_EN);
> 
> -   ss_ctrl = OP_CMD_BYTES(1) | OP_CMD_BUSW(fls(op->cmd.buswidth) - 1);
> -
> -   if (op->addr.nbytes)
> -      ss_ctrl |= OP_ADDR_BYTES(op->addr.nbytes) |
> -            OP_ADDR_BUSW(fls(op->addr.buswidth) - 1);
> -
> -   if (op->dummy.nbytes)
> -      ss_ctrl |= OP_DUMMY_CYC(op->dummy.nbytes);
> -
> -   if (op->data.nbytes) {
> -      ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1);
> -      if (op->data.dir == SPI_MEM_DATA_IN)
> -         ss_ctrl |= OP_READ;
> -   }
> -
> -   writel(ss_ctrl, mxic->regs + SS_CTRL(mem->spi->chip_select));
> +   writel(mxic_spi_mem_prep_op_cfg(op),
> +          mxic->regs + SS_CTRL(mem->spi->chip_select));
> 
>     writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
>            mxic->regs + HC_CFG);
> @@ -423,6 +528,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
>  static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
>     .supports_op = mxic_spi_mem_supports_op,
>     .exec_op = mxic_spi_mem_exec_op,
> +   .dirmap_create = mxic_spi_mem_dirmap_create,
> +   .dirmap_read = mxic_spi_mem_dirmap_read,
> +   .dirmap_write = mxic_spi_mem_dirmap_write,
>  };
> 
>  static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
> @@ -552,6 +660,15 @@ static int mxic_spi_probe(struct platform_device 
*pdev)
>     if (IS_ERR(mxic->regs))
>        return PTR_ERR(mxic->regs);
> 
> +   res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
> +   mxic->linear.map = devm_ioremap_resource(&pdev->dev, res);
> +   if (!IS_ERR(mxic->linear.map)) {
> +      mxic->linear.dma = res->start;
> +      mxic->linear.size = resource_size(res);
> +   } else {
> +      mxic->linear.map = NULL;
> +   }
> +
>     pm_runtime_enable(&pdev->dev);
>     master->auto_runtime_pm = true;
> 
> -- 
> 2.27.0
> 


CONFIDENTIALITY NOTE:

This e-mail and any attachments may contain confidential information 
and/or personal data, which is protected by applicable laws. Please be 
reminded that duplication, disclosure, distribution, or use of this e-mail 
(and/or its attachments) or any part thereof is prohibited. If you receive 
this e-mail in error, please notify us immediately and delete this mail as 
well as its attachment(s) from your system. In addition, please be 
informed that collection, processing, and/or use of personal data is 
prohibited unless expressly permitted by personal data protection laws. 
Thank you for your attention and cooperation.

Macronix International Co., Ltd.

=====================================================================



============================================================================

CONFIDENTIALITY NOTE:

This e-mail and any attachments may contain confidential information and/or personal data, which is protected by applicable laws. Please be reminded that duplication, disclosure, distribution, or use of this e-mail (and/or its attachments) or any part thereof is prohibited. If you receive this e-mail in error, please notify us immediately and delete this mail as well as its attachment(s) from your system. In addition, please be informed that collection, processing, and/or use of personal data is prohibited unless expressly permitted by personal data protection laws. Thank you for your attention and cooperation.

Macronix International Co., Ltd.

=====================================================================




More information about the linux-mtd mailing list