Commit f89a6d8f authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Mark Brown

spi: dw-mid: move to use core SPI DMA mappings

SPI core has a comprehensive function set to map and unmap a message when it's
needed. This patch converts driver to use that advantage.
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 4d5ac1ed
...@@ -69,6 +69,7 @@ static int mid_spi_dma_init(struct dw_spi *dws) ...@@ -69,6 +69,7 @@ static int mid_spi_dma_init(struct dw_spi *dws)
rxs->hs_mode = LNW_DMA_HW_HS; rxs->hs_mode = LNW_DMA_HW_HS;
rxs->cfg_mode = LNW_DMA_PER_TO_MEM; rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
dws->rxchan->private = rxs; dws->rxchan->private = rxs;
dws->master->dma_rx = dws->rxchan;
/* 2. Init tx channel */ /* 2. Init tx channel */
dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws); dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
...@@ -78,6 +79,7 @@ static int mid_spi_dma_init(struct dw_spi *dws) ...@@ -78,6 +79,7 @@ static int mid_spi_dma_init(struct dw_spi *dws)
txs->hs_mode = LNW_DMA_HW_HS; txs->hs_mode = LNW_DMA_HW_HS;
txs->cfg_mode = LNW_DMA_MEM_TO_PER; txs->cfg_mode = LNW_DMA_MEM_TO_PER;
dws->txchan->private = txs; dws->txchan->private = txs;
dws->master->dma_tx = dws->txchan;
dws->dma_inited = 1; dws->dma_inited = 1;
return 0; return 0;
...@@ -116,6 +118,17 @@ static irqreturn_t dma_transfer(struct dw_spi *dws) ...@@ -116,6 +118,17 @@ static irqreturn_t dma_transfer(struct dw_spi *dws)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static bool mid_spi_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer)
{
struct dw_spi *dws = spi_master_get_devdata(master);
if (!dws->dma_inited)
return false;
return xfer->len > dws->fifo_len;
}
static enum dma_slave_buswidth convert_dma_width(u32 dma_width) { static enum dma_slave_buswidth convert_dma_width(u32 dma_width) {
if (dma_width == 1) if (dma_width == 1)
return DMA_SLAVE_BUSWIDTH_1_BYTE; return DMA_SLAVE_BUSWIDTH_1_BYTE;
...@@ -139,12 +152,13 @@ static void dw_spi_dma_tx_done(void *arg) ...@@ -139,12 +152,13 @@ static void dw_spi_dma_tx_done(void *arg)
spi_finalize_current_transfer(dws->master); spi_finalize_current_transfer(dws->master);
} }
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws) static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
struct spi_transfer *xfer)
{ {
struct dma_slave_config txconf; struct dma_slave_config txconf;
struct dma_async_tx_descriptor *txdesc; struct dma_async_tx_descriptor *txdesc;
if (!dws->tx_dma) if (!xfer->tx_buf)
return NULL; return NULL;
txconf.direction = DMA_MEM_TO_DEV; txconf.direction = DMA_MEM_TO_DEV;
...@@ -156,13 +170,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws) ...@@ -156,13 +170,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
dmaengine_slave_config(dws->txchan, &txconf); dmaengine_slave_config(dws->txchan, &txconf);
memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len;
txdesc = dmaengine_prep_slave_sg(dws->txchan, txdesc = dmaengine_prep_slave_sg(dws->txchan,
&dws->tx_sgl, xfer->tx_sg.sgl,
1, xfer->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc) if (!txdesc)
...@@ -188,12 +198,13 @@ static void dw_spi_dma_rx_done(void *arg) ...@@ -188,12 +198,13 @@ static void dw_spi_dma_rx_done(void *arg)
spi_finalize_current_transfer(dws->master); spi_finalize_current_transfer(dws->master);
} }
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws) static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
struct spi_transfer *xfer)
{ {
struct dma_slave_config rxconf; struct dma_slave_config rxconf;
struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *rxdesc;
if (!dws->rx_dma) if (!xfer->rx_buf)
return NULL; return NULL;
rxconf.direction = DMA_DEV_TO_MEM; rxconf.direction = DMA_DEV_TO_MEM;
...@@ -205,13 +216,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws) ...@@ -205,13 +216,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
dmaengine_slave_config(dws->rxchan, &rxconf); dmaengine_slave_config(dws->rxchan, &rxconf);
memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len;
rxdesc = dmaengine_prep_slave_sg(dws->rxchan, rxdesc = dmaengine_prep_slave_sg(dws->rxchan,
&dws->rx_sgl, xfer->rx_sg.sgl,
1, xfer->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!rxdesc) if (!rxdesc)
...@@ -223,16 +230,16 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws) ...@@ -223,16 +230,16 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
return rxdesc; return rxdesc;
} }
static int mid_spi_dma_setup(struct dw_spi *dws) static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
{ {
u16 dma_ctrl = 0; u16 dma_ctrl = 0;
dw_writew(dws, DW_SPI_DMARDLR, 0xf); dw_writew(dws, DW_SPI_DMARDLR, 0xf);
dw_writew(dws, DW_SPI_DMATDLR, 0x10); dw_writew(dws, DW_SPI_DMATDLR, 0x10);
if (dws->tx_dma) if (xfer->tx_buf)
dma_ctrl |= SPI_DMA_TDMAE; dma_ctrl |= SPI_DMA_TDMAE;
if (dws->rx_dma) if (xfer->rx_buf)
dma_ctrl |= SPI_DMA_RDMAE; dma_ctrl |= SPI_DMA_RDMAE;
dw_writew(dws, DW_SPI_DMACR, dma_ctrl); dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
...@@ -244,15 +251,15 @@ static int mid_spi_dma_setup(struct dw_spi *dws) ...@@ -244,15 +251,15 @@ static int mid_spi_dma_setup(struct dw_spi *dws)
return 0; return 0;
} }
static int mid_spi_dma_transfer(struct dw_spi *dws) static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
{ {
struct dma_async_tx_descriptor *txdesc, *rxdesc; struct dma_async_tx_descriptor *txdesc, *rxdesc;
/* Prepare the TX dma transfer */ /* Prepare the TX dma transfer */
txdesc = dw_spi_dma_prepare_tx(dws); txdesc = dw_spi_dma_prepare_tx(dws, xfer);
/* Prepare the RX dma transfer */ /* Prepare the RX dma transfer */
rxdesc = dw_spi_dma_prepare_rx(dws); rxdesc = dw_spi_dma_prepare_rx(dws, xfer);
/* rx must be started before tx due to spi instinct */ /* rx must be started before tx due to spi instinct */
if (rxdesc) { if (rxdesc) {
...@@ -286,6 +293,7 @@ static struct dw_spi_dma_ops mid_dma_ops = { ...@@ -286,6 +293,7 @@ static struct dw_spi_dma_ops mid_dma_ops = {
.dma_init = mid_spi_dma_init, .dma_init = mid_spi_dma_init,
.dma_exit = mid_spi_dma_exit, .dma_exit = mid_spi_dma_exit,
.dma_setup = mid_spi_dma_setup, .dma_setup = mid_spi_dma_setup,
.can_dma = mid_spi_can_dma,
.dma_transfer = mid_spi_dma_transfer, .dma_transfer = mid_spi_dma_transfer,
.dma_stop = mid_spi_dma_stop, .dma_stop = mid_spi_dma_stop,
}; };
......
...@@ -217,32 +217,6 @@ static void dw_reader(struct dw_spi *dws) ...@@ -217,32 +217,6 @@ static void dw_reader(struct dw_spi *dws)
} }
} }
/*
* Note: first step is the protocol driver prepares
* a dma-capable memory, and this func just need translate
* the virt addr to physical
*/
static int map_dma_buffers(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *transfer)
{
struct dw_spi *dws = spi_master_get_devdata(master);
struct chip_data *chip = spi_get_ctldata(spi);
if (!master->cur_msg->is_dma_mapped
|| !dws->dma_inited
|| !chip->enable_dma
|| !dws->dma_ops)
return 0;
if (transfer->tx_dma)
dws->tx_dma = transfer->tx_dma;
if (transfer->rx_dma)
dws->rx_dma = transfer->rx_dma;
return 1;
}
static void int_error_stop(struct dw_spi *dws, const char *msg) static void int_error_stop(struct dw_spi *dws, const char *msg)
{ {
spi_reset_chip(dws); spi_reset_chip(dws);
...@@ -322,11 +296,10 @@ static int dw_spi_transfer_one(struct spi_master *master, ...@@ -322,11 +296,10 @@ static int dw_spi_transfer_one(struct spi_master *master,
u32 cr0 = 0; u32 cr0 = 0;
int ret; int ret;
dws->dma_mapped = 0;
dws->n_bytes = chip->n_bytes; dws->n_bytes = chip->n_bytes;
dws->dma_width = chip->dma_width; dws->dma_width = chip->dma_width;
dws->rx_dma = transfer->rx_dma;
dws->tx_dma = transfer->tx_dma;
dws->tx = (void *)transfer->tx_buf; dws->tx = (void *)transfer->tx_buf;
dws->tx_end = dws->tx + transfer->len; dws->tx_end = dws->tx + transfer->len;
dws->rx = transfer->rx_buf; dws->rx = transfer->rx_buf;
...@@ -386,7 +359,8 @@ static int dw_spi_transfer_one(struct spi_master *master, ...@@ -386,7 +359,8 @@ static int dw_spi_transfer_one(struct spi_master *master,
dw_writew(dws, DW_SPI_CTRL0, cr0); dw_writew(dws, DW_SPI_CTRL0, cr0);
/* Check if current transfer is a DMA transaction */ /* Check if current transfer is a DMA transaction */
dws->dma_mapped = map_dma_buffers(master, spi, transfer); if (master->can_dma && master->can_dma(master, spi, transfer))
dws->dma_mapped = master->cur_msg_mapped;
/* For poll mode just disable all interrupts */ /* For poll mode just disable all interrupts */
spi_mask_intr(dws, 0xff); spi_mask_intr(dws, 0xff);
...@@ -396,7 +370,7 @@ static int dw_spi_transfer_one(struct spi_master *master, ...@@ -396,7 +370,7 @@ static int dw_spi_transfer_one(struct spi_master *master,
* we only need set the TXEI IRQ, as TX/RX always happen syncronizely * we only need set the TXEI IRQ, as TX/RX always happen syncronizely
*/ */
if (dws->dma_mapped) { if (dws->dma_mapped) {
ret = dws->dma_ops->dma_setup(dws); ret = dws->dma_ops->dma_setup(dws, transfer);
if (ret < 0) { if (ret < 0) {
spi_enable_chip(dws, 1); spi_enable_chip(dws, 1);
return ret; return ret;
...@@ -416,7 +390,7 @@ static int dw_spi_transfer_one(struct spi_master *master, ...@@ -416,7 +390,7 @@ static int dw_spi_transfer_one(struct spi_master *master,
spi_enable_chip(dws, 1); spi_enable_chip(dws, 1);
if (dws->dma_mapped) { if (dws->dma_mapped) {
ret = dws->dma_ops->dma_transfer(dws); ret = dws->dma_ops->dma_transfer(dws, transfer);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -470,8 +444,6 @@ static int dw_spi_setup(struct spi_device *spi) ...@@ -470,8 +444,6 @@ static int dw_spi_setup(struct spi_device *spi)
chip->rx_threshold = 0; chip->rx_threshold = 0;
chip->tx_threshold = 0; chip->tx_threshold = 0;
chip->enable_dma = chip_info->enable_dma;
} }
if (spi->bits_per_word == 8) { if (spi->bits_per_word == 8) {
...@@ -584,6 +556,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -584,6 +556,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (ret) { if (ret) {
dev_warn(dev, "DMA init failed\n"); dev_warn(dev, "DMA init failed\n");
dws->dma_inited = 0; dws->dma_inited = 0;
} else {
master->can_dma = dws->dma_ops->can_dma;
} }
} }
......
...@@ -91,8 +91,10 @@ struct dw_spi; ...@@ -91,8 +91,10 @@ struct dw_spi;
struct dw_spi_dma_ops { struct dw_spi_dma_ops {
int (*dma_init)(struct dw_spi *dws); int (*dma_init)(struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws); void (*dma_exit)(struct dw_spi *dws);
int (*dma_setup)(struct dw_spi *dws); int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws); bool (*can_dma)(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
void (*dma_stop)(struct dw_spi *dws); void (*dma_stop)(struct dw_spi *dws);
}; };
...@@ -117,20 +119,14 @@ struct dw_spi { ...@@ -117,20 +119,14 @@ struct dw_spi {
void *rx; void *rx;
void *rx_end; void *rx_end;
int dma_mapped; int dma_mapped;
dma_addr_t rx_dma;
dma_addr_t tx_dma;
size_t rx_map_len;
size_t tx_map_len;
u8 n_bytes; /* current is a 1/2 bytes op */ u8 n_bytes; /* current is a 1/2 bytes op */
u32 dma_width; u32 dma_width;
irqreturn_t (*transfer_handler)(struct dw_spi *dws); irqreturn_t (*transfer_handler)(struct dw_spi *dws);
/* Dma info */ /* DMA info */
int dma_inited; int dma_inited;
struct dma_chan *txchan; struct dma_chan *txchan;
struct scatterlist tx_sgl;
struct dma_chan *rxchan; struct dma_chan *rxchan;
struct scatterlist rx_sgl;
unsigned long dma_chan_busy; unsigned long dma_chan_busy;
struct device *dma_dev; struct device *dma_dev;
dma_addr_t dma_addr; /* phy address of the Data register */ dma_addr_t dma_addr; /* phy address of the Data register */
...@@ -206,14 +202,13 @@ static inline void spi_reset_chip(struct dw_spi *dws) ...@@ -206,14 +202,13 @@ static inline void spi_reset_chip(struct dw_spi *dws)
/* /*
* Each SPI slave device to work with dw_api controller should * Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (PIO/DMA etc), * has such a structure claiming its working mode (poll or PIO/DMA),
* which can be save in the "controller_data" member of the * which can be save in the "controller_data" member of the
* struct spi_device. * struct spi_device.
*/ */
struct dw_spi_chip { struct dw_spi_chip {
u8 poll_mode; /* 1 for controller polling mode */ u8 poll_mode; /* 1 for controller polling mode */
u8 type; /* SPI/SSP/MicroWire */ u8 type; /* SPI/SSP/MicroWire */
u8 enable_dma;
void (*cs_control)(u32 command); void (*cs_control)(u32 command);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment