forked from Minki/linux
Merge remote-tracking branches 'spi/topic/ti-qspi' and 'spi/topic/xlp' into spi-next
This commit is contained in:
commit
282ec0ea65
@ -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
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user