diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 37f4443ce9a097..41bc5ed607eea2 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,25 @@ #define SPI_MEM_MAX_BUSWIDTH 8 +bool update_stripe(const struct spi_mem_op *op) +{ + if (op->cmd.opcode == SPINOR_OP_BE_4K || + op->cmd.opcode == SPINOR_OP_BE_32K || + op->cmd.opcode == SPINOR_OP_CHIP_ERASE || + op->cmd.opcode == SPINOR_OP_SE || + op->cmd.opcode == SPINOR_OP_BE_32K_4B || + op->cmd.opcode == SPINOR_OP_SE_4B || + op->cmd.opcode == SPINOR_OP_BE_4K_4B || + op->cmd.opcode == SPINOR_OP_WRSR || + op->cmd.opcode == SPINOR_OP_WREAR || + op->cmd.opcode == SPINOR_OP_BRWR || + (op->cmd.opcode == SPINOR_OP_WRSR2 && !op->addr.nbytes)) + return false; + + return true; +} +EXPORT_SYMBOL(update_stripe); + /** * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a * memory operation @@ -371,6 +391,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1; xfers[xferpos].len = op->dummy.nbytes; xfers[xferpos].tx_nbits = op->dummy.buswidth; + xfers[xferpos].dummy = op->dummy.nbytes * 8; xfers[xferpos].dummy_data = 1; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; @@ -386,6 +407,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) xfers[xferpos].tx_nbits = op->data.buswidth; } + xfers[xferpos].stripe = update_stripe(op); xfers[xferpos].len = op->data.nbytes; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 56627bfddab4b5..83bdc7674be184 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -23,6 +23,7 @@ #include #include #include +#include /* Generic QSPI register offsets */ #define GQSPI_CONFIG_OFST 0x00000100 @@ -337,6 +338,16 @@ static void zynqmp_qspi_set_tapdelay(struct zynqmp_qspi *xqspi, u32 baudrateval) zynqmp_gqspi_write(xqspi, GQSPI_DATA_DLY_ADJ_OFST, datadlyadj); } +static u32 zynqmp_disable_intr(struct zynqmp_qspi *xqspi) +{ + u32 value; + + zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK); + value = zynqmp_gqspi_read(xqspi, GQSPI_IMASK_OFST); + zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK); + + return value; +} /** * zynqmp_qspi_init_hw - Initialize the hardware * @xqspi: Pointer to the zynqmp_qspi structure @@ -364,9 +375,7 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi) /* Select the GQSPI mode */ zynqmp_gqspi_write(xqspi, GQSPI_SEL_OFST, GQSPI_SEL_MASK); /* Clear and disable interrupts */ - zynqmp_gqspi_write(xqspi, GQSPI_ISR_OFST, - zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST) | - GQSPI_ISR_WR_TO_CLR_MASK); + zynqmp_disable_intr(xqspi); /* Clear the DMA STS */ zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_I_STS_OFST, zynqmp_gqspi_read(xqspi, @@ -456,11 +465,22 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) u32 genfifoentry = 0, statusreg; genfifoentry |= GQSPI_GENFIFO_MODE_SPI; + if (qspi->master->flags & SPI_MASTER_BOTH_CS) { + zynqmp_gqspi_selectslave(xqspi, + GQSPI_SELECT_FLASH_CS_BOTH, + GQSPI_SELECT_FLASH_BUS_BOTH); + } else if (qspi->master->flags & SPI_MASTER_U_PAGE) { + zynqmp_gqspi_selectslave(xqspi, + GQSPI_SELECT_FLASH_CS_UPPER, + GQSPI_SELECT_FLASH_BUS_LOWER); + } else { + zynqmp_gqspi_selectslave(xqspi, + GQSPI_SELECT_FLASH_CS_LOWER, + GQSPI_SELECT_FLASH_BUS_LOWER); + } + genfifoentry |= xqspi->genfifobus; if (!is_high) { - xqspi->genfifobus = GQSPI_GENFIFO_BUS_LOWER; - xqspi->genfifocs = GQSPI_GENFIFO_CS_LOWER; - genfifoentry |= xqspi->genfifobus; genfifoentry |= xqspi->genfifocs; genfifoentry |= GQSPI_GENFIFO_CS_SETUP; } else { @@ -842,7 +862,8 @@ static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) u64 dma_align = (u64)(uintptr_t)xqspi->rxbuf; if ((xqspi->bytes_to_receive < 8 || xqspi->io_mode) || - ((dma_align & GQSPI_DMA_UNALIGN) != 0x0)) { + ((dma_align & GQSPI_DMA_UNALIGN) != 0x0) || + is_vmalloc_addr(xqspi->rxbuf)) { /* Setting to IO mode */ config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST); config_reg &= ~GQSPI_CFG_MODE_EN_MASK; @@ -1065,6 +1086,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | GQSPI_CFG_START_GEN_FIFO_MASK); zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, + GQSPI_IER_TXEMPTY_MASK | GQSPI_IER_GENFIFOEMPTY_MASK | GQSPI_IER_TXNOT_FULL_MASK); if (!wait_for_completion_timeout @@ -1122,6 +1144,10 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, } if (op->data.nbytes) { + if (mem->spi->master->flags & SPI_MASTER_DATA_STRIPE) { + if (update_stripe(op)) + genfifoentry |= GQSPI_GENFIFO_STRIPE; + } reinit_completion(&xqspi->data_completion); if (op->data.dir == SPI_MEM_DATA_OUT) { xqspi->txbuf = (u8 *)op->data.buf.out; @@ -1176,9 +1202,20 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, return err; } +static int __maybe_unused zynqmp_runtime_idle(struct device *dev) +{ + struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); + u32 value; + + value = zynqmp_gqspi_read(xqspi, GQSPI_EN_OFST); + if (value) + return -EBUSY; + + return 0; +} static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = { SET_RUNTIME_PM_OPS(zynqmp_runtime_suspend, - zynqmp_runtime_resume, NULL) + zynqmp_runtime_resume, zynqmp_runtime_idle) SET_SYSTEM_SLEEP_PM_OPS(zynqmp_qspi_suspend, zynqmp_qspi_resume) }; @@ -1214,6 +1251,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; const struct of_device_id *match; + u32 num_cs; ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); if (!ctlr) @@ -1290,6 +1328,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) xqspi->irq = platform_get_irq(pdev, 0); if (xqspi->irq <= 0) { ret = -ENXIO; + dev_err(dev, "irq resource not found\n"); goto clk_dis_all; } ret = devm_request_irq(&pdev->dev, xqspi->irq, zynqmp_qspi_irq, @@ -1300,9 +1339,13 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } + ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); + if (ret < 0) + ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; + else + ctlr->num_chipselect = num_cs; dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); ctlr->bits_per_word_mask = SPI_BPW_MASK(8); - ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; ctlr->mem_ops = &zynqmp_qspi_mem_ops; ctlr->setup = zynqmp_qspi_setup_op; ctlr->bits_per_word_mask = SPI_BPW_MASK(8); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 926b68aa45d3ed..0557fb5c3d1429 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2064,6 +2064,9 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, if (!of_property_read_u32(nc, "spi-max-frequency", &value)) spi->max_speed_hz = value; + /* Multi die flash */ + if (of_property_read_bool(nc, "multi-die")) + spi->multi_die = true; return 0; } diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index a8f92552c18a47..2ca3c81129b2c3 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -361,6 +361,7 @@ bool spi_mem_dtr_supports_op(struct spi_mem *mem, int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op); +bool update_stripe(const struct spi_mem_op *op); bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 90c688acafec50..7900a85a3018fb 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -844,6 +844,7 @@ extern void spi_res_release(struct spi_controller *ctlr, * @len: size of rx and tx buffers (in bytes) * @speed_hz: Select a speed other than the device default for this * transfer. If 0 the default (from @spi_device) is used. + * @dummy: number of dummy cycles. * @bits_per_word: select a bits_per_word other than the device default * for this transfer. If 0 the default (from @spi_device) is used. * @dummy_data: indicates transfer is dummy bytes transfer. @@ -861,6 +862,7 @@ extern void spi_res_release(struct spi_controller *ctlr, * @transfer_list: transfers are sequenced through @spi_message.transfers * @tx_sg: Scatterlist for transmit, currently not for client use * @rx_sg: Scatterlist for receive, currently not for client use + * @stripe: true-> enable stripe, false-> disable stripe. * @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset * within @tx_buf for which the SPI device is requesting that the time * snapshot for this transfer begins. Upon completing the SPI transfer, @@ -968,6 +970,8 @@ struct spi_transfer { struct spi_delay cs_change_delay; struct spi_delay word_delay; u32 speed_hz; + u32 dummy; + bool stripe; u32 effective_speed_hz;