Skip to content

Commit da6de6d

Browse files
committed
spi: qup: Allow scaling power domains and
Merge series from Stephan Gerhold <[email protected]>: Make it possible to scale performance states of the power domain and interconnect of the SPI QUP controller in relation to the selected SPI speed / core clock. This is done separately by: - Parsing the OPP table from the device tree for performance state votes of the power domain - Voting for the necessary bandwidth on the interconnect path to DRAM
2 parents 8a77107 + ecdaa94 commit da6de6d

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

Documentation/devicetree/bindings/spi/qcom,spi-qup.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,17 @@ properties:
4444
- const: tx
4545
- const: rx
4646

47+
interconnects:
48+
maxItems: 1
49+
4750
interrupts:
4851
maxItems: 1
4952

53+
operating-points-v2: true
54+
55+
power-domains:
56+
maxItems: 1
57+
5058
reg:
5159
maxItems: 1
5260

@@ -62,7 +70,9 @@ unevaluatedProperties: false
6270
examples:
6371
- |
6472
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
73+
#include <dt-bindings/interconnect/qcom,msm8996.h>
6574
#include <dt-bindings/interrupt-controller/arm-gic.h>
75+
#include <dt-bindings/power/qcom-rpmpd.h>
6676
6777
spi@7575000 {
6878
compatible = "qcom,spi-qup-v2.2.1";
@@ -76,6 +86,9 @@ examples:
7686
pinctrl-1 = <&blsp1_spi1_sleep>;
7787
dmas = <&blsp1_dma 12>, <&blsp1_dma 13>;
7888
dma-names = "tx", "rx";
89+
power-domains = <&rpmpd MSM8996_VDDCX>;
90+
operating-points-v2 = <&spi_opp_table>;
91+
interconnects = <&pnoc MASTER_BLSP_1 &bimc SLAVE_EBI_CH0>;
7992
#address-cells = <1>;
8093
#size-cells = <0>;
8194
};

drivers/spi/spi-qup.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
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>
1213
#include <linux/module.h>
1314
#include <linux/of.h>
1415
#include <linux/platform_device.h>
16+
#include <linux/pm_opp.h>
1517
#include <linux/pm_runtime.h>
1618
#include <linux/spi/spi.h>
1719
#include <linux/dmaengine.h>
@@ -121,11 +123,14 @@
121123
#define SPI_DELAY_THRESHOLD 1
122124
#define SPI_DELAY_RETRY 10
123125

126+
#define SPI_BUS_WIDTH 8
127+
124128
struct spi_qup {
125129
void __iomem *base;
126130
struct device *dev;
127131
struct clk *cclk; /* core clock */
128132
struct clk *iclk; /* interface clock */
133+
struct icc_path *icc_path; /* interconnect to RAM */
129134
int irq;
130135
spinlock_t lock;
131136

@@ -148,6 +153,8 @@ struct spi_qup {
148153
int mode;
149154
struct dma_slave_config rx_conf;
150155
struct dma_slave_config tx_conf;
156+
157+
u32 bw_speed_hz;
151158
};
152159

153160
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
@@ -180,6 +187,23 @@ static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
180187
return opstate & QUP_STATE_VALID;
181188
}
182189

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+
183207
static int spi_qup_set_state(struct spi_qup *controller, u32 state)
184208
{
185209
unsigned long loop;
@@ -450,6 +474,12 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
450474
struct scatterlist *tx_sgl, *rx_sgl;
451475
int ret;
452476

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+
453483
if (xfer->rx_buf)
454484
rx_done = spi_qup_dma_done;
455485
else if (xfer->tx_buf)
@@ -667,7 +697,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
667697
return -EIO;
668698
}
669699

670-
ret = clk_set_rate(controller->cclk, xfer->speed_hz);
700+
ret = dev_pm_opp_set_rate(controller->dev, xfer->speed_hz);
671701
if (ret) {
672702
dev_err(controller->dev, "fail to set frequency %d",
673703
xfer->speed_hz);
@@ -993,6 +1023,7 @@ static void spi_qup_set_cs(struct spi_device *spi, bool val)
9931023
static int spi_qup_probe(struct platform_device *pdev)
9941024
{
9951025
struct spi_controller *host;
1026+
struct icc_path *icc_path;
9961027
struct clk *iclk, *cclk;
9971028
struct spi_qup *controller;
9981029
struct resource *res;
@@ -1018,6 +1049,11 @@ static int spi_qup_probe(struct platform_device *pdev)
10181049
if (IS_ERR(iclk))
10191050
return PTR_ERR(iclk);
10201051

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+
10211057
/* This is optional parameter */
10221058
if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
10231059
max_freq = SPI_MAX_RATE;
@@ -1027,6 +1063,15 @@ static int spi_qup_probe(struct platform_device *pdev)
10271063
return -ENXIO;
10281064
}
10291065

1066+
ret = devm_pm_opp_set_clkname(dev, "core");
1067+
if (ret)
1068+
return ret;
1069+
1070+
/* OPP table is optional */
1071+
ret = devm_pm_opp_of_add_table(dev);
1072+
if (ret && ret != -ENODEV)
1073+
return dev_err_probe(dev, ret, "invalid OPP table\n");
1074+
10301075
host = spi_alloc_host(dev, sizeof(struct spi_qup));
10311076
if (!host) {
10321077
dev_err(dev, "cannot allocate host\n");
@@ -1060,6 +1105,7 @@ static int spi_qup_probe(struct platform_device *pdev)
10601105
controller->base = base;
10611106
controller->iclk = iclk;
10621107
controller->cclk = cclk;
1108+
controller->icc_path = icc_path;
10631109
controller->irq = irq;
10641110

10651111
ret = spi_qup_init_dma(host, res->start);
@@ -1180,6 +1226,7 @@ static int spi_qup_pm_suspend_runtime(struct device *device)
11801226
writel_relaxed(config, controller->base + QUP_CONFIG);
11811227

11821228
clk_disable_unprepare(controller->cclk);
1229+
spi_qup_vote_bw(controller, 0);
11831230
clk_disable_unprepare(controller->iclk);
11841231

11851232
return 0;
@@ -1231,6 +1278,7 @@ static int spi_qup_suspend(struct device *device)
12311278
return ret;
12321279

12331280
clk_disable_unprepare(controller->cclk);
1281+
spi_qup_vote_bw(controller, 0);
12341282
clk_disable_unprepare(controller->iclk);
12351283
return 0;
12361284
}

0 commit comments

Comments
 (0)