spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling
We need both RX and TX data for each transfer in any case (PIO, PDC, DMA). So convert the driver to the core dummy buffer handling with the SPI_MASTER_MUST_RX/SPI_MASTER_MUST_TX infrastructure. This move changes the maximum PDC/DMA buffer handling to 65535 bytes instead of a single page and sets master->max_dma_len to this value. All dummy buffer management is removed from the driver. Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Mark Brown <broonie@kernel.org>hifive-unleashed-5.1
parent
ce24a513fb
commit
7910d9af00
|
@ -303,10 +303,6 @@ struct atmel_spi {
|
||||||
|
|
||||||
struct completion xfer_completion;
|
struct completion xfer_completion;
|
||||||
|
|
||||||
/* scratch buffer */
|
|
||||||
void *buffer;
|
|
||||||
dma_addr_t buffer_dma;
|
|
||||||
|
|
||||||
struct atmel_spi_caps caps;
|
struct atmel_spi_caps caps;
|
||||||
|
|
||||||
bool use_dma;
|
bool use_dma;
|
||||||
|
@ -327,7 +323,7 @@ struct atmel_spi_device {
|
||||||
u32 csr;
|
u32 csr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BUFFER_SIZE PAGE_SIZE
|
#define SPI_MAX_DMA_XFER 65535 /* true for both PDC and DMA */
|
||||||
#define INVALID_DMA_ADDRESS 0xffffffff
|
#define INVALID_DMA_ADDRESS 0xffffffff
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -612,14 +608,10 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xfer->tx_buf) {
|
if (xfer->bits_per_word > 8)
|
||||||
if (xfer->bits_per_word > 8)
|
spi_writel(as, TDR, *(u16 *)(xfer->tx_buf + xfer_pos));
|
||||||
spi_writel(as, TDR, *(u16 *)(xfer->tx_buf + xfer_pos));
|
else
|
||||||
else
|
spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos));
|
||||||
spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos));
|
|
||||||
} else {
|
|
||||||
spi_writel(as, TDR, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(master->dev.parent,
|
dev_dbg(master->dev.parent,
|
||||||
" start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
|
" start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
|
||||||
|
@ -666,17 +658,12 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
|
||||||
|
|
||||||
/* Fill TX FIFO */
|
/* Fill TX FIFO */
|
||||||
while (num_data >= 2) {
|
while (num_data >= 2) {
|
||||||
if (xfer->tx_buf) {
|
if (xfer->bits_per_word > 8) {
|
||||||
if (xfer->bits_per_word > 8) {
|
td0 = *words++;
|
||||||
td0 = *words++;
|
td1 = *words++;
|
||||||
td1 = *words++;
|
|
||||||
} else {
|
|
||||||
td0 = *bytes++;
|
|
||||||
td1 = *bytes++;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
td0 = 0;
|
td0 = *bytes++;
|
||||||
td1 = 0;
|
td1 = *bytes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_writel(as, TDR, (td1 << 16) | td0);
|
spi_writel(as, TDR, (td1 << 16) | td0);
|
||||||
|
@ -684,14 +671,10 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_data) {
|
if (num_data) {
|
||||||
if (xfer->tx_buf) {
|
if (xfer->bits_per_word > 8)
|
||||||
if (xfer->bits_per_word > 8)
|
td0 = *words++;
|
||||||
td0 = *words++;
|
else
|
||||||
else
|
td0 = *bytes++;
|
||||||
td0 = *bytes++;
|
|
||||||
} else {
|
|
||||||
td0 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_writew(as, TDR, td0);
|
spi_writew(as, TDR, td0);
|
||||||
num_data--;
|
num_data--;
|
||||||
|
@ -750,24 +733,14 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||||
|
|
||||||
/* prepare the RX dma transfer */
|
/* prepare the RX dma transfer */
|
||||||
sg_init_table(&as->dma.sgrx, 1);
|
sg_init_table(&as->dma.sgrx, 1);
|
||||||
if (xfer->rx_buf) {
|
as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;
|
||||||
as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;
|
|
||||||
} else {
|
|
||||||
as->dma.sgrx.dma_address = as->buffer_dma;
|
|
||||||
if (len > BUFFER_SIZE)
|
|
||||||
len = BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare the TX dma transfer */
|
/* prepare the TX dma transfer */
|
||||||
sg_init_table(&as->dma.sgtx, 1);
|
sg_init_table(&as->dma.sgtx, 1);
|
||||||
if (xfer->tx_buf) {
|
as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen;
|
||||||
as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen;
|
|
||||||
} else {
|
if (len > master->max_dma_len)
|
||||||
as->dma.sgtx.dma_address = as->buffer_dma;
|
len = master->max_dma_len;
|
||||||
if (len > BUFFER_SIZE)
|
|
||||||
len = BUFFER_SIZE;
|
|
||||||
memset(as->buffer, 0, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
sg_dma_len(&as->dma.sgtx) = len;
|
sg_dma_len(&as->dma.sgtx) = len;
|
||||||
sg_dma_len(&as->dma.sgrx) = len;
|
sg_dma_len(&as->dma.sgrx) = len;
|
||||||
|
@ -834,25 +807,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
|
||||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||||
u32 len = *plen;
|
u32 len = *plen;
|
||||||
|
|
||||||
/* use scratch buffer only when rx or tx data is unspecified */
|
*rx_dma = xfer->rx_dma + xfer->len - *plen;
|
||||||
if (xfer->rx_buf)
|
*tx_dma = xfer->tx_dma + xfer->len - *plen;
|
||||||
*rx_dma = xfer->rx_dma + xfer->len - *plen;
|
if (len > master->max_dma_len)
|
||||||
else {
|
len = master->max_dma_len;
|
||||||
*rx_dma = as->buffer_dma;
|
|
||||||
if (len > BUFFER_SIZE)
|
|
||||||
len = BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xfer->tx_buf)
|
|
||||||
*tx_dma = xfer->tx_dma + xfer->len - *plen;
|
|
||||||
else {
|
|
||||||
*tx_dma = as->buffer_dma;
|
|
||||||
if (len > BUFFER_SIZE)
|
|
||||||
len = BUFFER_SIZE;
|
|
||||||
memset(as->buffer, 0, len);
|
|
||||||
dma_sync_single_for_device(&as->pdev->dev,
|
|
||||||
as->buffer_dma, len, DMA_TO_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
*plen = len;
|
*plen = len;
|
||||||
}
|
}
|
||||||
|
@ -1026,16 +984,12 @@ atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer)
|
||||||
u16 *rxp16;
|
u16 *rxp16;
|
||||||
unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
|
unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
|
||||||
|
|
||||||
if (xfer->rx_buf) {
|
if (xfer->bits_per_word > 8) {
|
||||||
if (xfer->bits_per_word > 8) {
|
rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos);
|
||||||
rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos);
|
*rxp16 = spi_readl(as, RDR);
|
||||||
*rxp16 = spi_readl(as, RDR);
|
|
||||||
} else {
|
|
||||||
rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
|
|
||||||
*rxp = spi_readl(as, RDR);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
spi_readl(as, RDR);
|
rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
|
||||||
|
*rxp = spi_readl(as, RDR);
|
||||||
}
|
}
|
||||||
if (xfer->bits_per_word > 8) {
|
if (xfer->bits_per_word > 8) {
|
||||||
if (as->current_remaining_bytes > 2)
|
if (as->current_remaining_bytes > 2)
|
||||||
|
@ -1074,12 +1028,10 @@ atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer)
|
||||||
/* Read data */
|
/* Read data */
|
||||||
while (num_data) {
|
while (num_data) {
|
||||||
rd = spi_readl(as, RDR);
|
rd = spi_readl(as, RDR);
|
||||||
if (xfer->rx_buf) {
|
if (xfer->bits_per_word > 8)
|
||||||
if (xfer->bits_per_word > 8)
|
*words++ = rd;
|
||||||
*words++ = rd;
|
else
|
||||||
else
|
*bytes++ = rd;
|
||||||
*bytes++ = rd;
|
|
||||||
}
|
|
||||||
num_data--;
|
num_data--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1561,29 +1513,22 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
||||||
master->setup = atmel_spi_setup;
|
master->setup = atmel_spi_setup;
|
||||||
|
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
|
||||||
master->transfer_one_message = atmel_spi_transfer_one_message;
|
master->transfer_one_message = atmel_spi_transfer_one_message;
|
||||||
master->cleanup = atmel_spi_cleanup;
|
master->cleanup = atmel_spi_cleanup;
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
|
master->max_dma_len = SPI_MAX_DMA_XFER;
|
||||||
platform_set_drvdata(pdev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
as = spi_master_get_devdata(master);
|
as = spi_master_get_devdata(master);
|
||||||
|
|
||||||
/*
|
|
||||||
* Scratch buffer is used for throwaway rx and tx data.
|
|
||||||
* It's coherent to minimize dcache pollution.
|
|
||||||
*/
|
|
||||||
as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
|
|
||||||
&as->buffer_dma, GFP_KERNEL);
|
|
||||||
if (!as->buffer)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
spin_lock_init(&as->lock);
|
spin_lock_init(&as->lock);
|
||||||
|
|
||||||
as->pdev = pdev;
|
as->pdev = pdev;
|
||||||
as->regs = devm_ioremap_resource(&pdev->dev, regs);
|
as->regs = devm_ioremap_resource(&pdev->dev, regs);
|
||||||
if (IS_ERR(as->regs)) {
|
if (IS_ERR(as->regs)) {
|
||||||
ret = PTR_ERR(as->regs);
|
ret = PTR_ERR(as->regs);
|
||||||
goto out_free_buffer;
|
goto out_unmap_regs;
|
||||||
}
|
}
|
||||||
as->phybase = regs->start;
|
as->phybase = regs->start;
|
||||||
as->irq = irq;
|
as->irq = irq;
|
||||||
|
@ -1681,9 +1626,6 @@ out_free_dma:
|
||||||
clk_disable_unprepare(clk);
|
clk_disable_unprepare(clk);
|
||||||
out_free_irq:
|
out_free_irq:
|
||||||
out_unmap_regs:
|
out_unmap_regs:
|
||||||
out_free_buffer:
|
|
||||||
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
|
|
||||||
as->buffer_dma);
|
|
||||||
out_free:
|
out_free:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1708,9 +1650,6 @@ static int atmel_spi_remove(struct platform_device *pdev)
|
||||||
spi_readl(as, SR);
|
spi_readl(as, SR);
|
||||||
spin_unlock_irq(&as->lock);
|
spin_unlock_irq(&as->lock);
|
||||||
|
|
||||||
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
|
|
||||||
as->buffer_dma);
|
|
||||||
|
|
||||||
clk_disable_unprepare(as->clk);
|
clk_disable_unprepare(as->clk);
|
||||||
|
|
||||||
pm_runtime_put_noidle(&pdev->dev);
|
pm_runtime_put_noidle(&pdev->dev);
|
||||||
|
|
Loading…
Reference in New Issue