Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: qup: Allow scaling power domains and

Merge series from Stephan Gerhold <stephan.gerhold@kernkonzept.com>:

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

+62 -1
+13
Documentation/devicetree/bindings/spi/qcom,spi-qup.yaml
··· 44 44 - const: tx 45 45 - const: rx 46 46 47 + interconnects: 48 + maxItems: 1 49 + 47 50 interrupts: 51 + maxItems: 1 52 + 53 + operating-points-v2: true 54 + 55 + power-domains: 48 56 maxItems: 1 49 57 50 58 reg: ··· 70 62 examples: 71 63 - | 72 64 #include <dt-bindings/clock/qcom,gcc-msm8996.h> 65 + #include <dt-bindings/interconnect/qcom,msm8996.h> 73 66 #include <dt-bindings/interrupt-controller/arm-gic.h> 67 + #include <dt-bindings/power/qcom-rpmpd.h> 74 68 75 69 spi@7575000 { 76 70 compatible = "qcom,spi-qup-v2.2.1"; ··· 86 76 pinctrl-1 = <&blsp1_spi1_sleep>; 87 77 dmas = <&blsp1_dma 12>, <&blsp1_dma 13>; 88 78 dma-names = "tx", "rx"; 79 + power-domains = <&rpmpd MSM8996_VDDCX>; 80 + operating-points-v2 = <&spi_opp_table>; 81 + interconnects = <&pnoc MASTER_BLSP_1 &bimc SLAVE_EBI_CH0>; 89 82 #address-cells = <1>; 90 83 #size-cells = <0>; 91 84 };
+49 -1
drivers/spi/spi-qup.c
··· 6 6 #include <linux/clk.h> 7 7 #include <linux/delay.h> 8 8 #include <linux/err.h> 9 + #include <linux/interconnect.h> 9 10 #include <linux/interrupt.h> 10 11 #include <linux/io.h> 11 12 #include <linux/list.h> 12 13 #include <linux/module.h> 13 14 #include <linux/of.h> 14 15 #include <linux/platform_device.h> 16 + #include <linux/pm_opp.h> 15 17 #include <linux/pm_runtime.h> 16 18 #include <linux/spi/spi.h> 17 19 #include <linux/dmaengine.h> ··· 123 121 #define SPI_DELAY_THRESHOLD 1 124 122 #define SPI_DELAY_RETRY 10 125 123 124 + #define SPI_BUS_WIDTH 8 125 + 126 126 struct spi_qup { 127 127 void __iomem *base; 128 128 struct device *dev; 129 129 struct clk *cclk; /* core clock */ 130 130 struct clk *iclk; /* interface clock */ 131 + struct icc_path *icc_path; /* interconnect to RAM */ 131 132 int irq; 132 133 spinlock_t lock; 133 134 ··· 153 148 int mode; 154 149 struct dma_slave_config rx_conf; 155 150 struct dma_slave_config tx_conf; 151 + 152 + u32 bw_speed_hz; 156 153 }; 157 154 158 155 static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer); ··· 185 178 u32 opstate = readl_relaxed(controller->base + QUP_STATE); 186 179 187 180 return opstate & QUP_STATE_VALID; 181 + } 182 + 183 + static int spi_qup_vote_bw(struct spi_qup *controller, u32 speed_hz) 184 + { 185 + u32 needed_peak_bw; 186 + int ret; 187 + 188 + if (controller->bw_speed_hz == speed_hz) 189 + return 0; 190 + 191 + needed_peak_bw = Bps_to_icc(speed_hz * SPI_BUS_WIDTH); 192 + ret = icc_set_bw(controller->icc_path, 0, needed_peak_bw); 193 + if (ret) 194 + return ret; 195 + 196 + controller->bw_speed_hz = speed_hz; 197 + return 0; 188 198 } 189 199 190 200 static int spi_qup_set_state(struct spi_qup *controller, u32 state) ··· 474 450 struct scatterlist *tx_sgl, *rx_sgl; 475 451 int ret; 476 452 453 + ret = spi_qup_vote_bw(qup, xfer->speed_hz); 454 + if (ret) { 455 + dev_err(qup->dev, "fail to vote for ICC bandwidth: %d\n", ret); 456 + return -EIO; 457 + } 458 + 477 459 if (xfer->rx_buf) 478 460 rx_done = spi_qup_dma_done; 479 461 else if (xfer->tx_buf) ··· 697 667 return -EIO; 698 668 } 699 669 700 - ret = clk_set_rate(controller->cclk, xfer->speed_hz); 670 + ret = dev_pm_opp_set_rate(controller->dev, xfer->speed_hz); 701 671 if (ret) { 702 672 dev_err(controller->dev, "fail to set frequency %d", 703 673 xfer->speed_hz); ··· 1023 993 static int spi_qup_probe(struct platform_device *pdev) 1024 994 { 1025 995 struct spi_controller *host; 996 + struct icc_path *icc_path; 1026 997 struct clk *iclk, *cclk; 1027 998 struct spi_qup *controller; 1028 999 struct resource *res; ··· 1049 1018 if (IS_ERR(iclk)) 1050 1019 return PTR_ERR(iclk); 1051 1020 1021 + icc_path = devm_of_icc_get(dev, NULL); 1022 + if (IS_ERR(icc_path)) 1023 + return dev_err_probe(dev, PTR_ERR(icc_path), 1024 + "failed to get interconnect path\n"); 1025 + 1052 1026 /* This is optional parameter */ 1053 1027 if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq)) 1054 1028 max_freq = SPI_MAX_RATE; ··· 1062 1026 dev_err(dev, "invalid clock frequency %d\n", max_freq); 1063 1027 return -ENXIO; 1064 1028 } 1029 + 1030 + ret = devm_pm_opp_set_clkname(dev, "core"); 1031 + if (ret) 1032 + return ret; 1033 + 1034 + /* OPP table is optional */ 1035 + ret = devm_pm_opp_of_add_table(dev); 1036 + if (ret && ret != -ENODEV) 1037 + return dev_err_probe(dev, ret, "invalid OPP table\n"); 1065 1038 1066 1039 host = spi_alloc_host(dev, sizeof(struct spi_qup)); 1067 1040 if (!host) { ··· 1105 1060 controller->base = base; 1106 1061 controller->iclk = iclk; 1107 1062 controller->cclk = cclk; 1063 + controller->icc_path = icc_path; 1108 1064 controller->irq = irq; 1109 1065 1110 1066 ret = spi_qup_init_dma(host, res->start); ··· 1226 1180 writel_relaxed(config, controller->base + QUP_CONFIG); 1227 1181 1228 1182 clk_disable_unprepare(controller->cclk); 1183 + spi_qup_vote_bw(controller, 0); 1229 1184 clk_disable_unprepare(controller->iclk); 1230 1185 1231 1186 return 0; ··· 1278 1231 return ret; 1279 1232 1280 1233 clk_disable_unprepare(controller->cclk); 1234 + spi_qup_vote_bw(controller, 0); 1281 1235 clk_disable_unprepare(controller->iclk); 1282 1236 return 0; 1283 1237 }