Message ID | 20211008162228.1753083-10-miquel.raynal@bootlin.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Macronix ECC engine | expand |
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@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. =====================================================================
> 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@bootlin.com> > --- > drivers/spi/spi-mxic.c | 171 ++++++++++++++++++++++++++++++++++------- > 1 file changed, 144 insertions(+), 27 deletions(-) Hi Miquel, I verified it by reading, writing, and erasing through normal and quad modes on the Xilinx Zynq PicoZed FPGA board. Except for the need to update the SPI MXIC driver version, it looks good. Tested-by: Zhengxun Li <zhengxunli@mxic.com.tw> Reviewed-by: Zhengxun Li <zhengxunli@mxic.com.tw> 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. =====================================================================
Hello Jaime, jaimeliao@mxic.com.tw wrote on Tue, 12 Oct 2021 15:14:56 +0800: > 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. Yes you are right. I didn't rebase my series before sending it, as mentioned in the cover letter this was just a way to provide this code publicly as someone from Mediatek needed it (hence, the RFC). I will soon send a real v1 with the bindings fixed as well. Thanks, Miquèl
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;
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@bootlin.com> --- drivers/spi/spi-mxic.c | 171 ++++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 27 deletions(-)