1
0
Fork 0

Merge remote-tracking branches 'spi/topic/ti-qspi' and 'spi/topic/xlp' into spi-next

zero-colors
Mark Brown 2017-04-26 15:58:22 +01:00
commit 282ec0ea65
6 changed files with 68 additions and 12 deletions

View File

@ -169,6 +169,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
#ifdef CONFIG_ARM64 #ifdef CONFIG_ARM64
{ "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, { "APMC0D0F", APD_ADDR(xgene_i2c_desc) },
{ "BRCM900D", APD_ADDR(vulcan_spi_desc) }, { "BRCM900D", APD_ADDR(vulcan_spi_desc) },
{ "CAV900D", APD_ADDR(vulcan_spi_desc) },
#endif #endif
{ } { }
}; };

View File

@ -715,7 +715,7 @@ config SPI_XILINX
config SPI_XLP config SPI_XLP
tristate "Netlogic XLP SPI controller driver" tristate "Netlogic XLP SPI controller driver"
depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
help help
Enable support for the SPI controller on the Netlogic XLP SoCs. Enable support for the SPI controller on the Netlogic XLP SoCs.
Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX

View File

@ -33,6 +33,7 @@
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
@ -57,6 +58,8 @@ struct ti_qspi {
struct ti_qspi_regs ctx_reg; struct ti_qspi_regs ctx_reg;
dma_addr_t mmap_phys_base; dma_addr_t mmap_phys_base;
dma_addr_t rx_bb_dma_addr;
void *rx_bb_addr;
struct dma_chan *rx_chan; struct dma_chan *rx_chan;
u32 spi_max_frequency; u32 spi_max_frequency;
@ -126,6 +129,8 @@ struct ti_qspi {
#define QSPI_SETUP_ADDR_SHIFT 8 #define QSPI_SETUP_ADDR_SHIFT 8
#define QSPI_SETUP_DUMMY_SHIFT 10 #define QSPI_SETUP_DUMMY_SHIFT 10
#define QSPI_DMA_BUFFER_SIZE SZ_64K
static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
unsigned long reg) unsigned long reg)
{ {
@ -395,14 +400,12 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
dma_addr_t dma_src, size_t len) dma_addr_t dma_src, size_t len)
{ {
struct dma_chan *chan = qspi->rx_chan; struct dma_chan *chan = qspi->rx_chan;
struct dma_device *dma_dev = chan->device;
dma_cookie_t cookie; dma_cookie_t cookie;
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx;
int ret; int ret;
tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
len, flags);
if (!tx) { if (!tx) {
dev_err(qspi->dev, "device_prep_dma_memcpy error\n"); dev_err(qspi->dev, "device_prep_dma_memcpy error\n");
return -EIO; return -EIO;
@ -431,6 +434,35 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
return 0; return 0;
} }
static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi,
struct spi_flash_read_message *msg)
{
size_t readsize = msg->len;
void *to = msg->buf;
dma_addr_t dma_src = qspi->mmap_phys_base + msg->from;
int ret = 0;
/*
* Use bounce buffer as FS like jffs2, ubifs may pass
* buffers that does not belong to kernel lowmem region.
*/
while (readsize != 0) {
size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE,
readsize);
ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr,
dma_src, xfer_len);
if (ret != 0)
return ret;
memcpy(to, qspi->rx_bb_addr, xfer_len);
readsize -= xfer_len;
dma_src += xfer_len;
to += xfer_len;
}
return ret;
}
static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg, static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
loff_t from) loff_t from)
{ {
@ -498,6 +530,12 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi,
QSPI_SPI_SETUP_REG(spi->chip_select)); QSPI_SPI_SETUP_REG(spi->chip_select));
} }
static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi,
struct spi_flash_read_message *msg)
{
return virt_addr_valid(msg->buf);
}
static int ti_qspi_spi_flash_read(struct spi_device *spi, static int ti_qspi_spi_flash_read(struct spi_device *spi,
struct spi_flash_read_message *msg) struct spi_flash_read_message *msg)
{ {
@ -511,15 +549,12 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi,
ti_qspi_setup_mmap_read(spi, msg); ti_qspi_setup_mmap_read(spi, msg);
if (qspi->rx_chan) { if (qspi->rx_chan) {
if (msg->cur_msg_mapped) { if (msg->cur_msg_mapped)
ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from); ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from);
if (ret) else
goto err_unlock; ret = ti_qspi_dma_bounce_buffer(qspi, msg);
} else { if (ret)
dev_err(qspi->dev, "Invalid address for DMA\n");
ret = -EIO;
goto err_unlock; goto err_unlock;
}
} else { } else {
memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
} }
@ -725,6 +760,17 @@ static int ti_qspi_probe(struct platform_device *pdev)
ret = 0; ret = 0;
goto no_dma; goto no_dma;
} }
qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev,
QSPI_DMA_BUFFER_SIZE,
&qspi->rx_bb_dma_addr,
GFP_KERNEL | GFP_DMA);
if (!qspi->rx_bb_addr) {
dev_err(qspi->dev,
"dma_alloc_coherent failed, using PIO mode\n");
dma_release_channel(qspi->rx_chan);
goto no_dma;
}
master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma;
master->dma_rx = qspi->rx_chan; master->dma_rx = qspi->rx_chan;
init_completion(&qspi->transfer_complete); init_completion(&qspi->transfer_complete);
if (res_mmap) if (res_mmap)
@ -765,6 +811,10 @@ static int ti_qspi_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
if (qspi->rx_bb_addr)
dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE,
qspi->rx_bb_addr,
qspi->rx_bb_dma_addr);
if (qspi->rx_chan) if (qspi->rx_chan)
dma_release_channel(qspi->rx_chan); dma_release_channel(qspi->rx_chan);

View File

@ -442,6 +442,7 @@ static int xlp_spi_probe(struct platform_device *pdev)
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id xlp_spi_acpi_match[] = { static const struct acpi_device_id xlp_spi_acpi_match[] = {
{ "BRCM900D", 0 }, { "BRCM900D", 0 },
{ "CAV900D", 0 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match); MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match);

View File

@ -2854,7 +2854,7 @@ int spi_flash_read(struct spi_device *spi,
mutex_lock(&master->bus_lock_mutex); mutex_lock(&master->bus_lock_mutex);
mutex_lock(&master->io_mutex); mutex_lock(&master->io_mutex);
if (master->dma_rx) { if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) {
rx_dev = master->dma_rx->device->dev; rx_dev = master->dma_rx->device->dev;
ret = spi_map_buf(master, rx_dev, &msg->rx_sg, ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
msg->buf, msg->len, msg->buf, msg->len,

View File

@ -376,6 +376,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @unprepare_message: undo any work done by prepare_message(). * @unprepare_message: undo any work done by prepare_message().
* @spi_flash_read: to support spi-controller hardwares that provide * @spi_flash_read: to support spi-controller hardwares that provide
* accelerated interface to read from flash devices. * accelerated interface to read from flash devices.
* @spi_flash_can_dma: analogous to can_dma() interface, but for
* controllers implementing spi_flash_read.
* @flash_read_supported: spi device supports flash read * @flash_read_supported: spi device supports flash read
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
* number. Any individual value may be -ENOENT for CS lines that * number. Any individual value may be -ENOENT for CS lines that
@ -539,6 +541,8 @@ struct spi_master {
struct spi_message *message); struct spi_message *message);
int (*spi_flash_read)(struct spi_device *spi, int (*spi_flash_read)(struct spi_device *spi,
struct spi_flash_read_message *msg); struct spi_flash_read_message *msg);
bool (*spi_flash_can_dma)(struct spi_device *spi,
struct spi_flash_read_message *msg);
bool (*flash_read_supported)(struct spi_device *spi); bool (*flash_read_supported)(struct spi_device *spi);
/* /*