回信: [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