Skip to content

Commit ecdaa94

Browse files
stephan-ghbroonie
authored andcommitted
spi: qup: Vote for interconnect bandwidth to DRAM
When the SPI QUP controller is used together with a DMA engine it needs to vote for the interconnect path to the DRAM. Otherwise it may be unable to access the memory quickly enough. The requested peak bandwidth is dependent on the SPI core/bus clock so that the bandwidth scales together with the selected SPI speed. To avoid sending votes too often the bandwidth is always requested when a DMA transfer starts, but dropped only on runtime suspend. Runtime suspend should only happen if no transfer is active. After resumption we can defer the next vote until the first DMA transfer actually happens. Signed-off-by: Stephan Gerhold <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent d15befc commit ecdaa94

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

drivers/spi/spi-qup.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/clk.h>
77
#include <linux/delay.h>
88
#include <linux/err.h>
9+
#include <linux/interconnect.h>
910
#include <linux/interrupt.h>
1011
#include <linux/io.h>
1112
#include <linux/list.h>
@@ -122,11 +123,14 @@
122123
#define SPI_DELAY_THRESHOLD 1
123124
#define SPI_DELAY_RETRY 10
124125

126+
#define SPI_BUS_WIDTH 8
127+
125128
struct spi_qup {
126129
void __iomem *base;
127130
struct device *dev;
128131
struct clk *cclk; /* core clock */
129132
struct clk *iclk; /* interface clock */
133+
struct icc_path *icc_path; /* interconnect to RAM */
130134
int irq;
131135
spinlock_t lock;
132136

@@ -149,6 +153,8 @@ struct spi_qup {
149153
int mode;
150154
struct dma_slave_config rx_conf;
151155
struct dma_slave_config tx_conf;
156+
157+
u32 bw_speed_hz;
152158
};
153159

154160
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
@@ -181,6 +187,23 @@ static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
181187
return opstate & QUP_STATE_VALID;
182188
}
183189

190+
static int spi_qup_vote_bw(struct spi_qup *controller, u32 speed_hz)
191+
{
192+
u32 needed_peak_bw;
193+
int ret;
194+
195+
if (controller->bw_speed_hz == speed_hz)
196+
return 0;
197+
198+
needed_peak_bw = Bps_to_icc(speed_hz * SPI_BUS_WIDTH);
199+
ret = icc_set_bw(controller->icc_path, 0, needed_peak_bw);
200+
if (ret)
201+
return ret;
202+
203+
controller->bw_speed_hz = speed_hz;
204+
return 0;
205+
}
206+
184207
static int spi_qup_set_state(struct spi_qup *controller, u32 state)
185208
{
186209
unsigned long loop;
@@ -451,6 +474,12 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
451474
struct scatterlist *tx_sgl, *rx_sgl;
452475
int ret;
453476

477+
ret = spi_qup_vote_bw(qup, xfer->speed_hz);
478+
if (ret) {
479+
dev_err(qup->dev, "fail to vote for ICC bandwidth: %d\n", ret);
480+
return -EIO;
481+
}
482+
454483
if (xfer->rx_buf)
455484
rx_done = spi_qup_dma_done;
456485
else if (xfer->tx_buf)
@@ -994,6 +1023,7 @@ static void spi_qup_set_cs(struct spi_device *spi, bool val)
9941023
static int spi_qup_probe(struct platform_device *pdev)
9951024
{
9961025
struct spi_controller *host;
1026+
struct icc_path *icc_path;
9971027
struct clk *iclk, *cclk;
9981028
struct spi_qup *controller;
9991029
struct resource *res;
@@ -1019,6 +1049,11 @@ static int spi_qup_probe(struct platform_device *pdev)
10191049
if (IS_ERR(iclk))
10201050
return PTR_ERR(iclk);
10211051

1052+
icc_path = devm_of_icc_get(dev, NULL);
1053+
if (IS_ERR(icc_path))
1054+
return dev_err_probe(dev, PTR_ERR(icc_path),
1055+
"failed to get interconnect path\n");
1056+
10221057
/* This is optional parameter */
10231058
if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
10241059
max_freq = SPI_MAX_RATE;
@@ -1070,6 +1105,7 @@ static int spi_qup_probe(struct platform_device *pdev)
10701105
controller->base = base;
10711106
controller->iclk = iclk;
10721107
controller->cclk = cclk;
1108+
controller->icc_path = icc_path;
10731109
controller->irq = irq;
10741110

10751111
ret = spi_qup_init_dma(host, res->start);
@@ -1190,6 +1226,7 @@ static int spi_qup_pm_suspend_runtime(struct device *device)
11901226
writel_relaxed(config, controller->base + QUP_CONFIG);
11911227

11921228
clk_disable_unprepare(controller->cclk);
1229+
spi_qup_vote_bw(controller, 0);
11931230
clk_disable_unprepare(controller->iclk);
11941231

11951232
return 0;
@@ -1241,6 +1278,7 @@ static int spi_qup_suspend(struct device *device)
12411278
return ret;
12421279

12431280
clk_disable_unprepare(controller->cclk);
1281+
spi_qup_vote_bw(controller, 0);
12441282
clk_disable_unprepare(controller->iclk);
12451283
return 0;
12461284
}

0 commit comments

Comments
 (0)