diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-bcm63xx.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-cadence.c | 19 | ||||
-rw-r--r-- | drivers/spi/spi-qcom-qspi.c | 54 | ||||
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-stm32.c | 6 |
5 files changed, 67 insertions, 16 deletions
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 9aecb77c3d89..07b5b71b2352 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -126,7 +126,7 @@ enum bcm63xx_regs_spi { SPI_MSG_DATA_SIZE, }; -#define BCM63XX_SPI_MAX_PREPEND 15 +#define BCM63XX_SPI_MAX_PREPEND 7 #define BCM63XX_SPI_MAX_CS 8 #define BCM63XX_SPI_BUS_NUM 0 diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index de8fe3c5becb..9b021390263e 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -317,12 +317,6 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) xspi->rx_bytes -= nrx; while (ntx || nrx) { - /* When xspi in busy condition, bytes may send failed, - * then spi control did't work thoroughly, add one byte delay - */ - if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) - udelay(10); - if (ntx) { if (xspi->txbuf) cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); @@ -392,6 +386,11 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id) if (xspi->tx_bytes) { cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt); } else { + /* Fixed delay due to controller limitation with + * RX_NEMPTY incorrect status + * Xilinx AR:65885 contains more details + */ + udelay(10); cdns_spi_process_fifo(xspi, 0, trans_cnt); cdns_spi_write(xspi, CDNS_SPI_IDR, CDNS_SPI_IXR_DEFAULT); @@ -439,12 +438,18 @@ static int cdns_transfer_one(struct spi_controller *ctlr, cdns_spi_setup_transfer(spi, transfer); } else { /* Set TX empty threshold to half of FIFO depth - * only if TX bytes are more than half FIFO depth. + * only if TX bytes are more than FIFO depth. */ if (xspi->tx_bytes > xspi->tx_fifo_depth) cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1); } + /* When xspi in busy condition, bytes may send failed, + * then spi control didn't work thoroughly, add one byte delay + */ + if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) + udelay(10); + cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0); spi_transfer_delay_exec(transfer); diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index a8a683d6145c..1954c39b3d08 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -69,7 +69,7 @@ WR_FIFO_OVERRUN) #define QSPI_ALL_IRQS (QSPI_ERR_IRQS | RESP_FIFO_RDY | \ WR_FIFO_EMPTY | WR_FIFO_FULL | \ - TRANSACTION_DONE) + TRANSACTION_DONE | DMA_CHAIN_DONE) #define PIO_XFER_CTRL 0x0014 #define REQUEST_COUNT_MSK 0xffff @@ -308,9 +308,11 @@ static int qcom_qspi_alloc_desc(struct qcom_qspi *ctrl, dma_addr_t dma_ptr, dma_addr_t dma_cmd_desc; /* allocate for dma cmd descriptor */ - virt_cmd_desc = dma_pool_alloc(ctrl->dma_cmd_pool, GFP_KERNEL | __GFP_ZERO, &dma_cmd_desc); - if (!virt_cmd_desc) - return -ENOMEM; + virt_cmd_desc = dma_pool_alloc(ctrl->dma_cmd_pool, GFP_ATOMIC | __GFP_ZERO, &dma_cmd_desc); + if (!virt_cmd_desc) { + dev_warn_once(ctrl->dev, "Couldn't find memory for descriptor\n"); + return -EAGAIN; + } ctrl->virt_cmd_desc[ctrl->n_cmd_desc] = virt_cmd_desc; ctrl->dma_cmd_desc[ctrl->n_cmd_desc] = dma_cmd_desc; @@ -355,10 +357,22 @@ static int qcom_qspi_setup_dma_desc(struct qcom_qspi *ctrl, for (i = 0; i < sgt->nents; i++) { dma_ptr_sg = sg_dma_address(sgt->sgl + i); + dma_len_sg = sg_dma_len(sgt->sgl + i); if (!IS_ALIGNED(dma_ptr_sg, QSPI_ALIGN_REQ)) { dev_warn_once(ctrl->dev, "dma_address not aligned to %d\n", QSPI_ALIGN_REQ); return -EAGAIN; } + /* + * When reading with DMA the controller writes to memory 1 word + * at a time. If the length isn't a multiple of 4 bytes then + * the controller can clobber the things later in memory. + * Fallback to PIO to be safe. + */ + if (ctrl->xfer.dir == QSPI_READ && (dma_len_sg & 0x03)) { + dev_warn_once(ctrl->dev, "fallback to PIO for read of size %#010x\n", + dma_len_sg); + return -EAGAIN; + } } for (i = 0; i < sgt->nents; i++) { @@ -441,8 +455,10 @@ static int qcom_qspi_transfer_one(struct spi_master *master, ret = qcom_qspi_setup_dma_desc(ctrl, xfer); if (ret != -EAGAIN) { - if (!ret) + if (!ret) { + dma_wmb(); qcom_qspi_dma_xfer(ctrl); + } goto exit; } dev_warn_once(ctrl->dev, "DMA failure, falling back to PIO\n"); @@ -603,6 +619,9 @@ static irqreturn_t qcom_qspi_irq(int irq, void *dev_id) int_status = readl(ctrl->base + MSTR_INT_STATUS); writel(int_status, ctrl->base + MSTR_INT_STATUS); + /* Ignore disabled interrupts */ + int_status &= readl(ctrl->base + MSTR_INT_EN); + /* PIO mode handling */ if (ctrl->xfer.dir == QSPI_WRITE) { if (int_status & WR_FIFO_EMPTY) @@ -647,6 +666,30 @@ static irqreturn_t qcom_qspi_irq(int irq, void *dev_id) return ret; } +static int qcom_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + /* + * If qcom_qspi_can_dma() is going to return false we don't need to + * adjust anything. + */ + if (op->data.nbytes <= QSPI_MAX_BYTES_FIFO) + return 0; + + /* + * When reading, the transfer needs to be a multiple of 4 bytes so + * shrink the transfer if that's not true. The caller will then do a + * second transfer to finish things up. + */ + if (op->data.dir == SPI_MEM_DATA_IN && (op->data.nbytes & 0x3)) + op->data.nbytes &= ~0x3; + + return 0; +} + +static const struct spi_controller_mem_ops qcom_qspi_mem_ops = { + .adjust_op_size = qcom_qspi_adjust_op_size, +}; + static int qcom_qspi_probe(struct platform_device *pdev) { int ret; @@ -731,6 +774,7 @@ static int qcom_qspi_probe(struct platform_device *pdev) if (of_property_read_bool(pdev->dev.of_node, "iommus")) master->can_dma = qcom_qspi_can_dma; master->auto_runtime_pm = true; + master->mem_ops = &qcom_qspi_mem_ops; ret = devm_pm_opp_set_clkname(&pdev->dev, "core"); if (ret) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index fd55697144cc..b6c2659a66ca 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -684,6 +684,8 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) if ((sdd->cur_mode & SPI_LOOP) && sdd->port_conf->has_loopback) val |= S3C64XX_SPI_MODE_SELF_LOOPBACK; + else + val &= ~S3C64XX_SPI_MODE_SELF_LOOPBACK; writel(val, regs + S3C64XX_SPI_MODE_CFG); diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 6d10fa4ab783..7ddf9db776b0 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1001,9 +1001,9 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl, if (spi->cfg->set_number_of_data) { int ret; - ret = spi_split_transfers_maxsize(ctrl, msg, - STM32H7_SPI_TSIZE_MAX, - GFP_KERNEL | GFP_DMA); + ret = spi_split_transfers_maxwords(ctrl, msg, + STM32H7_SPI_TSIZE_MAX, + GFP_KERNEL | GFP_DMA); if (ret) return ret; } |