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

Merge tag 'qcom-drivers-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers

Qualcomm driver updates for v5.16

This drops the use of power-domains for exposing the load_state from the
QMP driver to clients, to avoid issues related to system suspend.

SMP2P becomes wakeup capable, to allow dying remoteprocs to wake up
Linux from suspend to perform recovery.

It adds RPM power-domain support for SM6350 and MSM8953 and base RPM
support for MSM8953 and QCM2290.

It adds support for MSM8996, SDM630 and SDM660 in the SPM driver, which
will enable the introduction of proper voltage scaling of the CPU
subsystem.

Support for releasing secondary CPUs on MSM8226 is introduced.

The Asynchronous Packet Router (APR) driver is extended to support the
new Generic Packet Router (GPR) variant, which is used to communicate
with the firmware in the new AudioReach audio driver.

Lastly it transitions a number of drivers to safer string functions, as
well as switching things to use devm_platform_ioremap_resource().

* tag 'qcom-drivers-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (40 commits)
soc: qcom: apr: Add GPR support
soc: dt-bindings: qcom: add gpr bindings
soc: qcom: apr: make code more reuseable
soc: dt-bindings: qcom: apr: deprecate qcom,apr-domain property
soc: dt-bindings: qcom: apr: convert to yaml
dt-bindings: soc: qcom: aoss: Delete unused power-domain definitions
dt-bindings: msm/dp: Remove aoss-qmp header
soc: qcom: aoss: Drop power domain support
dt-bindings: soc: qcom: aoss: Drop the load state power-domain
soc: qcom: smp2p: Add wakeup capability to SMP2P IRQ
dt-bindings: power: rpmpd: Add SM6350 to rpmpd binding
dt-bindings: soc: qcom: aoss: Add SM6350 compatible
soc: qcom: llcc: Disable MMUHWT retention
soc: qcom: smd-rpm: Add QCM2290 compatible
dt-bindings: soc: qcom: smd-rpm: Add QCM2290 compatible
firmware: qcom_scm: Add compatible for MSM8953 SoC
dt-bindings: firmware: qcom-scm: Document msm8953 bindings
soc: qcom: pdr: Prefer strscpy over strcpy
soc: qcom: rpmh-rsc: Make use of the helper function devm_platform_ioremap_resource_byname()
soc: qcom: gsbi: Make use of the helper function devm_platform_ioremap_resource()
...

Link: https://lore.kernel.org/r/20211012173442.1017010-1-bjorn.andersson@linaro.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+1263 -602
+2 -1
Documentation/devicetree/bindings/arm/cpus.yaml
··· 209 209 - qcom,gcc-msm8660 210 210 - qcom,kpss-acc-v1 211 211 - qcom,kpss-acc-v2 212 + - qcom,msm8226-smp 212 213 - renesas,apmu 213 214 - renesas,r9a06g032-smp 214 215 - rockchip,rk3036-smp ··· 294 293 Specifies the ACC* node associated with this CPU. 295 294 296 295 Required for systems that have an "enable-method" property 297 - value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2" 296 + value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2" or "qcom,msm8226-smp" 298 297 299 298 * arm/msm/qcom,kpss-acc.txt 300 299
-1
Documentation/devicetree/bindings/display/msm/dp-controller.yaml
··· 95 95 - | 96 96 #include <dt-bindings/interrupt-controller/arm-gic.h> 97 97 #include <dt-bindings/clock/qcom,dispcc-sc7180.h> 98 - #include <dt-bindings/power/qcom-aoss-qmp.h> 99 98 #include <dt-bindings/power/qcom-rpmpd.h> 100 99 101 100 displayport-controller@ae90000 {
+3 -1
Documentation/devicetree/bindings/firmware/qcom,scm.txt
··· 13 13 * "qcom,scm-ipq806x" 14 14 * "qcom,scm-ipq8074" 15 15 * "qcom,scm-mdm9607" 16 + * "qcom,scm-msm8226" 16 17 * "qcom,scm-msm8660" 17 18 * "qcom,scm-msm8916" 19 + * "qcom,scm-msm8953" 18 20 * "qcom,scm-msm8960" 19 21 * "qcom,scm-msm8974" 20 22 * "qcom,scm-msm8994" ··· 35 33 * core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and 36 34 "qcom,scm-msm8960" 37 35 * core, iface and bus clocks required for "qcom,scm-apq8084", 38 - "qcom,scm-msm8916" and "qcom,scm-msm8974" 36 + "qcom,scm-msm8916", "qcom,scm-msm8953" and "qcom,scm-msm8974" 39 37 - clock-names: Must contain "core" for the core clock, "iface" for the interface 40 38 clock and "bus" for the bus clock per the requirements of the compatible. 41 39 - qcom,dload-mode: phandle to the TCSR hardware block and offset of the
+2
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
··· 19 19 - qcom,mdm9607-rpmpd 20 20 - qcom,msm8916-rpmpd 21 21 - qcom,msm8939-rpmpd 22 + - qcom,msm8953-rpmpd 22 23 - qcom,msm8976-rpmpd 23 24 - qcom,msm8994-rpmpd 24 25 - qcom,msm8996-rpmpd ··· 32 31 - qcom,sdm845-rpmhpd 33 32 - qcom,sdx55-rpmhpd 34 33 - qcom,sm6115-rpmpd 34 + - qcom,sm6350-rpmhpd 35 35 - qcom,sm8150-rpmhpd 36 36 - qcom,sm8250-rpmhpd 37 37 - qcom,sm8350-rpmhpd
+2 -10
Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
··· 19 19 20 20 The AOSS side channel exposes control over a set of resources, used to control 21 21 a set of debug related clocks and to affect the low power state of resources 22 - related to the secondary subsystems. These resources are exposed as a set of 23 - power-domains. 22 + related to the secondary subsystems. 24 23 25 24 properties: 26 25 compatible: ··· 29 30 - qcom,sc7280-aoss-qmp 30 31 - qcom,sc8180x-aoss-qmp 31 32 - qcom,sdm845-aoss-qmp 33 + - qcom,sm6350-aoss-qmp 32 34 - qcom,sm8150-aoss-qmp 33 35 - qcom,sm8250-aoss-qmp 34 36 - qcom,sm8350-aoss-qmp ··· 56 56 const: 0 57 57 description: 58 58 The single clock represents the QDSS clock. 59 - 60 - "#power-domain-cells": 61 - const: 1 62 - description: | 63 - The provided power-domains are: 64 - CDSP state (0), LPASS state (1), modem state (2), SLPI 65 - state (3), SPSS state (4) and Venus state (5). 66 59 67 60 required: 68 61 - compatible ··· 94 101 mboxes = <&apss_shared 0>; 95 102 96 103 #clock-cells = <0>; 97 - #power-domain-cells = <1>; 98 104 99 105 cx_cdev: cx { 100 106 #cooling-cells = <2>;
-134
Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt
··· 1 - Qualcomm APR (Asynchronous Packet Router) binding 2 - 3 - This binding describes the Qualcomm APR. APR is a IPC protocol for 4 - communication between Application processor and QDSP. APR is mainly 5 - used for audio/voice services on the QDSP. 6 - 7 - - compatible: 8 - Usage: required 9 - Value type: <stringlist> 10 - Definition: must be "qcom,apr-v<VERSION-NUMBER>", example "qcom,apr-v2" 11 - 12 - - qcom,apr-domain 13 - Usage: required 14 - Value type: <u32> 15 - Definition: Destination processor ID. 16 - Possible values are : 17 - 1 - APR simulator 18 - 2 - PC 19 - 3 - MODEM 20 - 4 - ADSP 21 - 5 - APPS 22 - 6 - MODEM2 23 - 7 - APPS2 24 - 25 - = APR SERVICES 26 - Each subnode of the APR node represents service tied to this apr. The name 27 - of the nodes are not important. The properties of these nodes are defined 28 - by the individual bindings for the specific service 29 - - All APR services MUST contain the following property: 30 - 31 - - reg 32 - Usage: required 33 - Value type: <u32> 34 - Definition: APR Service ID 35 - Possible values are : 36 - 3 - DSP Core Service 37 - 4 - Audio Front End Service. 38 - 5 - Voice Stream Manager Service. 39 - 6 - Voice processing manager. 40 - 7 - Audio Stream Manager Service. 41 - 8 - Audio Device Manager Service. 42 - 9 - Multimode voice manager. 43 - 10 - Core voice stream. 44 - 11 - Core voice processor. 45 - 12 - Ultrasound stream manager. 46 - 13 - Listen stream manager. 47 - 48 - - qcom,protection-domain 49 - Usage: optional 50 - Value type: <stringlist> 51 - Definition: Must list the protection domain service name and path 52 - that the particular apr service has a dependency on. 53 - Possible values are : 54 - "avs/audio", "msm/adsp/audio_pd". 55 - "kernel/elf_loader", "msm/modem/wlan_pd". 56 - "tms/servreg", "msm/adsp/audio_pd". 57 - "tms/servreg", "msm/modem/wlan_pd". 58 - "tms/servreg", "msm/slpi/sensor_pd". 59 - 60 - = EXAMPLE 61 - The following example represents a QDSP based sound card on a MSM8996 device 62 - which uses apr as communication between Apps and QDSP. 63 - 64 - apr { 65 - compatible = "qcom,apr-v2"; 66 - qcom,apr-domain = <APR_DOMAIN_ADSP>; 67 - 68 - apr-service@3 { 69 - compatible = "qcom,q6core"; 70 - reg = <APR_SVC_ADSP_CORE>; 71 - }; 72 - 73 - apr-service@4 { 74 - compatible = "qcom,q6afe"; 75 - reg = <APR_SVC_AFE>; 76 - 77 - dais { 78 - #sound-dai-cells = <1>; 79 - dai@1 { 80 - reg = <HDMI_RX>; 81 - }; 82 - }; 83 - }; 84 - 85 - apr-service@7 { 86 - compatible = "qcom,q6asm"; 87 - reg = <APR_SVC_ASM>; 88 - ... 89 - }; 90 - 91 - apr-service@8 { 92 - compatible = "qcom,q6adm"; 93 - reg = <APR_SVC_ADM>; 94 - ... 95 - }; 96 - }; 97 - 98 - = EXAMPLE 2 99 - The following example represents a QDSP based sound card with protection domain 100 - dependencies specified. Here some of the apr services are dependent on services 101 - running on protection domain hosted on ADSP/SLPI remote processors while others 102 - have no such dependency. 103 - 104 - apr { 105 - compatible = "qcom,apr-v2"; 106 - qcom,glink-channels = "apr_audio_svc"; 107 - qcom,apr-domain = <APR_DOMAIN_ADSP>; 108 - 109 - apr-service@3 { 110 - compatible = "qcom,q6core"; 111 - reg = <APR_SVC_ADSP_CORE>; 112 - }; 113 - 114 - q6afe: apr-service@4 { 115 - compatible = "qcom,q6afe"; 116 - reg = <APR_SVC_AFE>; 117 - qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 118 - ... 119 - }; 120 - 121 - q6asm: apr-service@7 { 122 - compatible = "qcom,q6asm"; 123 - reg = <APR_SVC_ASM>; 124 - qcom,protection-domain = "tms/servreg", "msm/slpi/sensor_pd"; 125 - ... 126 - }; 127 - 128 - q6adm: apr-service@8 { 129 - compatible = "qcom,q6adm"; 130 - reg = <APR_SVC_ADM>; 131 - qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 132 - ... 133 - }; 134 - };
+177
Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: "http://devicetree.org/schemas/soc/qcom/qcom,apr.yaml#" 5 + $schema: "http://devicetree.org/meta-schemas/core.yaml#" 6 + 7 + title: Qualcomm APR/GPR (Asynchronous/Generic Packet Router) binding 8 + 9 + maintainers: 10 + - Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 11 + 12 + description: | 13 + This binding describes the Qualcomm APR/GPR, APR/GPR is a IPC protocol for 14 + communication between Application processor and QDSP. APR/GPR is mainly 15 + used for audio/voice services on the QDSP. 16 + 17 + properties: 18 + compatible: 19 + enum: 20 + - qcom,apr-v2 21 + - qcom,gpr 22 + 23 + qcom,apr-domain: 24 + $ref: /schemas/types.yaml#/definitions/uint32 25 + enum: [1, 2, 3, 4, 5, 6, 7] 26 + description: 27 + Selects the processor domain for apr 28 + 1 = APR simulator 29 + 2 = PC Domain 30 + 3 = Modem Domain 31 + 4 = ADSP Domain 32 + 5 = Application processor Domain 33 + 6 = Modem2 Domain 34 + 7 = Application Processor2 Domain 35 + deprecated: true 36 + 37 + qcom,domain: 38 + $ref: /schemas/types.yaml#/definitions/uint32 39 + minimum: 1 40 + maximum: 7 41 + description: 42 + Selects the processor domain for apr 43 + 1 = APR simulator 44 + 2 = PC Domain 45 + 3 = Modem Domain 46 + 4 = ADSP Domain 47 + 5 = Application processor Domain 48 + 6 = Modem2 Domain 49 + 7 = Application Processor2 Domain 50 + Selects the processor domain for gpr 51 + 1 = Modem Domain 52 + 2 = Audio DSP Domain 53 + 3 = Application Processor Domain 54 + 55 + '#address-cells': 56 + const: 1 57 + 58 + '#size-cells': 59 + const: 0 60 + 61 + #APR/GPR Services 62 + patternProperties: 63 + "^service@[1-9a-d]$": 64 + type: object 65 + description: 66 + APR/GPR node's client devices use subnodes for desired static port services. 67 + 68 + properties: 69 + compatible: 70 + enum: 71 + - qcom,q6core 72 + - qcom,q6asm 73 + - qcom,q6afe 74 + - qcom,q6adm 75 + - qcom,q6apm 76 + - qcom,q6prm 77 + 78 + reg: 79 + minimum: 1 80 + maximum: 13 81 + description: 82 + APR Service ID 83 + 3 = DSP Core Service 84 + 4 = Audio Front End Service. 85 + 5 = Voice Stream Manager Service. 86 + 6 = Voice processing manager. 87 + 7 = Audio Stream Manager Service. 88 + 8 = Audio Device Manager Service. 89 + 9 = Multimode voice manager. 90 + 10 = Core voice stream. 91 + 11 = Core voice processor. 92 + 12 = Ultrasound stream manager. 93 + 13 = Listen stream manager. 94 + GPR Service ID 95 + 1 = Audio Process Manager Service 96 + 2 = Proxy Resource Manager Service. 97 + 3 = AMDB Service. 98 + 4 = Voice processing manager. 99 + 100 + qcom,protection-domain: 101 + $ref: /schemas/types.yaml#/definitions/string-array 102 + description: protection domain service name and path for apr service 103 + possible values are 104 + "avs/audio", "msm/adsp/audio_pd". 105 + "kernel/elf_loader", "msm/modem/wlan_pd". 106 + "tms/servreg", "msm/adsp/audio_pd". 107 + "tms/servreg", "msm/modem/wlan_pd". 108 + "tms/servreg", "msm/slpi/sensor_pd". 109 + 110 + '#address-cells': 111 + const: 1 112 + 113 + '#size-cells': 114 + const: 0 115 + 116 + patternProperties: 117 + "^.*@[0-9a-f]+$": 118 + type: object 119 + description: 120 + Service based devices like clock controllers or digital audio interfaces. 121 + 122 + additionalProperties: false 123 + 124 + required: 125 + - compatible 126 + - qcom,domain 127 + 128 + additionalProperties: false 129 + 130 + examples: 131 + - | 132 + #include <dt-bindings/soc/qcom,apr.h> 133 + apr { 134 + compatible = "qcom,apr-v2"; 135 + qcom,domain = <APR_DOMAIN_ADSP>; 136 + #address-cells = <1>; 137 + #size-cells = <0>; 138 + 139 + q6core: service@3 { 140 + compatible = "qcom,q6core"; 141 + reg = <APR_SVC_ADSP_CORE>; 142 + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 143 + }; 144 + 145 + q6afe: service@4 { 146 + compatible = "qcom,q6afe"; 147 + reg = <APR_SVC_AFE>; 148 + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 149 + }; 150 + 151 + q6asm: service@7 { 152 + compatible = "qcom,q6asm"; 153 + reg = <APR_SVC_ASM>; 154 + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 155 + }; 156 + 157 + q6adm: service@8 { 158 + compatible = "qcom,q6adm"; 159 + reg = <APR_SVC_ADM>; 160 + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 161 + }; 162 + }; 163 + 164 + - | 165 + #include <dt-bindings/soc/qcom,gpr.h> 166 + gpr { 167 + compatible = "qcom,gpr"; 168 + qcom,domain = <GPR_DOMAIN_ID_ADSP>; 169 + #address-cells = <1>; 170 + #size-cells = <0>; 171 + 172 + service@1 { 173 + compatible = "qcom,q6apm"; 174 + reg = <GPR_APM_MODULE_IID>; 175 + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; 176 + }; 177 + };
+3
Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
··· 34 34 - qcom,rpm-ipq6018 35 35 - qcom,rpm-msm8226 36 36 - qcom,rpm-msm8916 37 + - qcom,rpm-msm8953 37 38 - qcom,rpm-msm8974 38 39 - qcom,rpm-msm8976 39 40 - qcom,rpm-msm8996 ··· 42 41 - qcom,rpm-sdm660 43 42 - qcom,rpm-sm6115 44 43 - qcom,rpm-sm6125 44 + - qcom,rpm-qcm2290 45 45 - qcom,rpm-qcs404 46 46 47 47 qcom,smd-channels: ··· 59 57 - qcom,rpm-apq8084 60 58 - qcom,rpm-msm8916 61 59 - qcom,rpm-msm8974 60 + - qcom,rpm-msm8953 62 61 then: 63 62 required: 64 63 - qcom,smd-channels
+80
Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: "http://devicetree.org/schemas/soc/qcom/qcom,spm.yaml#" 5 + $schema: "http://devicetree.org/meta-schemas/core.yaml#" 6 + 7 + title: Qualcomm Subsystem Power Manager binding 8 + 9 + maintainers: 10 + - Andy Gross <agross@kernel.org> 11 + - Bjorn Andersson <bjorn.andersson@linaro.org> 12 + 13 + description: | 14 + This binding describes the Qualcomm Subsystem Power Manager, used to control 15 + the peripheral logic surrounding the application cores in Qualcomm platforms. 16 + 17 + properties: 18 + compatible: 19 + items: 20 + - enum: 21 + - qcom,sdm660-gold-saw2-v4.1-l2 22 + - qcom,sdm660-silver-saw2-v4.1-l2 23 + - qcom,msm8998-gold-saw2-v4.1-l2 24 + - qcom,msm8998-silver-saw2-v4.1-l2 25 + - qcom,msm8226-saw2-v2.1-cpu 26 + - qcom,msm8974-saw2-v2.1-cpu 27 + - qcom,apq8084-saw2-v2.1-cpu 28 + - qcom,apq8064-saw2-v1.1-cpu 29 + - const: qcom,saw2 30 + 31 + reg: 32 + description: Base address and size of the SPM register region 33 + maxItems: 1 34 + 35 + required: 36 + - compatible 37 + - reg 38 + 39 + additionalProperties: false 40 + 41 + examples: 42 + - | 43 + 44 + /* Example 1: SoC using SAW2 and kpss-acc-v2 CPUIdle */ 45 + cpus { 46 + #address-cells = <1>; 47 + #size-cells = <0>; 48 + 49 + cpu@0 { 50 + compatible = "qcom,kryo"; 51 + device_type = "cpu"; 52 + enable-method = "qcom,kpss-acc-v2"; 53 + qcom,saw = <&saw0>; 54 + reg = <0x0>; 55 + operating-points-v2 = <&cpu_opp_table>; 56 + }; 57 + }; 58 + 59 + saw0: power-manager@f9089000 { 60 + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; 61 + reg = <0xf9089000 0x1000>; 62 + }; 63 + 64 + - | 65 + 66 + /* 67 + * Example 2: New-gen multi cluster SoC using SAW only for L2; 68 + * This does not require any cpuidle driver, nor any cpu phandle. 69 + */ 70 + power-manager@17812000 { 71 + compatible = "qcom,msm8998-gold-saw2-v4.1-l2", "qcom,saw2"; 72 + reg = <0x17812000 0x1000>; 73 + }; 74 + 75 + power-manager@17912000 { 76 + compatible = "qcom,msm8998-silver-saw2-v4.1-l2", "qcom,saw2"; 77 + reg = <0x17912000 0x1000>; 78 + }; 79 + 80 + ...
+71
arch/arm/mach-qcom/platsmp.c
··· 29 29 #define COREPOR_RST BIT(5) 30 30 #define CORE_RST BIT(4) 31 31 #define L2DT_SLP BIT(3) 32 + #define CORE_MEM_CLAMP BIT(1) 32 33 #define CLAMP BIT(0) 33 34 34 35 #define APC_PWR_GATE_CTL 0x14 ··· 74 73 iounmap(base); 75 74 76 75 return 0; 76 + } 77 + 78 + static int cortex_a7_release_secondary(unsigned int cpu) 79 + { 80 + int ret = 0; 81 + void __iomem *reg; 82 + struct device_node *cpu_node, *acc_node; 83 + u32 reg_val; 84 + 85 + cpu_node = of_get_cpu_node(cpu, NULL); 86 + if (!cpu_node) 87 + return -ENODEV; 88 + 89 + acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0); 90 + if (!acc_node) { 91 + ret = -ENODEV; 92 + goto out_acc; 93 + } 94 + 95 + reg = of_iomap(acc_node, 0); 96 + if (!reg) { 97 + ret = -ENOMEM; 98 + goto out_acc_map; 99 + } 100 + 101 + /* Put the CPU into reset. */ 102 + reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP; 103 + writel(reg_val, reg + APCS_CPU_PWR_CTL); 104 + 105 + /* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */ 106 + writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL); 107 + /* Wait for the BHS to settle */ 108 + udelay(2); 109 + 110 + reg_val &= ~CORE_MEM_CLAMP; 111 + writel(reg_val, reg + APCS_CPU_PWR_CTL); 112 + reg_val |= L2DT_SLP; 113 + writel(reg_val, reg + APCS_CPU_PWR_CTL); 114 + udelay(2); 115 + 116 + reg_val = (reg_val | BIT(17)) & ~CLAMP; 117 + writel(reg_val, reg + APCS_CPU_PWR_CTL); 118 + udelay(2); 119 + 120 + /* Release CPU out of reset and bring it to life. */ 121 + reg_val &= ~(CORE_RST | COREPOR_RST); 122 + writel(reg_val, reg + APCS_CPU_PWR_CTL); 123 + reg_val |= CORE_PWRD_UP; 124 + writel(reg_val, reg + APCS_CPU_PWR_CTL); 125 + 126 + iounmap(reg); 127 + out_acc_map: 128 + of_node_put(acc_node); 129 + out_acc: 130 + of_node_put(cpu_node); 131 + return ret; 77 132 } 78 133 79 134 static int kpssv1_release_secondary(unsigned int cpu) ··· 338 281 return qcom_boot_secondary(cpu, scss_release_secondary); 339 282 } 340 283 284 + static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle) 285 + { 286 + return qcom_boot_secondary(cpu, cortex_a7_release_secondary); 287 + } 288 + 341 289 static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle) 342 290 { 343 291 return qcom_boot_secondary(cpu, kpssv1_release_secondary); ··· 376 314 #endif 377 315 }; 378 316 CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops); 317 + 318 + static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = { 319 + .smp_prepare_cpus = qcom_smp_prepare_cpus, 320 + .smp_boot_secondary = cortex_a7_boot_secondary, 321 + #ifdef CONFIG_HOTPLUG_CPU 322 + .cpu_die = qcom_cpu_die, 323 + #endif 324 + }; 325 + CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops); 379 326 380 327 static const struct smp_operations qcom_smp_kpssv1_ops __initconst = { 381 328 .smp_prepare_cpus = qcom_smp_prepare_cpus,
+1
drivers/cpuidle/Kconfig.arm
··· 112 112 select CPU_IDLE_MULTIPLE_DRIVERS 113 113 select DT_IDLE_STATES 114 114 select QCOM_SCM 115 + select QCOM_SPM 115 116 help 116 117 Select this to enable cpuidle for Qualcomm processors. 117 118 The Subsystem Power Manager (SPM) controls low power modes for the
+72 -254
drivers/cpuidle/cpuidle-qcom-spm.c
··· 18 18 #include <linux/cpuidle.h> 19 19 #include <linux/cpu_pm.h> 20 20 #include <linux/qcom_scm.h> 21 + #include <soc/qcom/spm.h> 21 22 22 23 #include <asm/proc-fns.h> 23 24 #include <asm/suspend.h> 24 25 25 26 #include "dt_idle_states.h" 26 27 27 - #define MAX_PMIC_DATA 2 28 - #define MAX_SEQ_DATA 64 29 - #define SPM_CTL_INDEX 0x7f 30 - #define SPM_CTL_INDEX_SHIFT 4 31 - #define SPM_CTL_EN BIT(0) 32 - 33 - enum pm_sleep_mode { 34 - PM_SLEEP_MODE_STBY, 35 - PM_SLEEP_MODE_RET, 36 - PM_SLEEP_MODE_SPC, 37 - PM_SLEEP_MODE_PC, 38 - PM_SLEEP_MODE_NR, 39 - }; 40 - 41 - enum spm_reg { 42 - SPM_REG_CFG, 43 - SPM_REG_SPM_CTL, 44 - SPM_REG_DLY, 45 - SPM_REG_PMIC_DLY, 46 - SPM_REG_PMIC_DATA_0, 47 - SPM_REG_PMIC_DATA_1, 48 - SPM_REG_VCTL, 49 - SPM_REG_SEQ_ENTRY, 50 - SPM_REG_SPM_STS, 51 - SPM_REG_PMIC_STS, 52 - SPM_REG_NR, 53 - }; 54 - 55 - struct spm_reg_data { 56 - const u8 *reg_offset; 57 - u32 spm_cfg; 58 - u32 spm_dly; 59 - u32 pmic_dly; 60 - u32 pmic_data[MAX_PMIC_DATA]; 61 - u8 seq[MAX_SEQ_DATA]; 62 - u8 start_index[PM_SLEEP_MODE_NR]; 63 - }; 64 - 65 - struct spm_driver_data { 28 + struct cpuidle_qcom_spm_data { 66 29 struct cpuidle_driver cpuidle_driver; 67 - void __iomem *reg_base; 68 - const struct spm_reg_data *reg_data; 30 + struct spm_driver_data *spm; 69 31 }; 70 - 71 - static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = { 72 - [SPM_REG_CFG] = 0x08, 73 - [SPM_REG_SPM_CTL] = 0x30, 74 - [SPM_REG_DLY] = 0x34, 75 - [SPM_REG_SEQ_ENTRY] = 0x80, 76 - }; 77 - 78 - /* SPM register data for 8974, 8084 */ 79 - static const struct spm_reg_data spm_reg_8974_8084_cpu = { 80 - .reg_offset = spm_reg_offset_v2_1, 81 - .spm_cfg = 0x1, 82 - .spm_dly = 0x3C102800, 83 - .seq = { 0x03, 0x0B, 0x0F, 0x00, 0x20, 0x80, 0x10, 0xE8, 0x5B, 0x03, 84 - 0x3B, 0xE8, 0x5B, 0x82, 0x10, 0x0B, 0x30, 0x06, 0x26, 0x30, 85 - 0x0F }, 86 - .start_index[PM_SLEEP_MODE_STBY] = 0, 87 - .start_index[PM_SLEEP_MODE_SPC] = 3, 88 - }; 89 - 90 - /* SPM register data for 8226 */ 91 - static const struct spm_reg_data spm_reg_8226_cpu = { 92 - .reg_offset = spm_reg_offset_v2_1, 93 - .spm_cfg = 0x0, 94 - .spm_dly = 0x3C102800, 95 - .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90, 96 - 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B, 97 - 0x80, 0x10, 0x26, 0x30, 0x0F }, 98 - .start_index[PM_SLEEP_MODE_STBY] = 0, 99 - .start_index[PM_SLEEP_MODE_SPC] = 5, 100 - }; 101 - 102 - static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = { 103 - [SPM_REG_CFG] = 0x08, 104 - [SPM_REG_SPM_CTL] = 0x20, 105 - [SPM_REG_PMIC_DLY] = 0x24, 106 - [SPM_REG_PMIC_DATA_0] = 0x28, 107 - [SPM_REG_PMIC_DATA_1] = 0x2C, 108 - [SPM_REG_SEQ_ENTRY] = 0x80, 109 - }; 110 - 111 - /* SPM register data for 8064 */ 112 - static const struct spm_reg_data spm_reg_8064_cpu = { 113 - .reg_offset = spm_reg_offset_v1_1, 114 - .spm_cfg = 0x1F, 115 - .pmic_dly = 0x02020004, 116 - .pmic_data[0] = 0x0084009C, 117 - .pmic_data[1] = 0x00A4001C, 118 - .seq = { 0x03, 0x0F, 0x00, 0x24, 0x54, 0x10, 0x09, 0x03, 0x01, 119 - 0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F }, 120 - .start_index[PM_SLEEP_MODE_STBY] = 0, 121 - .start_index[PM_SLEEP_MODE_SPC] = 2, 122 - }; 123 - 124 - static inline void spm_register_write(struct spm_driver_data *drv, 125 - enum spm_reg reg, u32 val) 126 - { 127 - if (drv->reg_data->reg_offset[reg]) 128 - writel_relaxed(val, drv->reg_base + 129 - drv->reg_data->reg_offset[reg]); 130 - } 131 - 132 - /* Ensure a guaranteed write, before return */ 133 - static inline void spm_register_write_sync(struct spm_driver_data *drv, 134 - enum spm_reg reg, u32 val) 135 - { 136 - u32 ret; 137 - 138 - if (!drv->reg_data->reg_offset[reg]) 139 - return; 140 - 141 - do { 142 - writel_relaxed(val, drv->reg_base + 143 - drv->reg_data->reg_offset[reg]); 144 - ret = readl_relaxed(drv->reg_base + 145 - drv->reg_data->reg_offset[reg]); 146 - if (ret == val) 147 - break; 148 - cpu_relax(); 149 - } while (1); 150 - } 151 - 152 - static inline u32 spm_register_read(struct spm_driver_data *drv, 153 - enum spm_reg reg) 154 - { 155 - return readl_relaxed(drv->reg_base + drv->reg_data->reg_offset[reg]); 156 - } 157 - 158 - static void spm_set_low_power_mode(struct spm_driver_data *drv, 159 - enum pm_sleep_mode mode) 160 - { 161 - u32 start_index; 162 - u32 ctl_val; 163 - 164 - start_index = drv->reg_data->start_index[mode]; 165 - 166 - ctl_val = spm_register_read(drv, SPM_REG_SPM_CTL); 167 - ctl_val &= ~(SPM_CTL_INDEX << SPM_CTL_INDEX_SHIFT); 168 - ctl_val |= start_index << SPM_CTL_INDEX_SHIFT; 169 - ctl_val |= SPM_CTL_EN; 170 - spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val); 171 - } 172 32 173 33 static int qcom_pm_collapse(unsigned long int unused) 174 34 { ··· 61 201 static int spm_enter_idle_state(struct cpuidle_device *dev, 62 202 struct cpuidle_driver *drv, int idx) 63 203 { 64 - struct spm_driver_data *data = container_of(drv, struct spm_driver_data, 65 - cpuidle_driver); 204 + struct cpuidle_qcom_spm_data *data = container_of(drv, struct cpuidle_qcom_spm_data, 205 + cpuidle_driver); 66 206 67 - return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data); 207 + return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data->spm); 68 208 } 69 209 70 210 static struct cpuidle_driver qcom_spm_idle_driver = { ··· 85 225 { }, 86 226 }; 87 227 88 - static int spm_cpuidle_init(struct cpuidle_driver *drv, int cpu) 228 + static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu) 89 229 { 230 + struct platform_device *pdev = NULL; 231 + struct device_node *cpu_node, *saw_node; 232 + struct cpuidle_qcom_spm_data *data = NULL; 90 233 int ret; 91 234 92 - memcpy(drv, &qcom_spm_idle_driver, sizeof(*drv)); 93 - drv->cpumask = (struct cpumask *)cpumask_of(cpu); 235 + cpu_node = of_cpu_device_node_get(cpu); 236 + if (!cpu_node) 237 + return -ENODEV; 94 238 95 - /* Parse idle states from device tree */ 96 - ret = dt_init_idle_driver(drv, qcom_idle_state_match, 1); 239 + saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); 240 + if (!saw_node) 241 + return -ENODEV; 242 + 243 + pdev = of_find_device_by_node(saw_node); 244 + of_node_put(saw_node); 245 + of_node_put(cpu_node); 246 + if (!pdev) 247 + return -ENODEV; 248 + 249 + data = devm_kzalloc(cpuidle_dev, sizeof(*data), GFP_KERNEL); 250 + if (!data) 251 + return -ENOMEM; 252 + 253 + data->spm = dev_get_drvdata(&pdev->dev); 254 + if (!data->spm) 255 + return -EINVAL; 256 + 257 + data->cpuidle_driver = qcom_spm_idle_driver; 258 + data->cpuidle_driver.cpumask = (struct cpumask *)cpumask_of(cpu); 259 + 260 + ret = dt_init_idle_driver(&data->cpuidle_driver, 261 + qcom_idle_state_match, 1); 97 262 if (ret <= 0) 98 263 return ret ? : -ENODEV; 99 264 100 - /* We have atleast one power down mode */ 101 - return qcom_scm_set_warm_boot_addr(cpu_resume_arm, drv->cpumask); 265 + ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm, cpumask_of(cpu)); 266 + if (ret) 267 + return ret; 268 + 269 + return cpuidle_register(&data->cpuidle_driver, NULL); 102 270 } 103 271 104 - static struct spm_driver_data *spm_get_drv(struct platform_device *pdev, 105 - int *spm_cpu) 272 + static int spm_cpuidle_drv_probe(struct platform_device *pdev) 106 273 { 107 - struct spm_driver_data *drv = NULL; 108 - struct device_node *cpu_node, *saw_node; 109 - int cpu; 110 - bool found = 0; 111 - 112 - for_each_possible_cpu(cpu) { 113 - cpu_node = of_cpu_device_node_get(cpu); 114 - if (!cpu_node) 115 - continue; 116 - saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); 117 - found = (saw_node == pdev->dev.of_node); 118 - of_node_put(saw_node); 119 - of_node_put(cpu_node); 120 - if (found) 121 - break; 122 - } 123 - 124 - if (found) { 125 - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); 126 - if (drv) 127 - *spm_cpu = cpu; 128 - } 129 - 130 - return drv; 131 - } 132 - 133 - static const struct of_device_id spm_match_table[] = { 134 - { .compatible = "qcom,msm8226-saw2-v2.1-cpu", 135 - .data = &spm_reg_8226_cpu }, 136 - { .compatible = "qcom,msm8974-saw2-v2.1-cpu", 137 - .data = &spm_reg_8974_8084_cpu }, 138 - { .compatible = "qcom,apq8084-saw2-v2.1-cpu", 139 - .data = &spm_reg_8974_8084_cpu }, 140 - { .compatible = "qcom,apq8064-saw2-v1.1-cpu", 141 - .data = &spm_reg_8064_cpu }, 142 - { }, 143 - }; 144 - 145 - static int spm_dev_probe(struct platform_device *pdev) 146 - { 147 - struct spm_driver_data *drv; 148 - struct resource *res; 149 - const struct of_device_id *match_id; 150 - void __iomem *addr; 151 274 int cpu, ret; 152 275 153 276 if (!qcom_scm_is_available()) 154 277 return -EPROBE_DEFER; 155 278 156 - drv = spm_get_drv(pdev, &cpu); 157 - if (!drv) 158 - return -EINVAL; 159 - platform_set_drvdata(pdev, drv); 279 + for_each_possible_cpu(cpu) { 280 + ret = spm_cpuidle_register(&pdev->dev, cpu); 281 + if (ret && ret != -ENODEV) { 282 + dev_err(&pdev->dev, 283 + "Cannot register for CPU%d: %d\n", cpu, ret); 284 + } 285 + } 160 286 161 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 162 - drv->reg_base = devm_ioremap_resource(&pdev->dev, res); 163 - if (IS_ERR(drv->reg_base)) 164 - return PTR_ERR(drv->reg_base); 165 - 166 - match_id = of_match_node(spm_match_table, pdev->dev.of_node); 167 - if (!match_id) 168 - return -ENODEV; 169 - 170 - drv->reg_data = match_id->data; 171 - 172 - ret = spm_cpuidle_init(&drv->cpuidle_driver, cpu); 173 - if (ret) 174 - return ret; 175 - 176 - /* Write the SPM sequences first.. */ 177 - addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY]; 178 - __iowrite32_copy(addr, drv->reg_data->seq, 179 - ARRAY_SIZE(drv->reg_data->seq) / 4); 180 - 181 - /* 182 - * ..and then the control registers. 183 - * On some SoC if the control registers are written first and if the 184 - * CPU was held in reset, the reset signal could trigger the SPM state 185 - * machine, before the sequences are completely written. 186 - */ 187 - spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg); 188 - spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly); 189 - spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly); 190 - spm_register_write(drv, SPM_REG_PMIC_DATA_0, 191 - drv->reg_data->pmic_data[0]); 192 - spm_register_write(drv, SPM_REG_PMIC_DATA_1, 193 - drv->reg_data->pmic_data[1]); 194 - 195 - /* Set up Standby as the default low power mode */ 196 - spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); 197 - 198 - return cpuidle_register(&drv->cpuidle_driver, NULL); 199 - } 200 - 201 - static int spm_dev_remove(struct platform_device *pdev) 202 - { 203 - struct spm_driver_data *drv = platform_get_drvdata(pdev); 204 - 205 - cpuidle_unregister(&drv->cpuidle_driver); 206 287 return 0; 207 288 } 208 289 209 - static struct platform_driver spm_driver = { 210 - .probe = spm_dev_probe, 211 - .remove = spm_dev_remove, 290 + static struct platform_driver spm_cpuidle_driver = { 291 + .probe = spm_cpuidle_drv_probe, 212 292 .driver = { 213 - .name = "saw", 214 - .of_match_table = spm_match_table, 293 + .name = "qcom-spm-cpuidle", 294 + .suppress_bind_attrs = true, 215 295 }, 216 296 }; 217 297 218 - builtin_platform_driver(spm_driver); 298 + static int __init qcom_spm_cpuidle_init(void) 299 + { 300 + struct platform_device *pdev; 301 + int ret; 302 + 303 + ret = platform_driver_register(&spm_cpuidle_driver); 304 + if (ret) 305 + return ret; 306 + 307 + pdev = platform_device_register_simple("qcom-spm-cpuidle", 308 + -1, NULL, 0); 309 + if (IS_ERR(pdev)) { 310 + platform_driver_unregister(&spm_cpuidle_driver); 311 + return PTR_ERR(pdev); 312 + } 313 + 314 + return 0; 315 + } 316 + device_initcall(qcom_spm_cpuidle_init);
+4
drivers/firmware/qcom_scm.c
··· 1348 1348 SCM_HAS_IFACE_CLK | 1349 1349 SCM_HAS_BUS_CLK) 1350 1350 }, 1351 + { .compatible = "qcom,scm-msm8953", .data = (void *)(SCM_HAS_CORE_CLK | 1352 + SCM_HAS_IFACE_CLK | 1353 + SCM_HAS_BUS_CLK) 1354 + }, 1351 1355 { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK | 1352 1356 SCM_HAS_IFACE_CLK | 1353 1357 SCM_HAS_BUS_CLK)
+10 -1
drivers/soc/qcom/Kconfig
··· 190 190 Say yes here to support the Qualcomm socinfo driver, providing 191 191 information about the SoC to user space. 192 192 193 + config QCOM_SPM 194 + tristate "Qualcomm Subsystem Power Manager (SPM)" 195 + depends on ARCH_QCOM 196 + select QCOM_SCM 197 + help 198 + Enable the support for the Qualcomm Subsystem Power Manager, used 199 + to manage cores, L2 low power modes and to configure the internal 200 + Adaptive Voltage Scaler parameters, where supported. 201 + 193 202 config QCOM_WCNSS_CTRL 194 203 tristate "Qualcomm WCNSS control driver" 195 204 depends on ARCH_QCOM || COMPILE_TEST ··· 208 199 firmware to a newly booted WCNSS chip. 209 200 210 201 config QCOM_APR 211 - tristate "Qualcomm APR Bus (Asynchronous Packet Router)" 202 + tristate "Qualcomm APR/GPR Bus (Asynchronous/Generic Packet Router)" 212 203 depends on ARCH_QCOM || COMPILE_TEST 213 204 depends on RPMSG 214 205 depends on NET
+1
drivers/soc/qcom/Makefile
··· 20 20 obj-$(CONFIG_QCOM_SMP2P) += smp2p.o 21 21 obj-$(CONFIG_QCOM_SMSM) += smsm.o 22 22 obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o 23 + obj-$(CONFIG_QCOM_SPM) += spm.o 23 24 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o 24 25 obj-$(CONFIG_QCOM_APR) += apr.o 25 26 obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
+235 -52
drivers/soc/qcom/apr.c
··· 15 15 #include <linux/rpmsg.h> 16 16 #include <linux/of.h> 17 17 18 - struct apr { 18 + enum { 19 + PR_TYPE_APR = 0, 20 + PR_TYPE_GPR, 21 + }; 22 + 23 + /* Some random values tbh which does not collide with static modules */ 24 + #define GPR_DYNAMIC_PORT_START 0x10000000 25 + #define GPR_DYNAMIC_PORT_END 0x20000000 26 + 27 + struct packet_router { 19 28 struct rpmsg_endpoint *ch; 20 29 struct device *dev; 21 30 spinlock_t svcs_lock; 22 31 spinlock_t rx_lock; 23 32 struct idr svcs_idr; 24 33 int dest_domain_id; 34 + int type; 25 35 struct pdr_handle *pdr; 26 36 struct workqueue_struct *rxwq; 27 37 struct work_struct rx_work; ··· 54 44 */ 55 45 int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt) 56 46 { 57 - struct apr *apr = dev_get_drvdata(adev->dev.parent); 47 + struct packet_router *apr = dev_get_drvdata(adev->dev.parent); 58 48 struct apr_hdr *hdr; 59 49 unsigned long flags; 60 50 int ret; 61 51 62 - spin_lock_irqsave(&adev->lock, flags); 52 + spin_lock_irqsave(&adev->svc.lock, flags); 63 53 64 54 hdr = &pkt->hdr; 65 55 hdr->src_domain = APR_DOMAIN_APPS; 66 - hdr->src_svc = adev->svc_id; 56 + hdr->src_svc = adev->svc.id; 67 57 hdr->dest_domain = adev->domain_id; 68 - hdr->dest_svc = adev->svc_id; 58 + hdr->dest_svc = adev->svc.id; 69 59 70 60 ret = rpmsg_trysend(apr->ch, pkt, hdr->pkt_size); 71 - spin_unlock_irqrestore(&adev->lock, flags); 61 + spin_unlock_irqrestore(&adev->svc.lock, flags); 72 62 73 63 return ret ? ret : hdr->pkt_size; 74 64 } 75 65 EXPORT_SYMBOL_GPL(apr_send_pkt); 66 + 67 + void gpr_free_port(gpr_port_t *port) 68 + { 69 + struct packet_router *gpr = port->pr; 70 + unsigned long flags; 71 + 72 + spin_lock_irqsave(&gpr->svcs_lock, flags); 73 + idr_remove(&gpr->svcs_idr, port->id); 74 + spin_unlock_irqrestore(&gpr->svcs_lock, flags); 75 + 76 + kfree(port); 77 + } 78 + EXPORT_SYMBOL_GPL(gpr_free_port); 79 + 80 + gpr_port_t *gpr_alloc_port(struct apr_device *gdev, struct device *dev, 81 + gpr_port_cb cb, void *priv) 82 + { 83 + struct packet_router *pr = dev_get_drvdata(gdev->dev.parent); 84 + gpr_port_t *port; 85 + struct pkt_router_svc *svc; 86 + int id; 87 + 88 + port = kzalloc(sizeof(*port), GFP_KERNEL); 89 + if (!port) 90 + return ERR_PTR(-ENOMEM); 91 + 92 + svc = port; 93 + svc->callback = cb; 94 + svc->pr = pr; 95 + svc->priv = priv; 96 + svc->dev = dev; 97 + spin_lock_init(&svc->lock); 98 + 99 + spin_lock(&pr->svcs_lock); 100 + id = idr_alloc_cyclic(&pr->svcs_idr, svc, GPR_DYNAMIC_PORT_START, 101 + GPR_DYNAMIC_PORT_END, GFP_ATOMIC); 102 + if (id < 0) { 103 + dev_err(dev, "Unable to allocate dynamic GPR src port\n"); 104 + kfree(port); 105 + spin_unlock(&pr->svcs_lock); 106 + return ERR_PTR(id); 107 + } 108 + 109 + svc->id = id; 110 + spin_unlock(&pr->svcs_lock); 111 + 112 + return port; 113 + } 114 + EXPORT_SYMBOL_GPL(gpr_alloc_port); 115 + 116 + static int pkt_router_send_svc_pkt(struct pkt_router_svc *svc, struct gpr_pkt *pkt) 117 + { 118 + struct packet_router *pr = svc->pr; 119 + struct gpr_hdr *hdr; 120 + unsigned long flags; 121 + int ret; 122 + 123 + hdr = &pkt->hdr; 124 + 125 + spin_lock_irqsave(&svc->lock, flags); 126 + ret = rpmsg_trysend(pr->ch, pkt, hdr->pkt_size); 127 + spin_unlock_irqrestore(&svc->lock, flags); 128 + 129 + return ret ? ret : hdr->pkt_size; 130 + } 131 + 132 + int gpr_send_pkt(struct apr_device *gdev, struct gpr_pkt *pkt) 133 + { 134 + return pkt_router_send_svc_pkt(&gdev->svc, pkt); 135 + } 136 + EXPORT_SYMBOL_GPL(gpr_send_pkt); 137 + 138 + int gpr_send_port_pkt(gpr_port_t *port, struct gpr_pkt *pkt) 139 + { 140 + return pkt_router_send_svc_pkt(port, pkt); 141 + } 142 + EXPORT_SYMBOL_GPL(gpr_send_port_pkt); 76 143 77 144 static void apr_dev_release(struct device *dev) 78 145 { ··· 161 74 static int apr_callback(struct rpmsg_device *rpdev, void *buf, 162 75 int len, void *priv, u32 addr) 163 76 { 164 - struct apr *apr = dev_get_drvdata(&rpdev->dev); 77 + struct packet_router *apr = dev_get_drvdata(&rpdev->dev); 165 78 struct apr_rx_buf *abuf; 166 79 unsigned long flags; 167 80 ··· 187 100 return 0; 188 101 } 189 102 190 - 191 - static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf) 103 + static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf) 192 104 { 193 105 uint16_t hdr_size, msg_type, ver, svc_id; 194 - struct apr_device *svc = NULL; 106 + struct pkt_router_svc *svc; 107 + struct apr_device *adev; 195 108 struct apr_driver *adrv = NULL; 196 109 struct apr_resp_pkt resp; 197 110 struct apr_hdr *hdr; ··· 232 145 svc_id = hdr->dest_svc; 233 146 spin_lock_irqsave(&apr->svcs_lock, flags); 234 147 svc = idr_find(&apr->svcs_idr, svc_id); 235 - if (svc && svc->dev.driver) 236 - adrv = to_apr_driver(svc->dev.driver); 148 + if (svc && svc->dev->driver) { 149 + adev = svc_to_apr_device(svc); 150 + adrv = to_apr_driver(adev->dev.driver); 151 + } 237 152 spin_unlock_irqrestore(&apr->svcs_lock, flags); 238 153 239 - if (!adrv) { 240 - dev_err(apr->dev, "APR: service is not registered\n"); 154 + if (!adrv || !adev) { 155 + dev_err(apr->dev, "APR: service is not registered (%d)\n", 156 + svc_id); 241 157 return -EINVAL; 242 158 } 243 159 ··· 254 164 if (resp.payload_size > 0) 255 165 resp.payload = buf + hdr_size; 256 166 257 - adrv->callback(svc, &resp); 167 + adrv->callback(adev, &resp); 168 + 169 + return 0; 170 + } 171 + 172 + static int gpr_do_rx_callback(struct packet_router *gpr, struct apr_rx_buf *abuf) 173 + { 174 + uint16_t hdr_size, ver; 175 + struct pkt_router_svc *svc = NULL; 176 + struct gpr_resp_pkt resp; 177 + struct gpr_hdr *hdr; 178 + unsigned long flags; 179 + void *buf = abuf->buf; 180 + int len = abuf->len; 181 + 182 + hdr = buf; 183 + ver = hdr->version; 184 + if (ver > GPR_PKT_VER + 1) 185 + return -EINVAL; 186 + 187 + hdr_size = hdr->hdr_size; 188 + if (hdr_size < GPR_PKT_HEADER_WORD_SIZE) { 189 + dev_err(gpr->dev, "GPR: Wrong hdr size:%d\n", hdr_size); 190 + return -EINVAL; 191 + } 192 + 193 + if (hdr->pkt_size < GPR_PKT_HEADER_BYTE_SIZE || hdr->pkt_size != len) { 194 + dev_err(gpr->dev, "GPR: Wrong packet size\n"); 195 + return -EINVAL; 196 + } 197 + 198 + resp.hdr = *hdr; 199 + resp.payload_size = hdr->pkt_size - (hdr_size * 4); 200 + 201 + /* 202 + * NOTE: hdr_size is not same as GPR_HDR_SIZE as remote can include 203 + * optional headers in to gpr_hdr which should be ignored 204 + */ 205 + if (resp.payload_size > 0) 206 + resp.payload = buf + (hdr_size * 4); 207 + 208 + 209 + spin_lock_irqsave(&gpr->svcs_lock, flags); 210 + svc = idr_find(&gpr->svcs_idr, hdr->dest_port); 211 + spin_unlock_irqrestore(&gpr->svcs_lock, flags); 212 + 213 + if (!svc) { 214 + dev_err(gpr->dev, "GPR: Port(%x) is not registered\n", 215 + hdr->dest_port); 216 + return -EINVAL; 217 + } 218 + 219 + if (svc->callback) 220 + svc->callback(&resp, svc->priv, 0); 258 221 259 222 return 0; 260 223 } 261 224 262 225 static void apr_rxwq(struct work_struct *work) 263 226 { 264 - struct apr *apr = container_of(work, struct apr, rx_work); 227 + struct packet_router *apr = container_of(work, struct packet_router, rx_work); 265 228 struct apr_rx_buf *abuf, *b; 266 229 unsigned long flags; 267 230 268 231 if (!list_empty(&apr->rx_list)) { 269 232 list_for_each_entry_safe(abuf, b, &apr->rx_list, node) { 270 - apr_do_rx_callback(apr, abuf); 233 + switch (apr->type) { 234 + case PR_TYPE_APR: 235 + apr_do_rx_callback(apr, abuf); 236 + break; 237 + case PR_TYPE_GPR: 238 + gpr_do_rx_callback(apr, abuf); 239 + break; 240 + default: 241 + break; 242 + } 271 243 spin_lock_irqsave(&apr->rx_lock, flags); 272 244 list_del(&abuf->node); 273 245 spin_unlock_irqrestore(&apr->rx_lock, flags); ··· 353 201 354 202 while (id->domain_id != 0 || id->svc_id != 0) { 355 203 if (id->domain_id == adev->domain_id && 356 - id->svc_id == adev->svc_id) 204 + id->svc_id == adev->svc.id) 357 205 return 1; 358 206 id++; 359 207 } ··· 365 213 { 366 214 struct apr_device *adev = to_apr_device(dev); 367 215 struct apr_driver *adrv = to_apr_driver(dev->driver); 216 + int ret; 368 217 369 - return adrv->probe(adev); 218 + ret = adrv->probe(adev); 219 + if (!ret) 220 + adev->svc.callback = adrv->gpr_callback; 221 + 222 + return ret; 370 223 } 371 224 372 225 static void apr_device_remove(struct device *dev) 373 226 { 374 227 struct apr_device *adev = to_apr_device(dev); 375 228 struct apr_driver *adrv; 376 - struct apr *apr = dev_get_drvdata(adev->dev.parent); 229 + struct packet_router *apr = dev_get_drvdata(adev->dev.parent); 377 230 378 231 if (dev->driver) { 379 232 adrv = to_apr_driver(dev->driver); 380 233 if (adrv->remove) 381 234 adrv->remove(adev); 382 235 spin_lock(&apr->svcs_lock); 383 - idr_remove(&apr->svcs_idr, adev->svc_id); 236 + idr_remove(&apr->svcs_idr, adev->svc.id); 384 237 spin_unlock(&apr->svcs_lock); 385 238 } 386 239 } ··· 412 255 EXPORT_SYMBOL_GPL(aprbus); 413 256 414 257 static int apr_add_device(struct device *dev, struct device_node *np, 415 - const struct apr_device_id *id) 258 + u32 svc_id, u32 domain_id) 416 259 { 417 - struct apr *apr = dev_get_drvdata(dev); 260 + struct packet_router *apr = dev_get_drvdata(dev); 418 261 struct apr_device *adev = NULL; 262 + struct pkt_router_svc *svc; 419 263 int ret; 420 264 421 265 adev = kzalloc(sizeof(*adev), GFP_KERNEL); 422 266 if (!adev) 423 267 return -ENOMEM; 424 268 425 - spin_lock_init(&adev->lock); 269 + adev->svc_id = svc_id; 270 + svc = &adev->svc; 426 271 427 - adev->svc_id = id->svc_id; 428 - adev->domain_id = id->domain_id; 429 - adev->version = id->svc_version; 272 + svc->id = svc_id; 273 + svc->pr = apr; 274 + svc->priv = adev; 275 + svc->dev = dev; 276 + spin_lock_init(&svc->lock); 277 + 278 + adev->domain_id = domain_id; 279 + 430 280 if (np) 431 281 snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np); 432 - else 433 - strscpy(adev->name, id->name, APR_NAME_SIZE); 434 282 435 - dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, 436 - id->domain_id, id->svc_id); 283 + switch (apr->type) { 284 + case PR_TYPE_APR: 285 + dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, 286 + domain_id, svc_id); 287 + break; 288 + case PR_TYPE_GPR: 289 + dev_set_name(&adev->dev, "gprsvc:%s:%x:%x", adev->name, 290 + domain_id, svc_id); 291 + break; 292 + default: 293 + break; 294 + } 437 295 438 296 adev->dev.bus = &aprbus; 439 297 adev->dev.parent = dev; ··· 457 285 adev->dev.driver = NULL; 458 286 459 287 spin_lock(&apr->svcs_lock); 460 - idr_alloc(&apr->svcs_idr, adev, id->svc_id, 461 - id->svc_id + 1, GFP_ATOMIC); 288 + idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC); 462 289 spin_unlock(&apr->svcs_lock); 463 290 464 291 of_property_read_string_index(np, "qcom,protection-domain", 465 292 1, &adev->service_path); 466 293 467 - dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev)); 294 + dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev)); 468 295 469 296 ret = device_register(&adev->dev); 470 297 if (ret) { ··· 477 306 static int of_apr_add_pd_lookups(struct device *dev) 478 307 { 479 308 const char *service_name, *service_path; 480 - struct apr *apr = dev_get_drvdata(dev); 309 + struct packet_router *apr = dev_get_drvdata(dev); 481 310 struct device_node *node; 482 311 struct pdr_service *pds; 483 312 int ret; ··· 507 336 508 337 static void of_register_apr_devices(struct device *dev, const char *svc_path) 509 338 { 510 - struct apr *apr = dev_get_drvdata(dev); 339 + struct packet_router *apr = dev_get_drvdata(dev); 511 340 struct device_node *node; 512 341 const char *service_path; 513 342 int ret; 514 343 515 344 for_each_child_of_node(dev->of_node, node) { 516 - struct apr_device_id id = { {0} }; 345 + u32 svc_id; 346 + u32 domain_id; 517 347 518 348 /* 519 349 * This function is called with svc_path NULL during ··· 544 372 continue; 545 373 } 546 374 547 - if (of_property_read_u32(node, "reg", &id.svc_id)) 375 + if (of_property_read_u32(node, "reg", &svc_id)) 548 376 continue; 549 377 550 - id.domain_id = apr->dest_domain_id; 378 + domain_id = apr->dest_domain_id; 551 379 552 - if (apr_add_device(dev, node, &id)) 553 - dev_err(dev, "Failed to add apr %d svc\n", id.svc_id); 380 + if (apr_add_device(dev, node, svc_id, domain_id)) 381 + dev_err(dev, "Failed to add apr %d svc\n", svc_id); 554 382 } 555 383 } 556 384 ··· 570 398 571 399 static void apr_pd_status(int state, char *svc_path, void *priv) 572 400 { 573 - struct apr *apr = (struct apr *)priv; 401 + struct packet_router *apr = (struct packet_router *)priv; 574 402 575 403 switch (state) { 576 404 case SERVREG_SERVICE_STATE_UP: ··· 585 413 static int apr_probe(struct rpmsg_device *rpdev) 586 414 { 587 415 struct device *dev = &rpdev->dev; 588 - struct apr *apr; 416 + struct packet_router *apr; 589 417 int ret; 590 418 591 419 apr = devm_kzalloc(dev, sizeof(*apr), GFP_KERNEL); 592 420 if (!apr) 593 421 return -ENOMEM; 594 422 595 - ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id); 423 + ret = of_property_read_u32(dev->of_node, "qcom,domain", &apr->dest_domain_id); 424 + 425 + if (of_device_is_compatible(dev->of_node, "qcom,gpr")) { 426 + apr->type = PR_TYPE_GPR; 427 + } else { 428 + if (ret) /* try deprecated apr-domain property */ 429 + ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", 430 + &apr->dest_domain_id); 431 + apr->type = PR_TYPE_APR; 432 + } 433 + 596 434 if (ret) { 597 - dev_err(dev, "APR Domain ID not specified in DT\n"); 435 + dev_err(dev, "Domain ID not specified in DT\n"); 598 436 return ret; 599 437 } 600 438 ··· 647 465 648 466 static void apr_remove(struct rpmsg_device *rpdev) 649 467 { 650 - struct apr *apr = dev_get_drvdata(&rpdev->dev); 468 + struct packet_router *apr = dev_get_drvdata(&rpdev->dev); 651 469 652 470 pdr_handle_release(apr->pdr); 653 471 device_for_each_child(&rpdev->dev, NULL, apr_remove_device); ··· 684 502 } 685 503 EXPORT_SYMBOL_GPL(apr_driver_unregister); 686 504 687 - static const struct of_device_id apr_of_match[] = { 505 + static const struct of_device_id pkt_router_of_match[] = { 688 506 { .compatible = "qcom,apr"}, 689 507 { .compatible = "qcom,apr-v2"}, 508 + { .compatible = "qcom,gpr"}, 690 509 {} 691 510 }; 692 - MODULE_DEVICE_TABLE(of, apr_of_match); 511 + MODULE_DEVICE_TABLE(of, pkt_router_of_match); 693 512 694 - static struct rpmsg_driver apr_driver = { 513 + static struct rpmsg_driver packet_router_driver = { 695 514 .probe = apr_probe, 696 515 .remove = apr_remove, 697 516 .callback = apr_callback, 698 517 .drv = { 699 518 .name = "qcom,apr", 700 - .of_match_table = apr_of_match, 519 + .of_match_table = pkt_router_of_match, 701 520 }, 702 521 }; 703 522 ··· 708 525 709 526 ret = bus_register(&aprbus); 710 527 if (!ret) 711 - ret = register_rpmsg_driver(&apr_driver); 528 + ret = register_rpmsg_driver(&packet_router_driver); 712 529 else 713 530 bus_unregister(&aprbus); 714 531 ··· 718 535 static void __exit apr_exit(void) 719 536 { 720 537 bus_unregister(&aprbus); 721 - unregister_rpmsg_driver(&apr_driver); 538 + unregister_rpmsg_driver(&packet_router_driver); 722 539 } 723 540 724 541 subsys_initcall(apr_init);
+1 -3
drivers/soc/qcom/cpr.c
··· 1614 1614 1615 1615 static int cpr_probe(struct platform_device *pdev) 1616 1616 { 1617 - struct resource *res; 1618 1617 struct device *dev = &pdev->dev; 1619 1618 struct cpr_drv *drv; 1620 1619 int irq, ret; ··· 1647 1648 if (IS_ERR(drv->tcsr)) 1648 1649 return PTR_ERR(drv->tcsr); 1649 1650 1650 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1651 - drv->base = devm_ioremap_resource(dev, res); 1651 + drv->base = devm_platform_ioremap_resource(pdev, 0); 1652 1652 if (IS_ERR(drv->base)) 1653 1653 return PTR_ERR(drv->base); 1654 1654
+17 -1
drivers/soc/qcom/llcc-qcom.c
··· 115 115 { LLCC_CMPT, 10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, 116 116 { LLCC_GPUHTW, 11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, 117 117 { LLCC_GPU, 12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, 118 - { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 1, 0}, 118 + { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0}, 119 119 { LLCC_MDMPNG, 21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, 120 120 { LLCC_WLHW, 24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, 121 121 { LLCC_MODPE, 29, 64, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, ··· 140 140 { LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0 }, 141 141 { LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0 }, 142 142 { LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0 }, 143 + }; 144 + 145 + static const struct llcc_slice_config sm6350_data[] = { 146 + { LLCC_CPUSS, 1, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1 }, 147 + { LLCC_MDM, 8, 512, 2, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, 148 + { LLCC_GPUHTW, 11, 256, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, 149 + { LLCC_GPU, 12, 512, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, 150 + { LLCC_MDMPNG, 21, 768, 0, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, 151 + { LLCC_NPU, 23, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, 152 + { LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, 143 153 }; 144 154 145 155 static const struct llcc_slice_config sm8150_data[] = { ··· 211 201 .sct_data = sdm845_data, 212 202 .size = ARRAY_SIZE(sdm845_data), 213 203 .need_llcc_cfg = false, 204 + }; 205 + 206 + static const struct qcom_llcc_config sm6350_cfg = { 207 + .sct_data = sm6350_data, 208 + .size = ARRAY_SIZE(sm6350_data), 214 209 }; 215 210 216 211 static const struct qcom_llcc_config sm8150_cfg = { ··· 641 626 { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg }, 642 627 { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg }, 643 628 { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg }, 629 + { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg }, 644 630 { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, 645 631 { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, 646 632 { }
+1 -3
drivers/soc/qcom/ocmem.c
··· 300 300 struct device *dev = &pdev->dev; 301 301 unsigned long reg, region_size; 302 302 int i, j, ret, num_banks; 303 - struct resource *res; 304 303 struct ocmem *ocmem; 305 304 306 305 if (!qcom_scm_is_available()) ··· 320 321 return ret; 321 322 } 322 323 323 - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); 324 - ocmem->mmio = devm_ioremap_resource(&pdev->dev, res); 324 + ocmem->mmio = devm_platform_ioremap_resource_byname(pdev, "ctrl"); 325 325 if (IS_ERR(ocmem->mmio)) { 326 326 dev_err(&pdev->dev, "Failed to ioremap ocmem_ctrl resource\n"); 327 327 return PTR_ERR(ocmem->mmio);
+6 -6
drivers/soc/qcom/pdr_interface.c
··· 131 131 return ret; 132 132 133 133 req.enable = enable; 134 - strcpy(req.service_path, pds->service_path); 134 + strscpy(req.service_path, pds->service_path, sizeof(req.service_path)); 135 135 136 136 ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr, 137 137 &txn, SERVREG_REGISTER_LISTENER_REQ, ··· 257 257 return ret; 258 258 259 259 req.transaction_id = tid; 260 - strcpy(req.service_path, pds->service_path); 260 + strscpy(req.service_path, pds->service_path, sizeof(req.service_path)); 261 261 262 262 ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr, 263 263 &txn, SERVREG_SET_ACK_REQ, ··· 406 406 return -ENOMEM; 407 407 408 408 /* Prepare req message */ 409 - strcpy(req.service_name, pds->service_name); 409 + strscpy(req.service_name, pds->service_name, sizeof(req.service_name)); 410 410 req.domain_offset_valid = true; 411 411 req.domain_offset = 0; 412 412 ··· 531 531 return ERR_PTR(-ENOMEM); 532 532 533 533 pds->service = SERVREG_NOTIFIER_SERVICE; 534 - strcpy(pds->service_name, service_name); 535 - strcpy(pds->service_path, service_path); 534 + strscpy(pds->service_name, service_name, sizeof(pds->service_name)); 535 + strscpy(pds->service_path, service_path, sizeof(pds->service_path)); 536 536 pds->need_locator_lookup = true; 537 537 538 538 mutex_lock(&pdr->list_lock); ··· 587 587 break; 588 588 589 589 /* Prepare req message */ 590 - strcpy(req.service_path, pds->service_path); 590 + strscpy(req.service_path, pds->service_path, sizeof(req.service_path)); 591 591 addr = pds->addr; 592 592 break; 593 593 }
+1 -3
drivers/soc/qcom/qcom-geni-se.c
··· 871 871 static int geni_se_probe(struct platform_device *pdev) 872 872 { 873 873 struct device *dev = &pdev->dev; 874 - struct resource *res; 875 874 struct geni_wrapper *wrapper; 876 875 int ret; 877 876 ··· 879 880 return -ENOMEM; 880 881 881 882 wrapper->dev = dev; 882 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 883 - wrapper->base = devm_ioremap_resource(dev, res); 883 + wrapper->base = devm_platform_ioremap_resource(pdev, 0); 884 884 if (IS_ERR(wrapper->base)) 885 885 return PTR_ERR(wrapper->base); 886 886
+54 -111
drivers/soc/qcom/qcom_aoss.c
··· 2 2 /* 3 3 * Copyright (c) 2019, Linaro Ltd 4 4 */ 5 - #include <dt-bindings/power/qcom-aoss-qmp.h> 6 5 #include <linux/clk-provider.h> 7 6 #include <linux/interrupt.h> 8 7 #include <linux/io.h> 9 8 #include <linux/mailbox_client.h> 10 9 #include <linux/module.h> 10 + #include <linux/of_platform.h> 11 11 #include <linux/platform_device.h> 12 - #include <linux/pm_domain.h> 13 12 #include <linux/thermal.h> 14 13 #include <linux/slab.h> 14 + #include <linux/soc/qcom/qcom_aoss.h> 15 15 16 16 #define QMP_DESC_MAGIC 0x0 17 17 #define QMP_DESC_VERSION 0x4 ··· 64 64 * @event: wait_queue for synchronization with the IRQ 65 65 * @tx_lock: provides synchronization between multiple callers of qmp_send() 66 66 * @qdss_clk: QDSS clock hw struct 67 - * @pd_data: genpd data 68 67 * @cooling_devs: thermal cooling devices 69 68 */ 70 69 struct qmp { ··· 81 82 struct mutex tx_lock; 82 83 83 84 struct clk_hw qdss_clk; 84 - struct genpd_onecell_data pd_data; 85 85 struct qmp_cooling_device *cooling_devs; 86 86 }; 87 - 88 - struct qmp_pd { 89 - struct qmp *qmp; 90 - struct generic_pm_domain pd; 91 - }; 92 - 93 - #define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd) 94 87 95 88 static void qmp_kick(struct qmp *qmp) 96 89 { ··· 214 223 * 215 224 * Return: 0 on success, negative errno on failure 216 225 */ 217 - static int qmp_send(struct qmp *qmp, const void *data, size_t len) 226 + int qmp_send(struct qmp *qmp, const void *data, size_t len) 218 227 { 219 228 long time_left; 220 229 int ret; 230 + 231 + if (WARN_ON(IS_ERR_OR_NULL(qmp) || !data)) 232 + return -EINVAL; 221 233 222 234 if (WARN_ON(len + sizeof(u32) > qmp->size)) 223 235 return -EINVAL; ··· 255 261 256 262 return ret; 257 263 } 264 + EXPORT_SYMBOL(qmp_send); 258 265 259 266 static int qmp_qdss_clk_prepare(struct clk_hw *hw) 260 267 { ··· 307 312 { 308 313 of_clk_del_provider(qmp->dev->of_node); 309 314 clk_hw_unregister(&qmp->qdss_clk); 310 - } 311 - 312 - static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable) 313 - { 314 - char buf[QMP_MSG_LEN] = {}; 315 - 316 - snprintf(buf, sizeof(buf), 317 - "{class: image, res: load_state, name: %s, val: %s}", 318 - res->pd.name, enable ? "on" : "off"); 319 - return qmp_send(res->qmp, buf, sizeof(buf)); 320 - } 321 - 322 - static int qmp_pd_power_on(struct generic_pm_domain *domain) 323 - { 324 - return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true); 325 - } 326 - 327 - static int qmp_pd_power_off(struct generic_pm_domain *domain) 328 - { 329 - return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false); 330 - } 331 - 332 - static const char * const sdm845_resources[] = { 333 - [AOSS_QMP_LS_CDSP] = "cdsp", 334 - [AOSS_QMP_LS_LPASS] = "adsp", 335 - [AOSS_QMP_LS_MODEM] = "modem", 336 - [AOSS_QMP_LS_SLPI] = "slpi", 337 - [AOSS_QMP_LS_SPSS] = "spss", 338 - [AOSS_QMP_LS_VENUS] = "venus", 339 - }; 340 - 341 - static int qmp_pd_add(struct qmp *qmp) 342 - { 343 - struct genpd_onecell_data *data = &qmp->pd_data; 344 - struct device *dev = qmp->dev; 345 - struct qmp_pd *res; 346 - size_t num = ARRAY_SIZE(sdm845_resources); 347 - int ret; 348 - int i; 349 - 350 - res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL); 351 - if (!res) 352 - return -ENOMEM; 353 - 354 - data->domains = devm_kcalloc(dev, num, sizeof(*data->domains), 355 - GFP_KERNEL); 356 - if (!data->domains) 357 - return -ENOMEM; 358 - 359 - for (i = 0; i < num; i++) { 360 - res[i].qmp = qmp; 361 - res[i].pd.name = sdm845_resources[i]; 362 - res[i].pd.power_on = qmp_pd_power_on; 363 - res[i].pd.power_off = qmp_pd_power_off; 364 - 365 - ret = pm_genpd_init(&res[i].pd, NULL, true); 366 - if (ret < 0) { 367 - dev_err(dev, "failed to init genpd\n"); 368 - goto unroll_genpds; 369 - } 370 - 371 - data->domains[i] = &res[i].pd; 372 - } 373 - 374 - data->num_domains = i; 375 - 376 - ret = of_genpd_add_provider_onecell(dev->of_node, data); 377 - if (ret < 0) 378 - goto unroll_genpds; 379 - 380 - return 0; 381 - 382 - unroll_genpds: 383 - for (i--; i >= 0; i--) 384 - pm_genpd_remove(data->domains[i]); 385 - 386 - return ret; 387 - } 388 - 389 - static void qmp_pd_remove(struct qmp *qmp) 390 - { 391 - struct genpd_onecell_data *data = &qmp->pd_data; 392 - struct device *dev = qmp->dev; 393 - int i; 394 - 395 - of_genpd_del_provider(dev->of_node); 396 - 397 - for (i = 0; i < data->num_domains; i++) 398 - pm_genpd_remove(data->domains[i]); 399 315 } 400 316 401 317 static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev, ··· 425 519 thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev); 426 520 } 427 521 522 + /** 523 + * qmp_get() - get a qmp handle from a device 524 + * @dev: client device pointer 525 + * 526 + * Return: handle to qmp device on success, ERR_PTR() on failure 527 + */ 528 + struct qmp *qmp_get(struct device *dev) 529 + { 530 + struct platform_device *pdev; 531 + struct device_node *np; 532 + struct qmp *qmp; 533 + 534 + if (!dev || !dev->of_node) 535 + return ERR_PTR(-EINVAL); 536 + 537 + np = of_parse_phandle(dev->of_node, "qcom,qmp", 0); 538 + if (!np) 539 + return ERR_PTR(-ENODEV); 540 + 541 + pdev = of_find_device_by_node(np); 542 + of_node_put(np); 543 + if (!pdev) 544 + return ERR_PTR(-EINVAL); 545 + 546 + qmp = platform_get_drvdata(pdev); 547 + 548 + return qmp ? qmp : ERR_PTR(-EPROBE_DEFER); 549 + } 550 + EXPORT_SYMBOL(qmp_get); 551 + 552 + /** 553 + * qmp_put() - release a qmp handle 554 + * @qmp: qmp handle obtained from qmp_get() 555 + */ 556 + void qmp_put(struct qmp *qmp) 557 + { 558 + /* 559 + * Match get_device() inside of_find_device_by_node() in 560 + * qmp_get() 561 + */ 562 + if (!IS_ERR_OR_NULL(qmp)) 563 + put_device(qmp->dev); 564 + } 565 + EXPORT_SYMBOL(qmp_put); 566 + 428 567 static int qmp_probe(struct platform_device *pdev) 429 568 { 430 - struct resource *res; 431 569 struct qmp *qmp; 432 570 int irq; 433 571 int ret; ··· 484 534 init_waitqueue_head(&qmp->event); 485 535 mutex_init(&qmp->tx_lock); 486 536 487 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 488 - qmp->msgram = devm_ioremap_resource(&pdev->dev, res); 537 + qmp->msgram = devm_platform_ioremap_resource(pdev, 0); 489 538 if (IS_ERR(qmp->msgram)) 490 539 return PTR_ERR(qmp->msgram); 491 540 ··· 512 563 if (ret) 513 564 goto err_close_qmp; 514 565 515 - ret = qmp_pd_add(qmp); 516 - if (ret) 517 - goto err_remove_qdss_clk; 518 - 519 566 ret = qmp_cooling_devices_register(qmp); 520 567 if (ret) 521 568 dev_err(&pdev->dev, "failed to register aoss cooling devices\n"); ··· 520 575 521 576 return 0; 522 577 523 - err_remove_qdss_clk: 524 - qmp_qdss_clk_remove(qmp); 525 578 err_close_qmp: 526 579 qmp_close(qmp); 527 580 err_free_mbox: ··· 533 590 struct qmp *qmp = platform_get_drvdata(pdev); 534 591 535 592 qmp_qdss_clk_remove(qmp); 536 - qmp_pd_remove(qmp); 537 593 qmp_cooling_devices_remove(qmp); 538 594 539 595 qmp_close(qmp); ··· 557 615 .driver = { 558 616 .name = "qcom_aoss_qmp", 559 617 .of_match_table = qmp_dt_match, 618 + .suppress_bind_attrs = true, 560 619 }, 561 620 .probe = qmp_probe, 562 621 .remove = qmp_remove,
+1 -3
drivers/soc/qcom/qcom_gsbi.c
··· 127 127 struct device_node *node = pdev->dev.of_node; 128 128 struct device_node *tcsr_node; 129 129 const struct of_device_id *match; 130 - struct resource *res; 131 130 void __iomem *base; 132 131 struct gsbi_info *gsbi; 133 132 int i, ret; ··· 138 139 if (!gsbi) 139 140 return -ENOMEM; 140 141 141 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 142 - base = devm_ioremap_resource(&pdev->dev, res); 142 + base = devm_platform_ioremap_resource(pdev, 0); 143 143 if (IS_ERR(base)) 144 144 return PTR_ERR(base); 145 145
+1 -3
drivers/soc/qcom/rpmh-rsc.c
··· 910 910 { 911 911 struct device_node *dn = pdev->dev.of_node; 912 912 struct rsc_drv *drv; 913 - struct resource *res; 914 913 char drv_id[10] = {0}; 915 914 int ret, irq; 916 915 u32 solver_config; ··· 940 941 drv->name = dev_name(&pdev->dev); 941 942 942 943 snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id); 943 - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, drv_id); 944 - base = devm_ioremap_resource(&pdev->dev, res); 944 + base = devm_platform_ioremap_resource_byname(pdev, drv_id); 945 945 if (IS_ERR(base)) 946 946 return PTR_ERR(base); 947 947
+16
drivers/soc/qcom/rpmhpd.c
··· 147 147 .num_pds = ARRAY_SIZE(sdx55_rpmhpds), 148 148 }; 149 149 150 + /* SM6350 RPMH powerdomains */ 151 + static struct rpmhpd *sm6350_rpmhpds[] = { 152 + [SM6350_CX] = &sdm845_cx, 153 + [SM6350_GFX] = &sdm845_gfx, 154 + [SM6350_LCX] = &sdm845_lcx, 155 + [SM6350_LMX] = &sdm845_lmx, 156 + [SM6350_MSS] = &sdm845_mss, 157 + [SM6350_MX] = &sdm845_mx, 158 + }; 159 + 160 + static const struct rpmhpd_desc sm6350_desc = { 161 + .rpmhpds = sm6350_rpmhpds, 162 + .num_pds = ARRAY_SIZE(sm6350_rpmhpds), 163 + }; 164 + 150 165 /* SM8150 RPMH powerdomains */ 151 166 152 167 static struct rpmhpd sm8150_mmcx_ao; ··· 312 297 { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, 313 298 { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, 314 299 { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, 300 + { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc }, 315 301 { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, 316 302 { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, 317 303 { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc },
+24
drivers/soc/qcom/rpmpd.c
··· 185 185 .max_state = MAX_CORNER_RPMPD_STATE, 186 186 }; 187 187 188 + /* msm8953 RPM Power Domains */ 189 + DEFINE_RPMPD_PAIR(msm8953, vddmd, vddmd_ao, SMPA, LEVEL, 1); 190 + DEFINE_RPMPD_PAIR(msm8953, vddcx, vddcx_ao, SMPA, LEVEL, 2); 191 + DEFINE_RPMPD_PAIR(msm8953, vddmx, vddmx_ao, SMPA, LEVEL, 7); 192 + 193 + DEFINE_RPMPD_VFL(msm8953, vddcx_vfl, SMPA, 2); 194 + 195 + static struct rpmpd *msm8953_rpmpds[] = { 196 + [MSM8953_VDDMD] = &msm8953_vddmd, 197 + [MSM8953_VDDMD_AO] = &msm8953_vddmd_ao, 198 + [MSM8953_VDDCX] = &msm8953_vddcx, 199 + [MSM8953_VDDCX_AO] = &msm8953_vddcx_ao, 200 + [MSM8953_VDDCX_VFL] = &msm8953_vddcx_vfl, 201 + [MSM8953_VDDMX] = &msm8953_vddmx, 202 + [MSM8953_VDDMX_AO] = &msm8953_vddmx_ao, 203 + }; 204 + 205 + static const struct rpmpd_desc msm8953_desc = { 206 + .rpmpds = msm8953_rpmpds, 207 + .num_pds = ARRAY_SIZE(msm8953_rpmpds), 208 + .max_state = RPM_SMD_LEVEL_TURBO, 209 + }; 210 + 188 211 /* msm8976 RPM Power Domains */ 189 212 DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2); 190 213 DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6); ··· 400 377 { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc }, 401 378 { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, 402 379 { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, 380 + { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc }, 403 381 { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, 404 382 { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, 405 383 { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
+2
drivers/soc/qcom/smd-rpm.c
··· 236 236 { .compatible = "qcom,rpm-msm8226" }, 237 237 { .compatible = "qcom,rpm-msm8916" }, 238 238 { .compatible = "qcom,rpm-msm8936" }, 239 + { .compatible = "qcom,rpm-msm8953" }, 239 240 { .compatible = "qcom,rpm-msm8974" }, 240 241 { .compatible = "qcom,rpm-msm8976" }, 241 242 { .compatible = "qcom,rpm-msm8994" }, ··· 245 244 { .compatible = "qcom,rpm-sdm660" }, 246 245 { .compatible = "qcom,rpm-sm6115" }, 247 246 { .compatible = "qcom,rpm-sm6125" }, 247 + { .compatible = "qcom,rpm-qcm2290" }, 248 248 { .compatible = "qcom,rpm-qcs404" }, 249 249 {} 250 250 };
+20
drivers/soc/qcom/smp2p.c
··· 14 14 #include <linux/mfd/syscon.h> 15 15 #include <linux/module.h> 16 16 #include <linux/platform_device.h> 17 + #include <linux/pm_wakeirq.h> 17 18 #include <linux/regmap.h> 18 19 #include <linux/soc/qcom/smem.h> 19 20 #include <linux/soc/qcom/smem_state.h> ··· 539 538 goto unwind_interfaces; 540 539 } 541 540 541 + /* 542 + * Treat smp2p interrupt as wakeup source, but keep it disabled 543 + * by default. User space can decide enabling it depending on its 544 + * use cases. For example if remoteproc crashes and device wants 545 + * to handle it immediatedly (e.g. to not miss phone calls) it can 546 + * enable wakeup source from user space, while other devices which 547 + * do not have proper autosleep feature may want to handle it with 548 + * other wakeup events (e.g. Power button) instead waking up immediately. 549 + */ 550 + device_set_wakeup_capable(&pdev->dev, true); 551 + 552 + ret = dev_pm_set_wake_irq(&pdev->dev, irq); 553 + if (ret) 554 + goto set_wake_irq_fail; 542 555 543 556 return 0; 557 + 558 + set_wake_irq_fail: 559 + dev_pm_clear_wake_irq(&pdev->dev); 544 560 545 561 unwind_interfaces: 546 562 list_for_each_entry(entry, &smp2p->inbound, node) ··· 582 564 { 583 565 struct qcom_smp2p *smp2p = platform_get_drvdata(pdev); 584 566 struct smp2p_entry *entry; 567 + 568 + dev_pm_clear_wake_irq(&pdev->dev); 585 569 586 570 list_for_each_entry(entry, &smp2p->inbound, node) 587 571 irq_domain_remove(entry->domain);
+12
drivers/soc/qcom/socinfo.c
··· 281 281 { 319, "APQ8098" }, 282 282 { 321, "SDM845" }, 283 283 { 322, "MDM9206" }, 284 + { 323, "IPQ8074" }, 284 285 { 324, "SDA660" }, 285 286 { 325, "SDM658" }, 286 287 { 326, "SDA658" }, 287 288 { 327, "SDA630" }, 288 289 { 338, "SDM450" }, 289 290 { 341, "SDA845" }, 291 + { 342, "IPQ8072" }, 292 + { 343, "IPQ8076" }, 293 + { 344, "IPQ8078" }, 290 294 { 345, "SDM636" }, 291 295 { 346, "SDA636" }, 292 296 { 349, "SDM632" }, 293 297 { 350, "SDA632" }, 294 298 { 351, "SDA450" }, 295 299 { 356, "SM8250" }, 300 + { 375, "IPQ8070" }, 301 + { 376, "IPQ8071" }, 302 + { 389, "IPQ8072A" }, 303 + { 390, "IPQ8074A" }, 304 + { 391, "IPQ8076A" }, 305 + { 392, "IPQ8078A" }, 296 306 { 394, "SM6125" }, 307 + { 395, "IPQ8070A" }, 308 + { 396, "IPQ8071A" }, 297 309 { 402, "IPQ6018" }, 298 310 { 403, "IPQ6028" }, 299 311 { 421, "IPQ6000" },
+258
drivers/soc/qcom/spm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2014,2015, Linaro Ltd. 5 + * 6 + * SAW power controller driver 7 + */ 8 + 9 + #include <linux/kernel.h> 10 + #include <linux/init.h> 11 + #include <linux/io.h> 12 + #include <linux/module.h> 13 + #include <linux/slab.h> 14 + #include <linux/of.h> 15 + #include <linux/of_address.h> 16 + #include <linux/of_device.h> 17 + #include <linux/err.h> 18 + #include <linux/platform_device.h> 19 + #include <soc/qcom/spm.h> 20 + 21 + #define SPM_CTL_INDEX 0x7f 22 + #define SPM_CTL_INDEX_SHIFT 4 23 + #define SPM_CTL_EN BIT(0) 24 + 25 + enum spm_reg { 26 + SPM_REG_CFG, 27 + SPM_REG_SPM_CTL, 28 + SPM_REG_DLY, 29 + SPM_REG_PMIC_DLY, 30 + SPM_REG_PMIC_DATA_0, 31 + SPM_REG_PMIC_DATA_1, 32 + SPM_REG_VCTL, 33 + SPM_REG_SEQ_ENTRY, 34 + SPM_REG_SPM_STS, 35 + SPM_REG_PMIC_STS, 36 + SPM_REG_AVS_CTL, 37 + SPM_REG_AVS_LIMIT, 38 + SPM_REG_NR, 39 + }; 40 + 41 + static const u16 spm_reg_offset_v4_1[SPM_REG_NR] = { 42 + [SPM_REG_AVS_CTL] = 0x904, 43 + [SPM_REG_AVS_LIMIT] = 0x908, 44 + }; 45 + 46 + static const struct spm_reg_data spm_reg_660_gold_l2 = { 47 + .reg_offset = spm_reg_offset_v4_1, 48 + .avs_ctl = 0x1010031, 49 + .avs_limit = 0x4580458, 50 + }; 51 + 52 + static const struct spm_reg_data spm_reg_660_silver_l2 = { 53 + .reg_offset = spm_reg_offset_v4_1, 54 + .avs_ctl = 0x101c031, 55 + .avs_limit = 0x4580458, 56 + }; 57 + 58 + static const struct spm_reg_data spm_reg_8998_gold_l2 = { 59 + .reg_offset = spm_reg_offset_v4_1, 60 + .avs_ctl = 0x1010031, 61 + .avs_limit = 0x4700470, 62 + }; 63 + 64 + static const struct spm_reg_data spm_reg_8998_silver_l2 = { 65 + .reg_offset = spm_reg_offset_v4_1, 66 + .avs_ctl = 0x1010031, 67 + .avs_limit = 0x4200420, 68 + }; 69 + 70 + static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = { 71 + [SPM_REG_CFG] = 0x08, 72 + [SPM_REG_SPM_CTL] = 0x30, 73 + [SPM_REG_DLY] = 0x34, 74 + [SPM_REG_SEQ_ENTRY] = 0x80, 75 + }; 76 + 77 + /* SPM register data for 8974, 8084 */ 78 + static const struct spm_reg_data spm_reg_8974_8084_cpu = { 79 + .reg_offset = spm_reg_offset_v2_1, 80 + .spm_cfg = 0x1, 81 + .spm_dly = 0x3C102800, 82 + .seq = { 0x03, 0x0B, 0x0F, 0x00, 0x20, 0x80, 0x10, 0xE8, 0x5B, 0x03, 83 + 0x3B, 0xE8, 0x5B, 0x82, 0x10, 0x0B, 0x30, 0x06, 0x26, 0x30, 84 + 0x0F }, 85 + .start_index[PM_SLEEP_MODE_STBY] = 0, 86 + .start_index[PM_SLEEP_MODE_SPC] = 3, 87 + }; 88 + 89 + /* SPM register data for 8226 */ 90 + static const struct spm_reg_data spm_reg_8226_cpu = { 91 + .reg_offset = spm_reg_offset_v2_1, 92 + .spm_cfg = 0x0, 93 + .spm_dly = 0x3C102800, 94 + .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90, 95 + 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B, 96 + 0x80, 0x10, 0x26, 0x30, 0x0F }, 97 + .start_index[PM_SLEEP_MODE_STBY] = 0, 98 + .start_index[PM_SLEEP_MODE_SPC] = 5, 99 + }; 100 + 101 + static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = { 102 + [SPM_REG_CFG] = 0x08, 103 + [SPM_REG_SPM_CTL] = 0x20, 104 + [SPM_REG_PMIC_DLY] = 0x24, 105 + [SPM_REG_PMIC_DATA_0] = 0x28, 106 + [SPM_REG_PMIC_DATA_1] = 0x2C, 107 + [SPM_REG_SEQ_ENTRY] = 0x80, 108 + }; 109 + 110 + /* SPM register data for 8064 */ 111 + static const struct spm_reg_data spm_reg_8064_cpu = { 112 + .reg_offset = spm_reg_offset_v1_1, 113 + .spm_cfg = 0x1F, 114 + .pmic_dly = 0x02020004, 115 + .pmic_data[0] = 0x0084009C, 116 + .pmic_data[1] = 0x00A4001C, 117 + .seq = { 0x03, 0x0F, 0x00, 0x24, 0x54, 0x10, 0x09, 0x03, 0x01, 118 + 0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F }, 119 + .start_index[PM_SLEEP_MODE_STBY] = 0, 120 + .start_index[PM_SLEEP_MODE_SPC] = 2, 121 + }; 122 + 123 + static inline void spm_register_write(struct spm_driver_data *drv, 124 + enum spm_reg reg, u32 val) 125 + { 126 + if (drv->reg_data->reg_offset[reg]) 127 + writel_relaxed(val, drv->reg_base + 128 + drv->reg_data->reg_offset[reg]); 129 + } 130 + 131 + /* Ensure a guaranteed write, before return */ 132 + static inline void spm_register_write_sync(struct spm_driver_data *drv, 133 + enum spm_reg reg, u32 val) 134 + { 135 + u32 ret; 136 + 137 + if (!drv->reg_data->reg_offset[reg]) 138 + return; 139 + 140 + do { 141 + writel_relaxed(val, drv->reg_base + 142 + drv->reg_data->reg_offset[reg]); 143 + ret = readl_relaxed(drv->reg_base + 144 + drv->reg_data->reg_offset[reg]); 145 + if (ret == val) 146 + break; 147 + cpu_relax(); 148 + } while (1); 149 + } 150 + 151 + static inline u32 spm_register_read(struct spm_driver_data *drv, 152 + enum spm_reg reg) 153 + { 154 + return readl_relaxed(drv->reg_base + drv->reg_data->reg_offset[reg]); 155 + } 156 + 157 + void spm_set_low_power_mode(struct spm_driver_data *drv, 158 + enum pm_sleep_mode mode) 159 + { 160 + u32 start_index; 161 + u32 ctl_val; 162 + 163 + start_index = drv->reg_data->start_index[mode]; 164 + 165 + ctl_val = spm_register_read(drv, SPM_REG_SPM_CTL); 166 + ctl_val &= ~(SPM_CTL_INDEX << SPM_CTL_INDEX_SHIFT); 167 + ctl_val |= start_index << SPM_CTL_INDEX_SHIFT; 168 + ctl_val |= SPM_CTL_EN; 169 + spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val); 170 + } 171 + 172 + static const struct of_device_id spm_match_table[] = { 173 + { .compatible = "qcom,sdm660-gold-saw2-v4.1-l2", 174 + .data = &spm_reg_660_gold_l2 }, 175 + { .compatible = "qcom,sdm660-silver-saw2-v4.1-l2", 176 + .data = &spm_reg_660_silver_l2 }, 177 + { .compatible = "qcom,msm8226-saw2-v2.1-cpu", 178 + .data = &spm_reg_8226_cpu }, 179 + { .compatible = "qcom,msm8974-saw2-v2.1-cpu", 180 + .data = &spm_reg_8974_8084_cpu }, 181 + { .compatible = "qcom,msm8998-gold-saw2-v4.1-l2", 182 + .data = &spm_reg_8998_gold_l2 }, 183 + { .compatible = "qcom,msm8998-silver-saw2-v4.1-l2", 184 + .data = &spm_reg_8998_silver_l2 }, 185 + { .compatible = "qcom,apq8084-saw2-v2.1-cpu", 186 + .data = &spm_reg_8974_8084_cpu }, 187 + { .compatible = "qcom,apq8064-saw2-v1.1-cpu", 188 + .data = &spm_reg_8064_cpu }, 189 + { }, 190 + }; 191 + MODULE_DEVICE_TABLE(of, spm_match_table); 192 + 193 + static int spm_dev_probe(struct platform_device *pdev) 194 + { 195 + const struct of_device_id *match_id; 196 + struct spm_driver_data *drv; 197 + struct resource *res; 198 + void __iomem *addr; 199 + 200 + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); 201 + if (!drv) 202 + return -ENOMEM; 203 + 204 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 205 + drv->reg_base = devm_ioremap_resource(&pdev->dev, res); 206 + if (IS_ERR(drv->reg_base)) 207 + return PTR_ERR(drv->reg_base); 208 + 209 + match_id = of_match_node(spm_match_table, pdev->dev.of_node); 210 + if (!match_id) 211 + return -ENODEV; 212 + 213 + drv->reg_data = match_id->data; 214 + platform_set_drvdata(pdev, drv); 215 + 216 + /* Write the SPM sequences first.. */ 217 + addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY]; 218 + __iowrite32_copy(addr, drv->reg_data->seq, 219 + ARRAY_SIZE(drv->reg_data->seq) / 4); 220 + 221 + /* 222 + * ..and then the control registers. 223 + * On some SoC if the control registers are written first and if the 224 + * CPU was held in reset, the reset signal could trigger the SPM state 225 + * machine, before the sequences are completely written. 226 + */ 227 + spm_register_write(drv, SPM_REG_AVS_CTL, drv->reg_data->avs_ctl); 228 + spm_register_write(drv, SPM_REG_AVS_LIMIT, drv->reg_data->avs_limit); 229 + spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg); 230 + spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly); 231 + spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly); 232 + spm_register_write(drv, SPM_REG_PMIC_DATA_0, 233 + drv->reg_data->pmic_data[0]); 234 + spm_register_write(drv, SPM_REG_PMIC_DATA_1, 235 + drv->reg_data->pmic_data[1]); 236 + 237 + /* Set up Standby as the default low power mode */ 238 + if (drv->reg_data->reg_offset[SPM_REG_SPM_CTL]) 239 + spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); 240 + 241 + return 0; 242 + } 243 + 244 + static struct platform_driver spm_driver = { 245 + .probe = spm_dev_probe, 246 + .driver = { 247 + .name = "qcom_spm", 248 + .of_match_table = spm_match_table, 249 + }, 250 + }; 251 + 252 + static int __init qcom_spm_init(void) 253 + { 254 + return platform_driver_register(&spm_driver); 255 + } 256 + arch_initcall(qcom_spm_init); 257 + 258 + MODULE_LICENSE("GPL v2");
-14
include/dt-bindings/power/qcom-aoss-qmp.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* Copyright (c) 2018, Linaro Ltd. */ 3 - 4 - #ifndef __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H 5 - #define __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H 6 - 7 - #define AOSS_QMP_LS_CDSP 0 8 - #define AOSS_QMP_LS_LPASS 1 9 - #define AOSS_QMP_LS_MODEM 2 10 - #define AOSS_QMP_LS_SLPI 3 11 - #define AOSS_QMP_LS_SPSS 4 12 - #define AOSS_QMP_LS_VENUS 5 13 - 14 - #endif
+17
include/dt-bindings/power/qcom-rpmpd.h
··· 20 20 #define SDX55_MX 1 21 21 #define SDX55_CX 2 22 22 23 + /* SM6350 Power Domain Indexes */ 24 + #define SM6350_CX 0 25 + #define SM6350_GFX 1 26 + #define SM6350_LCX 2 27 + #define SM6350_LMX 3 28 + #define SM6350_MSS 4 29 + #define SM6350_MX 5 30 + 23 31 /* SM8150 Power Domain Indexes */ 24 32 #define SM8150_MSS 0 25 33 #define SM8150_EBI 1 ··· 140 132 #define MSM8916_VDDCX_VFC 2 141 133 #define MSM8916_VDDMX 3 142 134 #define MSM8916_VDDMX_AO 4 135 + 136 + /* MSM8953 Power Domain Indexes */ 137 + #define MSM8953_VDDMD 0 138 + #define MSM8953_VDDMD_AO 1 139 + #define MSM8953_VDDCX 2 140 + #define MSM8953_VDDCX_AO 3 141 + #define MSM8953_VDDCX_VFL 4 142 + #define MSM8953_VDDMX 5 143 + #define MSM8953_VDDMX_AO 6 143 144 144 145 /* MSM8976 Power Domain Indexes */ 145 146 #define MSM8976_VDDCX 0
+19
include/dt-bindings/soc/qcom,gpr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ 2 + 3 + #ifndef __DT_BINDINGS_QCOM_GPR_H 4 + #define __DT_BINDINGS_QCOM_GPR_H 5 + 6 + /* DOMAINS */ 7 + 8 + #define GPR_DOMAIN_ID_MODEM 1 9 + #define GPR_DOMAIN_ID_ADSP 2 10 + #define GPR_DOMAIN_ID_APPS 3 11 + 12 + /* Static Services */ 13 + 14 + #define GPR_APM_MODULE_IID 1 15 + #define GPR_PRM_MODULE_IID 2 16 + #define GPR_AMDB_MODULE_IID 3 17 + #define GPR_VCPM_MODULE_IID 4 18 + 19 + #endif /* __DT_BINDINGS_QCOM_GPR_H */
+69 -1
include/linux/soc/qcom/apr.h
··· 7 7 #include <linux/device.h> 8 8 #include <linux/mod_devicetable.h> 9 9 #include <dt-bindings/soc/qcom,apr.h> 10 + #include <dt-bindings/soc/qcom,gpr.h> 10 11 11 12 extern struct bus_type aprbus; 12 13 ··· 76 75 int payload_size; 77 76 }; 78 77 78 + struct gpr_hdr { 79 + uint32_t version:4; 80 + uint32_t hdr_size:4; 81 + uint32_t pkt_size:24; 82 + uint32_t dest_domain:8; 83 + uint32_t src_domain:8; 84 + uint32_t reserved:16; 85 + uint32_t src_port; 86 + uint32_t dest_port; 87 + uint32_t token; 88 + uint32_t opcode; 89 + } __packed; 90 + 91 + struct gpr_pkt { 92 + struct gpr_hdr hdr; 93 + uint32_t payload[]; 94 + }; 95 + 96 + struct gpr_resp_pkt { 97 + struct gpr_hdr hdr; 98 + void *payload; 99 + int payload_size; 100 + }; 101 + 102 + #define GPR_HDR_SIZE sizeof(struct gpr_hdr) 103 + #define GPR_PKT_VER 0x0 104 + #define GPR_PKT_HEADER_WORD_SIZE ((sizeof(struct gpr_pkt) + 3) >> 2) 105 + #define GPR_PKT_HEADER_BYTE_SIZE (GPR_PKT_HEADER_WORD_SIZE << 2) 106 + 107 + #define GPR_BASIC_RSP_RESULT 0x02001005 108 + 109 + struct gpr_ibasic_rsp_result_t { 110 + uint32_t opcode; 111 + uint32_t status; 112 + }; 113 + 114 + #define GPR_BASIC_EVT_ACCEPTED 0x02001006 115 + 116 + struct gpr_ibasic_rsp_accepted_t { 117 + uint32_t opcode; 118 + }; 119 + 79 120 /* Bits 0 to 15 -- Minor version, Bits 16 to 31 -- Major version */ 80 121 #define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF) 81 122 #define APR_SVC_MINOR_VERSION(v) (v & 0xFF) 123 + 124 + typedef int (*gpr_port_cb) (struct gpr_resp_pkt *d, void *priv, int op); 125 + struct packet_router; 126 + struct pkt_router_svc { 127 + struct device *dev; 128 + gpr_port_cb callback; 129 + struct packet_router *pr; 130 + spinlock_t lock; 131 + int id; 132 + void *priv; 133 + }; 134 + 135 + typedef struct pkt_router_svc gpr_port_t; 82 136 83 137 struct apr_device { 84 138 struct device dev; ··· 142 86 uint32_t version; 143 87 char name[APR_NAME_SIZE]; 144 88 const char *service_path; 145 - spinlock_t lock; 89 + struct pkt_router_svc svc; 146 90 struct list_head node; 147 91 }; 148 92 93 + typedef struct apr_device gpr_device_t; 94 + 149 95 #define to_apr_device(d) container_of(d, struct apr_device, dev) 96 + #define svc_to_apr_device(d) container_of(d, struct apr_device, svc) 150 97 151 98 struct apr_driver { 152 99 int (*probe)(struct apr_device *sl); 153 100 int (*remove)(struct apr_device *sl); 154 101 int (*callback)(struct apr_device *a, 155 102 struct apr_resp_pkt *d); 103 + int (*gpr_callback)(struct gpr_resp_pkt *d, void *data, int op); 156 104 struct device_driver driver; 157 105 const struct apr_device_id *id_table; 158 106 }; 159 107 108 + typedef struct apr_driver gpr_driver_t; 160 109 #define to_apr_driver(d) container_of(d, struct apr_driver, driver) 161 110 162 111 /* ··· 184 123 #define module_apr_driver(__apr_driver) \ 185 124 module_driver(__apr_driver, apr_driver_register, \ 186 125 apr_driver_unregister) 126 + #define module_gpr_driver(__gpr_driver) module_apr_driver(__gpr_driver) 187 127 188 128 int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt); 129 + 130 + gpr_port_t *gpr_alloc_port(gpr_device_t *gdev, struct device *dev, 131 + gpr_port_cb cb, void *priv); 132 + void gpr_free_port(gpr_port_t *port); 133 + int gpr_send_port_pkt(gpr_port_t *port, struct gpr_pkt *pkt); 134 + int gpr_send_pkt(gpr_device_t *gdev, struct gpr_pkt *pkt); 189 135 190 136 #endif /* __QCOM_APR_H_ */
+38
include/linux/soc/qcom/qcom_aoss.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (c) 2021, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #ifndef __QCOM_AOSS_H__ 7 + #define __QCOM_AOSS_H__ 8 + 9 + #include <linux/err.h> 10 + #include <linux/device.h> 11 + 12 + struct qmp; 13 + 14 + #if IS_ENABLED(CONFIG_QCOM_AOSS_QMP) 15 + 16 + int qmp_send(struct qmp *qmp, const void *data, size_t len); 17 + struct qmp *qmp_get(struct device *dev); 18 + void qmp_put(struct qmp *qmp); 19 + 20 + #else 21 + 22 + static inline int qmp_send(struct qmp *qmp, const void *data, size_t len) 23 + { 24 + return -ENODEV; 25 + } 26 + 27 + static inline struct qmp *qmp_get(struct device *dev) 28 + { 29 + return ERR_PTR(-ENODEV); 30 + } 31 + 32 + static inline void qmp_put(struct qmp *qmp) 33 + { 34 + } 35 + 36 + #endif 37 + 38 + #endif
+43
include/soc/qcom/spm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2014,2015, Linaro Ltd. 5 + */ 6 + 7 + #ifndef __SPM_H__ 8 + #define __SPM_H__ 9 + 10 + #include <linux/cpuidle.h> 11 + 12 + #define MAX_PMIC_DATA 2 13 + #define MAX_SEQ_DATA 64 14 + 15 + enum pm_sleep_mode { 16 + PM_SLEEP_MODE_STBY, 17 + PM_SLEEP_MODE_RET, 18 + PM_SLEEP_MODE_SPC, 19 + PM_SLEEP_MODE_PC, 20 + PM_SLEEP_MODE_NR, 21 + }; 22 + 23 + struct spm_reg_data { 24 + const u16 *reg_offset; 25 + u32 spm_cfg; 26 + u32 spm_dly; 27 + u32 pmic_dly; 28 + u32 pmic_data[MAX_PMIC_DATA]; 29 + u32 avs_ctl; 30 + u32 avs_limit; 31 + u8 seq[MAX_SEQ_DATA]; 32 + u8 start_index[PM_SLEEP_MODE_NR]; 33 + }; 34 + 35 + struct spm_driver_data { 36 + void __iomem *reg_base; 37 + const struct spm_reg_data *reg_data; 38 + }; 39 + 40 + void spm_set_low_power_mode(struct spm_driver_data *drv, 41 + enum pm_sleep_mode mode); 42 + 43 + #endif /* __SPM_H__ */