diff options
Diffstat (limited to 'drivers/spi/spi-zynqmp-gqspi.c')
-rw-r--r-- | drivers/spi/spi-zynqmp-gqspi.c | 720 |
1 files changed, 407 insertions, 313 deletions
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index e17a20125255..c8fa6ee18ae7 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -21,6 +21,7 @@ #include <linux/spi/spi.h> #include <linux/spinlock.h> #include <linux/workqueue.h> +#include <linux/spi/spi-mem.h> /* Generic QSPI register offsets */ #define GQSPI_CONFIG_OFST 0x00000100 @@ -153,6 +154,7 @@ enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; * @dma_addr: DMA address after mapping the kernel buffer * @genfifoentry: Used for storing the genfifoentry instruction. * @mode: Defines the mode in which QSPI is operating + * @data_completion: completion structure */ struct zynqmp_qspi { void __iomem *regs; @@ -170,12 +172,14 @@ struct zynqmp_qspi { dma_addr_t dma_addr; u32 genfifoentry; enum mode_type mode; + struct completion data_completion; }; /** - * zynqmp_gqspi_read: For GQSPI controller read operation + * zynqmp_gqspi_read - For GQSPI controller read operation * @xqspi: Pointer to the zynqmp_qspi structure * @offset: Offset from where to read + * Return: Value at the offset */ static u32 zynqmp_gqspi_read(struct zynqmp_qspi *xqspi, u32 offset) { @@ -183,7 +187,7 @@ static u32 zynqmp_gqspi_read(struct zynqmp_qspi *xqspi, u32 offset) } /** - * zynqmp_gqspi_write: For GQSPI controller write operation + * zynqmp_gqspi_write - For GQSPI controller write operation * @xqspi: Pointer to the zynqmp_qspi structure * @offset: Offset where to write * @val: Value to be written @@ -195,7 +199,7 @@ static inline void zynqmp_gqspi_write(struct zynqmp_qspi *xqspi, u32 offset, } /** - * zynqmp_gqspi_selectslave: For selection of slave device + * zynqmp_gqspi_selectslave - For selection of slave device * @instanceptr: Pointer to the zynqmp_qspi structure * @slavecs: For chip select * @slavebus: To check which bus is selected- upper or lower @@ -242,7 +246,7 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr, } /** - * zynqmp_qspi_init_hw: Initialize the hardware + * zynqmp_qspi_init_hw - Initialize the hardware * @xqspi: Pointer to the zynqmp_qspi structure * * The default settings of the QSPI controller's configurable parameters on @@ -322,15 +326,15 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi) GQSPI_SELECT_FLASH_BUS_LOWER); /* Initialize DMA */ zynqmp_gqspi_write(xqspi, - GQSPI_QSPIDMA_DST_CTRL_OFST, - GQSPI_QSPIDMA_DST_CTRL_RESET_VAL); + GQSPI_QSPIDMA_DST_CTRL_OFST, + GQSPI_QSPIDMA_DST_CTRL_RESET_VAL); /* Enable the GQSPI */ zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); } /** - * zynqmp_qspi_copy_read_data: Copy data to RX buffer + * zynqmp_qspi_copy_read_data - Copy data to RX buffer * @xqspi: Pointer to the zynqmp_qspi structure * @data: The variable where data is stored * @size: Number of bytes to be copied from data to RX buffer @@ -344,41 +348,7 @@ static void zynqmp_qspi_copy_read_data(struct zynqmp_qspi *xqspi, } /** - * zynqmp_prepare_transfer_hardware: Prepares hardware for transfer. - * @master: Pointer to the spi_master structure which provides - * information about the controller. - * - * This function enables SPI master controller. - * - * Return: 0 on success; error value otherwise - */ -static int zynqmp_prepare_transfer_hardware(struct spi_master *master) -{ - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); - - zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); - return 0; -} - -/** - * zynqmp_unprepare_transfer_hardware: Relaxes hardware after transfer - * @master: Pointer to the spi_master structure which provides - * information about the controller. - * - * This function disables the SPI master controller. - * - * Return: Always 0 - */ -static int zynqmp_unprepare_transfer_hardware(struct spi_master *master) -{ - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); - - zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); - return 0; -} - -/** - * zynqmp_qspi_chipselect: Select or deselect the chip select line + * zynqmp_qspi_chipselect - Select or deselect the chip select line * @qspi: Pointer to the spi_device structure * @is_high: Select(0) or deselect (1) the chip select line */ @@ -386,12 +356,14 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) { struct zynqmp_qspi *xqspi = spi_master_get_devdata(qspi->master); ulong timeout; - u32 genfifoentry = 0x0, statusreg; + u32 genfifoentry = 0, statusreg; genfifoentry |= GQSPI_GENFIFO_MODE_SPI; - 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 { @@ -402,8 +374,8 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) /* Manually start the generic FIFO command */ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, - zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | - GQSPI_CFG_START_GEN_FIFO_MASK); + zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | + GQSPI_CFG_START_GEN_FIFO_MASK); timeout = jiffies + msecs_to_jiffies(1000); @@ -412,10 +384,9 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) statusreg = zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST); if ((statusreg & GQSPI_ISR_GENFIFOEMPTY_MASK) && - (statusreg & GQSPI_ISR_TXEMPTY_MASK)) + (statusreg & GQSPI_ISR_TXEMPTY_MASK)) break; - else - cpu_relax(); + cpu_relax(); } while (!time_after_eq(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) @@ -423,11 +394,38 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) } /** - * zynqmp_qspi_setup_transfer: Configure QSPI controller for specified + * zynqmp_qspi_selectspimode - Selects SPI mode - x1 or x2 or x4. + * @xqspi: xqspi is a pointer to the GQSPI instance + * @spimode: spimode - SPI or DUAL or QUAD. + * Return: Mask to set desired SPI mode in GENFIFO entry. + */ +static inline u32 zynqmp_qspi_selectspimode(struct zynqmp_qspi *xqspi, + u8 spimode) +{ + u32 mask = 0; + + switch (spimode) { + case GQSPI_SELECT_MODE_DUALSPI: + mask = GQSPI_GENFIFO_MODE_DUALSPI; + break; + case GQSPI_SELECT_MODE_QUADSPI: + mask = GQSPI_GENFIFO_MODE_QUADSPI; + break; + case GQSPI_SELECT_MODE_SPI: + mask = GQSPI_GENFIFO_MODE_SPI; + break; + default: + dev_warn(xqspi->dev, "Invalid SPI mode\n"); + } + + return mask; +} + +/** + * zynqmp_qspi_config_op - Configure QSPI controller for specified * transfer + * @xqspi: Pointer to the zynqmp_qspi structure * @qspi: Pointer to the spi_device structure - * @transfer: Pointer to the spi_transfer structure which provides - * information about next transfer setup parameters * * Sets the operational mode of QSPI controller for the next QSPI transfer and * sets the requested clock frequency. @@ -444,17 +442,11 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) * by the QSPI controller the driver will set the highest or lowest * frequency supported by controller. */ -static int zynqmp_qspi_setup_transfer(struct spi_device *qspi, - struct spi_transfer *transfer) +static int zynqmp_qspi_config_op(struct zynqmp_qspi *xqspi, + struct spi_device *qspi) { - struct zynqmp_qspi *xqspi = spi_master_get_devdata(qspi->master); ulong clk_rate; - u32 config_reg, req_hz, baud_rate_val = 0; - - if (transfer) - req_hz = transfer->speed_hz; - else - req_hz = qspi->max_speed_hz; + u32 config_reg, baud_rate_val = 0; /* Set the clock frequency */ /* If req_hz == 0, default to lowest speed */ @@ -462,7 +454,7 @@ static int zynqmp_qspi_setup_transfer(struct spi_device *qspi, while ((baud_rate_val < GQSPI_BAUD_DIV_MAX) && (clk_rate / - (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) > req_hz) + (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) > qspi->max_speed_hz) baud_rate_val++; config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST); @@ -482,7 +474,7 @@ static int zynqmp_qspi_setup_transfer(struct spi_device *qspi, } /** - * zynqmp_qspi_setup: Configure the QSPI controller + * zynqmp_qspi_setup_op - Configure the QSPI controller * @qspi: Pointer to the spi_device structure * * Sets the operational mode of QSPI controller for the next QSPI transfer, @@ -490,15 +482,35 @@ static int zynqmp_qspi_setup_transfer(struct spi_device *qspi, * * Return: 0 on success; error value otherwise. */ -static int zynqmp_qspi_setup(struct spi_device *qspi) +static int zynqmp_qspi_setup_op(struct spi_device *qspi) { - if (qspi->master->busy) + struct spi_controller *ctlr = qspi->master; + struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); + struct device *dev = &ctlr->dev; + int ret; + + if (ctlr->busy) return -EBUSY; + + ret = clk_enable(xqspi->refclk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + return ret; + } + + ret = clk_enable(xqspi->pclk); + if (ret) { + dev_err(dev, "Cannot enable APB clock.\n"); + clk_disable(xqspi->refclk); + return ret; + } + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); + return 0; } /** - * zynqmp_qspi_filltxfifo: Fills the TX FIFO as long as there is room in + * zynqmp_qspi_filltxfifo - Fills the TX FIFO as long as there is room in * the FIFO or the bytes required to be * transmitted. * @xqspi: Pointer to the zynqmp_qspi structure @@ -524,7 +536,7 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size) } /** - * zynqmp_qspi_readrxfifo: Fills the RX FIFO as long as there is room in + * zynqmp_qspi_readrxfifo - Fills the RX FIFO as long as there is room in * the FIFO. * @xqspi: Pointer to the zynqmp_qspi structure * @size: Number of bytes to be copied from RX buffer to RX FIFO @@ -536,7 +548,7 @@ static void zynqmp_qspi_readrxfifo(struct zynqmp_qspi *xqspi, u32 size) while ((count < size) && (xqspi->bytes_to_receive > 0)) { if (xqspi->bytes_to_receive >= 4) { - (*(u32 *) xqspi->rxbuf) = + (*(u32 *)xqspi->rxbuf) = zynqmp_gqspi_read(xqspi, GQSPI_RXD_OFST); xqspi->rxbuf += 4; xqspi->bytes_to_receive -= 4; @@ -552,7 +564,76 @@ static void zynqmp_qspi_readrxfifo(struct zynqmp_qspi *xqspi, u32 size) } /** - * zynqmp_process_dma_irq: Handler for DMA done interrupt of QSPI + * zynqmp_qspi_fillgenfifo - Fills the GENFIFO. + * @xqspi: Pointer to the zynqmp_qspi structure + * @nbits: Transfer/Receive buswidth. + * @genfifoentry: Variable in which GENFIFO mask is saved + */ +static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits, + u32 genfifoentry) +{ + u32 transfer_len = 0; + + if (xqspi->txbuf) { + genfifoentry &= ~GQSPI_GENFIFO_RX; + genfifoentry |= GQSPI_GENFIFO_DATA_XFER; + genfifoentry |= GQSPI_GENFIFO_TX; + transfer_len = xqspi->bytes_to_transfer; + } else { + genfifoentry &= ~GQSPI_GENFIFO_TX; + genfifoentry |= GQSPI_GENFIFO_DATA_XFER; + genfifoentry |= GQSPI_GENFIFO_RX; + if (xqspi->mode == GQSPI_MODE_DMA) + transfer_len = xqspi->dma_rx_bytes; + else + transfer_len = xqspi->bytes_to_receive; + } + genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits); + xqspi->genfifoentry = genfifoentry; + + if ((transfer_len) < GQSPI_GENFIFO_IMM_DATA_MASK) { + genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK; + genfifoentry |= transfer_len; + zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry); + } else { + int tempcount = transfer_len; + u32 exponent = 8; /* 2^8 = 256 */ + u8 imm_data = tempcount & 0xFF; + + tempcount &= ~(tempcount & 0xFF); + /* Immediate entry */ + if (tempcount != 0) { + /* Exponent entries */ + genfifoentry |= GQSPI_GENFIFO_EXP; + while (tempcount != 0) { + if (tempcount & GQSPI_GENFIFO_EXP_START) { + genfifoentry &= + ~GQSPI_GENFIFO_IMM_DATA_MASK; + genfifoentry |= exponent; + zynqmp_gqspi_write(xqspi, + GQSPI_GEN_FIFO_OFST, + genfifoentry); + } + tempcount = tempcount >> 1; + exponent++; + } + } + if (imm_data != 0) { + genfifoentry &= ~GQSPI_GENFIFO_EXP; + genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK; + genfifoentry |= (u8)(imm_data & 0xFF); + zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, + genfifoentry); + } + } + if (xqspi->mode == GQSPI_MODE_IO && xqspi->rxbuf) { + /* Dummy generic FIFO entry */ + zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0); + } +} + +/** + * zynqmp_process_dma_irq - Handler for DMA done interrupt of QSPI * controller * @xqspi: zynqmp_qspi instance pointer * @@ -563,14 +644,14 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi) u32 config_reg, genfifoentry; dma_unmap_single(xqspi->dev, xqspi->dma_addr, - xqspi->dma_rx_bytes, DMA_FROM_DEVICE); + xqspi->dma_rx_bytes, DMA_FROM_DEVICE); xqspi->rxbuf += xqspi->dma_rx_bytes; xqspi->bytes_to_receive -= xqspi->dma_rx_bytes; xqspi->dma_rx_bytes = 0; /* Disabling the DMA interrupts */ zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_I_DIS_OFST, - GQSPI_QSPIDMA_DST_I_EN_DONE_MASK); + GQSPI_QSPIDMA_DST_I_EN_DONE_MASK); if (xqspi->bytes_to_receive > 0) { /* Switch to IO mode,for remaining bytes to receive */ @@ -588,19 +669,20 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi) /* Manual start */ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, - (zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | - GQSPI_CFG_START_GEN_FIFO_MASK)); + (zynqmp_gqspi_read(xqspi, + GQSPI_CONFIG_OFST) | + GQSPI_CFG_START_GEN_FIFO_MASK)); /* Enable the RX interrupts for IO mode */ zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, - GQSPI_IER_GENFIFOEMPTY_MASK | - GQSPI_IER_RXNEMPTY_MASK | - GQSPI_IER_RXEMPTY_MASK); + GQSPI_IER_GENFIFOEMPTY_MASK | + GQSPI_IER_RXNEMPTY_MASK | + GQSPI_IER_RXEMPTY_MASK); } } /** - * zynqmp_qspi_irq: Interrupt service routine of the QSPI controller + * zynqmp_qspi_irq - Interrupt service routine of the QSPI controller * @irq: IRQ number * @dev_id: Pointer to the xqspi structure * @@ -613,9 +695,8 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi) */ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) { - struct spi_master *master = dev_id; - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); - int ret = IRQ_NONE; + struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_id; + irqreturn_t ret = IRQ_NONE; u32 status, mask, dma_status = 0; status = zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST); @@ -627,7 +708,7 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) dma_status = zynqmp_gqspi_read(xqspi, GQSPI_QSPIDMA_DST_I_STS_OFST); zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_I_STS_OFST, - dma_status); + dma_status); } if (mask & GQSPI_ISR_TXNOT_FULL_MASK) { @@ -644,55 +725,27 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) ret = IRQ_HANDLED; } - if ((xqspi->bytes_to_receive == 0) && (xqspi->bytes_to_transfer == 0) - && ((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) { + if (xqspi->bytes_to_receive == 0 && xqspi->bytes_to_transfer == 0 && + ((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) { zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK); - spi_finalize_current_transfer(master); + complete(&xqspi->data_completion); ret = IRQ_HANDLED; } return ret; } /** - * zynqmp_qspi_selectspimode: Selects SPI mode - x1 or x2 or x4. - * @xqspi: xqspi is a pointer to the GQSPI instance - * @spimode: spimode - SPI or DUAL or QUAD. - * Return: Mask to set desired SPI mode in GENFIFO entry. - */ -static inline u32 zynqmp_qspi_selectspimode(struct zynqmp_qspi *xqspi, - u8 spimode) -{ - u32 mask = 0; - - switch (spimode) { - case GQSPI_SELECT_MODE_DUALSPI: - mask = GQSPI_GENFIFO_MODE_DUALSPI; - break; - case GQSPI_SELECT_MODE_QUADSPI: - mask = GQSPI_GENFIFO_MODE_QUADSPI; - break; - case GQSPI_SELECT_MODE_SPI: - mask = GQSPI_GENFIFO_MODE_SPI; - break; - default: - dev_warn(xqspi->dev, "Invalid SPI mode\n"); - } - - return mask; -} - -/** - * zynq_qspi_setuprxdma: This function sets up the RX DMA operation + * zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation * @xqspi: xqspi is a pointer to the GQSPI instance. */ -static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi) +static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) { u32 rx_bytes, rx_rem, config_reg; dma_addr_t addr; u64 dma_align = (u64)(uintptr_t)xqspi->rxbuf; - if ((xqspi->bytes_to_receive < 8) || - ((dma_align & GQSPI_DMA_UNALIGN) != 0x0)) { + if (xqspi->bytes_to_receive < 8 || + ((dma_align & GQSPI_DMA_UNALIGN) != 0x0)) { /* Setting to IO mode */ config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST); config_reg &= ~GQSPI_CFG_MODE_EN_MASK; @@ -706,17 +759,17 @@ static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi) rx_bytes = (xqspi->bytes_to_receive - rx_rem); addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf, - rx_bytes, DMA_FROM_DEVICE); + rx_bytes, DMA_FROM_DEVICE); if (dma_mapping_error(xqspi->dev, addr)) dev_err(xqspi->dev, "ERR:rxdma:memory not mapped\n"); xqspi->dma_rx_bytes = rx_bytes; xqspi->dma_addr = addr; zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_ADDR_OFST, - (u32)(addr & 0xffffffff)); + (u32)(addr & 0xffffffff)); addr = ((addr >> 16) >> 16); zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_ADDR_MSB_OFST, - ((u32)addr) & 0xfff); + ((u32)addr) & 0xfff); /* Enabling the DMA mode */ config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST); @@ -732,166 +785,48 @@ static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi) } /** - * zynqmp_qspi_txrxsetup: This function checks the TX/RX buffers in - * the transfer and sets up the GENFIFO entries, - * TX FIFO as required. - * @xqspi: xqspi is a pointer to the GQSPI instance. - * @transfer: It is a pointer to the structure containing transfer data. - * @genfifoentry: genfifoentry is pointer to the variable in which - * GENFIFO mask is returned to calling function + * zynqmp_qspi_write_op - This function sets up the GENFIFO entries, + * TX FIFO, and fills the TX FIFO with as many + * bytes as possible. + * @xqspi: Pointer to the GQSPI instance. + * @tx_nbits: Transfer buswidth. + * @genfifoentry: Variable in which GENFIFO mask is returned + * to calling function */ -static void zynqmp_qspi_txrxsetup(struct zynqmp_qspi *xqspi, - struct spi_transfer *transfer, - u32 *genfifoentry) +static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits, + u32 genfifoentry) { u32 config_reg; - /* Transmit */ - if ((xqspi->txbuf != NULL) && (xqspi->rxbuf == NULL)) { - /* Setup data to be TXed */ - *genfifoentry &= ~GQSPI_GENFIFO_RX; - *genfifoentry |= GQSPI_GENFIFO_DATA_XFER; - *genfifoentry |= GQSPI_GENFIFO_TX; - *genfifoentry |= - zynqmp_qspi_selectspimode(xqspi, transfer->tx_nbits); - xqspi->bytes_to_transfer = transfer->len; - if (xqspi->mode == GQSPI_MODE_DMA) { - config_reg = zynqmp_gqspi_read(xqspi, - GQSPI_CONFIG_OFST); - config_reg &= ~GQSPI_CFG_MODE_EN_MASK; - zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, - config_reg); - xqspi->mode = GQSPI_MODE_IO; - } - zynqmp_qspi_filltxfifo(xqspi, GQSPI_TXD_DEPTH); - /* Discard RX data */ - xqspi->bytes_to_receive = 0; - } else if ((xqspi->txbuf == NULL) && (xqspi->rxbuf != NULL)) { - /* Receive */ - - /* TX auto fill */ - *genfifoentry &= ~GQSPI_GENFIFO_TX; - /* Setup RX */ - *genfifoentry |= GQSPI_GENFIFO_DATA_XFER; - *genfifoentry |= GQSPI_GENFIFO_RX; - *genfifoentry |= - zynqmp_qspi_selectspimode(xqspi, transfer->rx_nbits); - xqspi->bytes_to_transfer = 0; - xqspi->bytes_to_receive = transfer->len; - zynq_qspi_setuprxdma(xqspi); + zynqmp_qspi_fillgenfifo(xqspi, tx_nbits, genfifoentry); + zynqmp_qspi_filltxfifo(xqspi, GQSPI_TXD_DEPTH); + if (xqspi->mode == GQSPI_MODE_DMA) { + config_reg = zynqmp_gqspi_read(xqspi, + GQSPI_CONFIG_OFST); + config_reg &= ~GQSPI_CFG_MODE_EN_MASK; + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, + config_reg); + xqspi->mode = GQSPI_MODE_IO; } } /** - * zynqmp_qspi_start_transfer: Initiates the QSPI transfer - * @master: Pointer to the spi_master structure which provides - * information about the controller. - * @qspi: Pointer to the spi_device structure - * @transfer: Pointer to the spi_transfer structure which provide information - * about next transfer parameters - * - * This function fills the TX FIFO, starts the QSPI transfer, and waits for the - * transfer to be completed. - * - * Return: Number of bytes transferred in the last transfer + * zynqmp_qspi_read_op - This function sets up the GENFIFO entries and + * RX DMA operation. + * @xqspi: xqspi is a pointer to the GQSPI instance. + * @rx_nbits: Receive buswidth. + * @genfifoentry: genfifoentry is pointer to the variable in which + * GENFIFO mask is returned to calling function */ -static int zynqmp_qspi_start_transfer(struct spi_master *master, - struct spi_device *qspi, - struct spi_transfer *transfer) +static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, + u32 genfifoentry) { - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); - u32 genfifoentry = 0x0, transfer_len; - - xqspi->txbuf = transfer->tx_buf; - xqspi->rxbuf = transfer->rx_buf; - - zynqmp_qspi_setup_transfer(qspi, transfer); - - genfifoentry |= xqspi->genfifocs; - genfifoentry |= xqspi->genfifobus; - - zynqmp_qspi_txrxsetup(xqspi, transfer, &genfifoentry); - - if (xqspi->mode == GQSPI_MODE_DMA) - transfer_len = xqspi->dma_rx_bytes; - else - transfer_len = transfer->len; - - xqspi->genfifoentry = genfifoentry; - if ((transfer_len) < GQSPI_GENFIFO_IMM_DATA_MASK) { - genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK; - genfifoentry |= transfer_len; - zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry); - } else { - int tempcount = transfer_len; - u32 exponent = 8; /* 2^8 = 256 */ - u8 imm_data = tempcount & 0xFF; - - tempcount &= ~(tempcount & 0xFF); - /* Immediate entry */ - if (tempcount != 0) { - /* Exponent entries */ - genfifoentry |= GQSPI_GENFIFO_EXP; - while (tempcount != 0) { - if (tempcount & GQSPI_GENFIFO_EXP_START) { - genfifoentry &= - ~GQSPI_GENFIFO_IMM_DATA_MASK; - genfifoentry |= exponent; - zynqmp_gqspi_write(xqspi, - GQSPI_GEN_FIFO_OFST, - genfifoentry); - } - tempcount = tempcount >> 1; - exponent++; - } - } - if (imm_data != 0) { - genfifoentry &= ~GQSPI_GENFIFO_EXP; - genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK; - genfifoentry |= (u8) (imm_data & 0xFF); - zynqmp_gqspi_write(xqspi, - GQSPI_GEN_FIFO_OFST, genfifoentry); - } - } - - if ((xqspi->mode == GQSPI_MODE_IO) && - (xqspi->rxbuf != NULL)) { - /* Dummy generic FIFO entry */ - zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0); - } - - /* Since we are using manual mode */ - zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, - zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | - GQSPI_CFG_START_GEN_FIFO_MASK); - - if (xqspi->txbuf != NULL) - /* Enable interrupts for TX */ - zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, - GQSPI_IER_TXEMPTY_MASK | - GQSPI_IER_GENFIFOEMPTY_MASK | - GQSPI_IER_TXNOT_FULL_MASK); - - if (xqspi->rxbuf != NULL) { - /* Enable interrupts for RX */ - if (xqspi->mode == GQSPI_MODE_DMA) { - /* Enable DMA interrupts */ - zynqmp_gqspi_write(xqspi, - GQSPI_QSPIDMA_DST_I_EN_OFST, - GQSPI_QSPIDMA_DST_I_EN_DONE_MASK); - } else { - zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, - GQSPI_IER_GENFIFOEMPTY_MASK | - GQSPI_IER_RXNEMPTY_MASK | - GQSPI_IER_RXEMPTY_MASK); - } - } - - return transfer->len; + zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry); + zynqmp_qspi_setuprxdma(xqspi); } /** - * zynqmp_qspi_suspend: Suspend method for the QSPI driver + * zynqmp_qspi_suspend - Suspend method for the QSPI driver * @dev: Address of the platform_device structure * * This function stops the QSPI driver queue and disables the QSPI controller @@ -900,17 +835,18 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master, */ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); - spi_master_suspend(master); + spi_controller_suspend(ctlr); - zynqmp_unprepare_transfer_hardware(master); + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); return 0; } /** - * zynqmp_qspi_resume: Resume method for the QSPI driver + * zynqmp_qspi_resume - Resume method for the QSPI driver * @dev: Address of the platform_device structure * * The function starts the QSPI driver queue and initializes the QSPI @@ -920,8 +856,8 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) */ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); int ret = 0; ret = clk_enable(xqspi->pclk); @@ -937,7 +873,7 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) return ret; } - spi_master_resume(master); + spi_controller_resume(ctlr); clk_disable(xqspi->refclk); clk_disable(xqspi->pclk); @@ -954,8 +890,7 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) */ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_get_drvdata(dev); clk_disable(xqspi->refclk); clk_disable(xqspi->pclk); @@ -973,8 +908,7 @@ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) */ static int __maybe_unused zynqmp_runtime_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_get_drvdata(dev); int ret; ret = clk_enable(xqspi->pclk); @@ -993,14 +927,179 @@ static int __maybe_unused zynqmp_runtime_resume(struct device *dev) return 0; } +/** + * zynqmp_qspi_exec_op() - Initiates the QSPI transfer + * @mem: The SPI memory + * @op: The memory operation to execute + * + * Executes a memory operation. + * + * This function first selects the chip and starts the memory operation. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +static int zynqmp_qspi_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct zynqmp_qspi *xqspi = spi_controller_get_devdata + (mem->spi->master); + int err = 0, i; + u8 *tmpbuf; + u32 genfifoentry = 0; + + dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n", + op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + op->dummy.buswidth, op->data.buswidth); + + zynqmp_qspi_config_op(xqspi, mem->spi); + zynqmp_qspi_chipselect(mem->spi, false); + genfifoentry |= xqspi->genfifocs; + genfifoentry |= xqspi->genfifobus; + + if (op->cmd.opcode) { + tmpbuf = kzalloc(op->cmd.nbytes, GFP_KERNEL | GFP_DMA); + if (!tmpbuf) + return -ENOMEM; + tmpbuf[0] = op->cmd.opcode; + reinit_completion(&xqspi->data_completion); + xqspi->txbuf = tmpbuf; + xqspi->rxbuf = NULL; + xqspi->bytes_to_transfer = op->cmd.nbytes; + xqspi->bytes_to_receive = 0; + zynqmp_qspi_write_op(xqspi, op->cmd.buswidth, genfifoentry); + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, + zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | + GQSPI_CFG_START_GEN_FIFO_MASK); + zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, + GQSPI_IER_GENFIFOEMPTY_MASK | + GQSPI_IER_TXNOT_FULL_MASK); + if (!wait_for_completion_interruptible_timeout + (&xqspi->data_completion, msecs_to_jiffies(1000))) { + err = -ETIMEDOUT; + kfree(tmpbuf); + goto return_err; + } + kfree(tmpbuf); + } + + if (op->addr.nbytes) { + for (i = 0; i < op->addr.nbytes; i++) { + *(((u8 *)xqspi->txbuf) + i) = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + } + + reinit_completion(&xqspi->data_completion); + xqspi->rxbuf = NULL; + xqspi->bytes_to_transfer = op->addr.nbytes; + xqspi->bytes_to_receive = 0; + zynqmp_qspi_write_op(xqspi, op->addr.buswidth, genfifoentry); + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, + 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_interruptible_timeout + (&xqspi->data_completion, msecs_to_jiffies(1000))) { + err = -ETIMEDOUT; + goto return_err; + } + } + + if (op->dummy.nbytes) { + tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL | GFP_DMA); + if (!tmpbuf) + return -ENOMEM; + memset(tmpbuf, 0xff, op->dummy.nbytes); + reinit_completion(&xqspi->data_completion); + xqspi->txbuf = tmpbuf; + xqspi->rxbuf = NULL; + xqspi->bytes_to_transfer = op->dummy.nbytes; + xqspi->bytes_to_receive = 0; + zynqmp_qspi_write_op(xqspi, op->dummy.buswidth, + genfifoentry); + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, + 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_interruptible_timeout + (&xqspi->data_completion, msecs_to_jiffies(1000))) { + err = -ETIMEDOUT; + kfree(tmpbuf); + goto return_err; + } + + kfree(tmpbuf); + } + + if (op->data.nbytes) { + reinit_completion(&xqspi->data_completion); + if (op->data.dir == SPI_MEM_DATA_OUT) { + xqspi->txbuf = (u8 *)op->data.buf.out; + xqspi->rxbuf = NULL; + xqspi->bytes_to_transfer = op->data.nbytes; + xqspi->bytes_to_receive = 0; + zynqmp_qspi_write_op(xqspi, op->data.buswidth, + genfifoentry); + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, + 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); + } else { + xqspi->txbuf = NULL; + xqspi->rxbuf = (u8 *)op->data.buf.in; + xqspi->bytes_to_receive = op->data.nbytes; + xqspi->bytes_to_transfer = 0; + zynqmp_qspi_read_op(xqspi, op->data.buswidth, + genfifoentry); + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, + zynqmp_gqspi_read + (xqspi, GQSPI_CONFIG_OFST) | + GQSPI_CFG_START_GEN_FIFO_MASK); + if (xqspi->mode == GQSPI_MODE_DMA) { + zynqmp_gqspi_write + (xqspi, GQSPI_QSPIDMA_DST_I_EN_OFST, + GQSPI_QSPIDMA_DST_I_EN_DONE_MASK); + } else { + zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, + GQSPI_IER_GENFIFOEMPTY_MASK | + GQSPI_IER_RXNEMPTY_MASK | + GQSPI_IER_RXEMPTY_MASK); + } + } + if (!wait_for_completion_interruptible_timeout + (&xqspi->data_completion, msecs_to_jiffies(1000))) + err = -ETIMEDOUT; + } + +return_err: + + zynqmp_qspi_chipselect(mem->spi, true); + + return err; +} + static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = { SET_RUNTIME_PM_OPS(zynqmp_runtime_suspend, zynqmp_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(zynqmp_qspi_suspend, zynqmp_qspi_resume) }; +static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = { + .exec_op = zynqmp_qspi_exec_op, +}; + /** - * zynqmp_qspi_probe: Probe method for the QSPI driver + * zynqmp_qspi_probe - Probe method for the QSPI driver * @pdev: Pointer to the platform_device structure * * This function initializes the driver data structures and the hardware. @@ -1010,17 +1109,18 @@ static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = { static int zynqmp_qspi_probe(struct platform_device *pdev) { int ret = 0; - struct spi_master *master; + struct spi_controller *ctlr; struct zynqmp_qspi *xqspi; struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; - master = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); - if (!master) + ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); + if (!ctlr) return -ENOMEM; - xqspi = spi_master_get_devdata(master); - master->dev.of_node = pdev->dev.of_node; - platform_set_drvdata(pdev, master); + xqspi = spi_controller_get_devdata(ctlr); + xqspi->dev = dev; + platform_set_drvdata(pdev, xqspi); xqspi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(xqspi->regs)) { @@ -1028,7 +1128,6 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto remove_master; } - xqspi->dev = dev; xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(xqspi->pclk)) { dev_err(dev, "pclk clock not found.\n"); @@ -1036,11 +1135,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto remove_master; } - ret = clk_prepare_enable(xqspi->pclk); - if (ret) { - dev_err(dev, "Unable to enable APB clock.\n"); - goto remove_master; - } + init_completion(&xqspi->data_completion); xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk"); if (IS_ERR(xqspi->refclk)) { @@ -1049,6 +1144,12 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_pclk; } + ret = clk_prepare_enable(xqspi->pclk); + if (ret) { + dev_err(dev, "Unable to enable APB clock.\n"); + goto remove_master; + } + ret = clk_prepare_enable(xqspi->refclk); if (ret) { dev_err(dev, "Unable to enable device clock.\n"); @@ -1070,32 +1171,28 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } ret = devm_request_irq(&pdev->dev, xqspi->irq, zynqmp_qspi_irq, - 0, pdev->name, master); + 0, pdev->name, xqspi); if (ret != 0) { ret = -ENXIO; dev_err(dev, "request_irq failed\n"); goto clk_dis_all; } - master->num_chipselect = GQSPI_DEFAULT_NUM_CS; - - master->setup = zynqmp_qspi_setup; - master->set_cs = zynqmp_qspi_chipselect; - master->transfer_one = zynqmp_qspi_start_transfer; - master->prepare_transfer_hardware = zynqmp_prepare_transfer_hardware; - master->unprepare_transfer_hardware = - zynqmp_unprepare_transfer_hardware; - master->max_speed_hz = clk_get_rate(xqspi->refclk) / 2; - master->bits_per_word_mask = SPI_BPW_MASK(8); - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD | + 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->max_speed_hz = clk_get_rate(xqspi->refclk) / 2; + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; + ctlr->dev.of_node = np; - if (master->dev.parent == NULL) - master->dev.parent = &master->dev; - - ret = spi_register_master(master); - if (ret) + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { + dev_err(&pdev->dev, "spi_register_controller failed\n"); goto clk_dis_all; + } return 0; @@ -1106,13 +1203,13 @@ clk_dis_all: clk_dis_pclk: clk_disable_unprepare(xqspi->pclk); remove_master: - spi_master_put(master); + spi_controller_put(ctlr); return ret; } /** - * zynqmp_qspi_remove: Remove method for the QSPI driver + * zynqmp_qspi_remove - Remove method for the QSPI driver * @pdev: Pointer to the platform_device structure * * This function is called if a device is physically removed from the system or @@ -1123,8 +1220,7 @@ remove_master: */ static int zynqmp_qspi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev); zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); clk_disable_unprepare(xqspi->refclk); @@ -1132,8 +1228,6 @@ static int zynqmp_qspi_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); - spi_unregister_master(master); - return 0; } |