1
0
Fork 0

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
Nicolas Ferre 2016-11-24 12:24:58 +01:00 committed by Mark Brown
parent ce24a513fb
commit 7910d9af00
1 changed files with 35 additions and 96 deletions

View File

@ -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);