aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/firmware/qcom,scm.yaml4
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml95
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml3
-rw-r--r--MAINTAINERS11
-rw-r--r--arch/arm/mach-qcom/platsmp.c2
-rw-r--r--drivers/cpuidle/cpuidle-qcom-spm.c2
-rw-r--r--drivers/firmware/qcom_scm-legacy.c2
-rw-r--r--drivers/firmware/qcom_scm-smc.c2
-rw-r--r--drivers/firmware/qcom_scm.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c2
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c2
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c2
-rw-r--r--drivers/iommu/arm/arm-smmu/qcom_iommu.c2
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c2
-rw-r--r--drivers/misc/fastrpc.c2
-rw-r--r--drivers/mmc/host/sdhci-msm.c2
-rw-r--r--drivers/net/ipa/ipa_main.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c2
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c2
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c2
-rw-r--r--drivers/remoteproc/qcom_wcnss.c2
-rw-r--r--drivers/soc/qcom/Kconfig26
-rw-r--r--drivers/soc/qcom/Makefile3
-rw-r--r--drivers/soc/qcom/dcc.c1300
-rw-r--r--drivers/soc/qcom/mdt_loader.c2
-rw-r--r--drivers/soc/qcom/ocmem.c2
-rw-r--r--drivers/soc/qcom/pmic_glink.c336
-rw-r--r--drivers/soc/qcom/pmic_glink_altmode.c478
-rw-r--r--drivers/soc/qcom/qcom_stats.c10
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c2
-rw-r--r--drivers/soc/qcom/smd-rpm.c1
-rw-r--r--drivers/soc/qcom/socinfo.c16
-rw-r--r--drivers/thermal/qcom/lmh.c2
-rw-r--r--drivers/ufs/host/ufs-qcom-ice.c2
-rw-r--r--include/dt-bindings/arm/qcom,ids.h8
-rw-r--r--include/dt-bindings/power/qcom-rpmpd.h1
-rw-r--r--include/linux/firmware/qcom/qcom_scm.h (renamed from include/linux/qcom_scm.h)0
-rw-r--r--include/linux/soc/qcom/pmic_glink.h32
41 files changed, 1022 insertions, 1352 deletions
diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
index 4193492ba73e..a66e99812b1f 100644
--- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
+++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
@@ -39,6 +39,7 @@ properties:
- qcom,scm-msm8996
- qcom,scm-msm8998
- qcom,scm-qdu1000
+ - qcom,scm-sa8775p
- qcom,scm-sc7180
- qcom,scm-sc7280
- qcom,scm-sc8280xp
@@ -54,6 +55,7 @@ properties:
- qcom,scm-sm8250
- qcom,scm-sm8350
- qcom,scm-sm8450
+ - qcom,scm-sm8550
- qcom,scm-qcs404
- const: qcom,scm
@@ -165,6 +167,7 @@ allOf:
contains:
enum:
- qcom,scm-sm8450
+ - qcom,scm-sm8550
then:
properties:
interconnects: false
@@ -177,6 +180,7 @@ allOf:
contains:
enum:
- qcom,scm-sm8450
+ - qcom,scm-sm8550
then:
properties:
interrupts: false
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
new file mode 100644
index 000000000000..cf863683c21a
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/qcom/qcom,pmic-glink.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm PMIC GLINK firmware interface for battery management, USB
+ Type-C and other things.
+
+maintainers:
+ - Bjorn Andersson <andersson@kernel.org>
+
+description:
+ The PMIC GLINK service, running on a coprocessor on some modern Qualcomm
+ platforms and implement USB Type-C handling and battery management. This
+ binding describes the component in the OS used to communicate with the
+ firmware and connect it's resources to those described in the Devicetree,
+ particularly the USB Type-C controllers relationship with USB and DisplayPort
+ components.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - qcom,sc8180x-pmic-glink
+ - qcom,sc8280xp-pmic-glink
+ - qcom,sm8350-pmic-glink
+ - const: qcom,pmic-glink
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+patternProperties:
+ '^connector@\d$':
+ $ref: /schemas/connector/usb-connector.yaml#
+
+ properties:
+ reg: true
+
+ required:
+ - reg
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |+
+ pmic-glink {
+ compatible = "qcom,sc8280xp-pmic-glink", "qcom,pmic-glink";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ connector@0 {
+ compatible = "usb-c-connector";
+ reg = <0>;
+ power-role = "dual";
+ data-role = "dual";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&usb_role>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&ss_phy_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ endpoint {
+ remote-endpoint = <&sbu_mux>;
+ };
+ };
+ };
+ };
+ };
+...
+
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
index b246500d3d5d..a4046ba60846 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
@@ -112,8 +112,9 @@ properties:
$ref: /schemas/power/qcom,rpmpd.yaml#
patternProperties:
- '-regulators$':
+ '^regulators(-[0-9])?$':
$ref: /schemas/regulator/qcom,rpmh-regulator.yaml#
+ unevaluatedProperties: false
required:
- compatible
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b49887c1dc7..b7abbcb9927e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5821,14 +5821,6 @@ W: http://lists.twibble.org/mailman/listinfo/dc395x/
F: Documentation/scsi/dc395x.rst
F: drivers/scsi/dc395x.*
-DCC QTI DRIVER
-M: Souradeep Chowdhury <quic_schowdhu@quicinc.com>
-L: linux-arm-msm@vger.kernel.org
-S: Maintained
-F: Documentation/ABI/testing/debugfs-driver-dcc
-F: Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml
-F: drivers/soc/qcom/dcc.c
-
DCCP PROTOCOL
L: dccp@vger.kernel.org
S: Orphan
@@ -17263,7 +17255,8 @@ F: drivers/clk/qcom/
F: include/dt-bindings/clock/qcom,*
QUALCOMM CORE POWER REDUCTION (CPR) AVS DRIVER
-M: Niklas Cassel <nks@flawful.org>
+M: Bjorn Andersson <andersson@kernel.org>
+M: Konrad Dybcio <konrad.dybcio@linaro.org>
L: linux-pm@vger.kernel.org
L: linux-arm-msm@vger.kernel.org
S: Maintained
diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c
index 5d2f386a46d8..eca2fe0f4314 100644
--- a/arch/arm/mach-qcom/platsmp.c
+++ b/arch/arm/mach-qcom/platsmp.c
@@ -14,7 +14,7 @@
#include <linux/of_address.h>
#include <linux/smp.h>
#include <linux/io.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <asm/smp_plat.h>
diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c
index beedf22cbe78..4ac83918edf2 100644
--- a/drivers/cpuidle/cpuidle-qcom-spm.c
+++ b/drivers/cpuidle/cpuidle-qcom-spm.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <soc/qcom/spm.h>
#include <asm/proc-fns.h>
diff --git a/drivers/firmware/qcom_scm-legacy.c b/drivers/firmware/qcom_scm-legacy.c
index 9f918b9e6f8f..029e6d117cb8 100644
--- a/drivers/firmware/qcom_scm-legacy.c
+++ b/drivers/firmware/qcom_scm-legacy.c
@@ -9,7 +9,7 @@
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
index bb3235a64b8f..16cf88acfa8e 100644
--- a/drivers/firmware/qcom_scm-smc.c
+++ b/drivers/firmware/qcom_scm-smc.c
@@ -8,7 +8,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 2000323722bf..468d4d5ab550 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -12,7 +12,7 @@
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 660ba0db8900..d09221f97f71 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -5,7 +5,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/cpumask.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/pm_opp.h>
#include <linux/nvmem-consumer.h>
#include <linux/slab.h>
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 57586c794b84..89ff978b81bb 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -8,7 +8,7 @@
#include <linux/ascii85.h>
#include <linux/interconnect.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h>
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
index e7748461cffc..0752fe373351 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
@@ -3,7 +3,7 @@
*/
#include "hdmi.h"
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define HDCP_REG_ENABLE 0x01
#define HDCP_REG_DISABLE 0x00
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c
index 74e9ef2fd580..b5b14108e086 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c
@@ -4,7 +4,7 @@
*/
#include <linux/of_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/ratelimit.h>
#include "arm-smmu.h"
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 91d404deb115..ef42329e82ce 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -7,7 +7,7 @@
#include <linux/adreno-smmu-priv.h>
#include <linux/delay.h>
#include <linux/of_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include "arm-smmu.h"
#include "arm-smmu-qcom.h"
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 270c3d9128ba..1e0b7b2e9fbd 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 142d4c74017c..e5759d7e9ede 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -12,7 +12,7 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/soc/qcom/mdt_loader.h>
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index c9902a1dcf5d..04f80e754477 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -18,7 +18,7 @@
#include <linux/rpmsg.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <uapi/misc/fastrpc.h>
#include <linux/of_reserved_mem.h>
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4ac8651d0b29..8ac81d57a3df 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -13,7 +13,7 @@
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/iopoll.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/interconnect.h>
#include <linux/pinctrl/consumer.h>
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 4fb92f771974..90baf7a54d9a 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -16,7 +16,7 @@
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/soc/qcom/mdt_loader.h>
#include "ipa.h"
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 3f94fbf83702..90f457b8e1fe 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/net.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/soc/qcom/smem.h>
#include <linux/string.h>
#include <net/sock.h>
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 47e9a8b0d474..e0128c69bfbf 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -14,7 +14,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/reboot.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index fddb63cffee0..da2513bb6387 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -34,7 +34,7 @@
#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define MPSS_CRASH_REASON_SMEM 421
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index dc6f07ca8341..d5a049669616 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 68f37296b151..9881443cb8df 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 21c4ce2315ba..a8f283086a21 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -70,14 +70,6 @@ config QCOM_LLCC
SDM845. This provides interfaces to clients that use the LLCC.
Say yes here to enable LLCC slice driver.
-config QCOM_DCC
- tristate "Qualcomm Technologies, Inc. Data Capture and Compare(DCC) engine driver"
- depends on ARCH_QCOM || COMPILE_TEST
- help
- This option enables driver for Data Capture and Compare engine. DCC
- driver provides interface to configure DCC block and read back
- captured data from DCC's internal SRAM.
-
config QCOM_KRYO_L2_ACCESSORS
bool
depends on ARCH_QCOM && ARM64 || COMPILE_TEST
@@ -99,6 +91,24 @@ config QCOM_OCMEM
config QCOM_PDR_HELPERS
tristate
select QCOM_QMI_HELPERS
+ depends on NET
+
+config QCOM_PMIC_GLINK
+ tristate "Qualcomm PMIC GLINK driver"
+ depends on RPMSG
+ depends on TYPEC
+ depends on DRM
+ depends on NET
+ depends on OF
+ select AUXILIARY_BUS
+ select QCOM_PDR_HELPERS
+ help
+ The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
+ USB and battery firmware running on one of the coprocessors in
+ several modern Qualcomm platforms.
+
+ Say yes here to support USB-C and battery status on modern Qualcomm
+ platforms.
config QCOM_QMI_HELPERS
tristate
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 3b92c6c8e0ec..6e88da899f60 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -4,11 +4,12 @@ obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QCOM_CPR) += cpr.o
-obj-$(CONFIG_QCOM_DCC) += dcc.o
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
obj-$(CONFIG_QCOM_OCMEM) += ocmem.o
obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o
+obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
+obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
deleted file mode 100644
index 5b50d638771d..000000000000
--- a/drivers/soc/qcom/dcc.c
+++ /dev/null
@@ -1,1300 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
- */
-
-#include <linux/bitfield.h>
-#include <linux/bitops.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#define STATUS_READY_TIMEOUT 5000 /* microseconds */
-
-#define DCC_SRAM_NODE "dcc_sram"
-
-/* DCC registers */
-#define DCC_HW_INFO 0x04
-#define DCC_LL_NUM_INFO 0x10
-#define DCC_STATUS(vers) ((vers) == 1 ? 0x0c : 0x1c)
-#define DCC_LL_LOCK 0x00
-#define DCC_LL_CFG 0x04
-#define DCC_LL_BASE 0x08
-#define DCC_FD_BASE 0x0c
-#define DCC_LL_TIMEOUT 0x10
-#define DCC_LL_INT_ENABLE 0x18
-#define DCC_LL_INT_STATUS 0x1c
-#define DCC_LL_SW_TRIGGER 0x2c
-#define DCC_LL_BUS_ACCESS_STATUS 0x30
-
-/* Default value used if a bit 6 in the HW_INFO register is set. */
-#define DCC_FIX_LOOP_OFFSET 16
-
-/* Mask to find version info from HW_Info register */
-#define DCC_VER_INFO_MASK BIT(9)
-
-#define MAX_DCC_OFFSET GENMASK(9, 2)
-#define MAX_DCC_LEN GENMASK(6, 0)
-#define MAX_LOOP_CNT GENMASK(7, 0)
-#define MAX_LOOP_ADDR 10
-
-#define DCC_ADDR_DESCRIPTOR 0x00
-#define DCC_ADDR_LIMIT 27
-#define DCC_WORD_SIZE sizeof(u32)
-#define DCC_ADDR_RANGE_MASK GENMASK(31, 4)
-#define DCC_LOOP_DESCRIPTOR BIT(30)
-#define DCC_RD_MOD_WR_DESCRIPTOR BIT(31)
-#define DCC_LINK_DESCRIPTOR GENMASK(31, 30)
-#define DCC_STATUS_MASK GENMASK(1, 0)
-#define DCC_LOCK_MASK BIT(0)
-#define DCC_LOOP_OFFSET_MASK BIT(6)
-#define DCC_TRIGGER_MASK BIT(9)
-
-#define DCC_WRITE_MASK BIT(15)
-#define DCC_WRITE_OFF_MASK GENMASK(7, 0)
-#define DCC_WRITE_LEN_MASK GENMASK(14, 8)
-
-#define DCC_READ_IND 0x00
-#define DCC_WRITE_IND (BIT(28))
-
-#define DCC_AHB_IND 0x00
-#define DCC_APB_IND BIT(29)
-
-#define DCC_MAX_LINK_LIST 8
-
-#define DCC_VER_MASK2 GENMASK(5, 0)
-
-#define DCC_SRAM_WORD_LENGTH 4
-
-#define DCC_RD_MOD_WR_ADDR 0xc105e
-
-enum dcc_descriptor_type {
- DCC_READ_TYPE,
- DCC_LOOP_TYPE,
- DCC_READ_WRITE_TYPE,
- DCC_WRITE_TYPE
-};
-
-struct dcc_config_entry {
- u32 base;
- u32 offset;
- u32 len;
- u32 loop_cnt;
- u32 write_val;
- u32 mask;
- bool apb_bus;
- enum dcc_descriptor_type desc_type;
- struct list_head list;
-};
-
-/**
- * struct dcc_drvdata - configuration information related to a dcc device
- * @base: Base Address of the dcc device
- * @dev: The device attached to the driver data
- * @mutex: Lock to protect access and manipulation of dcc_drvdata
- * @ram_base: Base address for the SRAM dedicated for the dcc device
- * @ram_size: Total size of the SRAM dedicated for the dcc device
- * @ram_offset: Offset to the SRAM dedicated for dcc device
- * @mem_map_ver: Memory map version of DCC hardware
- * @ram_cfg: Used for address limit calculation for dcc
- * @ram_start: Starting address of DCC SRAM
- * @sram_dev: Miscellaneous device equivalent of dcc SRAM
- * @cfg_head: Points to the head of the linked list of addresses
- * @dbg_dir: The dcc debugfs directory under which all the debugfs files are placed
- * @nr_link_list: Total number of linkedlists supported by the DCC configuration
- * @loop_shift: Loop offset bits range for the addresses
- * @enable_bitmap: Bitmap to capture the enabled status of each linked list of addresses
- */
-struct dcc_drvdata {
- void __iomem *base;
- void __iomem *ram_base;
- struct device *dev;
- struct mutex mutex;
- size_t ram_size;
- size_t ram_offset;
- int mem_map_ver;
- unsigned int ram_cfg;
- unsigned int ram_start;
- struct miscdevice sram_dev;
- struct list_head *cfg_head;
- struct dentry *dbg_dir;
- size_t nr_link_list;
- u8 loop_shift;
- unsigned long *enable_bitmap;
-};
-
-struct dcc_cfg_attr {
- u32 addr;
- u32 prev_addr;
- u32 prev_off;
- u32 link;
- u32 sram_offset;
-};
-
-struct dcc_cfg_loop_attr {
- u32 loop_cnt;
- u32 loop_len;
- u32 loop_off;
- bool loop_start;
-};
-
-static inline u32 dcc_list_offset(int version)
-{
- return version == 1 ? 0x1c : version == 2 ? 0x2c : 0x34;
-}
-
-static inline void dcc_list_writel(struct dcc_drvdata *drvdata,
- u32 ll, u32 val, u32 off)
-{
- u32 offset = dcc_list_offset(drvdata->mem_map_ver) + off;
-
- writel(val, drvdata->base + ll * 0x80 + offset);
-}
-
-static inline u32 dcc_list_readl(struct dcc_drvdata *drvdata, u32 ll, u32 off)
-{
- u32 offset = dcc_list_offset(drvdata->mem_map_ver) + off;
-
- return readl(drvdata->base + ll * 0x80 + offset);
-}
-
-static void dcc_sram_write_auto(struct dcc_drvdata *drvdata,
- u32 val, u32 *off)
-{
- /* If the overflow condition is met increment the offset
- * and return to indicate that overflow has occurred
- */
- if (unlikely(*off > drvdata->ram_size - 4)) {
- *off += 4;
- return;
- }
-
- writel(val, drvdata->ram_base + *off);
-
- *off += 4;
-}
-
-static int dcc_sw_trigger(struct dcc_drvdata *drvdata)
-{
- void __iomem *addr;
- int ret = 0;
- int i;
- u32 status;
- u32 ll_cfg;
- u32 tmp_ll_cfg;
- u32 val;
-
- mutex_lock(&drvdata->mutex);
-
- for (i = 0; i < drvdata->nr_link_list; i++) {
- if (!test_bit(i, drvdata->enable_bitmap))
- continue;
- ll_cfg = dcc_list_readl(drvdata, i, DCC_LL_CFG);
- tmp_ll_cfg = ll_cfg & ~DCC_TRIGGER_MASK;
- dcc_list_writel(drvdata, tmp_ll_cfg, i, DCC_LL_CFG);
- dcc_list_writel(drvdata, 1, i, DCC_LL_SW_TRIGGER);
- dcc_list_writel(drvdata, ll_cfg, i, DCC_LL_CFG);
- }
-
- addr = drvdata->base + DCC_STATUS(drvdata->mem_map_ver);
- if (readl_poll_timeout(addr, val, !FIELD_GET(DCC_STATUS_MASK, val),
- 1, STATUS_READY_TIMEOUT)) {
- dev_err(drvdata->dev, "DCC is busy after receiving sw trigger\n");
- ret = -EBUSY;
- goto out_unlock;
- }
-
- for (i = 0; i < drvdata->nr_link_list; i++) {
- if (!test_bit(i, drvdata->enable_bitmap))
- continue;
-
- status = dcc_list_readl(drvdata, i, DCC_LL_BUS_ACCESS_STATUS);
- if (!status)
- continue;
-
- dev_err(drvdata->dev, "Read access error for list %d err: 0x%x\n",
- i, status);
- ll_cfg = dcc_list_readl(drvdata, i, DCC_LL_CFG);
- tmp_ll_cfg = ll_cfg & ~DCC_TRIGGER_MASK;
- dcc_list_writel(drvdata, tmp_ll_cfg, i, DCC_LL_CFG);
- dcc_list_writel(drvdata, DCC_STATUS_MASK, i, DCC_LL_BUS_ACCESS_STATUS);
- dcc_list_writel(drvdata, ll_cfg, i, DCC_LL_CFG);
- ret = -ENODATA;
- break;
- }
-
-out_unlock:
- mutex_unlock(&drvdata->mutex);
- return ret;
-}
-
-static void dcc_ll_cfg_reset_link(struct dcc_cfg_attr *cfg)
-{
- cfg->addr = 0x00;
- cfg->link = 0;
- cfg->prev_off = 0;
- cfg->prev_addr = cfg->addr;
-}
-
-static void dcc_emit_read_write(struct dcc_drvdata *drvdata,
- struct dcc_config_entry *entry,
- struct dcc_cfg_attr *cfg)
-{
- if (cfg->link) {
- /*
- * write new offset = 1 to continue
- * processing the list
- */
-
- dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset);
-
- /* Reset link and prev_off */
- dcc_ll_cfg_reset_link(cfg);
- }
-
- cfg->addr = DCC_RD_MOD_WR_DESCRIPTOR;
- dcc_sram_write_auto(drvdata, cfg->addr, &cfg->sram_offset);
-
- dcc_sram_write_auto(drvdata, entry->mask, &cfg->sram_offset);
-
- dcc_sram_write_auto(drvdata, entry->write_val, &cfg->sram_offset);
-
- cfg->addr = 0;
-}
-
-static void dcc_emit_loop(struct dcc_drvdata *drvdata, struct dcc_config_entry *entry,
- struct dcc_cfg_attr *cfg,
- struct dcc_cfg_loop_attr *cfg_loop,
- u32 *total_len)
-{
- int loop;
-
- /* Check if we need to write link of prev entry */
- if (cfg->link)
- dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset);
-
- if (cfg_loop->loop_start) {
- loop = (cfg->sram_offset - cfg_loop->loop_off) / 4;
- loop |= (cfg_loop->loop_cnt << drvdata->loop_shift) &
- GENMASK(DCC_ADDR_LIMIT, drvdata->loop_shift);
- loop |= DCC_LOOP_DESCRIPTOR;
- *total_len += (*total_len - cfg_loop->loop_len) * cfg_loop->loop_cnt;
-
- dcc_sram_write_auto(drvdata, loop, &cfg->sram_offset);
-
- cfg_loop->loop_start = false;
- cfg_loop->loop_len = 0;
- cfg_loop->loop_off = 0;
- } else {
- cfg_loop->loop_start = true;
- cfg_loop->loop_cnt = entry->loop_cnt - 1;
- cfg_loop->loop_len = *total_len;
- cfg_loop->loop_off = cfg->sram_offset;
- }
-
- /* Reset link and prev_off */
- dcc_ll_cfg_reset_link(cfg);
-}
-
-static void dcc_emit_write(struct dcc_drvdata *drvdata,
- struct dcc_config_entry *entry,
- struct dcc_cfg_attr *cfg)
-{
- u32 off;
-
- if (cfg->link) {
- /*
- * write new offset = 1 to continue
- * processing the list
- */
- dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset);
-
- /* Reset link and prev_off */
- cfg->addr = 0x00;
- cfg->prev_off = 0;
- cfg->prev_addr = cfg->addr;
- }
-
- off = entry->offset / 4;
- /* write new offset-length pair to correct position */
- cfg->link |= ((off & DCC_WRITE_OFF_MASK) | DCC_WRITE_MASK |
- FIELD_PREP(DCC_WRITE_LEN_MASK, entry->len));
- cfg->link |= DCC_LINK_DESCRIPTOR;
-
- /* Address type */
- cfg->addr = (entry->base >> 4) & GENMASK(DCC_ADDR_LIMIT, 0);
- if (entry->apb_bus)
- cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND | DCC_APB_IND;
- else
- cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND | DCC_AHB_IND;
- dcc_sram_write_auto(drvdata, cfg->addr, &cfg->sram_offset);
-
- dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset);
-
- dcc_sram_write_auto(drvdata, entry->write_val, &cfg->sram_offset);
-
- cfg->addr = 0x00;
- cfg->link = 0;
-}
-
-static int dcc_emit_read(struct dcc_drvdata *drvdata,
- struct dcc_config_entry *entry,
- struct dcc_cfg_attr *cfg,
- u32 *pos, u32 *total_len)
-{
- u32 off;
- u32 temp_off;
-
- cfg->addr = (entry->base >> 4) & GENMASK(27, 0);
-
- if (entry->apb_bus)
- cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND | DCC_APB_IND;
- else
- cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND | DCC_AHB_IND;
-
- off = entry->offset / 4;
-
- *total_len += entry->len * 4;
-
- if (!cfg->prev_addr || cfg->prev_addr != cfg->addr || cfg->prev_off > off) {
- /* Check if we need to write prev link entry */
- if (cfg->link)
- dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset);
- dev_dbg(drvdata->dev, "DCC: sram address 0x%x\n", cfg->sram_offset);
-
- /* Write address */
- dcc_sram_write_auto(drvdata, cfg->addr, &cfg->sram_offset);
-
- /* Reset link and prev_off */
- cfg->link = 0;
- cfg->prev_off = 0;
- }
-
- if ((off - cfg->prev_off) > 0xff || entry->len > MAX_DCC_LEN) {
- dev_err(drvdata->dev, "DCC: Programming error Base: 0x%x, offset 0x%x\n",
- entry->base, entry->offset);
- return -EINVAL;
- }
-
- if (cfg->link) {
- /*
- * link already has one offset-length so new
- * offset-length needs to be placed at
- * bits [29:15]
- */
- *pos = 15;
-
- /* Clear bits [31:16] */
- cfg->link &= GENMASK(14, 0);
- } else {
- /*
- * link is empty, so new offset-length needs
- * to be placed at bits [15:0]
- */
- *pos = 0;
- cfg->link = 1 << 15;
- }
-
- /* write new offset-length pair to correct position */
- temp_off = (off - cfg->prev_off) & GENMASK(7, 0);
- cfg->link |= temp_off | ((entry->len << 8) & GENMASK(14, 8)) << *pos;
-
- cfg->link |= DCC_LINK_DESCRIPTOR;
-
- if (*pos) {
- dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset);
- cfg->link = 0;
- }
-
- cfg->prev_off = off + entry->len - 1;
- cfg->prev_addr = cfg->addr;
- return 0;
-}
-
-static int dcc_emit_config(struct dcc_drvdata *drvdata, unsigned int curr_list)
-{
- int ret;
- u32 total_len, pos;
- struct dcc_config_entry *entry;
- struct dcc_cfg_attr cfg;
- struct dcc_cfg_loop_attr cfg_loop;
-
- memset(&cfg, 0, sizeof(cfg));
- memset(&cfg_loop, 0, sizeof(cfg_loop));
- cfg.sram_offset = drvdata->ram_cfg * 4;
- total_len = 0;
-
- list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) {
- switch (entry->desc_type) {
- case DCC_READ_WRITE_TYPE:
- dcc_emit_read_write(drvdata, entry, &cfg);
- break;
-
- case DCC_LOOP_TYPE:
- dcc_emit_loop(drvdata, entry, &cfg, &cfg_loop, &total_len);
- break;
-
- case DCC_WRITE_TYPE:
- dcc_emit_write(drvdata, entry, &cfg);
- break;
-
- case DCC_READ_TYPE:
- ret = dcc_emit_read(drvdata, entry, &cfg, &pos, &total_len);
- if (ret)
- goto err;
- break;
- }
- }
-
- if (cfg.link)
- dcc_sram_write_auto(drvdata, cfg.link, &cfg.sram_offset);
-
- if (cfg_loop.loop_start) {
- dev_err(drvdata->dev, "DCC: Programming error: Loop unterminated\n");
- ret = -EINVAL;
- goto err;
- }
-
- /* Handling special case of list ending with a rd_mod_wr */
- if (cfg.addr == DCC_RD_MOD_WR_DESCRIPTOR) {
- cfg.addr = (DCC_RD_MOD_WR_ADDR) & GENMASK(27, 0);
- cfg.addr |= DCC_ADDR_DESCRIPTOR;
- dcc_sram_write_auto(drvdata, cfg.addr, &cfg.sram_offset);
- }
-
- /* Setting zero to indicate end of the list */
- cfg.link = DCC_LINK_DESCRIPTOR;
- dcc_sram_write_auto(drvdata, cfg.link, &cfg.sram_offset);
-
- /* Check if sram offset exceeds the ram size */
- if (cfg.sram_offset > drvdata->ram_size)
- goto overstep;
-
- /* Update ram_cfg and check if the data will overstep */
- drvdata->ram_cfg = (cfg.sram_offset + total_len) / 4;
-
- if (cfg.sram_offset + total_len > drvdata->ram_size) {
- cfg.sram_offset += total_len;
- goto overstep;
- }
-
- drvdata->ram_start = cfg.sram_offset / 4;
- return 0;
-overstep:
- ret = -EINVAL;
- memset_io(drvdata->ram_base, 0, drvdata->ram_size);
-
-err:
- return ret;
-}
-
-static bool dcc_valid_list(struct dcc_drvdata *drvdata, unsigned int curr_list)
-{
- u32 lock_reg;
-
- if (list_empty(&drvdata->cfg_head[curr_list]))
- return false;
-
- if (test_bit(curr_list, drvdata->enable_bitmap)) {
- dev_err(drvdata->dev, "List %d is already enabled\n", curr_list);
- return false;
- }
-
- lock_reg = dcc_list_readl(drvdata, curr_list, DCC_LL_LOCK);
- if (lock_reg & DCC_LOCK_MASK) {
- dev_err(drvdata->dev, "List %d is already locked\n", curr_list);
- return false;
- }
-
- return true;
-}
-
-static bool is_dcc_enabled(struct dcc_drvdata *drvdata)
-{
- int list;
-
- for (list = 0; list < drvdata->nr_link_list; list++)
- if (test_bit(list, drvdata->enable_bitmap))
- return true;
-
- return false;
-}
-
-static int dcc_enable(struct dcc_drvdata *drvdata, unsigned int curr_list)
-{
- int ret;
- u32 ram_cfg_base;
-
- mutex_lock(&drvdata->mutex);
-
- if (!dcc_valid_list(drvdata, curr_list)) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- /* Fill dcc sram with the poison value.
- * This helps in understanding bus
- * hang from registers returning a zero
- */
- if (!is_dcc_enabled(drvdata))
- memset_io(drvdata->ram_base, 0xde, drvdata->ram_size);
-
- /* 1. Take ownership of the list */
- dcc_list_writel(drvdata, DCC_LOCK_MASK, curr_list, DCC_LL_LOCK);
-
- /* 2. Program linked-list in the SRAM */
- ram_cfg_base = drvdata->ram_cfg;
- ret = dcc_emit_config(drvdata, curr_list);
- if (ret) {
- dcc_list_writel(drvdata, 0, curr_list, DCC_LL_LOCK);
- goto out_unlock;
- }
-
- /* 3. Program DCC_RAM_CFG reg */
- dcc_list_writel(drvdata, ram_cfg_base +
- drvdata->ram_offset / 4, curr_list, DCC_LL_BASE);
- dcc_list_writel(drvdata, drvdata->ram_start +
- drvdata->ram_offset / 4, curr_list, DCC_FD_BASE);
- dcc_list_writel(drvdata, 0xFFF, curr_list, DCC_LL_TIMEOUT);
-
- /* 4. Clears interrupt status register */
- dcc_list_writel(drvdata, 0, curr_list, DCC_LL_INT_ENABLE);
- dcc_list_writel(drvdata, (BIT(0) | BIT(1) | BIT(2)),
- curr_list, DCC_LL_INT_STATUS);
-
- set_bit(curr_list, drvdata->enable_bitmap);
-
- /* 5. Configure trigger */
- dcc_list_writel(drvdata, DCC_TRIGGER_MASK,
- curr_list, DCC_LL_CFG);
-
-out_unlock:
- mutex_unlock(&drvdata->mutex);
- return ret;
-}
-
-static void dcc_disable(struct dcc_drvdata *drvdata, int curr_list)
-{
- mutex_lock(&drvdata->mutex);
-
- if (!test_bit(curr_list, drvdata->enable_bitmap))
- goto out_unlock;
- dcc_list_writel(drvdata, 0, curr_list, DCC_LL_CFG);
- dcc_list_writel(drvdata, 0, curr_list, DCC_LL_BASE);
- dcc_list_writel(drvdata, 0, curr_list, DCC_FD_BASE);
- dcc_list_writel(drvdata, 0, curr_list, DCC_LL_LOCK);
- clear_bit(curr_list, drvdata->enable_bitmap);
-out_unlock:
- mutex_unlock(&drvdata->mutex);
-}
-
-static u32 dcc_filp_curr_list(const struct file *filp)
-{
- struct dentry *dentry = file_dentry(filp);
- int curr_list, ret;
-
- ret = kstrtoint(dentry->d_parent->d_name.name, 0, &curr_list);
- if (ret)
- return ret;
-
- return curr_list;
-}
-
-static ssize_t enable_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char *buf;
- struct dcc_drvdata *drvdata = filp->private_data;
-
- mutex_lock(&drvdata->mutex);
-
- if (is_dcc_enabled(drvdata))
- buf = "Y\n";
- else
- buf = "N\n";
-
- mutex_unlock(&drvdata->mutex);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-}
-
-static ssize_t enable_write(struct file *filp, const char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- int ret = 0, curr_list;
- bool val;
- struct dcc_drvdata *drvdata = filp->private_data;
-
- curr_list = dcc_filp_curr_list(filp);
- if (curr_list < 0)
- return curr_list;
-
- ret = kstrtobool_from_user(userbuf, count, &val);
- if (ret < 0)
- return ret;
-
- if (val) {
- ret = dcc_enable(drvdata, curr_list);
- if (ret)
- return ret;
- } else {
- dcc_disable(drvdata, curr_list);
- }
-
- return count;
-}
-
-static const struct file_operations enable_fops = {
- .read = enable_read,
- .write = enable_write,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
-static ssize_t trigger_write(struct file *filp,
- const char __user *user_buf, size_t count,
- loff_t *ppos)
-{
- int ret;
- unsigned int val;
- struct dcc_drvdata *drvdata = filp->private_data;
-
- ret = kstrtouint_from_user(user_buf, count, 0, &val);
- if (ret < 0)
- return ret;
-
- if (val != 1)
- return -EINVAL;
-
- ret = dcc_sw_trigger(drvdata);
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static const struct file_operations trigger_fops = {
- .write = trigger_write,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
-static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
- unsigned int len, bool apb_bus, int curr_list)
-{
- int ret = 0;
- struct dcc_config_entry *entry, *pentry;
- unsigned int base, offset;
-
- mutex_lock(&drvdata->mutex);
-
- if (!len || len > drvdata->ram_size / DCC_WORD_SIZE) {
- dev_err(drvdata->dev, "DCC: Invalid length\n");
- ret = -EINVAL;
- goto out_unlock;
- }
-
- base = addr & DCC_ADDR_RANGE_MASK;
-
- if (!list_empty(&drvdata->cfg_head[curr_list])) {
- pentry = list_last_entry(&drvdata->cfg_head[curr_list],
- struct dcc_config_entry, list);
-
- if (pentry->desc_type == DCC_READ_TYPE &&
- addr >= (pentry->base + pentry->offset) &&
- addr <= (pentry->base + pentry->offset + MAX_DCC_OFFSET)) {
- /* Re-use base address from last entry */
- base = pentry->base;
-
- if ((pentry->len * 4 + pentry->base + pentry->offset)
- == addr) {
- len += pentry->len;
-
- if (len > MAX_DCC_LEN)
- pentry->len = MAX_DCC_LEN;
- else
- pentry->len = len;
-
- addr = pentry->base + pentry->offset +
- pentry->len * 4;
- len -= pentry->len;
- }
- }
- }
-
- offset = addr - base;
-
- while (len) {
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry) {
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- entry->base = base;
- entry->offset = offset;
- entry->len = min_t(u32, len, MAX_DCC_LEN);
- entry->desc_type = DCC_READ_TYPE;
- entry->apb_bus = apb_bus;
- INIT_LIST_HEAD(&entry->list);
- list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]);
-
- len -= entry->len;
- offset += MAX_DCC_LEN * 4;
- }
-
-out_unlock:
- mutex_unlock(&drvdata->mutex);
- return ret;
-}
-
-static ssize_t dcc_config_add_read(struct dcc_drvdata *drvdata, char *buf, int curr_list)
-{
- bool bus;
- int len, nval;
- unsigned int base;
- char apb_bus[4];
-
- nval = sscanf(buf, "%x %i %3s", &base, &len, apb_bus);
- if (nval <= 0 || nval > 3)
- return -EINVAL;
-
- if (nval == 1) {
- len = 1;
- bus = false;
- } else if (nval == 2) {
- bus = false;
- } else if (!strcmp("apb", apb_bus)) {
- bus = true;
- } else if (!strcmp("ahb", apb_bus)) {
- bus = false;
- } else {
- return -EINVAL;
- }
-
- return dcc_config_add(drvdata, base, len, bus, curr_list);
-}
-
-static void dcc_config_reset(struct dcc_drvdata *drvdata)
-{
- struct dcc_config_entry *entry, *temp;
- int curr_list;
-
- mutex_lock(&drvdata->mutex);
-
- for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
- list_for_each_entry_safe(entry, temp,
- &drvdata->cfg_head[curr_list], list) {
- list_del(&entry->list);
- kfree(entry);
- }
- }
- drvdata->ram_start = 0;
- drvdata->ram_cfg = 0;
- mutex_unlock(&drvdata->mutex);
-}
-
-static ssize_t config_reset_write(struct file *filp,
- const char __user *user_buf, size_t count,
- loff_t *ppos)
-{
- unsigned int val;
- int ret;
- struct dcc_drvdata *drvdata = filp->private_data;
-
- ret = kstrtouint_from_user(user_buf, count, 0, &val);
- if (ret < 0)
- return ret;
-
- if (val)
- dcc_config_reset(drvdata);
-
- return count;
-}
-
-static const struct file_operations config_reset_fops = {
- .write = config_reset_write,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
-static ssize_t ready_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- int ret = 0;
- char *buf;
- struct dcc_drvdata *drvdata = filp->private_data;
-
- mutex_lock(&drvdata->mutex);
-
- if (!is_dcc_enabled(drvdata)) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- if (!FIELD_GET(BIT(1), readl(drvdata->base + DCC_STATUS(drvdata->mem_map_ver))))
- buf = "Y\n";
- else
- buf = "N\n";
-out_unlock:
- mutex_unlock(&drvdata->mutex);
-
- if (ret < 0)
- return -EINVAL;
- else
- return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf) + 1);
-}
-
-static const struct file_operations ready_fops = {
- .read = ready_read,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
-static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt, int curr_list)
-{
- struct dcc_config_entry *entry;
-
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->loop_cnt = min_t(u32, loop_cnt, MAX_LOOP_CNT);
- entry->desc_type = DCC_LOOP_TYPE;
- INIT_LIST_HEAD(&entry->list);
- list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]);
-
- return 0;
-}
-
-static ssize_t dcc_config_add_loop(struct dcc_drvdata *drvdata, char *buf, int curr_list)
-{
- int ret, i = 0;
- char *token, *input;
- char delim[2] = " ";
- unsigned int val[MAX_LOOP_ADDR];
-
- input = buf;
-
- while ((token = strsep(&input, delim)) && i < MAX_LOOP_ADDR) {
- ret = kstrtoint(token, 0, &val[i++]);
- if (ret)
- return ret;
- }
-
- if (token) {
- dev_err(drvdata->dev, "Max limit %u of loop address exceeded",
- MAX_LOOP_ADDR);
- return -EINVAL;
- }
-
- if (val[1] < 1 || val[1] > 8)
- return -EINVAL;
-
- ret = dcc_add_loop(drvdata, val[0], curr_list);
- if (ret)
- return ret;
-
- for (i = 0; i < val[1]; i++)
- dcc_config_add(drvdata, val[i + 2], 1, false, curr_list);
-
- return dcc_add_loop(drvdata, 1, curr_list);
-}
-
-static int dcc_rd_mod_wr_add(struct dcc_drvdata *drvdata, unsigned int mask,
- unsigned int val, int curr_list)
-{
- int ret = 0;
- struct dcc_config_entry *entry;
-
- mutex_lock(&drvdata->mutex);
-
- if (list_empty(&drvdata->cfg_head[curr_list])) {
- dev_err(drvdata->dev, "DCC: No read address programmed\n");
- ret = -EPERM;
- goto out_unlock;
- }
-
- entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
- if (!entry) {
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- entry->desc_type = DCC_READ_WRITE_TYPE;
- entry->mask = mask;
- entry->write_val = val;
- list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]);
-out_unlock:
- mutex_unlock(&drvdata->mutex);
- return ret;
-}
-
-static ssize_t dcc_config_add_read_write(struct dcc_drvdata *drvdata, char *buf, int curr_list)
-{
- int ret;
- int nval;
- unsigned int addr, mask, val;
-
- nval = sscanf(buf, "%x %x %x", &addr, &mask, &val);
-
- if (nval <= 1 || nval > 3)
- return -EINVAL;
-
- ret = dcc_config_add(drvdata, addr, 1, false, curr_list);
- if (ret)
- return ret;
-
- return dcc_rd_mod_wr_add(drvdata, mask, val, curr_list);
-}
-
-static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr,
- unsigned int write_val, int apb_bus, int curr_list)
-{
- struct dcc_config_entry *entry;
-
- entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->desc_type = DCC_WRITE_TYPE;
- entry->base = addr & GENMASK(31, 4);
- entry->offset = addr - entry->base;
- entry->write_val = write_val;
- entry->len = 1;
- entry->apb_bus = apb_bus;
- list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]);
-
- return 0;
-}
-
-static ssize_t dcc_config_add_write(struct dcc_drvdata *drvdata, char *buf, int curr_list)
-{
- bool bus;
- int nval;
- unsigned int addr, write_val;
- char apb_bus[4];
-
- nval = sscanf(buf, "%x %x %3s", &addr, &write_val, apb_bus);
-
- if (nval <= 1 || nval > 3)
- return -EINVAL;
-
- if (nval == 2)
- bus = true;
-
- if (nval == 3) {
- if (!strcmp("apb", apb_bus))
- bus = true;
- else if (!strcmp("ahb", apb_bus))
- bus = false;
- else
- return -EINVAL;
- }
-
- return dcc_add_write(drvdata, addr, write_val, bus, curr_list);
-}
-
-static int config_show(struct seq_file *m, void *data)
-{
- struct dcc_drvdata *drvdata = m->private;
- struct dcc_config_entry *entry;
- int index = 0, curr_list;
-
- curr_list = dcc_filp_curr_list(m->file);
- if (curr_list < 0)
- return curr_list;
-
- mutex_lock(&drvdata->mutex);
-
- list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) {
- index++;
- switch (entry->desc_type) {
- case DCC_READ_WRITE_TYPE:
- seq_printf(m, "RW mask: 0x%x, val: 0x%x\n index: 0x%x\n",
- entry->mask, entry->write_val, index);
- break;
- case DCC_LOOP_TYPE:
- seq_printf(m, "L index: 0x%x Loop: %d\n", index, entry->loop_cnt);
- break;
- case DCC_WRITE_TYPE:
- seq_printf(m, "W Base:0x%x, Offset: 0x%x, val: 0x%x, APB: %d\n, Index: 0x%x\n",
- entry->base, entry->offset, entry->write_val, entry->apb_bus,
- index);
- break;
- case DCC_READ_TYPE:
- seq_printf(m, "R Base:0x%x, Offset: 0x%x, len: 0x%x, APB: %d\n, Index: 0x%x\n",
- entry->base, entry->offset, entry->len, entry->apb_bus, index);
- }
- }
- mutex_unlock(&drvdata->mutex);
- return 0;
-}
-
-static int config_open(struct inode *inode, struct file *file)
-{
- struct dcc_drvdata *drvdata = inode->i_private;
-
- return single_open(file, config_show, drvdata);
-}
-
-static ssize_t config_write(struct file *filp,
- const char __user *user_buf, size_t count,
- loff_t *ppos)
-{
- int ret, curr_list;
- char *token, buf[50];
- char *bufp = buf;
- char *delim = " ";
- struct dcc_drvdata *drvdata = filp->private_data;
-
- if (count > sizeof(buf) || count == 0)
- return -EINVAL;
-
- ret = copy_from_user(buf, user_buf, count);
- if (ret)
- return -EFAULT;
-
- curr_list = dcc_filp_curr_list(filp);
- if (curr_list < 0)
- return curr_list;
-
- if (buf[count - 1] == '\n')
- buf[count - 1] = '\0';
- else
- return -EINVAL;
-
- token = strsep(&bufp, delim);
-
- if (!strcmp("R", token)) {
- ret = dcc_config_add_read(drvdata, bufp, curr_list);
- } else if (!strcmp("W", token)) {
- ret = dcc_config_add_write(drvdata, bufp, curr_list);
- } else if (!strcmp("RW", token)) {
- ret = dcc_config_add_read_write(drvdata, bufp, curr_list);
- } else if (!strcmp("L", token)) {
- ret = dcc_config_add_loop(drvdata, bufp, curr_list);
- } else {
- dev_err(drvdata->dev, "%s is not a correct input\n", token);
- return -EINVAL;
- }
-
- if (ret)
- return ret;
-
- return count;
-}
-
-static const struct file_operations config_fops = {
- .open = config_open,
- .read = seq_read,
- .write = config_write,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void dcc_delete_debug_dir(struct dcc_drvdata *drvdata)
-{
- debugfs_remove_recursive(drvdata->dbg_dir);
-};
-
-static void dcc_create_debug_dir(struct dcc_drvdata *drvdata)
-{
- int i;
- char list_num[10];
- struct dentry *list;
- struct device *dev = drvdata->dev;
-
- drvdata->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
- if (IS_ERR(drvdata->dbg_dir)) {
- pr_err("can't create debugfs dir\n");
- return;
- }
-
- for (i = 0; i <= drvdata->nr_link_list; i++) {
- sprintf(list_num, "%d", i);
- list = debugfs_create_dir(list_num, drvdata->dbg_dir);
- debugfs_create_file("enable", 0600, list, drvdata, &enable_fops);
- debugfs_create_file("config", 0600, list, drvdata, &config_fops);
- }
-
- debugfs_create_file("trigger", 0200, drvdata->dbg_dir, drvdata, &trigger_fops);
- debugfs_create_file("ready", 0400, drvdata->dbg_dir, drvdata, &ready_fops);
- debugfs_create_file("config_reset", 0200, drvdata->dbg_dir,
- drvdata, &config_reset_fops);
-}
-
-static ssize_t dcc_sram_read(struct file *file, char __user *data,
- size_t len, loff_t *ppos)
-{
- struct dcc_drvdata *drvdata = container_of(file->private_data, struct dcc_drvdata, sram_dev);
- unsigned char *buf;
-
- /* EOF check */
- if (*ppos >= drvdata->ram_size)
- return 0;
-
- if ((*ppos + len) > drvdata->ram_size)
- len = (drvdata->ram_size - *ppos);
-
- buf = kzalloc(len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- memcpy_fromio(buf, drvdata->ram_base + *ppos, len);
-
- if (copy_to_user(data, buf, len)) {
- kfree(buf);
- return -EFAULT;
- }
-
- *ppos += len;
-
- kfree(buf);
-
- return len;
-}
-
-static const struct file_operations dcc_sram_fops = {
- .owner = THIS_MODULE,
- .read = dcc_sram_read,
- .llseek = no_llseek,
-};
-
-static int dcc_sram_dev_init(struct dcc_drvdata *drvdata)
-{
- drvdata->sram_dev.minor = MISC_DYNAMIC_MINOR;
- drvdata->sram_dev.name = DCC_SRAM_NODE;
- drvdata->sram_dev.fops = &dcc_sram_fops;
-
- return misc_register(&drvdata->sram_dev);
-}
-
-static void dcc_sram_dev_exit(struct dcc_drvdata *drvdata)
-{
- misc_deregister(&drvdata->sram_dev);
-}
-
-static int dcc_probe(struct platform_device *pdev)
-{
- u32 val;
- int ret = 0, i;
- struct device *dev = &pdev->dev;
- struct dcc_drvdata *drvdata;
- struct resource *res;
-
- drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
-
- drvdata->dev = &pdev->dev;
- platform_set_drvdata(pdev, drvdata);
-
- drvdata->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(drvdata->base))
- return PTR_ERR(drvdata->base);
-
- drvdata->ram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
- if (IS_ERR(drvdata->ram_base))
- return PTR_ERR(drvdata->ram_base);
-
- drvdata->ram_size = resource_size(res);
-
- drvdata->ram_offset = (size_t)of_device_get_match_data(&pdev->dev);
-
- val = readl(drvdata->base + DCC_HW_INFO);
-
- if (FIELD_GET(DCC_VER_INFO_MASK, val)) {
- drvdata->mem_map_ver = 3;
- drvdata->nr_link_list = readl(drvdata->base + DCC_LL_NUM_INFO);
- if (!drvdata->nr_link_list)
- return -EINVAL;
- } else if ((val & DCC_VER_MASK2) == DCC_VER_MASK2) {
- drvdata->mem_map_ver = 2;
- drvdata->nr_link_list = readl(drvdata->base + DCC_LL_NUM_INFO);
- if (!drvdata->nr_link_list)
- return -EINVAL;
- } else {
- drvdata->mem_map_ver = 1;
- drvdata->nr_link_list = DCC_MAX_LINK_LIST;
- }
-
- /* Either set the fixed loop offset or calculate
- * it from the total number of words in dcc_sram.
- * Max consecutive addresses dcc can loop is
- * equivalent to the words in dcc_sram.
- */
- if (val & DCC_LOOP_OFFSET_MASK)
- drvdata->loop_shift = DCC_FIX_LOOP_OFFSET;
- else
- drvdata->loop_shift = get_bitmask_order((drvdata->ram_offset +
- drvdata->ram_size) / DCC_SRAM_WORD_LENGTH - 1);
-
- mutex_init(&drvdata->mutex);
-
- drvdata->enable_bitmap = devm_kcalloc(dev, BITS_TO_LONGS(drvdata->nr_link_list),
- sizeof(*drvdata->enable_bitmap), GFP_KERNEL);
- if (!drvdata->enable_bitmap)
- return -ENOMEM;
-
- drvdata->cfg_head = devm_kcalloc(dev, drvdata->nr_link_list,
- sizeof(*drvdata->cfg_head), GFP_KERNEL);
- if (!drvdata->cfg_head)
- return -ENOMEM;
-
- for (i = 0; i < drvdata->nr_link_list; i++)
- INIT_LIST_HEAD(&drvdata->cfg_head[i]);
-
- ret = dcc_sram_dev_init(drvdata);
- if (ret) {
- dev_err(drvdata->dev, "DCC: sram node not registered.\n");
- return ret;
- }
-
- dcc_create_debug_dir(drvdata);
-
- return 0;
-}
-
-static int dcc_remove(struct platform_device *pdev)
-{
- struct dcc_drvdata *drvdata = platform_get_drvdata(pdev);
-
- dcc_delete_debug_dir(drvdata);
- dcc_sram_dev_exit(drvdata);
- dcc_config_reset(drvdata);
-
- return 0;
-}
-
-static const struct of_device_id dcc_match_table[] = {
- { .compatible = "qcom,sc7180-dcc", .data = (void *)0x6000 },
- { .compatible = "qcom,sc7280-dcc", .data = (void *)0x12000 },
- { .compatible = "qcom,sdm845-dcc", .data = (void *)0x6000 },
- { .compatible = "qcom,sm8150-dcc", .data = (void *)0x5000 },
- { }
-};
-MODULE_DEVICE_TABLE(of, dcc_match_table);
-
-static struct platform_driver dcc_driver = {
- .probe = dcc_probe,
- .remove = dcc_remove,
- .driver = {
- .name = "qcom-dcc",
- .of_match_table = dcc_match_table,
- },
-};
-module_platform_driver(dcc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Qualcomm Technologies Inc. DCC driver");
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 3f11554df2f3..33dd8c315eb7 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -12,7 +12,7 @@
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c
index c92d26b73e6f..199fe9872035 100644
--- a/drivers/soc/qcom/ocmem.c
+++ b/drivers/soc/qcom/ocmem.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/types.h>
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
new file mode 100644
index 000000000000..bb3fb57abcc6
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/pdr.h>
+#include <linux/soc/qcom/pmic_glink.h>
+
+struct pmic_glink {
+ struct device *dev;
+ struct pdr_handle *pdr;
+
+ struct rpmsg_endpoint *ept;
+
+ struct auxiliary_device altmode_aux;
+ struct auxiliary_device ps_aux;
+ struct auxiliary_device ucsi_aux;
+
+ /* serializing client_state and pdr_state updates */
+ struct mutex state_lock;
+ unsigned int client_state;
+ unsigned int pdr_state;
+
+ /* serializing clients list updates */
+ struct mutex client_lock;
+ struct list_head clients;
+};
+
+static struct pmic_glink *__pmic_glink;
+static DEFINE_MUTEX(__pmic_glink_lock);
+
+struct pmic_glink_client {
+ struct list_head node;
+
+ struct pmic_glink *pg;
+ unsigned int id;
+
+ void (*cb)(const void *data, size_t len, void *priv);
+ void (*pdr_notify)(void *priv, int state);
+ void *priv;
+};
+
+static void _devm_pmic_glink_release_client(struct device *dev, void *res)
+{
+ struct pmic_glink_client *client = (struct pmic_glink_client *)res;
+ struct pmic_glink *pg = client->pg;
+
+ mutex_lock(&pg->client_lock);
+ list_del(&client->node);
+ mutex_unlock(&pg->client_lock);
+}
+
+struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
+ unsigned int id,
+ void (*cb)(const void *, size_t, void *),
+ void (*pdr)(void *, int),
+ void *priv)
+{
+ struct pmic_glink_client *client;
+ struct pmic_glink *pg = dev_get_drvdata(dev->parent);
+
+ client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->pg = pg;
+ client->id = id;
+ client->cb = cb;
+ client->pdr_notify = pdr;
+ client->priv = priv;
+
+ mutex_lock(&pg->client_lock);
+ list_add(&client->node, &pg->clients);
+ mutex_unlock(&pg->client_lock);
+
+ devres_add(dev, client);
+
+ return client;
+}
+EXPORT_SYMBOL_GPL(devm_pmic_glink_register_client);
+
+int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
+{
+ struct pmic_glink *pg = client->pg;
+
+ return rpmsg_send(pg->ept, data, len);
+}
+EXPORT_SYMBOL_GPL(pmic_glink_send);
+
+static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 addr)
+{
+ struct pmic_glink_client *client;
+ struct pmic_glink_hdr *hdr;
+ struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
+
+ if (len < sizeof(*hdr)) {
+ dev_warn(pg->dev, "ignoring truncated message\n");
+ return 0;
+ }
+
+ hdr = data;
+
+ list_for_each_entry(client, &pg->clients, node) {
+ if (client->id == le32_to_cpu(hdr->owner))
+ client->cb(data, len, client->priv);
+ }
+
+ return 0;
+}
+
+static void pmic_glink_aux_release(struct device *dev) {}
+
+static int pmic_glink_add_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux,
+ const char *name)
+{
+ struct device *parent = pg->dev;
+ int ret;
+
+ aux->name = name;
+ aux->dev.parent = parent;
+ aux->dev.release = pmic_glink_aux_release;
+ device_set_of_node_from_dev(&aux->dev, parent);
+ ret = auxiliary_device_init(aux);
+ if (ret)
+ return ret;
+
+ ret = auxiliary_device_add(aux);
+ if (ret)
+ auxiliary_device_uninit(aux);
+
+ return ret;
+}
+
+static void pmic_glink_del_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux)
+{
+ auxiliary_device_delete(aux);
+ auxiliary_device_uninit(aux);
+}
+
+static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
+{
+ struct pmic_glink_client *client;
+ unsigned int new_state = pg->client_state;
+
+ if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ new_state = SERVREG_SERVICE_STATE_UP;
+ } else {
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ new_state = SERVREG_SERVICE_STATE_DOWN;
+ }
+
+ if (new_state != pg->client_state) {
+ list_for_each_entry(client, &pg->clients, node)
+ client->pdr_notify(client->priv, new_state);
+ pg->client_state = new_state;
+ }
+}
+
+static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
+{
+ struct pmic_glink *pg = priv;
+
+ mutex_lock(&pg->state_lock);
+ pg->pdr_state = state;
+
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+}
+
+static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg = __pmic_glink;
+ int ret = 0;
+
+ mutex_lock(&__pmic_glink_lock);
+ if (!pg) {
+ ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n");
+ goto out_unlock;
+ }
+
+ dev_set_drvdata(&rpdev->dev, pg);
+
+ mutex_lock(&pg->state_lock);
+ pg->ept = rpdev->ept;
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+
+out_unlock:
+ mutex_unlock(&__pmic_glink_lock);
+ return ret;
+}
+
+static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg;
+
+ mutex_lock(&__pmic_glink_lock);
+ pg = __pmic_glink;
+ if (!pg)
+ goto out_unlock;
+
+ mutex_lock(&pg->state_lock);
+ pg->ept = NULL;
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+out_unlock:
+ mutex_unlock(&__pmic_glink_lock);
+}
+
+static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = {
+ { "PMIC_RTR_ADSP_APPS" },
+ {}
+};
+
+static struct rpmsg_driver pmic_glink_rpmsg_driver = {
+ .probe = pmic_glink_rpmsg_probe,
+ .remove = pmic_glink_rpmsg_remove,
+ .callback = pmic_glink_rpmsg_callback,
+ .id_table = pmic_glink_rpmsg_id_match,
+ .drv = {
+ .name = "qcom_pmic_glink_rpmsg",
+ },
+};
+
+static int pmic_glink_probe(struct platform_device *pdev)
+{
+ struct pdr_service *service;
+ struct pmic_glink *pg;
+ int ret;
+
+ pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, pg);
+
+ pg->dev = &pdev->dev;
+
+ INIT_LIST_HEAD(&pg->clients);
+ mutex_init(&pg->client_lock);
+ mutex_init(&pg->state_lock);
+
+ ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
+ if (ret)
+ return ret;
+ ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
+ if (ret)
+ goto out_release_altmode_aux;
+
+ pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
+ if (IS_ERR(pg->pdr)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), "failed to initialize pdr\n");
+ goto out_release_aux_devices;
+ }
+
+ service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
+ if (IS_ERR(service)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
+ "failed adding pdr lookup for charger_pd\n");
+ goto out_release_pdr_handle;
+ }
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = pg;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+
+out_release_pdr_handle:
+ pdr_handle_release(pg->pdr);
+out_release_aux_devices:
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+out_release_altmode_aux:
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+
+ return ret;
+}
+
+static int pmic_glink_remove(struct platform_device *pdev)
+{
+ struct pmic_glink *pg = dev_get_drvdata(&pdev->dev);
+
+ pdr_handle_release(pg->pdr);
+
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = NULL;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+}
+
+static const struct of_device_id pmic_glink_of_match[] = {
+ { .compatible = "qcom,pmic-glink", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
+
+static struct platform_driver pmic_glink_driver = {
+ .probe = pmic_glink_probe,
+ .remove = pmic_glink_remove,
+ .driver = {
+ .name = "qcom_pmic_glink",
+ .of_match_table = pmic_glink_of_match,
+ },
+};
+
+static int pmic_glink_init(void)
+{
+ platform_driver_register(&pmic_glink_driver);
+ register_rpmsg_driver(&pmic_glink_rpmsg_driver);
+
+ return 0;
+};
+module_init(pmic_glink_init);
+
+static void pmic_glink_exit(void)
+{
+ unregister_rpmsg_driver(&pmic_glink_rpmsg_driver);
+ platform_driver_unregister(&pmic_glink_driver);
+};
+module_exit(pmic_glink_exit);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
new file mode 100644
index 000000000000..4d7895bdeaf2
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink_altmode.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/soc/qcom/pdr.h>
+#include <drm/drm_bridge.h>
+
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+
+#include <linux/soc/qcom/pmic_glink.h>
+
+#define PMIC_GLINK_MAX_PORTS 2
+
+#define USBC_SC8180X_NOTIFY_IND 0x13
+#define USBC_CMD_WRITE_REQ 0x15
+#define USBC_NOTIFY_IND 0x16
+
+#define ALTMODE_PAN_EN 0x10
+#define ALTMODE_PAN_ACK 0x11
+
+struct usbc_write_req {
+ struct pmic_glink_hdr hdr;
+ __le32 cmd;
+ __le32 arg;
+ __le32 reserved;
+};
+
+#define NOTIFY_PAYLOAD_SIZE 16
+struct usbc_notify {
+ struct pmic_glink_hdr hdr;
+ char payload[NOTIFY_PAYLOAD_SIZE];
+ u32 reserved;
+};
+
+struct usbc_sc8180x_notify {
+ struct pmic_glink_hdr hdr;
+ __le32 notification;
+ __le32 reserved[2];
+};
+
+enum pmic_glink_altmode_pin_assignment {
+ DPAM_HPD_OUT,
+ DPAM_HPD_A,
+ DPAM_HPD_B,
+ DPAM_HPD_C,
+ DPAM_HPD_D,
+ DPAM_HPD_E,
+ DPAM_HPD_F,
+};
+
+struct pmic_glink_altmode;
+
+#define work_to_altmode_port(w) container_of((w), struct pmic_glink_altmode_port, work)
+
+struct pmic_glink_altmode_port {
+ struct pmic_glink_altmode *altmode;
+ unsigned int index;
+
+ struct typec_switch *typec_switch;
+ struct typec_mux *typec_mux;
+ struct typec_mux_state state;
+ struct typec_altmode dp_alt;
+
+ struct work_struct work;
+
+ struct drm_bridge bridge;
+
+ enum typec_orientation orientation;
+ u16 svid;
+ u8 dp_data;
+ u8 mode;
+ u8 hpd_state;
+ u8 hpd_irq;
+};
+
+#define work_to_altmode(w) container_of((w), struct pmic_glink_altmode, enable_work)
+
+struct pmic_glink_altmode {
+ struct device *dev;
+
+ unsigned int owner_id;
+
+ /* To synchronize WRITE_REQ acks */
+ struct mutex lock;
+
+ struct completion pan_ack;
+ struct pmic_glink_client *client;
+
+ struct work_struct enable_work;
+
+ struct pmic_glink_altmode_port ports[PMIC_GLINK_MAX_PORTS];
+};
+
+static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cmd, u32 arg)
+{
+ struct usbc_write_req req = {};
+ unsigned long left;
+ int ret;
+
+ /*
+ * The USBC_CMD_WRITE_REQ ack doesn't identify the request, so wait for
+ * one ack at a time.
+ */
+ mutex_lock(&altmode->lock);
+
+ req.hdr.owner = cpu_to_le32(altmode->owner_id);
+ req.hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP);
+ req.hdr.opcode = cpu_to_le32(USBC_CMD_WRITE_REQ);
+ req.cmd = cpu_to_le32(cmd);
+ req.arg = cpu_to_le32(arg);
+
+ ret = pmic_glink_send(altmode->client, &req, sizeof(req));
+ if (ret) {
+ dev_err(altmode->dev, "failed to send altmode request: %#x (%d)\n", cmd, ret);
+ goto out_unlock;
+ }
+
+ left = wait_for_completion_timeout(&altmode->pan_ack, 5 * HZ);
+ if (!left) {
+ dev_err(altmode->dev, "timeout waiting for altmode request ack for: %#x\n", cmd);
+ ret = -ETIMEDOUT;
+ }
+
+out_unlock:
+ mutex_unlock(&altmode->lock);
+ return ret;
+}
+
+static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port,
+ u8 mode, bool hpd_state,
+ bool hpd_irq)
+{
+ struct typec_displayport_data dp_data = {};
+ int ret;
+
+ dp_data.status = DP_STATUS_ENABLED;
+ if (hpd_state)
+ dp_data.status |= DP_STATUS_HPD_STATE;
+ if (hpd_irq)
+ dp_data.status |= DP_STATUS_IRQ_HPD;
+ dp_data.conf = DP_CONF_SET_PIN_ASSIGN(mode);
+
+ port->state.alt = &port->dp_alt;
+ port->state.data = &dp_data;
+ port->state.mode = TYPEC_MODAL_STATE(mode);
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to DP\n");
+}
+
+static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port)
+{
+ int ret;
+
+ port->state.alt = NULL;
+ port->state.data = NULL;
+ port->state.mode = TYPEC_STATE_USB;
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to USB\n");
+}
+
+static void pmic_glink_altmode_worker(struct work_struct *work)
+{
+ struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);
+ struct pmic_glink_altmode *altmode = alt_port->altmode;
+
+ typec_switch_set(alt_port->typec_switch, alt_port->orientation);
+
+ if (alt_port->svid == USB_TYPEC_DP_SID)
+ pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode,
+ alt_port->hpd_state, alt_port->hpd_irq);
+ else
+ pmic_glink_altmode_enable_usb(altmode, alt_port);
+
+ if (alt_port->hpd_state)
+ drm_bridge_hpd_notify(&alt_port->bridge, connector_status_connected);
+ else
+ drm_bridge_hpd_notify(&alt_port->bridge, connector_status_disconnected);
+
+ pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
+};
+
+static enum typec_orientation pmic_glink_altmode_orientation(unsigned int orientation)
+{
+ if (orientation == 0)
+ return TYPEC_ORIENTATION_NORMAL;
+ else if (orientation == 1)
+ return TYPEC_ORIENTATION_REVERSE;
+ else
+ return TYPEC_ORIENTATION_NONE;
+}
+
+#define SC8180X_PORT_MASK 0x000000ff
+#define SC8180X_ORIENTATION_MASK 0x0000ff00
+#define SC8180X_MUX_MASK 0x00ff0000
+#define SC8180X_MODE_MASK 0x3f000000
+#define SC8180X_HPD_STATE_MASK 0x40000000
+#define SC8180X_HPD_IRQ_MASK 0x80000000
+
+static void pmic_glink_altmode_sc8180xp_notify(struct pmic_glink_altmode *altmode,
+ const void *data, size_t len)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ const struct usbc_sc8180x_notify *msg;
+ u32 notification;
+ u8 orientation;
+ u8 hpd_state;
+ u8 hpd_irq;
+ u16 svid;
+ u8 port;
+ u8 mode;
+ u8 mux;
+
+ if (len != sizeof(*msg)) {
+ dev_warn(altmode->dev, "invalid length of USBC_NOTIFY indication: %zd\n", len);
+ return;
+ }
+
+ msg = data;
+ notification = le32_to_cpu(msg->notification);
+ port = FIELD_GET(SC8180X_PORT_MASK, notification);
+ orientation = FIELD_GET(SC8180X_ORIENTATION_MASK, notification);
+ mux = FIELD_GET(SC8180X_MUX_MASK, notification);
+ mode = FIELD_GET(SC8180X_MODE_MASK, notification);
+ hpd_state = FIELD_GET(SC8180X_HPD_STATE_MASK, notification);
+ hpd_irq = FIELD_GET(SC8180X_HPD_IRQ_MASK, notification);
+
+ svid = mux == 2 ? USB_TYPEC_DP_SID : 0;
+
+ if (!altmode->ports[port].altmode) {
+ dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
+ return;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->orientation = pmic_glink_altmode_orientation(orientation);
+ alt_port->svid = svid;
+ alt_port->mode = mode;
+ alt_port->hpd_state = hpd_state;
+ alt_port->hpd_irq = hpd_irq;
+ schedule_work(&alt_port->work);
+}
+
+#define SC8280XP_DPAM_MASK 0x3f
+#define SC8280XP_HPD_STATE_MASK BIT(6)
+#define SC8280XP_HPD_IRQ_MASK BIT(7)
+
+static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmode,
+ u16 svid, const void *data, size_t len)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ const struct usbc_notify *notify;
+ u8 orientation;
+ u8 hpd_state;
+ u8 hpd_irq;
+ u8 mode;
+ u8 port;
+
+ if (len != sizeof(*notify)) {
+ dev_warn(altmode->dev, "invalid length USBC_NOTIFY_IND: %zd\n",
+ len);
+ return;
+ }
+
+ notify = data;
+
+ port = notify->payload[0];
+ orientation = notify->payload[1];
+ mode = FIELD_GET(SC8280XP_DPAM_MASK, notify->payload[8]) - DPAM_HPD_A;
+ hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]);
+ hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]);
+
+ if (!altmode->ports[port].altmode) {
+ dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
+ return;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->orientation = pmic_glink_altmode_orientation(orientation);
+ alt_port->svid = svid;
+ alt_port->mode = mode;
+ alt_port->hpd_state = hpd_state;
+ alt_port->hpd_irq = hpd_irq;
+ schedule_work(&alt_port->work);
+}
+
+static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv)
+{
+ struct pmic_glink_altmode *altmode = priv;
+ const struct pmic_glink_hdr *hdr = data;
+ u16 opcode;
+ u16 svid;
+
+ opcode = le32_to_cpu(hdr->opcode) & 0xff;
+ svid = le32_to_cpu(hdr->opcode) >> 16;
+
+ switch (opcode) {
+ case USBC_CMD_WRITE_REQ:
+ complete(&altmode->pan_ack);
+ break;
+ case USBC_NOTIFY_IND:
+ pmic_glink_altmode_sc8280xp_notify(altmode, svid, data, len);
+ break;
+ case USBC_SC8180X_NOTIFY_IND:
+ pmic_glink_altmode_sc8180xp_notify(altmode, data, len);
+ break;
+ }
+}
+
+static int pmic_glink_altmode_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
+}
+
+static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = {
+ .attach = pmic_glink_altmode_attach,
+};
+
+static void pmic_glink_altmode_put_mux(void *data)
+{
+ typec_mux_put(data);
+}
+
+static void pmic_glink_altmode_put_switch(void *data)
+{
+ typec_switch_put(data);
+}
+
+static void pmic_glink_altmode_enable_worker(struct work_struct *work)
+{
+ struct pmic_glink_altmode *altmode = work_to_altmode(work);
+ int ret;
+
+ ret = pmic_glink_altmode_request(altmode, ALTMODE_PAN_EN, 0);
+ if (ret)
+ dev_err(altmode->dev, "failed to request altmode notifications\n");
+}
+
+static void pmic_glink_altmode_pdr_notify(void *priv, int state)
+{
+ struct pmic_glink_altmode *altmode = priv;
+
+ if (state == SERVREG_SERVICE_STATE_UP)
+ schedule_work(&altmode->enable_work);
+}
+
+static const struct of_device_id pmic_glink_altmode_of_quirks[] = {
+ { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)PMIC_GLINK_OWNER_USBC },
+ {}
+};
+
+static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ struct pmic_glink_altmode *altmode;
+ struct typec_altmode_desc mux_desc = {};
+ const struct of_device_id *match;
+ struct fwnode_handle *fwnode;
+ struct device *dev = &adev->dev;
+ u32 port;
+ int ret;
+
+ altmode = devm_kzalloc(dev, sizeof(*altmode), GFP_KERNEL);
+ if (!altmode)
+ return -ENOMEM;
+
+ altmode->dev = dev;
+
+ match = of_match_device(pmic_glink_altmode_of_quirks, dev->parent);
+ if (match)
+ altmode->owner_id = (unsigned long)match->data;
+ else
+ altmode->owner_id = PMIC_GLINK_OWNER_USBC_PAN;
+
+ INIT_WORK(&altmode->enable_work, pmic_glink_altmode_enable_worker);
+ init_completion(&altmode->pan_ack);
+ mutex_init(&altmode->lock);
+
+ device_for_each_child_node(dev, fwnode) {
+ ret = fwnode_property_read_u32(fwnode, "reg", &port);
+ if (ret < 0) {
+ dev_err(dev, "missing reg property of %pOFn\n", fwnode);
+ return ret;
+ }
+
+ if (port >= ARRAY_SIZE(altmode->ports)) {
+ dev_warn(dev, "invalid connector number, ignoring\n");
+ continue;
+ }
+
+ if (altmode->ports[port].altmode) {
+ dev_err(dev, "multiple connector definition for port %u\n", port);
+ return -EINVAL;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->altmode = altmode;
+ alt_port->index = port;
+ INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
+
+ alt_port->bridge.funcs = &pmic_glink_altmode_bridge_funcs;
+ alt_port->bridge.of_node = to_of_node(fwnode);
+ alt_port->bridge.ops = DRM_BRIDGE_OP_HPD;
+ alt_port->bridge.type = DRM_MODE_CONNECTOR_USB;
+
+ ret = devm_drm_bridge_add(dev, &alt_port->bridge);
+ if (ret)
+ return ret;
+
+ alt_port->dp_alt.svid = USB_TYPEC_DP_SID;
+ alt_port->dp_alt.mode = USB_TYPEC_DP_MODE;
+ alt_port->dp_alt.active = 1;
+
+ mux_desc.svid = USB_TYPEC_DP_SID;
+ mux_desc.mode = USB_TYPEC_DP_MODE;
+ alt_port->typec_mux = fwnode_typec_mux_get(fwnode, &mux_desc);
+ if (IS_ERR(alt_port->typec_mux))
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux),
+ "failed to acquire mode-switch for port: %d\n",
+ port);
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux,
+ alt_port->typec_mux);
+ if (ret)
+ return ret;
+
+ alt_port->typec_switch = fwnode_typec_switch_get(fwnode);
+ if (IS_ERR(alt_port->typec_switch))
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch),
+ "failed to acquire orientation-switch for port: %d\n",
+ port);
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch,
+ alt_port->typec_switch);
+ if (ret)
+ return ret;
+ }
+
+ altmode->client = devm_pmic_glink_register_client(dev,
+ altmode->owner_id,
+ pmic_glink_altmode_callback,
+ pmic_glink_altmode_pdr_notify,
+ altmode);
+ return PTR_ERR_OR_ZERO(altmode->client);
+}
+
+static const struct auxiliary_device_id pmic_glink_altmode_id_table[] = {
+ { .name = "pmic_glink.altmode", },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, pmic_glink_altmode_id_table);
+
+static struct auxiliary_driver pmic_glink_altmode_driver = {
+ .name = "pmic_glink_altmode",
+ .probe = pmic_glink_altmode_probe,
+ .id_table = pmic_glink_altmode_id_table,
+};
+
+module_auxiliary_driver(pmic_glink_altmode_driver);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK Altmode driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c
index 6228af057120..c207bb96c523 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -92,7 +92,7 @@ static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused)
/* Items are allocated lazily, so lookup pointer each time */
stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL);
if (IS_ERR(stat))
- return -EIO;
+ return 0;
qcom_print_stats(s, stat);
@@ -170,20 +170,14 @@ static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *
static void qcom_create_subsystem_stat_files(struct dentry *root,
const struct stats_config *config)
{
- const struct sleep_stats *stat;
int i;
if (!config->subsystem_stats_in_smem)
return;
- for (i = 0; i < ARRAY_SIZE(subsystems); i++) {
- stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL);
- if (IS_ERR(stat))
- continue;
-
+ for (i = 0; i < ARRAY_SIZE(subsystems); i++)
debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i],
&qcom_subsystem_sleep_stats_fops);
- }
}
static int qcom_stats_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index 9d59ad509a5c..2d3ee22b9249 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -14,7 +14,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define QCOM_RMTFS_MEM_DEV_MAX (MINORMASK + 1)
#define NUM_MAX_VMIDS 2
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index 7e3b6a7ea34c..523627d5d398 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -233,6 +233,7 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-apq8084" },
{ .compatible = "qcom,rpm-ipq6018" },
+ { .compatible = "qcom,rpm-ipq9574" },
{ .compatible = "qcom,rpm-msm8226" },
{ .compatible = "qcom,rpm-msm8909" },
{ .compatible = "qcom,rpm-msm8916" },
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 3b970a80f3aa..e9012ca1a87b 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -174,6 +174,8 @@ struct socinfo {
__le32 pcode;
__le32 npartnamemap_offset;
__le32 nnum_partname_mapping;
+ /* Version 17 */
+ __le32 oem_variant;
};
#ifdef CONFIG_DEBUG_FS
@@ -196,6 +198,7 @@ struct socinfo_params {
u32 nmodem_supported;
u32 feature_code;
u32 pcode;
+ u32 oem_variant;
};
struct smem_image_version {
@@ -281,6 +284,10 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(MSM8126) },
{ qcom_board_id(APQ8026) },
{ qcom_board_id(MSM8926) },
+ { qcom_board_id(IPQ8062) },
+ { qcom_board_id(IPQ8064) },
+ { qcom_board_id(IPQ8066) },
+ { qcom_board_id(IPQ8068) },
{ qcom_board_id(MSM8326) },
{ qcom_board_id(MSM8916) },
{ qcom_board_id(MSM8994) },
@@ -336,6 +343,8 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(MSM8609) },
{ qcom_board_id(APQ8076) },
{ qcom_board_id(MSM8976) },
+ { qcom_board_id(IPQ8065) },
+ { qcom_board_id(IPQ8069) },
{ qcom_board_id(MDM9650) },
{ qcom_board_id(MDM9655) },
{ qcom_board_id(MDM9250) },
@@ -439,6 +448,8 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(QRU1032) },
{ qcom_board_id(QRU1052) },
{ qcom_board_id(QRU1062) },
+ { qcom_board_id(IPQ5332) },
+ { qcom_board_id(IPQ5322) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
@@ -593,6 +604,11 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
&qcom_socinfo->info.fmt);
switch (qcom_socinfo->info.fmt) {
+ case SOCINFO_VERSION(0, 17):
+ qcom_socinfo->info.oem_variant = __le32_to_cpu(info->oem_variant);
+ debugfs_create_u32("oem_variant", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.oem_variant);
+ fallthrough;
case SOCINFO_VERSION(0, 16):
qcom_socinfo->info.feature_code = __le32_to_cpu(info->feature_code);
qcom_socinfo->info.pcode = __le32_to_cpu(info->pcode);
diff --git a/drivers/thermal/qcom/lmh.c b/drivers/thermal/qcom/lmh.c
index 4122a51e9874..f6edb12ec004 100644
--- a/drivers/thermal/qcom/lmh.c
+++ b/drivers/thermal/qcom/lmh.c
@@ -10,7 +10,7 @@
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define LMH_NODE_DCVS 0x44435653
#define LMH_CLUSTER0_NODE_ID 0x6370302D
diff --git a/drivers/ufs/host/ufs-qcom-ice.c b/drivers/ufs/host/ufs-qcom-ice.c
index 62387ccd5b30..453978877ae9 100644
--- a/drivers/ufs/host/ufs-qcom-ice.c
+++ b/drivers/ufs/host/ufs-qcom-ice.c
@@ -8,7 +8,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include "ufs-qcom.h"
diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h
index 22d7ba17804b..aa95439708dc 100644
--- a/include/dt-bindings/arm/qcom,ids.h
+++ b/include/dt-bindings/arm/qcom,ids.h
@@ -71,6 +71,10 @@
#define QCOM_ID_MSM8126 198
#define QCOM_ID_APQ8026 199
#define QCOM_ID_MSM8926 200
+#define QCOM_ID_IPQ8062 201
+#define QCOM_ID_IPQ8064 202
+#define QCOM_ID_IPQ8066 203
+#define QCOM_ID_IPQ8068 204
#define QCOM_ID_MSM8326 205
#define QCOM_ID_MSM8916 206
#define QCOM_ID_MSM8994 207
@@ -127,6 +131,8 @@
#define QCOM_ID_APQ8076 277
#define QCOM_ID_MSM8976 278
#define QCOM_ID_MDM9650 279
+#define QCOM_ID_IPQ8065 280
+#define QCOM_ID_IPQ8069 281
#define QCOM_ID_MDM9655 283
#define QCOM_ID_MDM9250 284
#define QCOM_ID_MDM9255 285
@@ -229,6 +235,8 @@
#define QCOM_ID_QRU1032 588
#define QCOM_ID_QRU1052 589
#define QCOM_ID_QRU1062 590
+#define QCOM_ID_IPQ5332 592
+#define QCOM_ID_IPQ5322 593
/*
* The board type and revision information, used by Qualcomm bootloaders and
diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h
index 6df4ee400ef8..293e5119354b 100644
--- a/include/dt-bindings/power/qcom-rpmpd.h
+++ b/include/dt-bindings/power/qcom-rpmpd.h
@@ -210,6 +210,7 @@
#define RPMH_REGULATOR_LEVEL_RETENTION 16
#define RPMH_REGULATOR_LEVEL_MIN_SVS 48
#define RPMH_REGULATOR_LEVEL_LOW_SVS 64
+#define RPMH_REGULATOR_LEVEL_LOW_SVS_L1 80
#define RPMH_REGULATOR_LEVEL_SVS 128
#define RPMH_REGULATOR_LEVEL_SVS_L0 144
#define RPMH_REGULATOR_LEVEL_SVS_L1 192
diff --git a/include/linux/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index 1e449a5d7f5c..1e449a5d7f5c 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
diff --git a/include/linux/soc/qcom/pmic_glink.h b/include/linux/soc/qcom/pmic_glink.h
new file mode 100644
index 000000000000..fd124aa18c81
--- /dev/null
+++ b/include/linux/soc/qcom/pmic_glink.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#ifndef __SOC_QCOM_PMIC_GLINK_H__
+#define __SOC_QCOM_PMIC_GLINK_H__
+
+struct pmic_glink;
+struct pmic_glink_client;
+
+#define PMIC_GLINK_OWNER_BATTMGR 32778
+#define PMIC_GLINK_OWNER_USBC 32779
+#define PMIC_GLINK_OWNER_USBC_PAN 32780
+
+#define PMIC_GLINK_REQ_RESP 1
+#define PMIC_GLINK_NOTIFY 2
+
+struct pmic_glink_hdr {
+ __le32 owner;
+ __le32 type;
+ __le32 opcode;
+};
+
+int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len);
+
+struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
+ unsigned int id,
+ void (*cb)(const void *, size_t, void *),
+ void (*pdr)(void *, int),
+ void *priv);
+
+#endif