summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,mmcc.txt1
-rw-r--r--Documentation/devicetree/bindings/media/video/msm-vidc.txt16
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt8
-rw-r--r--arch/arm/boot/dts/qcom/msm-audio.dtsi838
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi16
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi73
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi17
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts1
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi136
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi61
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-rumi.dts9
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-sim.dts4
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi268
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi183
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi79
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi311
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton-rumi.dts5
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi62
-rw-r--r--arch/arm/configs/msmfalcon_defconfig2
-rw-r--r--arch/arm/mach-qcom/Kconfig4
-rw-r--r--arch/arm64/configs/msmfalcon-perf_defconfig2
-rw-r--r--arch/arm64/configs/msmfalcon_defconfig2
-rw-r--r--block/genhd.c1
-rw-r--r--block/ioprio.c2
-rw-r--r--drivers/clk/qcom/Kconfig10
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c3301
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c19
-rw-r--r--drivers/clk/qcom/mmcc-msmfalcon.c3036
-rw-r--r--drivers/clk/qcom/vdd-level-falcon.h15
-rw-r--r--drivers/crypto/msm/qcedev.c120
-rw-r--r--drivers/gpu/msm/adreno-gpulist.h16
-rw-r--r--drivers/gpu/msm/adreno.h2
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c7
-rw-r--r--drivers/hid/hid-core.c3
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c7
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c722
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h59
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c20
-rw-r--r--drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c16
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c10
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c9
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c14
-rw-r--r--drivers/media/tuners/tuner-xc2028.c3
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c34
-rw-r--r--drivers/power/qcom-charger/smb-lib.c5
-rw-r--r--drivers/soc/qcom/Kconfig8
-rw-r--r--drivers/soc/qcom/gladiator_erp_v2.c8
-rw-r--r--drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c2
-rw-r--r--drivers/soc/qcom/scm.c10
-rw-r--r--drivers/soc/qcom/socinfo.c11
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c7
-rw-r--r--drivers/tty/tty_ldisc.c7
-rw-r--r--drivers/usb/gadget/function/f_fs.c10
-rw-r--r--drivers/usb/pd/Kconfig1
-rw-r--r--drivers/usb/pd/policy_engine.c531
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c142
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_panel.c54
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_panel.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c110
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c29
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c51
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c11
-rw-r--r--fs/proc/array.c6
-rw-r--r--include/dt-bindings/clock/audio-ext-clk.h10
-rw-r--r--include/dt-bindings/clock/qcom,mmcc-msmfalcon.h82
-rw-r--r--include/net/cfg80211.h17
-rw-r--r--include/net/tcp.h2
-rw-r--r--kernel/auditsc.c332
-rw-r--r--kernel/cgroup.c2
-rw-r--r--net/netfilter/nfnetlink.c10
-rw-r--r--net/wireless/chan.c2
-rw-r--r--net/wireless/core.c17
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c35
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/sme.c6
-rw-r--r--net/wireless/util.c91
-rw-r--r--sound/soc/codecs/wcd9335.c1
-rw-r--r--sound/soc/msm/msm-dai-fe.c57
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c470
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c12
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c300
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h7
88 files changed, 11245 insertions, 770 deletions
diff --git a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
index 8b0f7841af8d..6aaf89c47781 100644
--- a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
@@ -10,6 +10,7 @@ Required properties :
"qcom,mmcc-msm8960"
"qcom,mmcc-msm8974"
"qcom,mmcc-msm8996"
+ "qcom,mmcc-msmfalcon"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index b1869803d345..50b9b1ac8704 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -183,6 +183,9 @@ Optional properties:
- qcom,bus-rage-kbps : an array of two items (<min max>) that indicate the
minimum and maximum acceptable votes for the bus.
In the absence of this property <0 INT_MAX> is used.
+- qcom,ubwc-10bit : UBWC 10 bit content has different bus requirements,
+ this tag will be used to pick the appropriate bus as per the session profile
+ as shown below in example.
Example:
@@ -270,4 +273,17 @@ Example:
qcom,bus-governor = "msm-vidc-ddr";
qcom,bus-range-kbps = <1000 3388000>;
};
+ qcom,profile-dec-ubwc-10bit {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-10bit;
+ qcom,load-busfreq-tbl =
+ <979200 2446336>, /* UHD30D */
+ <864000 2108416>, /* 720p240D */
+ <489600 1207296>, /* 1080p60D */
+ <432000 1058816>, /* 720p120D */
+ <244800 616448>, /* 1080p30D */
+ <216000 534528>, /* 720p60D */
+ <108000 271360>, /* 720p30D */
+ <0 0>;
+ };
};
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
index 9d8670c7594b..382587ea5922 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
@@ -138,6 +138,14 @@ Charger specific properties:
then charge inhibit will be disabled by default.
Allowed values are: 50, 100, 200, 300.
+- qcom,auto-recharge-soc
+ Usage: optional
+ Value type: <empty>
+ Definition: Specifies if automatic recharge needs to be based off battery
+ SOC. If this property is not specified, then auto recharge will
+ be based off battery voltage. For both SOC and battery voltage,
+ charger receives the signal from FG to resume charging.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi
new file mode 100644
index 000000000000..74c1779e6fca
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi
@@ -0,0 +1,838 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ compr: qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "regular";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ pcm_noirq: qcom,msm-pcm-dsp-noirq {
+ compatible = "qcom,msm-pcm-dsp-noirq";
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
+ cpe3: qcom,msm-cpe-lsm@3 {
+ compatible = "qcom,msm-cpe-lsm";
+ qcom,msm-cpe-lsm-id = <3>;
+ };
+
+ compress: qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ };
+
+ voip: qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ voice: qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ stub_codec: qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ afe: qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
+ loopback: qcom,msm-pcm-loopback {
+ compatible = "qcom,msm-pcm-loopback";
+ };
+
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <1>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s2: qcom,msm-dai-q6-mi2s-tert {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <2>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_mi2s5: qcom,msm-dai-q6-mi2s-quin {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <5>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s6: qcom,msm-dai-q6-mi2s-senary {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <6>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <7>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <8>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <9>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <10>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <11>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <12>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <13>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+ };
+
+ lsm: qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ sb_0_rx: qcom,msm-dai-q6-sb-0-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16384>;
+ };
+
+ sb_0_tx: qcom,msm-dai-q6-sb-0-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16385>;
+ };
+
+ sb_1_rx: qcom,msm-dai-q6-sb-1-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16386>;
+ };
+
+ sb_1_tx: qcom,msm-dai-q6-sb-1-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16387>;
+ };
+
+ sb_2_rx: qcom,msm-dai-q6-sb-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16388>;
+ };
+
+ sb_2_tx: qcom,msm-dai-q6-sb-2-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16389>;
+ };
+
+
+ sb_3_rx: qcom,msm-dai-q6-sb-3-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16390>;
+ };
+
+ sb_3_tx: qcom,msm-dai-q6-sb-3-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16391>;
+ };
+
+ sb_4_rx: qcom,msm-dai-q6-sb-4-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16392>;
+ };
+
+ sb_4_tx: qcom,msm-dai-q6-sb-4-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16393>;
+ };
+
+ sb_5_tx: qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
+ sb_5_rx: qcom,msm-dai-q6-sb-5-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16394>;
+ };
+
+ sb_6_rx: qcom,msm-dai-q6-sb-6-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16396>;
+ };
+
+ sb_7_tx: qcom,msm-dai-q6-sb-7-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16399>;
+ };
+
+ sb_7_rx: qcom,msm-dai-q6-sb-7-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16398>;
+ };
+
+ sb_8_tx: qcom,msm-dai-q6-sb-8-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16401>;
+ };
+
+ sb_8_rx: qcom,msm-dai-q6-sb-8-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16400>;
+ };
+
+ bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+
+ usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28672>;
+ };
+
+ usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28673>;
+ };
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ };
+
+ dai_sec_auxpcm: qcom,msm-sec-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "secondary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_tert_auxpcm: qcom,msm-tert-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "tertiary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_quat_auxpcm: qcom,msm-quat-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "quaternary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,smmu-version = <2>;
+ qcom,smmu-enabled;
+ iommus = <&lpass_q6_smmu 1>;
+ };
+
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
+
+ qcom,msm-dai-tdm-pri-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37120>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36864>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36864>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-pri-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37121>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36865>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36865>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37136>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36880>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36880>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-tert-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37152>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36896>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-tert-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37153>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36897 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36897 >;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-quat-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37168>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36912>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36912>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-quat-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37169>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36913 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36913 >;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,avtimer@150f700c {
+ compatible = "qcom,avtimer";
+ reg = <0x150f700c 0x4>,
+ <0x150f7010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <27>;
+ };
+
+ tasha_snd: sound-9335 {
+ compatible = "qcom,msmfalcon-asoc-snd-tasha";
+ qcom,model = "msmfalcon-tasha-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+ reg = <0x1508a000 0x4>,
+ <0x1508b000 0x4>,
+ <0x1508c000 0x4>,
+ <0x1508d000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "AMIC6", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic6",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,us-euro-gpios = <&us_euro_gpio>;
+ qcom,tasha-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>, <&cpe3>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq",
+ "msm-cpe-lsm.3";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672",
+ "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896",
+ "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912",
+ "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ tavil_snd: sound-tavil {
+ compatible = "qcom,msmfalcon-asoc-snd-tavil";
+ qcom,model = "msmfalcon-tavil-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+ reg = <0x1508a000 0x4>,
+ <0x1508b000 0x4>,
+ <0x1508c000 0x4>,
+ <0x1508d000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,us-euro-gpios = <&tavil_us_euro_sw>;
+ qcom,hph-en0-gpio = <&tavil_hph_en0>;
+ qcom,hph-en1-gpio = <&tavil_hph_en1>;
+ qcom,tavil-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672",
+ "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896",
+ "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912",
+ "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+
+ us_euro_gpio: msm_cdc_pinctrl@75 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wcd_gnd_mic_swap_active>;
+ pinctrl-1 = <&wcd_gnd_mic_swap_idle>;
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ qcom,gpio-connect = <&tlmm 54 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
+ };
+
+ clock_audio: audio_ext_clk {
+ compatible = "qcom,audio-ref-clk";
+ qcom,audio-ref-clk-gpio = <&pmfalcon_gpios 3 0>;
+ clock-names = "osr_clk";
+ clocks = <&clock_gcc clk_div_clk1>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&spkr_i2s_clk_sleep>;
+ pinctrl-1 = <&spkr_i2s_clk_active>;
+ };
+
+ clock_audio_lnbb: audio_ext_clk_lnbb {
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ clocks = <&clock_gcc clk_ln_bb_clk2>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ };
+
+ wcd_rst_gpio: msm_cdc_pinctrl@64 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+
+};
+
diff --git a/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi
new file mode 100644
index 000000000000..dcf7030a78e4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi
@@ -0,0 +1,16 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Disable WLED */
+&pm2falcon_wled {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
index 8f8bdf2e899c..93cfab700aa9 100644
--- a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
@@ -402,6 +402,29 @@
};
};
+ pmfalcon_pdphy: qcom,usb-pdphy@1700 {
+ compatible = "qcom,qpnp-pdphy";
+ reg = <0x1700 0x100>;
+ vdd-pdphy-supply = <&pm2falcon_l7>;
+ vbus-supply = <&smb2_vbus>;
+ vconn-supply = <&smb2_vconn>;
+ interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "sig-tx",
+ "sig-rx",
+ "msg-tx",
+ "msg-rx",
+ "msg-tx-failed",
+ "msg-tx-discarded",
+ "msg-rx-discarded";
+ };
+
pmfalcon_adc_tm: vadc@3400 {
compatible = "qcom,qpnp-adc-tm-hc";
reg = <0x3400 0x100>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi
new file mode 100644
index 000000000000..20c69e0a9a1a
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi
@@ -0,0 +1,73 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&clock_audio {
+ qcom,audio-ref-clk-gpio = <&pmfalcon_gpios 3 0>;
+};
+
+&slim_aud {
+ tasha_codec {
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+ };
+
+ tavil_codec {
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+ };
+};
+
+&pmfalcon_gpios {
+ gpio@c200 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi
index 861be92a7bc2..1ca5ce6eabbb 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi
@@ -1853,7 +1853,7 @@
<61 512 240000 800000>;
qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
- extcon = <&pmi8998_pdphy>;
+ extcon = <&pmfalcon_pdphy>;
clocks = <&clock_gcc clk_gcc_usb30_master_clk>,
<&clock_gcc clk_gcc_cfg_noc_usb3_axi_clk>,
@@ -1921,9 +1921,9 @@
<0x01fcb24c 0x4>;
reg-names = "qusb_phy_base",
"tcsr_clamp_dig_n_1p8";
- vdd-supply = <&pm8998_l1>;
- vdda18-supply = <&pm8998_l12>;
- vdda33-supply = <&pm8998_l24>;
+ vdd-supply = <&pm2falcon_l1>;
+ vdda18-supply = <&pm2falcon_l10>;
+ vdda33-supply = <&pm2falcon_l7>;
qcom,vdd-voltage-level = <0 880000 880000>;
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
@@ -1951,8 +1951,8 @@
reg-names = "qmp_phy_base",
"vls_clamp_reg",
"tcsr_usb3_dp_phymode";
- vdd-supply = <&pm8998_l1>;
- core-supply = <&pm8998_l2>;
+ vdd-supply = <&pm2falcon_l1>;
+ core-supply = <&pmfalcon_l1>;
qcom,vdd-voltage-level = <0 880000 880000>;
qcom,vbus-valid-override;
qcom,qmp-phy-init-seq =
@@ -3083,12 +3083,11 @@
#include "msm8998-bus.dtsi"
#include "msm8998-gpu.dtsi"
#include "msm8998-pinctrl.dtsi"
-#include "msm-audio-lpass.dtsi"
#include "msm8998-mdss.dtsi"
#include "msm8998-mdss-pll.dtsi"
#include "msm8998-blsp.dtsi"
-#include "msm8998-audio.dtsi"
-
+#include "msm-audio.dtsi"
+#include "msmfalcon-audio.dtsi"
/* GPU overrides */
&msm_gpu {
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
index 3a7767cf2f2e..03e6a7e17215 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
@@ -16,6 +16,7 @@
#include "msm8998-v2.1-interposer-msmfalcon.dtsi"
#include "msm8998-interposer-msmfalcon-cdp.dtsi"
#include "msm8998-interposer-pmfalcon.dtsi"
+#include "msm8998-interposer-msmfalcon-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MSM FALCON Interposer CDP";
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
index 662086f0190f..b66e4bbe236f 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
@@ -16,6 +16,7 @@
#include "msm8998-v2.1-interposer-msmfalcon.dtsi"
#include "msm8998-interposer-msmfalcon-mtp.dtsi"
#include "msm8998-interposer-pmfalcon.dtsi"
+#include "msm8998-interposer-msmfalcon-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MSM FALCON Interposer MTP";
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi
new file mode 100644
index 000000000000..b6b3c1f6245f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msmfalcon-wsa881x.dtsi"
+
+&slim_aud {
+ msm_dai_slim {
+ compatible = "qcom,msm-dai-slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ tasha_codec {
+ compatible = "qcom,tasha-slim-pgd";
+ elemental-addr = [00 01 a0 01 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk", "wcd_native_clk";
+ clocks = <&clock_audio clk_audio_pmi_clk>,
+ <&clock_audio clk_audio_ap_clk2>;
+
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vddpx-1";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tasha-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+ };
+
+ wcd934x_cdc: tavil_codec {
+ compatible = "qcom,tavil-slim-pgd";
+ elemental-addr = [00 01 50 02 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30 31>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk";
+ clocks = <&clock_audio_lnbb clk_audio_pmi_lnbb_clk>;
+
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vddpx-1";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tavil-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+
+ qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+
+ wcd_spi_0: wcd_spi {
+ compatible = "qcom,wcd-spi-v2";
+ qcom,master-bus-num = <10>;
+ qcom,chip-select = <0>;
+ qcom,max-frequency = <24000000>;
+ qcom,mem-base-addr = <0x100000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
index 90aa771332a3..a029d8689111 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
@@ -595,6 +595,67 @@
};
};
+ /* WSA speaker reset pins */
+ spkr_1_sd_n {
+ spkr_1_sd_n_sleep: spkr_1_sd_n_sleep {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio26";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_1_sd_n_active: spkr_1_sd_n_active {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio26";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ spkr_2_sd_n {
+ spkr_2_sd_n_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio27";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_2_sd_n_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio27";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
/* HS UART CONFIGURATION */
blsp1_uart1_active: blsp1_uart1_active {
mux {
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
index 1575cea079ce..2b8a78ee1fdc 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
@@ -102,3 +102,12 @@
&pmfalcon_fg {
status = "disabled";
};
+
+&clock_gfx {
+ compatible = "qcom,dummycc";
+ clock-output-names = "gfx_clocks";
+};
+
+&pmfalcon_pdphy {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
index 4e83266e884f..d279e742c23a 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
@@ -81,3 +81,7 @@
&pmfalcon_fg {
status = "disabled";
};
+
+&pmfalcon_pdphy {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi
new file mode 100644
index 000000000000..73d1cac48f9e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi
@@ -0,0 +1,268 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/clock/qcom,gcc-msmfalcon.h>
+#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+
+&soc {
+ msm_vidc: qcom,vidc@cc00000 {
+ compatible = "qcom,msm-vidc";
+ status = "ok";
+ reg = <0xcc00000 0x100000>;
+ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,hfi = "venus";
+ qcom,hfi-version = "3xx";
+ qcom,firmware-name = "venus";
+ qcom,sw-power-collapse;
+ qcom,debug-timeout;
+ qcom,reg-presets =
+ <0x80124 0x00000003>,
+ <0x80550 0x01111111>,
+ <0x80560 0x01111111>,
+ <0x80568 0x01111111>,
+ <0x80570 0x01111111>,
+ <0x80580 0x01111111>,
+ <0x80588 0x01111111>,
+ <0xe2010 0x00000000>;
+
+ qcom,max-hw-load = <1036800>; /* Full 4k @ 30 */
+ qcom,allowed-clock-rates =
+ /* TURBO NOM+ NOM
+ * SVS+ SVS SVS-
+ */
+ <518400000 441600000 404000000
+ 320000000 269330000 133330000>;
+
+ qcom,dcvs-tbl =
+ /* Dec UHD@30 All decoder - NOM to SVS+ */
+ <897600 734400 979200 0x3f00000c>,
+
+ /* Dec DCI@24 HEVC - NOM to SVS+ */
+ <816000 734400 829440 0x0c000000>,
+
+ /* Enc UHD@30 H264/HEVC - TURBO to NOM+ */
+ <897600 897600 979200 0x4000004>;
+ qcom,dcvs-limit =
+ <32400 30>, /* Encoder UHD */
+ <32400 24>; /* Decoder UHD */
+
+ /* Regulators */
+ smmu-vdd-supply = <&gdsc_bimc_smmu>;
+ venus-supply = <&gdsc_venus>;
+ venus-core0-supply = <&gdsc_venus_core0>;
+
+ /* Clocks */
+ clock-names = "gcc_mmss_sys_noc_axi_clk",
+ "mmssnoc_axi_clk", "mmss_mnoc_ahb_clk",
+ "mmss_bimc_smmu_ahb_clk", "mmss_bimc_smmu_axi_clk",
+ "mmss_video_core_clk", "mmss_video_ahb_clk",
+ "mmss_video_axi_clk",
+ "mmss_video_core0_clk";
+ clocks = <&clock_gcc GCC_MMSS_SYS_NOC_AXI_CLK>,
+ <&clock_gcc MMSSNOC_AXI_CLK>,
+ <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>,
+ <&clock_mmss MMSS_VIDEO_CORE_CLK>,
+ <&clock_mmss MMSS_VIDEO_AHB_CLK>,
+ <&clock_mmss MMSS_VIDEO_AXI_CLK>,
+ <&clock_mmss MMSS_VIDEO_SUBCORE0_CLK>;
+ qcom,clock-configs = <0x0 0x0 0x0 0x0 0x0
+ 0x3 0x0 0x2 0x3>;
+
+ /* Buses */
+ bus_cnoc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "cnoc";
+ qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "venus-ddr-gov";
+ qcom,bus-range-kbps = <1000 2365000>;
+ };
+
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+
+ qcom,clock-freq-tbl {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,cycles-per-mb = <863>;
+ qcom,low-power-mode-factor = <35616>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xf3ffffff>;
+ qcom,cycles-per-mb = <355>;
+ };
+ qcom,profile-hevcdec {
+ qcom,codec-mask = <0x0c000000>;
+ qcom,cycles-per-mb = <400>;
+ };
+ };
+
+ venus-ddr-gov {
+ compatible = "qcom,msm-vidc,governor,table";
+ name = "venus-ddr-gov";
+ status = "ok";
+ qcom,bus-freq-table {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,load-busfreq-tbl =
+ <979200 1044000>, /* UHD30E */
+ <864000 887000>, /* 720p240LPE */
+ <489600 666000>, /* 1080p60E */
+ <432000 578000>, /* 720p120E */
+ <244800 346000>, /* 1080p30E */
+ <216000 293000>, /* 720p60E */
+ <108000 151000>, /* 720p30E */
+ <0 0>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,load-busfreq-tbl =
+ <979200 2365000>, /* UHD30D */
+ <864000 1978000>, /* 720p240D */
+ <489600 1133000>, /* 1080p60D */
+ <432000 994000>, /* 720p120D */
+ <244800 580000>, /* 1080p30D */
+ <216000 501000>, /* 720p60E */
+ <108000 255000>, /* 720p30D */
+ <0 0>;
+ };
+ qcom,profile-dec-ubwc {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-mode;
+ qcom,load-busfreq-tbl =
+ <979200 1892000>, /* UHD30D */
+ <864000 1554000>, /* 720p240D */
+ <489600 895000>, /* 1080p60D */
+ <432000 781000>, /* 720p120D */
+ <244800 460000>, /* 1080p30D */
+ <216000 301000>, /* 720p60E */
+ <108000 202000>, /* 720p30D */
+ <0 0>;
+ };
+ qcom,profile-dec-ubwc-10bit {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-10bit;
+ qcom,load-busfreq-tbl =
+ <979200 2446336>, /* UHD30D */
+ <864000 2108416>, /* 720p240D */
+ <489600 1207296>, /* 1080p60D */
+ <432000 1058816>, /* 720p120D */
+ <244800 616448>, /* 1080p30D */
+ <216000 534528>, /* 720p60D */
+ <108000 271360>, /* 720p30D */
+ <0 0>;
+ };
+ };
+ };
+
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus =
+ <&mmss_bimc_smmu 0x400>,
+ <&mmss_bimc_smmu 0x401>,
+ <&mmss_bimc_smmu 0x40a>,
+ <&mmss_bimc_smmu 0x407>,
+ <&mmss_bimc_smmu 0x40e>,
+ <&mmss_bimc_smmu 0x40f>,
+ <&mmss_bimc_smmu 0x408>,
+ <&mmss_bimc_smmu 0x409>,
+ <&mmss_bimc_smmu 0x40b>,
+ <&mmss_bimc_smmu 0x40c>,
+ <&mmss_bimc_smmu 0x40d>,
+ <&mmss_bimc_smmu 0x410>,
+ <&mmss_bimc_smmu 0x421>,
+ <&mmss_bimc_smmu 0x428>,
+ <&mmss_bimc_smmu 0x429>,
+ <&mmss_bimc_smmu 0x42b>,
+ <&mmss_bimc_smmu 0x42c>,
+ <&mmss_bimc_smmu 0x42d>,
+ <&mmss_bimc_smmu 0x411>,
+ <&mmss_bimc_smmu 0x431>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x70800000 0x8f800000>;
+ };
+
+ firmware_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ qcom,fw-context-bank;
+ iommus = <&mmss_bimc_smmu 0x580>,
+ <&mmss_bimc_smmu 0x586>;
+ };
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus = <&mmss_bimc_smmu 0x500>,
+ <&mmss_bimc_smmu 0x502>,
+ <&mmss_bimc_smmu 0x509>,
+ <&mmss_bimc_smmu 0x50a>,
+ <&mmss_bimc_smmu 0x50b>,
+ <&mmss_bimc_smmu 0x50e>,
+ <&mmss_bimc_smmu 0x526>,
+ <&mmss_bimc_smmu 0x529>,
+ <&mmss_bimc_smmu 0x52b>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ venus_secure_pixel_cb: secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus = <&mmss_bimc_smmu 0x504>,
+ <&mmss_bimc_smmu 0x50c>,
+ <&mmss_bimc_smmu 0x510>,
+ <&mmss_bimc_smmu 0x52c>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ venus_secure_non_pixel_cb: secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus = <&mmss_bimc_smmu 0x505>,
+ <&mmss_bimc_smmu 0x507>,
+ <&mmss_bimc_smmu 0x508>,
+ <&mmss_bimc_smmu 0x50d>,
+ <&mmss_bimc_smmu 0x50f>,
+ <&mmss_bimc_smmu 0x525>,
+ <&mmss_bimc_smmu 0x528>,
+ <&mmss_bimc_smmu 0x52d>,
+ <&mmss_bimc_smmu 0x540>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi
new file mode 100644
index 000000000000..29f4ccaede9f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi
@@ -0,0 +1,183 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&slim_aud {
+ tasha_codec {
+ wsa_spkr_sd1: msm_cdc_pinctrll {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_sd_n_active>;
+ pinctrl-1 = <&spkr_1_sd_n_sleep>;
+ };
+
+ wsa_spkr_sd2: msm_cdc_pinctrlr {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_sd_n_active>;
+ pinctrl-1 = <&spkr_2_sd_n_sleep>;
+ };
+ };
+
+ tavil_codec {
+ wcd: wcd_pinctrl@5 {
+ compatible = "qcom,wcd-pinctrl";
+ qcom,num-gpios = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ us_euro_sw_wcd_active: us_euro_sw_wcd_active {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-high;
+ };
+ };
+
+ us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-low;
+ };
+ };
+
+ spkr_1_wcd_en_active: spkr_1_wcd_en_active {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ output-high;
+ };
+ };
+
+ spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ input-enable;
+ };
+ };
+
+ spkr_2_wcd_en_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ output-high;
+ };
+ };
+
+ spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ input-enable;
+ };
+ };
+
+ hph_en0_wcd_active: hph_en0_wcd_active {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-high;
+ };
+ };
+
+ hph_en0_wcd_sleep: hph_en0_wcd_sleep {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-low;
+ };
+ };
+
+ hph_en1_wcd_active: hph_en1_wcd_active {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-high;
+ };
+ };
+
+ hph_en1_wcd_sleep: hph_en1_wcd_sleep {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-low;
+ };
+ };
+ };
+
+ wsa_spkr_wcd_sd1: msm_cdc_pinctrll {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_wcd_en_active>;
+ pinctrl-1 = <&spkr_1_wcd_en_sleep>;
+ };
+
+ wsa_spkr_wcd_sd2: msm_cdc_pinctrlr {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_wcd_en_active>;
+ pinctrl-1 = <&spkr_2_wcd_en_sleep>;
+ };
+
+ tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&us_euro_sw_wcd_active>;
+ pinctrl-1 = <&us_euro_sw_wcd_sleep>;
+ };
+
+ tavil_hph_en0: msm_cdc_pinctrl_hph_en0 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en0_wcd_active>;
+ pinctrl-1 = <&hph_en0_wcd_sleep>;
+ };
+
+ tavil_hph_en1: msm_cdc_pinctrl_hph_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en1_wcd_active>;
+ pinctrl-1 = <&hph_en1_wcd_sleep>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi
new file mode 100644
index 000000000000..123f922facdd
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi
@@ -0,0 +1,79 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msmfalcon-wcd.dtsi"
+
+&slim_aud {
+ tasha_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd1>;
+ };
+
+ wsa881x_212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd2>;
+ };
+
+ wsa881x_213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd1>;
+ };
+
+ wsa881x_214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd2>;
+ };
+ };
+ };
+
+ tavil_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_0211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+
+ wsa881x_0213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index e2f5e32cc544..ed8bee03b4d0 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -47,6 +47,7 @@
compatible = "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
};
CPU1: cpu@1 {
@@ -54,6 +55,7 @@
compatible = "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
};
CPU2: cpu@2 {
@@ -61,6 +63,7 @@
compatible = "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
};
CPU3: cpu@3 {
@@ -68,6 +71,7 @@
compatible = "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
};
CPU4: cpu@100 {
@@ -75,6 +79,7 @@
compatible = "arm,armv8";
reg = <0x0 0x100>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile1>;
};
CPU5: cpu@101 {
@@ -82,6 +87,7 @@
compatible = "arm,armv8";
reg = <0x0 0x101>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile2>;
};
CPU6: cpu@102 {
@@ -89,6 +95,7 @@
compatible = "arm,armv8";
reg = <0x0 0x102>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile3>;
};
CPU7: cpu@103 {
@@ -96,6 +103,7 @@
compatible = "arm,armv8";
reg = <0x0 0x103>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile4>;
};
cpu-map {
@@ -265,6 +273,13 @@
qcom,summing-threshold = <0x10>;
};
+ restart@10ac000 {
+ compatible = "qcom,pshold";
+ reg = <0x10ac000 0x4>,
+ <0x1fd3000 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
spmi_bus: qcom,spmi@800f000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0x800f000 0x1000>,
@@ -351,6 +366,180 @@
clock-names = "core", "iface";
};
+ qcom,sensor-information {
+ compatible = "qcom,sensor-information";
+ sensor_information0: qcom,sensor-information-0 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor0";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information1: qcom,sensor-information-1 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor1";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information2: qcom,sensor-information-2 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor2";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information3: qcom,sensor-information-3 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor3";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information4: qcom,sensor-information-4 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor4";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information5: qcom,sensor-information-5 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor5";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information6: qcom,sensor-information-6 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor6";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information7: qcom,sensor-information-7 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor7";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information8: qcom,sensor-information-8 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor8";
+ qcom,scaling-factor = <10>;
+ qcom,alias-name = "gpu";
+ };
+ sensor_information9: qcom,sensor-information-9 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor9";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information10: qcom,sensor-information-10 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor10";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information11: qcom,sensor-information-11 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor11";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information12: qcom,sensor-information-12 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor12";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information13: qcom,sensor-information-13 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor13";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information14: qcom,sensor-information-14 {
+ qcom,sensor-type = "alarm";
+ qcom,sensor-name = "pmfalcon_tz";
+ qcom,scaling-factor = <1000>;
+ };
+ sensor_information15: qcom,sensor-information-15 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "msm_therm";
+ };
+ sensor_information16: qcom,sensor-information-16 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "xo_therm";
+ };
+ sensor_information17: qcom,sensor-information-17 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "pa_therm0";
+ };
+ sensor_information18: qcom,sensor-information-18 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "pa_therm1";
+ };
+ sensor_information19: qcom,sensor-information-19 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "quiet_therm";
+ };
+ sensor_information20: qcom,sensor-information-20 {
+ qcom,sensor-type = "llm";
+ qcom,sensor-name = "limits_sensor-00";
+ };
+ sensor_information21: qcom,sensor-information-21 {
+ qcom,sensor-type = "llm";
+ qcom,sensor-name = "limits_sensor-01";
+ };
+ };
+
+ mitigation_profile0: qcom,limit_info-0 {
+ qcom,temperature-sensor = <&sensor_information1>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile1: qcom,limit_info-1 {
+ qcom,temperature-sensor = <&sensor_information3>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile2: qcom,limit_info-2 {
+ qcom,temperature-sensor = <&sensor_information4>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile3: qcom,limit_info-3 {
+ qcom,temperature-sensor = <&sensor_information5>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile4: qcom,limit_info-4 {
+ qcom,temperature-sensor = <&sensor_information6>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ qcom,msm-thermal {
+ compatible = "qcom,msm-thermal";
+ qcom,sensor-id = <1>;
+ qcom,poll-ms = <100>;
+ qcom,therm-reset-temp = <115>;
+ qcom,core-limit-temp = <70>;
+ qcom,core-temp-hysteresis = <10>;
+ qcom,hotplug-temp = <105>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,online-hotplug-core;
+ qcom,synchronous-cluster-id = <0 1>;
+ qcom,synchronous-cluster-map = <0 4 &CPU0 &CPU1 &CPU2 &CPU3>,
+ <1 4 &CPU4 &CPU5 &CPU6 &CPU7>;
+
+ qcom,vdd-restriction-temp = <5>;
+ qcom,vdd-restriction-temp-hysteresis = <10>;
+
+ vdd-dig-supply = <&pm2falcon_s3_floor_level>;
+ vdd-gfx-supply = <&gfx_vreg_corner>;
+
+ qcom,vdd-dig-rstr{
+ qcom,vdd-rstr-reg = "vdd-dig";
+ qcom,levels = <RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,min-level = <RPM_SMD_REGULATOR_LEVEL_NONE>;
+ };
+
+ qcom,vdd-gfx-rstr{
+ qcom,vdd-rstr-reg = "vdd-gfx";
+ qcom,levels = <5 6 6>; /* Nominal, Turbo, Turbo */
+ qcom,min-level = <1>; /* No Request */
+ };
+
+ msm_thermal_freq: qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd-apps";
+ qcom,levels = <1248000>;
+ qcom,freq-req;
+ };
+ };
+
uartblsp2dm1: serial@0c1b0000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xc1b0000 0x1000>;
@@ -467,8 +656,21 @@
};
clock_gfx: clock-controller@5065000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gfx_clocks";
+ compatible = "qcom,gpucc-msmfalcon";
+ reg = <0x5065000 0x10000>;
+ vdd_dig_gfx-supply = <&pm2falcon_s3_level>;
+ vdd_mx_gfx-supply = <&pm2falcon_s5_level>;
+ vdd_gfx-supply = <&gfx_vreg_corner>;
+ qcom,gfxfreq-corner =
+ < 0 0>,
+ < 160000000 1>, /* MinSVS */
+ < 266000000 2>, /* LowSVS */
+ < 370000000 3>, /* SVS */
+ < 465000000 4>, /* SVS_L1 */
+ < 588000000 5>, /* NOM */
+ < 647000000 6>, /* NOM_L1 */
+ < 700000000 7>, /* TURBO */
+ < 750000000 7>; /* TURBO */
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -493,6 +695,72 @@
status = "disabled";
};
+ ipa_hw: qcom,ipa@14780000 {
+ compatible = "qcom,ipa";
+ reg = <0x14780000 0x4effc>, <0x14784000 0x26934>;
+ reg-names = "ipa-base", "bam-base";
+ interrupts = <0 333 0>,
+ <0 432 0>;
+ interrupt-names = "ipa-irq", "bam-irq";
+ qcom,ipa-hw-ver = <6>; /* IPA core version = IPAv2.6L */
+ qcom,ipa-hw-mode = <0>; /* IPA hw type = Normal */
+ qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/
+ qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/
+ clocks = <&clock_rpmcc RPM_IPA_CLK>,
+ <&clock_rpmcc RPM_AGGR2_NOC_CLK>;
+ clock-names = "core_clk", "smmu_clk";
+ qcom,arm-smmu;
+ qcom,smmu-disable-htw;
+ qcom,smmu-s1-bypass;
+ qcom,ee = <0>;
+ qcom,use-ipa-tethering-bridge;
+ qcom,modem-cfg-emb-pipe-flt;
+ qcom,msm-bus,name = "ipa";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <90 512 0 0>,
+ <1 676 0 0>,
+ /* SVS */
+ <90 512 80000 640000>,
+ <1 676 80000 80000>,
+ /* NOMINAL */
+ <90 512 206000 960000>,
+ <1 676 206000 160000>,
+ /* TURBO */
+ <90 512 206000 960000>,
+ <1 676 206000 160000>;
+ qcom,bus-vector-names = "MIN", "SVS", "PERF", "TURBO";
+ qcom,rx-polling-sleep-ms = <2>; /* Polling sleep interval */
+ qcom,ipa-polling-iteration = <5>; /* Polling Iteration */
+
+ ipa_smmu_ap: ipa_smmu_ap {
+ compatible = "qcom,ipa-smmu-ap-cb";
+ iommus = <&anoc2_smmu 0x19C0>;
+ qcom,iova-mapping = <0x10000000 0x40000000>;
+ };
+
+ ipa_smmu_wlan: ipa_smmu_wlan {
+ status = "disabled";
+ compatible = "qcom,ipa-smmu-wlan-cb";
+ iommus = <&anoc2_smmu 0x19C1>;
+ };
+
+ ipa_smmu_uc: ipa_smmu_uc {
+ compatible = "qcom,ipa-smmu-uc-cb";
+ iommus = <&anoc2_smmu 0x19C2>;
+ qcom,iova-mapping = <0x40000000 0x20000000>;
+ };
+ };
+
+ qcom,rmnet-ipa {
+ compatible = "qcom,rmnet-ipa";
+ qcom,rmnet-ipa-ssr;
+ qcom,ipa-loaduC;
+ qcom,ipa-advertise-sg-support;
+ };
+
qcom,ipc-spinlock@1f40000 {
compatible = "qcom,ipc-spinlock-sfpb";
reg = <0x1f40000 0x8000>;
@@ -877,6 +1145,17 @@
status = "ok";
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>;
+ };
+
+ qcom,mpm2-sleep-counter@10a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x10a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom,msm-imem@146bf000 {
compatible = "qcom,msm-imem";
reg = <0x146bf000 0x1000>;
@@ -884,6 +1163,21 @@
#address-cells = <1>;
#size-cells = <1>;
+ dload_type@18 {
+ compatible = "qcom,msm-imem-dload-type";
+ reg = <0x18 4>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
@@ -906,6 +1200,12 @@
clock-names = "atb_clk";
clocks = <&clock_rpmcc RPM_QDSS_CLK>;
};
+
+ cpu_pmu: cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ qcom,irq-is-percpu;
+ interrupts = <1 6 4>;
+ };
};
#include "msmfalcon-ion.dtsi"
@@ -985,10 +1285,8 @@
};
&gdsc_gpu_gx {
- clock-names = "bimc_core_clk", "core_clk", "core_root_clk";
- clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>,
- <&clock_gfx GPUCC_GFX3D_CLK>,
- <&clock_gfx GFX3D_CLK_SRC>;
+ clock-names = "core_root_clk";
+ clocks = <&clock_gfx GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
parent-supply = <&gfx_vreg_corner>;
status = "ok";
@@ -1002,3 +1300,4 @@
#include "msm-arm-smmu-impl-defs-falcon.dtsi"
#include "msmfalcon-common.dtsi"
#include "msmfalcon-blsp.dtsi"
+#include "msmfalcon-vidc.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts
index 08809fb38cae..491b55aab9a6 100644
--- a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts
+++ b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts
@@ -63,3 +63,8 @@
compatible = "qcom,dummycc";
clock-output-names = "gcc_clocks";
};
+
+&clock_gfx {
+ compatible = "qcom,dummycc";
+ clock-output-names = "gfx_clocks";
+};
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index cd751f3181ee..e7416ebb8f58 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -241,6 +241,13 @@
clock-frequency = <19200000>;
};
+ restart@10ac000 {
+ compatible = "qcom,pshold";
+ reg = <0x10ac000 0x4>,
+ <0x1fd3000 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
qcom,sps {
compatible = "qcom,msm_sps_4k";
qcom,pipe-attr-ee;
@@ -382,8 +389,21 @@
};
clock_gfx: clock-controller@5065000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gfx_clocks";
+ compatible = "qcom,gpucc-msmfalcon";
+ reg = <0x5065000 0x10000>;
+ vdd_dig_gfx-supply = <&pm2falcon_s3_level>;
+ vdd_mx_gfx-supply = <&pm2falcon_s5_level>;
+ vdd_gfx-supply = <&gfx_vreg_corner>;
+ qcom,gfxfreq-corner =
+ < 0 0>,
+ < 160000000 1>, /* MinSVS */
+ < 266000000 2>, /* LowSVS */
+ < 370000000 3>, /* SVS */
+ < 465000000 4>, /* SVS_L1 */
+ < 588000000 5>, /* NOM */
+ < 647000000 6>, /* NOM_L1 */
+ < 700000000 7>, /* TURBO */
+ < 750000000 7>; /* TURBO */
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -698,6 +718,17 @@
status = "ok";
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>;
+ };
+
+ qcom,mpm2-sleep-counter@10a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x10a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom,msm-imem@146bf000 {
compatible = "qcom,msm-imem";
reg = <0x146bf000 0x1000>;
@@ -705,6 +736,21 @@
#address-cells = <1>;
#size-cells = <1>;
+ dload_type@18 {
+ compatible = "qcom,msm-imem-dload-type";
+ reg = <0x18 4>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
@@ -727,6 +773,12 @@
clock-names = "atb_clk";
clocks = <&clock_rpmcc RPM_QDSS_CLK>;
};
+
+ cpu_pmu: cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ qcom,irq-is-percpu;
+ interrupts = <1 6 4>;
+ };
};
#include "msmtriton-ion.dtsi"
@@ -794,10 +846,8 @@
};
&gdsc_gpu_gx {
- clock-names = "bimc_core_clk", "core_clk", "core_root_clk";
- clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>,
- <&clock_gfx GPUCC_GFX3D_CLK>,
- <&clock_gfx GFX3D_CLK_SRC>;
+ clock-names = "core_root_clk";
+ clocks = <&clock_gfx GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
parent-supply = <&gfx_vreg_corner>;
status = "ok";
diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig
index 8039441cc972..abd89c1ca060 100644
--- a/arch/arm/configs/msmfalcon_defconfig
+++ b/arch/arm/configs/msmfalcon_defconfig
@@ -422,7 +422,7 @@ CONFIG_RMNET_IPA3=y
CONFIG_GPIO_USB_DETECT=y
CONFIG_USB_BAM=y
CONFIG_QCOM_CLK_SMD_RPM=y
-CONFIG_MSM_GCC_FALCON=y
+CONFIG_MSM_GPUCC_FALCON=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index cbccbeb483c9..a4fba1af7744 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -2,7 +2,7 @@ if ARCH_QCOM
menu "QCOM SoC Type"
config ARCH_MSMFALCON
- bool "Enable Support for Qualcomm MSMFALCON"
+ bool "Enable Support for MSMFALCON"
select CLKDEV_LOOKUP
select HAVE_CLK
select HAVE_CLK_PREPARE
@@ -40,7 +40,7 @@ config ARCH_MSMFALCON
wish to build a kernel that runs on this chipset, say 'N' here.
config ARCH_MSMTRITON
- bool "Enable Support for Qualcomm MSMTRITON"
+ bool "Enable Support for MSMTRITON"
select CLKDEV_LOOKUP
select HAVE_CLK
select HAVE_CLK_PREPARE
diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig
index 54925c6bcf4e..1074672d252f 100644
--- a/arch/arm64/configs/msmfalcon-perf_defconfig
+++ b/arch/arm64/configs/msmfalcon-perf_defconfig
@@ -489,7 +489,7 @@ CONFIG_GPIO_USB_DETECT=y
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_QCOM_CLK_SMD_RPM=y
-CONFIG_MSM_GCC_FALCON=y
+CONFIG_MSM_GPUCC_FALCON=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig
index 820385a0217a..6d8d9eeab2d5 100644
--- a/arch/arm64/configs/msmfalcon_defconfig
+++ b/arch/arm64/configs/msmfalcon_defconfig
@@ -498,7 +498,7 @@ CONFIG_GPIO_USB_DETECT=y
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_QCOM_CLK_SMD_RPM=y
-CONFIG_MSM_GCC_FALCON=y
+CONFIG_MSM_GPUCC_FALCON=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
diff --git a/block/genhd.c b/block/genhd.c
index 817c67c9e45e..82bc52cad1c1 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -831,6 +831,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
if (iter) {
class_dev_iter_exit(iter);
kfree(iter);
+ seqf->private = NULL;
}
}
diff --git a/block/ioprio.c b/block/ioprio.c
index cc7800e9eb44..01b8116298a1 100644
--- a/block/ioprio.c
+++ b/block/ioprio.c
@@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p)
if (ret)
goto out;
ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
+ task_lock(p);
if (p->io_context)
ret = p->io_context->ioprio;
+ task_unlock(p);
out:
return ret;
}
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index e39686ca4feb..36ab5cf68740 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -173,6 +173,16 @@ config MSM_GPUCC_FALCON
Say Y if you want to support graphics controller devices which will
be required to enable those device.
+config MSM_MMCC_FALCON
+ tristate "MSMFALCON Multimedia Clock Controller"
+ select MSM_GCC_FALCON
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the multimedia clock controller on Qualcomm Technologies, Inc
+ MSMfalcon devices.
+ Say Y if you want to support multimedia devices such as display,
+ video encode/decode, camera, etc.
+
config QCOM_HFPLL
tristate "High-Frequency PLL (HFPLL) Clock Controller"
depends on COMMON_CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index adebefd63e71..595254f69db1 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
obj-$(CONFIG_MSM_GPUCC_FALCON) += gpucc-msmfalcon.o
+obj-$(CONFIG_MSM_MMCC_FALCON) += mmcc-msmfalcon.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
obj-$(CONFIG_KRAITCC) += krait-cc.o
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
new file mode 100644
index 000000000000..f97cd1b03c81
--- /dev/null
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -0,0 +1,3301 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/cpu.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/driver.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <soc/qcom/scm.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-alpha-pll.h>
+
+#include <dt-bindings/clock/msm-clocks-hwio-cobalt.h>
+#include <dt-bindings/clock/msm-clocks-cobalt.h>
+
+#include "clock.h"
+
+enum clk_osm_bases {
+ OSM_BASE,
+ PLL_BASE,
+ EFUSE_BASE,
+ ACD_BASE,
+ NUM_BASES,
+};
+
+enum clk_osm_lut_data {
+ FREQ,
+ FREQ_DATA,
+ PLL_OVERRIDES,
+ SPARE_DATA,
+ VIRTUAL_CORNER,
+ NUM_FIELDS,
+};
+
+enum clk_osm_trace_method {
+ XOR_PACKET,
+ PERIODIC_PACKET,
+};
+
+enum clk_osm_trace_packet_id {
+ TRACE_PACKET0,
+ TRACE_PACKET1,
+ TRACE_PACKET2,
+ TRACE_PACKET3,
+};
+
+#define SEQ_REG(n) (0x300 + (n) * 4)
+#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n)))
+#define MEM_ACC_SEQ_CONST(n) (n)
+#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40))
+#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n)))
+#define SEQ_REG1_MSMCOBALT_V2 0x1048
+#define VERSION_REG 0x0
+#define VERSION_1P1 0x00010100
+
+#define OSM_TABLE_SIZE 40
+#define MAX_CLUSTER_CNT 2
+#define MAX_CONFIG 4
+#define LLM_SW_OVERRIDE_CNT 3
+
+#define ENABLE_REG 0x1004
+#define INDEX_REG 0x1150
+#define FREQ_REG 0x1154
+#define VOLT_REG 0x1158
+#define OVERRIDE_REG 0x115C
+#define SPARE_REG 0x1164
+
+#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00
+#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04
+#define DCVS_PERF_STATE_DESIRED_REG 0x1F10
+#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14
+#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18
+#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28
+#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C
+#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30
+#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34
+#define OSM_CORE_TABLE_SIZE 8192
+#define OSM_REG_SIZE 32
+
+#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00
+#define WDOG_PROGRAM_COUNTER 0x1c74
+
+#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8)
+#define PLL_MODE 0x0
+#define PLL_L_VAL 0x4
+#define PLL_USER_CTRL 0xC
+#define PLL_CONFIG_CTL_LO 0x10
+#define PLL_TEST_CTL_HI 0x1C
+#define PLL_STATUS 0x2C
+#define PLL_LOCK_DET_MASK BIT(16)
+#define PLL_WAIT_LOCK_TIME_US 10
+#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000)
+#define PLL_MIN_LVAL 43
+
+#define CC_ZERO_BEHAV_CTRL 0x100C
+#define SPM_CC_DCVS_DISABLE 0x1020
+#define SPM_CC_CTRL 0x1028
+#define SPM_CC_HYSTERESIS 0x101C
+#define SPM_CORE_RET_MAPPING 0x1024
+#define CFG_DELAY_VAL_3 0x12C
+
+#define LLM_FREQ_VOTE_HYSTERESIS 0x102C
+#define LLM_VOLT_VOTE_HYSTERESIS 0x1030
+#define LLM_INTF_DCVS_DISABLE 0x1034
+
+#define ENABLE_OVERRIDE BIT(0)
+
+#define ITM_CL0_DISABLE_CL1_ENABLED 0x2
+#define ITM_CL0_ENABLED_CL1_DISABLE 0x1
+
+#define APM_MX_MODE 0
+#define APM_APC_MODE BIT(1)
+#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3))
+#define APM_MX_MODE_VAL 0
+#define APM_APC_MODE_VAL 0x3
+
+#define GPLL_SEL 0x400
+#define PLL_EARLY_SEL 0x500
+#define PLL_MAIN_SEL 0x300
+#define RCG_UPDATE 0x3
+#define RCG_UPDATE_SUCCESS 0x2
+#define PLL_POST_DIV1 0x1F
+#define PLL_POST_DIV2 0x11F
+
+#define LLM_SW_OVERRIDE_REG 0x1038
+#define VMIN_REDUC_ENABLE_REG 0x103C
+#define VMIN_REDUC_TIMER_REG 0x1040
+#define PDN_FSM_CTRL_REG 0x1070
+#define CC_BOOST_TIMER_REG0 0x1074
+#define CC_BOOST_TIMER_REG1 0x1078
+#define CC_BOOST_TIMER_REG2 0x107C
+#define CC_BOOST_EN_MASK BIT(0)
+#define PS_BOOST_EN_MASK BIT(1)
+#define DCVS_BOOST_EN_MASK BIT(2)
+#define PC_RET_EXIT_DROOP_EN_MASK BIT(3)
+#define WFX_DROOP_EN_MASK BIT(4)
+#define DCVS_DROOP_EN_MASK BIT(5)
+#define LMH_PS_EN_MASK BIT(6)
+#define IGNORE_PLL_LOCK_MASK BIT(15)
+#define SAFE_FREQ_WAIT_NS 5000
+#define DEXT_DECREMENT_WAIT_NS 1000
+#define DCVS_BOOST_TIMER_REG0 0x1084
+#define DCVS_BOOST_TIMER_REG1 0x1088
+#define DCVS_BOOST_TIMER_REG2 0x108C
+#define PS_BOOST_TIMER_REG0 0x1094
+#define PS_BOOST_TIMER_REG1 0x1098
+#define PS_BOOST_TIMER_REG2 0x109C
+#define BOOST_PROG_SYNC_DELAY_REG 0x10A0
+#define DROOP_CTRL_REG 0x10A4
+#define DROOP_RELEASE_TIMER_CTRL 0x10A8
+#define DROOP_PROG_SYNC_DELAY_REG 0x10BC
+#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC
+#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0
+#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4
+#define OSM_PLL_SW_OVERRIDE_EN 0x10C0
+
+#define PLL_SW_OVERRIDE_DROOP_EN BIT(0)
+#define DCVS_DROOP_TIMER_CTRL 0x10B8
+#define SEQ_MEM_ADDR 0x500
+#define SEQ_CFG_BR_ADDR 0x170
+#define MAX_INSTRUCTIONS 256
+#define MAX_BR_INSTRUCTIONS 49
+
+#define MAX_MEM_ACC_LEVELS 3
+#define MAX_MEM_ACC_VAL_PER_LEVEL 3
+#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
+ MAX_MEM_ACC_VAL_PER_LEVEL)
+#define MEM_ACC_APM_READ_MASK 0xff
+
+#define TRACE_CTRL 0x1F38
+#define TRACE_CTRL_EN_MASK BIT(0)
+#define TRACE_CTRL_ENABLE 1
+#define TRACE_CTRL_DISABLE 0
+#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30)
+#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3)
+#define TRACE_CTRL_PACKET_TYPE_SHIFT 1
+#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3)
+#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3)
+#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C
+#define PERIODIC_TRACE_MIN_NS 1000
+#define PERIODIC_TRACE_MAX_NS 21474836475
+#define PERIODIC_TRACE_DEFAULT_NS 1000000
+
+#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408
+#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f
+#define PLL_DD_D0_USER_CTL_LO 0x17916208
+#define PLL_DD_D1_USER_CTL_LO 0x17816208
+
+#define PWRCL_EFUSE_SHIFT 0
+#define PWRCL_EFUSE_MASK 0
+#define PERFCL_EFUSE_SHIFT 29
+#define PERFCL_EFUSE_MASK 0x7
+
+#define MSMCOBALTV1_PWRCL_BOOT_RATE 1478400000
+#define MSMCOBALTV1_PERFCL_BOOT_RATE 1536000000
+#define MSMCOBALTV2_PWRCL_BOOT_RATE 1555200000
+#define MSMCOBALTV2_PERFCL_BOOT_RATE 1728000000
+
+/* ACD registers */
+#define ACD_HW_VERSION 0x0
+#define ACDCR 0x4
+#define ACDTD 0x8
+#define ACDSSCR 0x28
+#define ACD_EXTINT_CFG 0x30
+#define ACD_DCVS_SW 0x34
+#define ACD_GFMUX_CFG 0x3c
+#define ACD_READOUT_CFG 0x48
+#define ACD_AUTOXFER_CFG 0x80
+#define ACD_AUTOXFER 0x84
+#define ACD_AUTOXFER_CTL 0x88
+#define ACD_AUTOXFER_STATUS 0x8c
+#define ACD_WRITE_CTL 0x90
+#define ACD_WRITE_STATUS 0x94
+#define ACD_READOUT 0x98
+
+#define ACD_MASTER_ONLY_REG_ADDR 0x80
+#define ACD_WRITE_CTL_UPDATE_EN BIT(0)
+#define ACD_WRITE_CTL_SELECT_SHIFT 1
+#define ACD_GFMUX_CFG_SELECT BIT(0)
+#define ACD_AUTOXFER_START_CLEAR 0
+#define ACD_AUTOXFER_START_SET BIT(0)
+#define AUTO_XFER_DONE_MASK BIT(0)
+#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0)
+#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0
+#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500
+
+static void __iomem *virt_base;
+static void __iomem *debug_base;
+
+#define lmh_lite_clk_src_source_val 1
+
+#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4)
+#define ACD_REG_RELATIVE_ADDR_BITMASK(addr) \
+ (1 << (ACD_REG_RELATIVE_ADDR(addr)))
+
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+static u32 seq_instr[] = {
+ 0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491,
+ 0x700a500b, 0x5001aefc, 0xaefd7000, 0x390938c8, 0xcb44c833,
+ 0xce56cd54, 0x341336e0, 0xa4baadba, 0xb480a493, 0x10004000,
+ 0x70005001, 0x1000500c, 0xc792c5a1, 0x501625e1, 0x3da335a2,
+ 0x50170006, 0x50150006, 0x1000c633, 0x1000acb3, 0xc422acb4,
+ 0xaefc1000, 0x700a500b, 0x70005001, 0x5010aefd, 0x5012700b,
+ 0xad41700c, 0x84e5adb9, 0xb3808566, 0x239b0003, 0x856484e3,
+ 0xb9800007, 0x2bad0003, 0xac3aa20b, 0x0003181b, 0x0003bb40,
+ 0xa30d239b, 0x500c181b, 0x5011500f, 0x181b3413, 0x853984b9,
+ 0x0003bd80, 0xa0012ba4, 0x72050803, 0x500e1000, 0x500c1000,
+ 0x1c011c0a, 0x3b181c06, 0x1c073b43, 0x1c061000, 0x1c073983,
+ 0x1c02500c, 0x10001c0a, 0x70015002, 0x81031000, 0x70025003,
+ 0x70035004, 0x3b441000, 0x81553985, 0x70025003, 0x50054003,
+ 0xa1467009, 0x0003b1c0, 0x4005238b, 0x835a1000, 0x855c84db,
+ 0x1000a51f, 0x84de835d, 0xa52c855c, 0x50061000, 0x39cd3a4c,
+ 0x3ad03a8f, 0x10004006, 0x70065007, 0xa00f2c12, 0x08034007,
+ 0xaefc7205, 0xaefd700d, 0xa9641000, 0x40071c1a, 0x700daefc,
+ 0x1000aefd, 0x70065007, 0x50101c16, 0x40075012, 0x700daefc,
+ 0x2411aefd, 0xa8211000, 0x0803a00f, 0x500c7005, 0x1c1591e0,
+ 0x500f5014, 0x10005011, 0x500c2bd4, 0x0803a00f, 0x10007205,
+ 0xa00fa9d1, 0x0803a821, 0xa9d07005, 0x91e0500c, 0x500f1c15,
+ 0x10005011, 0x1c162bce, 0x50125010, 0xa022a82a, 0x70050803,
+ 0x1c1591df, 0x5011500f, 0x5014500c, 0x0803a00f, 0x10007205,
+ 0x501391a4, 0x22172217, 0x70075008, 0xa9634008, 0x1c1a0006,
+ 0x70085009, 0x10004009, 0x00008ed9, 0x3e05c8dd, 0x1c033604,
+ 0xabaf1000, 0x856284e1, 0x0003bb80, 0x1000239f, 0x0803a037,
+ 0x10007205, 0x8dc61000, 0x38a71c2a, 0x1c2a8dc4, 0x100038a6,
+ 0x1c2a8dc5, 0x8dc73867, 0x38681c2a, 0x8c491000, 0x8d4b8cca,
+ 0x10001c00, 0x8ccd8c4c, 0x1c008d4e, 0x8c4f1000, 0x8d518cd0,
+ 0x10001c00, 0xa759a79a, 0x1000a718, 0xbf80af9b, 0x00001000,
+};
+
+static u32 seq_br_instr[] = {
+ 0x248, 0x20e, 0x21c, 0xf6, 0x112,
+ 0x11c, 0xe4, 0xea, 0xc6, 0xd6,
+ 0x126, 0x108, 0x184, 0x1a8, 0x1b0,
+ 0x134, 0x158, 0x16e, 0x14a, 0xc2,
+ 0x190, 0x1d2, 0x1cc, 0x1d4, 0x1e8,
+ 0x0, 0x1f6, 0x32, 0x66, 0xb0,
+ 0xa6, 0x1fc, 0x3c, 0x44, 0x5c,
+ 0x60, 0x204, 0x30, 0x22a, 0x234,
+ 0x23e, 0x0, 0x250, 0x0, 0x0, 0x9a,
+ 0x20c,
+};
+
+DEFINE_EXT_CLK(xo_ao, NULL);
+DEFINE_EXT_CLK(sys_apcsaux_clk_gcc, NULL);
+DEFINE_EXT_CLK(lmh_lite_clk_src, NULL);
+
+struct osm_entry {
+ u16 virtual_corner;
+ u16 open_loop_volt;
+ u32 freq_data;
+ u32 override_data;
+ u32 spare_data;
+ long frequency;
+};
+
+static struct dentry *osm_debugfs_base;
+
+struct clk_osm {
+ struct clk c;
+ struct osm_entry osm_table[OSM_TABLE_SIZE];
+ struct dentry *debugfs;
+ struct regulator *vdd_reg;
+ struct platform_device *vdd_dev;
+ void *vbases[NUM_BASES];
+ unsigned long pbases[NUM_BASES];
+ spinlock_t lock;
+
+ u32 version;
+ u32 cpu_reg_mask;
+ u32 num_entries;
+ u32 cluster_num;
+ u32 irq;
+ u32 apm_crossover_vc;
+ u32 apm_threshold_vc;
+ u32 cycle_counter_reads;
+ u32 cycle_counter_delay;
+ u32 cycle_counter_factor;
+ u64 total_cycle_counter;
+ u32 prev_cycle_counter;
+ u32 l_val_base;
+ u32 apcs_itm_present;
+ u32 apcs_cfg_rcgr;
+ u32 apcs_cmd_rcgr;
+ u32 apcs_pll_user_ctl;
+ u32 apcs_mem_acc_cfg[MAX_MEM_ACC_VAL_PER_LEVEL];
+ u32 apcs_mem_acc_val[MAX_MEM_ACC_VALUES];
+ u32 llm_sw_overr[LLM_SW_OVERRIDE_CNT];
+ u32 apm_mode_ctl;
+ u32 apm_ctrl_status;
+ u32 osm_clk_rate;
+ u32 xo_clk_rate;
+ u32 acd_td;
+ u32 acd_cr;
+ u32 acd_sscr;
+ u32 acd_extint0_cfg;
+ u32 acd_extint1_cfg;
+ u32 acd_autoxfer_ctl;
+ u32 acd_debugfs_addr;
+ bool acd_init;
+ bool secure_init;
+ bool red_fsm_en;
+ bool boost_fsm_en;
+ bool safe_fsm_en;
+ bool ps_fsm_en;
+ bool droop_fsm_en;
+ bool wfx_fsm_en;
+ bool pc_fsm_en;
+
+ enum clk_osm_trace_method trace_method;
+ enum clk_osm_trace_packet_id trace_id;
+ struct notifier_block panic_notifier;
+ u32 trace_periodic_timer;
+ bool trace_en;
+ bool wdog_trace_en;
+};
+
+static bool msmcobalt_v1;
+static bool msmcobalt_v2;
+
+static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val,
+ u32 offset, u32 mask)
+{
+ u32 val2, orig_val;
+
+ val2 = orig_val = readl_relaxed((char *)c->vbases[OSM_BASE] + offset);
+ val2 &= ~mask;
+ val2 |= val & mask;
+
+ if (val2 != orig_val)
+ writel_relaxed(val2, (char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline void clk_osm_write_reg(struct clk_osm *c, u32 val, u32 offset)
+{
+ writel_relaxed(val, (char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline int clk_osm_read_reg(struct clk_osm *c, u32 offset)
+{
+ return readl_relaxed((char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset)
+{
+ return readl_relaxed_no_log((char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline int clk_osm_mb(struct clk_osm *c, int base)
+{
+ return readl_relaxed_no_log((char *)c->vbases[base] + VERSION_REG);
+}
+
+static inline int clk_osm_acd_mb(struct clk_osm *c)
+{
+ return readl_relaxed_no_log((char *)c->vbases[ACD_BASE] +
+ ACD_HW_VERSION);
+}
+
+static inline void clk_osm_acd_master_write_reg(struct clk_osm *c,
+ u32 val, u32 offset)
+{
+ writel_relaxed(val, (char *)c->vbases[ACD_BASE] + offset);
+}
+
+static int clk_osm_acd_local_read_reg(struct clk_osm *c, u32 offset)
+{
+ u32 reg = 0;
+ int timeout;
+
+ if (offset >= ACD_MASTER_ONLY_REG_ADDR) {
+ pr_err("ACD register at offset=0x%x not locally readable\n",
+ offset);
+ return -EINVAL;
+ }
+
+ /* Set select field in read control register */
+ writel_relaxed(ACD_REG_RELATIVE_ADDR(offset),
+ (char *)c->vbases[ACD_BASE] + ACD_READOUT_CFG);
+
+ /* Clear write control register */
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Set select and update_en fields in write control register */
+ reg = (ACD_REG_RELATIVE_ADDR(ACD_READOUT_CFG)
+ << ACD_WRITE_CTL_SELECT_SHIFT)
+ | ACD_WRITE_CTL_UPDATE_EN;
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Ensure writes complete before polling */
+ clk_osm_acd_mb(c);
+
+ /* Poll write status register */
+ for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS; timeout > 0;
+ timeout -= 100) {
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_WRITE_STATUS);
+ if ((reg & (ACD_REG_RELATIVE_ADDR_BITMASK(ACD_READOUT_CFG))))
+ break;
+ ndelay(100);
+ }
+
+ if (!timeout) {
+ pr_err("local read timed out, offset=0x%x status=0x%x\n",
+ offset, reg);
+ return -ETIMEDOUT;
+ }
+
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_READOUT);
+ return reg;
+}
+
+static int clk_osm_acd_local_write_reg(struct clk_osm *c, u32 val, u32 offset)
+{
+ u32 reg = 0;
+ int timeout;
+
+ if (offset >= ACD_MASTER_ONLY_REG_ADDR) {
+ pr_err("ACD register at offset=0x%x not transferrable\n",
+ offset);
+ return -EINVAL;
+ }
+
+ /* Clear write control register */
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Set select and update_en fields in write control register */
+ reg = (ACD_REG_RELATIVE_ADDR(offset) << ACD_WRITE_CTL_SELECT_SHIFT)
+ | ACD_WRITE_CTL_UPDATE_EN;
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Ensure writes complete before polling */
+ clk_osm_acd_mb(c);
+
+ /* Poll write status register */
+ for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS; timeout > 0;
+ timeout -= 100) {
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_WRITE_STATUS);
+ if ((reg & (ACD_REG_RELATIVE_ADDR_BITMASK(offset))))
+ break;
+ ndelay(100);
+ }
+
+ if (!timeout) {
+ pr_err("local write timed out, offset=0x%x val=0x%x status=0x%x\n",
+ offset, val, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int clk_osm_acd_master_write_through_reg(struct clk_osm *c,
+ u32 val, u32 offset)
+{
+ writel_relaxed(val, (char *)c->vbases[ACD_BASE] + offset);
+
+ /* Ensure writes complete before transfer to local copy */
+ clk_osm_acd_mb(c);
+
+ return clk_osm_acd_local_write_reg(c, val, offset);
+}
+
+static int clk_osm_acd_auto_local_write_reg(struct clk_osm *c, u32 mask)
+{
+ u32 numregs, bitmask = mask;
+ u32 reg = 0;
+ int timeout;
+
+ /* count number of bits set in register mask */
+ for (numregs = 0; bitmask; numregs++)
+ bitmask &= bitmask - 1;
+
+ /* Program auto-transfter mask */
+ writel_relaxed(mask, (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER_CFG);
+
+ /* Clear start field in auto-transfer register */
+ writel_relaxed(ACD_AUTOXFER_START_CLEAR,
+ (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER);
+
+ /* Set start field in auto-transfer register */
+ writel_relaxed(ACD_AUTOXFER_START_SET,
+ (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER);
+
+ /* Ensure writes complete before polling */
+ clk_osm_acd_mb(c);
+
+ /* Poll auto-transfer status register */
+ for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS * numregs;
+ timeout > 0; timeout -= 100) {
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_AUTOXFER_STATUS);
+ if (reg & AUTO_XFER_DONE_MASK)
+ break;
+ ndelay(100);
+ }
+
+ if (!timeout) {
+ pr_err("local register auto-transfer timed out, mask=0x%x registers=%d status=0x%x\n",
+ mask, numregs, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec)
+{
+ u64 temp;
+
+ temp = (u64)c->osm_clk_rate * nsec;
+ do_div(temp, 1000000000);
+
+ return temp;
+}
+
+static inline struct clk_osm *to_clk_osm(struct clk *c)
+{
+ return container_of(c, struct clk_osm, c);
+}
+
+static enum handoff clk_osm_handoff(struct clk *c)
+{
+ return HANDOFF_DISABLED_CLK;
+}
+
+static long clk_osm_list_rate(struct clk *c, unsigned n)
+{
+ if (n >= c->num_fmax)
+ return -ENXIO;
+ return c->fmax[n];
+}
+
+static long clk_osm_round_rate(struct clk *c, unsigned long rate)
+{
+ int i;
+ unsigned long rrate = 0;
+
+ /*
+ * If the rate passed in is 0, return the first frequency in
+ * the FMAX table.
+ */
+ if (!rate)
+ return c->fmax[0];
+
+ for (i = 0; i < c->num_fmax; i++) {
+ if (is_better_rate(rate, rrate, c->fmax[i])) {
+ rrate = c->fmax[i];
+ if (rrate == rate)
+ break;
+ }
+ }
+
+ return rrate;
+}
+
+static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
+{
+ int i;
+
+ for (i = 0; i < entries; i++)
+ if (rate == table[i].frequency)
+ return i;
+ return -EINVAL;
+}
+
+static int clk_osm_set_rate(struct clk *c, unsigned long rate)
+{
+ struct clk_osm *cpuclk = to_clk_osm(c);
+ int index = 0;
+ unsigned long r_rate;
+
+ r_rate = clk_osm_round_rate(c, rate);
+
+ if (rate != r_rate) {
+ pr_err("invalid rate requested rate=%ld\n", rate);
+ return -EINVAL;
+ }
+
+ /* Convert rate to table index */
+ index = clk_osm_search_table(cpuclk->osm_table,
+ cpuclk->num_entries, r_rate);
+ if (index < 0) {
+ pr_err("cannot set cluster %u to %lu\n",
+ cpuclk->cluster_num, rate);
+ return -EINVAL;
+ }
+ pr_debug("rate: %lu --> index %d\n", rate, index);
+
+ if (cpuclk->llm_sw_overr[0]) {
+ clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[0],
+ LLM_SW_OVERRIDE_REG);
+ clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[1],
+ LLM_SW_OVERRIDE_REG);
+ udelay(1);
+ }
+
+ /* Choose index and send request to OSM hardware */
+ clk_osm_write_reg(cpuclk, index, DCVS_PERF_STATE_DESIRED_REG);
+
+ if (cpuclk->llm_sw_overr[0]) {
+ udelay(1);
+ clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[2],
+ LLM_SW_OVERRIDE_REG);
+ }
+
+ /* Make sure the write goes through before proceeding */
+ clk_osm_mb(cpuclk, OSM_BASE);
+
+ return 0;
+}
+
+static int clk_osm_enable(struct clk *c)
+{
+ struct clk_osm *cpuclk = to_clk_osm(c);
+
+ clk_osm_write_reg(cpuclk, 1, ENABLE_REG);
+
+ /* Make sure the write goes through before proceeding */
+ clk_osm_mb(cpuclk, OSM_BASE);
+
+ /* Wait for 5us for OSM hardware to enable */
+ udelay(5);
+
+ pr_debug("OSM clk enabled for cluster=%d\n", cpuclk->cluster_num);
+
+ return 0;
+}
+
+static struct clk_ops clk_ops_cpu_osm = {
+ .enable = clk_osm_enable,
+ .set_rate = clk_osm_set_rate,
+ .round_rate = clk_osm_round_rate,
+ .list_rate = clk_osm_list_rate,
+ .handoff = clk_osm_handoff,
+};
+
+static struct regulator *vdd_pwrcl;
+static struct regulator *vdd_perfcl;
+
+static struct clk_freq_tbl ftbl_osm_clk_src[] = {
+ F( 200000000, lmh_lite_clk_src, 1.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk osm_clk_src = {
+ .cmd_rcgr_reg = APCS_COMMON_LMH_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_osm_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "osm_clk_src",
+ .ops = &clk_ops_rcg,
+ CLK_INIT(osm_clk_src.c),
+ },
+};
+
+static struct clk_osm pwrcl_clk = {
+ .cluster_num = 0,
+ .cpu_reg_mask = 0x3,
+ .c = {
+ .dbg_name = "pwrcl_clk",
+ .ops = &clk_ops_cpu_osm,
+ .parent = &xo_ao.c,
+ CLK_INIT(pwrcl_clk.c),
+ },
+};
+
+static struct clk_osm perfcl_clk = {
+ .cluster_num = 1,
+ .cpu_reg_mask = 0x103,
+ .c = {
+ .dbg_name = "perfcl_clk",
+ .ops = &clk_ops_cpu_osm,
+ .parent = &xo_ao.c,
+ CLK_INIT(perfcl_clk.c),
+ },
+};
+
+static struct clk_ops clk_ops_cpu_dbg_mux;
+
+static struct mux_clk cpu_debug_mux = {
+ .offset = 0x0,
+ .mask = 0x3,
+ .shift = 8,
+ .ops = &mux_reg_ops,
+ MUX_SRC_LIST(
+ { &pwrcl_clk.c, 0x00 },
+ { &perfcl_clk.c, 0x01 },
+ ),
+ .base = &debug_base,
+ .c = {
+ .dbg_name = "cpu_debug_mux",
+ .ops = &clk_ops_cpu_dbg_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(cpu_debug_mux.c),
+ },
+};
+
+static struct clk_lookup cpu_clocks_osm[] = {
+ CLK_LIST(pwrcl_clk),
+ CLK_LIST(perfcl_clk),
+ CLK_LIST(sys_apcsaux_clk_gcc),
+ CLK_LIST(xo_ao),
+ CLK_LIST(osm_clk_src),
+ CLK_LIST(cpu_debug_mux),
+};
+
+static unsigned long cpu_dbg_mux_get_rate(struct clk *clk)
+{
+ /* Account for the divider between the clock and the debug mux */
+ if (!strcmp(clk->parent->dbg_name, "pwrcl_clk"))
+ return clk->rate/4;
+ else if (!strcmp(clk->parent->dbg_name, "perfcl_clk"))
+ return clk->rate/8;
+ return clk->rate;
+}
+
+static void clk_osm_print_osm_table(struct clk_osm *c)
+{
+ int i;
+ struct osm_entry *table = c->osm_table;
+ u32 pll_src, pll_div, lval, core_count;
+
+ pr_debug("Index, Frequency, VC, OLV (mv), Core Count, PLL Src, PLL Div, L-Val, ACC Level\n");
+ for (i = 0; i < c->num_entries; i++) {
+ pll_src = (table[i].freq_data & GENMASK(27, 26)) >> 26;
+ pll_div = (table[i].freq_data & GENMASK(25, 24)) >> 24;
+ lval = table[i].freq_data & GENMASK(7, 0);
+ core_count = (table[i].freq_data & GENMASK(18, 16)) >> 16;
+
+ pr_debug("%3d, %11lu, %2u, %5u, %2u, %6u, %8u, %7u, %5u\n",
+ i,
+ table[i].frequency,
+ table[i].virtual_corner,
+ table[i].open_loop_volt,
+ core_count,
+ pll_src,
+ pll_div,
+ lval,
+ table[i].spare_data);
+ }
+ pr_debug("APM threshold corner=%d, crossover corner=%d\n",
+ c->apm_threshold_vc, c->apm_crossover_vc);
+}
+
+static int clk_osm_get_lut(struct platform_device *pdev,
+ struct clk_osm *c, char *prop_name)
+{
+ struct clk *clk = &c->c;
+ struct device_node *of = pdev->dev.of_node;
+ int prop_len, total_elems, num_rows, i, j, k;
+ int rc = 0;
+ u32 *array;
+ u32 data;
+ bool last_entry = false;
+
+ if (!of_find_property(of, prop_name, &prop_len)) {
+ dev_err(&pdev->dev, "missing %s\n", prop_name);
+ return -EINVAL;
+ }
+
+ total_elems = prop_len / sizeof(u32);
+ if (total_elems % NUM_FIELDS) {
+ dev_err(&pdev->dev, "bad length %d\n", prop_len);
+ return -EINVAL;
+ }
+
+ num_rows = total_elems / NUM_FIELDS;
+
+ clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!clk->fmax)
+ return -ENOMEM;
+
+ array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of, prop_name, array, total_elems);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse OSM table, rc=%d\n", rc);
+ goto exit;
+ }
+
+ pr_debug("%s: Entries in Table: %d\n", __func__, num_rows);
+ c->num_entries = num_rows;
+ if (c->num_entries > OSM_TABLE_SIZE) {
+ pr_err("LUT entries %d exceed maximum size %d\n",
+ c->num_entries, OSM_TABLE_SIZE);
+ return -EINVAL;
+ }
+
+ for (i = 0, j = 0, k = 0; j < OSM_TABLE_SIZE; j++) {
+ c->osm_table[j].frequency = array[i + FREQ];
+ c->osm_table[j].freq_data = array[i + FREQ_DATA];
+ c->osm_table[j].override_data = array[i + PLL_OVERRIDES];
+ c->osm_table[j].spare_data = array[i + SPARE_DATA];
+ /* Voltage corners are 0 based in the OSM LUT */
+ c->osm_table[j].virtual_corner = array[i + VIRTUAL_CORNER] - 1;
+ pr_debug("index=%d freq=%ld virtual_corner=%d freq_data=0x%x override_data=0x%x spare_data=0x%x\n",
+ j, c->osm_table[j].frequency,
+ c->osm_table[j].virtual_corner,
+ c->osm_table[j].freq_data,
+ c->osm_table[j].override_data,
+ c->osm_table[j].spare_data);
+
+ data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16;
+ if (!last_entry) {
+ clk->fmax[k] = array[i];
+ k++;
+ }
+
+ if (i < total_elems - NUM_FIELDS)
+ i += NUM_FIELDS;
+ else
+ last_entry = true;
+ }
+ clk->num_fmax = k;
+exit:
+ devm_kfree(&pdev->dev, array);
+ return rc;
+}
+
+static int clk_osm_parse_dt_configs(struct platform_device *pdev)
+{
+ struct device_node *of = pdev->dev.of_node;
+ u32 *array;
+ int i, rc = 0;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of, "qcom,l-val-base",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,l-val-base property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.l_val_base = array[pwrcl_clk.cluster_num];
+ perfcl_clk.l_val_base = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-itm-present",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-itm-present property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_itm_present = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_itm_present = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-cfg-rcgr",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-cfg-rcgr property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_cfg_rcgr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_cfg_rcgr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-cmd-rcgr",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-cmd-rcgr property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_cmd_rcgr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_cmd_rcgr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-pll-user-ctl",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-pll-user-ctl property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_pll_user_ctl = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_pll_user_ctl = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apm-mode-ctl",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apm-mode-ctl property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apm_mode_ctl = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apm_mode_ctl = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apm-ctrl-status",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apm-ctrl-status property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apm_ctrl_status = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apm_ctrl_status = array[perfcl_clk.cluster_num];
+
+ for (i = 0; i < LLM_SW_OVERRIDE_CNT; i++)
+ of_property_read_u32_index(of, "qcom,llm-sw-overr",
+ pwrcl_clk.cluster_num *
+ LLM_SW_OVERRIDE_CNT + i,
+ &pwrcl_clk.llm_sw_overr[i]);
+
+ for (i = 0; i < LLM_SW_OVERRIDE_CNT; i++)
+ of_property_read_u32_index(of, "qcom,llm-sw-overr",
+ perfcl_clk.cluster_num *
+ LLM_SW_OVERRIDE_CNT + i,
+ &perfcl_clk.llm_sw_overr[i]);
+
+ if (pwrcl_clk.acd_init || perfcl_clk.acd_init) {
+ rc = of_property_read_u32_array(of, "qcom,acdtd-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdtd-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_td = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_td = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdcr-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdcr-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_cr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_cr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdsscr-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdsscr-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_sscr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_sscr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdextint0-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdextint0-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_extint0_cfg = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_extint0_cfg = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdextint1-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdextint1-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_extint1_cfg = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_extint1_cfg = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdautoxfer-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdautoxfer-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_autoxfer_ctl = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_autoxfer_ctl = array[perfcl_clk.cluster_num];
+ }
+
+ rc = of_property_read_u32(of, "qcom,xo-clk-rate",
+ &pwrcl_clk.xo_clk_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,xo-clk-rate property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ perfcl_clk.xo_clk_rate = pwrcl_clk.xo_clk_rate;
+
+ rc = of_property_read_u32(of, "qcom,osm-clk-rate",
+ &pwrcl_clk.osm_clk_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,osm-clk-rate property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+ perfcl_clk.osm_clk_rate = pwrcl_clk.osm_clk_rate;
+
+ rc = of_property_read_u32(of, "qcom,cc-reads",
+ &pwrcl_clk.cycle_counter_reads);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,cc-reads property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+ perfcl_clk.cycle_counter_reads = pwrcl_clk.cycle_counter_reads;
+
+ rc = of_property_read_u32(of, "qcom,cc-delay",
+ &pwrcl_clk.cycle_counter_delay);
+ if (rc)
+ dev_dbg(&pdev->dev, "no delays between cycle counter reads\n");
+ else
+ perfcl_clk.cycle_counter_delay = pwrcl_clk.cycle_counter_delay;
+
+ rc = of_property_read_u32(of, "qcom,cc-factor",
+ &pwrcl_clk.cycle_counter_factor);
+ if (rc)
+ dev_dbg(&pdev->dev, "no factor specified for cycle counter estimation\n");
+ else
+ perfcl_clk.cycle_counter_factor =
+ pwrcl_clk.cycle_counter_factor;
+
+ perfcl_clk.red_fsm_en = pwrcl_clk.red_fsm_en =
+ of_property_read_bool(of, "qcom,red-fsm-en");
+
+ perfcl_clk.boost_fsm_en = pwrcl_clk.boost_fsm_en =
+ of_property_read_bool(of, "qcom,boost-fsm-en");
+
+ perfcl_clk.safe_fsm_en = pwrcl_clk.safe_fsm_en =
+ of_property_read_bool(of, "qcom,safe-fsm-en");
+
+ perfcl_clk.ps_fsm_en = pwrcl_clk.ps_fsm_en =
+ of_property_read_bool(of, "qcom,ps-fsm-en");
+
+ perfcl_clk.droop_fsm_en = pwrcl_clk.droop_fsm_en =
+ of_property_read_bool(of, "qcom,droop-fsm-en");
+
+ perfcl_clk.wfx_fsm_en = pwrcl_clk.wfx_fsm_en =
+ of_property_read_bool(of, "qcom,wfx-fsm-en");
+
+ perfcl_clk.pc_fsm_en = pwrcl_clk.pc_fsm_en =
+ of_property_read_bool(of, "qcom,pc-fsm-en");
+
+ devm_kfree(&pdev->dev, array);
+
+ perfcl_clk.secure_init = pwrcl_clk.secure_init =
+ of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz");
+
+ if (!pwrcl_clk.secure_init)
+ return rc;
+
+ rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-cfg",
+ pwrcl_clk.apcs_mem_acc_cfg,
+ MAX_MEM_ACC_VAL_PER_LEVEL);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-cfg property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-cfg",
+ perfcl_clk.apcs_mem_acc_cfg,
+ MAX_MEM_ACC_VAL_PER_LEVEL);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-cfg property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-val",
+ pwrcl_clk.apcs_mem_acc_val,
+ MAX_MEM_ACC_VALUES);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-val",
+ perfcl_clk.apcs_mem_acc_val,
+ MAX_MEM_ACC_VALUES);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int clk_osm_resources_init(struct platform_device *pdev)
+{
+ struct device_node *node;
+ struct resource *res;
+ struct clk *c;
+ unsigned long pbase;
+ int i, rc = 0;
+ void *vbase;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osm");
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Unable to get platform resource for osm");
+ return -ENOMEM;
+ }
+
+ pwrcl_clk.pbases[OSM_BASE] = (unsigned long)res->start;
+ pwrcl_clk.vbases[OSM_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!pwrcl_clk.vbases[OSM_BASE]) {
+ dev_err(&pdev->dev, "Unable to map in osm base\n");
+ return -ENOMEM;
+ }
+
+ perfcl_clk.pbases[OSM_BASE] = pwrcl_clk.pbases[OSM_BASE] +
+ perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
+ perfcl_clk.vbases[OSM_BASE] = pwrcl_clk.vbases[OSM_BASE] +
+ perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
+
+ for (i = 0; i < MAX_CLUSTER_CNT; i++) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ i == pwrcl_clk.cluster_num ?
+ "pwrcl_pll" : "perfcl_pll");
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Unable to get platform resource\n");
+ return -ENOMEM;
+ }
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in base\n");
+ return -ENOMEM;
+ }
+
+ if (i == pwrcl_clk.cluster_num) {
+ pwrcl_clk.pbases[PLL_BASE] = pbase;
+ pwrcl_clk.vbases[PLL_BASE] = vbase;
+ } else {
+ perfcl_clk.pbases[PLL_BASE] = pbase;
+ perfcl_clk.vbases[PLL_BASE] = vbase;
+ }
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get debug mux base\n");
+ return -EINVAL;
+ }
+
+ debug_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!debug_base) {
+ dev_err(&pdev->dev, "Unable to map in debug mux base\n");
+ return -ENOMEM;
+ }
+
+ clk_ops_cpu_dbg_mux = clk_ops_gen_mux;
+ clk_ops_cpu_dbg_mux.get_rate = cpu_dbg_mux_get_rate;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_common");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get apcs common base\n");
+ return -EINVAL;
+ }
+
+ virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!virt_base) {
+ dev_err(&pdev->dev, "Failed to map apcs common registers\n");
+ return -ENOMEM;
+ }
+
+ /* efuse speed bin fuses are optional */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "pwrcl_efuse");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in pwrcl_efuse base\n");
+ return -ENOMEM;
+ }
+ pwrcl_clk.pbases[EFUSE_BASE] = pbase;
+ pwrcl_clk.vbases[EFUSE_BASE] = vbase;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "perfcl_efuse");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in perfcl_efuse base\n");
+ return -ENOMEM;
+ }
+ perfcl_clk.pbases[EFUSE_BASE] = pbase;
+ perfcl_clk.vbases[EFUSE_BASE] = vbase;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "pwrcl_acd");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in pwrcl_acd base\n");
+ return -ENOMEM;
+ }
+ pwrcl_clk.pbases[ACD_BASE] = pbase;
+ pwrcl_clk.vbases[ACD_BASE] = vbase;
+ pwrcl_clk.acd_init = true;
+ } else {
+ pwrcl_clk.acd_init = false;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "perfcl_acd");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in perfcl_acd base\n");
+ return -ENOMEM;
+ }
+ perfcl_clk.pbases[ACD_BASE] = pbase;
+ perfcl_clk.vbases[ACD_BASE] = vbase;
+ perfcl_clk.acd_init = true;
+ } else {
+ perfcl_clk.acd_init = false;
+ }
+
+ vdd_pwrcl = devm_regulator_get(&pdev->dev, "vdd-pwrcl");
+ if (IS_ERR(vdd_pwrcl)) {
+ rc = PTR_ERR(vdd_pwrcl);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get the pwrcl vreg, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ vdd_perfcl = devm_regulator_get(&pdev->dev, "vdd-perfcl");
+ if (IS_ERR(vdd_perfcl)) {
+ rc = PTR_ERR(vdd_perfcl);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get the perfcl vreg, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ pwrcl_clk.vdd_reg = vdd_pwrcl;
+ perfcl_clk.vdd_reg = vdd_perfcl;
+
+ node = of_parse_phandle(pdev->dev.of_node, "vdd-pwrcl-supply", 0);
+ if (!node) {
+ pr_err("Unable to find vdd-pwrcl-supply\n");
+ return -EINVAL;
+ }
+
+ pwrcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent);
+ if (!pwrcl_clk.vdd_dev) {
+ pr_err("Unable to find device for vdd-pwrcl-supply node\n");
+ return -EINVAL;
+ }
+
+ node = of_parse_phandle(pdev->dev.of_node,
+ "vdd-perfcl-supply", 0);
+ if (!node) {
+ pr_err("Unable to find vdd-perfcl-supply\n");
+ return -EINVAL;
+ }
+
+ perfcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent);
+ if (!perfcl_clk.vdd_dev) {
+ pr_err("Unable to find device for vdd-perfcl-supply\n");
+ return -EINVAL;
+ }
+
+ c = devm_clk_get(&pdev->dev, "aux_clk");
+ if (IS_ERR(c)) {
+ rc = PTR_ERR(c);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get aux_clk, rc=%d\n",
+ rc);
+ return rc;
+ }
+ sys_apcsaux_clk_gcc.c.parent = c;
+
+ c = devm_clk_get(&pdev->dev, "xo_ao");
+ if (IS_ERR(c)) {
+ rc = PTR_ERR(c);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get xo_ao clk, rc=%d\n",
+ rc);
+ return rc;
+ }
+ xo_ao.c.parent = c;
+
+ return 0;
+}
+
+static void clk_osm_setup_cluster_pll(struct clk_osm *c)
+{
+ writel_relaxed(0x0, c->vbases[PLL_BASE] + PLL_MODE);
+ writel_relaxed(0x20, c->vbases[PLL_BASE] + PLL_L_VAL);
+ writel_relaxed(0x01000008, c->vbases[PLL_BASE] +
+ PLL_USER_CTRL);
+ writel_relaxed(0x20004AA8, c->vbases[PLL_BASE] +
+ PLL_CONFIG_CTL_LO);
+ writel_relaxed(0x2, c->vbases[PLL_BASE] +
+ PLL_MODE);
+
+ /* Ensure writes complete before delaying */
+ clk_osm_mb(c, PLL_BASE);
+
+ udelay(PLL_WAIT_LOCK_TIME_US);
+
+ writel_relaxed(0x6, c->vbases[PLL_BASE] + PLL_MODE);
+
+ /* Ensure write completes before delaying */
+ clk_osm_mb(c, PLL_BASE);
+
+ usleep_range(50, 75);
+
+ writel_relaxed(0x7, c->vbases[PLL_BASE] + PLL_MODE);
+}
+
+static int clk_osm_setup_hw_table(struct clk_osm *c)
+{
+ struct osm_entry *entry = c->osm_table;
+ int i;
+ u32 freq_val, volt_val, override_val, spare_val;
+ u32 table_entry_offset, last_spare, last_virtual_corner = 0;
+
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ if (i < c->num_entries) {
+ freq_val = entry[i].freq_data;
+ volt_val = BVAL(21, 16, entry[i].virtual_corner)
+ | BVAL(11, 0, entry[i].open_loop_volt);
+ override_val = entry[i].override_data;
+ spare_val = entry[i].spare_data;
+
+ if (last_virtual_corner && last_virtual_corner ==
+ entry[i].virtual_corner && last_spare !=
+ entry[i].spare_data) {
+ pr_err("invalid LUT entry at row=%d virtual_corner=%d, spare_data=%d\n",
+ i, entry[i].virtual_corner,
+ entry[i].spare_data);
+ return -EINVAL;
+ }
+ last_virtual_corner = entry[i].virtual_corner;
+ last_spare = entry[i].spare_data;
+ }
+
+ table_entry_offset = i * OSM_REG_SIZE;
+ clk_osm_write_reg(c, i, INDEX_REG + table_entry_offset);
+ clk_osm_write_reg(c, freq_val, FREQ_REG + table_entry_offset);
+ clk_osm_write_reg(c, volt_val, VOLT_REG + table_entry_offset);
+ clk_osm_write_reg(c, override_val, OVERRIDE_REG +
+ table_entry_offset);
+ clk_osm_write_reg(c, spare_val, SPARE_REG +
+ table_entry_offset);
+ }
+
+ /* Make sure all writes go through */
+ clk_osm_mb(c, OSM_BASE);
+
+ return 0;
+}
+
+static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c)
+{
+ struct regulator *regulator = c->vdd_reg;
+ u32 vc, mv;
+ int i;
+
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ vc = c->osm_table[i].virtual_corner + 1;
+ /* Voltage is in uv. Convert to mv */
+ mv = regulator_list_corner_voltage(regulator, vc) / 1000;
+ c->osm_table[i].open_loop_volt = mv;
+ }
+
+ return 0;
+}
+
+static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
+ struct platform_device *pdev)
+{
+ struct regulator *regulator = c->vdd_reg;
+ int count, vc, i, threshold, rc = 0;
+ u32 corner_volt;
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,apm-threshold-voltage",
+ &threshold);
+ if (rc) {
+ pr_info("qcom,apm-threshold-voltage property not specified\n");
+ return rc;
+ }
+
+ /* Determine crossover virtual corner */
+ count = regulator_count_voltages(regulator);
+ if (count < 0) {
+ pr_err("Failed to get the number of virtual corners supported\n");
+ return count;
+ }
+
+ c->apm_crossover_vc = count - 1;
+
+ /* Determine threshold virtual corner */
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ vc = c->osm_table[i].virtual_corner + 1;
+ corner_volt = regulator_list_corner_voltage(regulator, vc);
+
+ if (corner_volt >= threshold) {
+ c->apm_threshold_vc = c->osm_table[i].virtual_corner;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int clk_osm_set_cc_policy(struct platform_device *pdev)
+{
+ int rc = 0, val;
+ u32 *array;
+ struct device_node *of = pdev->dev.of_node;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of, "qcom,up-timer", array,
+ MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No up timer value, rc=%d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CC_HYSTERESIS);
+ }
+
+ rc = of_property_read_u32_array(of, "qcom,down-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No down timer value, rc=%d\n", rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CC_HYSTERESIS);
+ }
+
+ /* OSM index override for cluster PC */
+ rc = of_property_read_u32_array(of, "qcom,pc-override-index",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No PC override index value, rc=%d\n",
+ rc);
+ clk_osm_write_reg(&pwrcl_clk, 0, CC_ZERO_BEHAV_CTRL);
+ clk_osm_write_reg(&perfcl_clk, 0, CC_ZERO_BEHAV_CTRL);
+ } else {
+ val = BVAL(6, 1, array[pwrcl_clk.cluster_num])
+ | ENABLE_OVERRIDE;
+ clk_osm_write_reg(&pwrcl_clk, val, CC_ZERO_BEHAV_CTRL);
+ val = BVAL(6, 1, array[perfcl_clk.cluster_num])
+ | ENABLE_OVERRIDE;
+ clk_osm_write_reg(&perfcl_clk, val, CC_ZERO_BEHAV_CTRL);
+ }
+
+ /* Wait for the writes to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ rc = of_property_read_bool(pdev->dev.of_node, "qcom,set-ret-inactive");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Treat cores in retention as active\n");
+ val = 0;
+ } else {
+ dev_dbg(&pdev->dev, "Treat cores in retention as inactive\n");
+ val = 1;
+ }
+
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CORE_RET_MAPPING);
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CORE_RET_MAPPING);
+
+ rc = of_property_read_bool(pdev->dev.of_node, "qcom,disable-cc-dvcs");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Disabling CC based DCVS\n");
+ val = 1;
+ } else
+ val = 0;
+
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CC_DCVS_DISABLE);
+
+ /* Wait for the writes to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ devm_kfree(&pdev->dev, array);
+ return 0;
+}
+
+static void clk_osm_setup_itm_to_osm_handoff(void)
+{
+ /* Program address of ITM_PRESENT of CPUSS */
+ clk_osm_write_reg(&pwrcl_clk, pwrcl_clk.apcs_itm_present,
+ SEQ_REG(37));
+ clk_osm_write_reg(&pwrcl_clk, 0, SEQ_REG(38));
+ clk_osm_write_reg(&perfcl_clk, perfcl_clk.apcs_itm_present,
+ SEQ_REG(37));
+ clk_osm_write_reg(&perfcl_clk, 0, SEQ_REG(38));
+
+ /*
+ * Program data to write to ITM_PRESENT assuming ITM for other domain
+ * is enabled and the ITM for this domain is to be disabled.
+ */
+ clk_osm_write_reg(&pwrcl_clk, ITM_CL0_DISABLE_CL1_ENABLED,
+ SEQ_REG(39));
+ clk_osm_write_reg(&perfcl_clk, ITM_CL0_ENABLED_CL1_DISABLE,
+ SEQ_REG(39));
+}
+
+static int clk_osm_set_llm_freq_policy(struct platform_device *pdev)
+{
+ struct device_node *of = pdev->dev.of_node;
+ u32 *array;
+ int rc = 0, val, regval;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM up frequency request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-freq-up-timer", array,
+ MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "Unable to get CC up timer value: %d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ }
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM down frequency request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-freq-down-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No LLM Frequency down timer value: %d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ }
+
+ /* Enable or disable honoring of LLM frequency requests */
+ rc = of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-llm-freq-vote");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Honoring LLM Frequency requests\n");
+ val = 0;
+ } else
+ val = 1;
+
+ /* Enable or disable LLM FREQ DVCS */
+ regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE);
+ regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE);
+
+ /* Wait for the write to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ devm_kfree(&pdev->dev, array);
+ return 0;
+}
+
+static int clk_osm_set_llm_volt_policy(struct platform_device *pdev)
+{
+ struct device_node *of = pdev->dev.of_node;
+ u32 *array;
+ int rc = 0, val, regval;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM up voltage request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-volt-up-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No LLM voltage up timer value, rc=%d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ }
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM down voltage request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-volt-down-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No LLM Voltage down timer value: %d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ }
+
+ /* Enable or disable honoring of LLM Voltage requests */
+ rc = of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-llm-volt-vote");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Honoring LLM Voltage requests\n");
+ val = 0;
+ } else
+ val = BIT(1);
+
+ /* Enable or disable LLM VOLT DVCS */
+ regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_INTF_DCVS_DISABLE);
+ regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, val, LLM_INTF_DCVS_DISABLE);
+
+ /* Wait for the writes to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ devm_kfree(&pdev->dev, array);
+ return 0;
+}
+
+static void clk_osm_program_apm_regs(struct clk_osm *c)
+{
+ /*
+ * Program address of the control register used to configure
+ * the Array Power Mux controller
+ */
+ clk_osm_write_reg(c, c->apm_mode_ctl, SEQ_REG(2));
+
+ /* Program address of controller status register */
+ clk_osm_write_reg(c, c->apm_ctrl_status, SEQ_REG(3));
+
+ /* Program mode value to switch APM from VDD_APCC to VDD_MX */
+ clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(77));
+
+ /* Program value used to determine current APM power supply is VDD_MX */
+ clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(78));
+
+ /* Program mask used to determine status of APM power supply switch */
+ clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(79));
+
+ /* Program mode value to switch APM from VDD_MX to VDD_APCC */
+ clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(80));
+
+ /*
+ * Program value used to determine current APM power supply
+ * is VDD_APCC
+ */
+ clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(81));
+}
+
+static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
+{
+ int i, curr_level, j = 0;
+ int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0};
+
+ curr_level = c->osm_table[0].spare_data;
+ for (i = 0; i < c->num_entries; i++) {
+ if (curr_level == MAX_MEM_ACC_LEVELS)
+ break;
+
+ if (c->osm_table[i].spare_data != curr_level) {
+ mem_acc_level_map[j++] = i - 1;
+ curr_level = c->osm_table[i].spare_data;
+ }
+ }
+
+ if (c->secure_init) {
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54));
+ clk_osm_write_reg(c, MEM_ACC_APM_READ_MASK, SEQ_REG(59));
+ clk_osm_write_reg(c, mem_acc_level_map[0], SEQ_REG(55));
+ clk_osm_write_reg(c, mem_acc_level_map[0] + 1, SEQ_REG(56));
+ clk_osm_write_reg(c, mem_acc_level_map[1], SEQ_REG(57));
+ clk_osm_write_reg(c, mem_acc_level_map[1] + 1, SEQ_REG(58));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(28),
+ SEQ_REG(49));
+
+ for (i = 0; i < MAX_MEM_ACC_VALUES; i++)
+ clk_osm_write_reg(c, c->apcs_mem_acc_val[i],
+ MEM_ACC_SEQ_REG_VAL_START(i));
+
+ for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++)
+ clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i],
+ MEM_ACC_SEQ_REG_CFG_START(i));
+ } else {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55),
+ mem_acc_level_map[0]);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56),
+ mem_acc_level_map[0] + 1);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57),
+ mem_acc_level_map[1]);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58),
+ mem_acc_level_map[1] + 1);
+ /* SEQ_REG(49) = SEQ_REG(28) init by TZ */
+ }
+}
+
+void clk_osm_setup_sequencer(struct clk_osm *c)
+{
+ u32 i;
+
+ pr_debug("Setting up sequencer for cluster=%d\n", c->cluster_num);
+ for (i = 0; i < ARRAY_SIZE(seq_instr); i++) {
+ clk_osm_write_reg(c, seq_instr[i],
+ (long)(SEQ_MEM_ADDR + i * 4));
+ }
+
+ pr_debug("Setting up sequencer branch instructions for cluster=%d\n",
+ c->cluster_num);
+ for (i = 0; i < ARRAY_SIZE(seq_br_instr); i++) {
+ clk_osm_write_reg(c, seq_br_instr[i],
+ (long)(SEQ_CFG_BR_ADDR + i * 4));
+ }
+}
+
+static void clk_osm_setup_cycle_counters(struct clk_osm *c)
+{
+ u32 ratio = c->osm_clk_rate;
+ u32 val = 0;
+
+ /* Enable cycle counter */
+ val |= BIT(0);
+ /* Setup OSM clock to XO ratio */
+ do_div(ratio, c->xo_clk_rate);
+ val |= BVAL(5, 1, ratio - 1) | OSM_CYCLE_COUNTER_USE_XO_EDGE_EN;
+ clk_osm_write_reg(c, val, OSM_CYCLE_COUNTER_CTRL_REG);
+ c->total_cycle_counter = 0;
+ c->prev_cycle_counter = 0;
+ pr_debug("OSM to XO clock ratio: %d\n", ratio);
+}
+
+static void clk_osm_setup_osm_was(struct clk_osm *c)
+{
+ u32 cc_hyst;
+ u32 val;
+
+ if (msmcobalt_v2)
+ return;
+
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ val |= IGNORE_PLL_LOCK_MASK;
+ cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS);
+
+ if (c->secure_init) {
+ clk_osm_write_reg(c, val, SEQ_REG(47));
+ val &= ~IGNORE_PLL_LOCK_MASK;
+ clk_osm_write_reg(c, val, SEQ_REG(48));
+
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(42),
+ SEQ_REG(40));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(43),
+ SEQ_REG(41));
+ clk_osm_write_reg(c, 0x1, SEQ_REG(44));
+ clk_osm_write_reg(c, 0x0, SEQ_REG(45));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG,
+ SEQ_REG(46));
+
+ /* C2D/C3 + D2D workaround */
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS,
+ SEQ_REG(6));
+ clk_osm_write_reg(c, cc_hyst, SEQ_REG(7));
+
+ /* Droop detector PLL lock detect workaround */
+ clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4));
+ clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO
+ : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21));
+
+ /* PLL lock detect and HMSS AHB clock workaround */
+ clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3);
+
+ /* DxFSM workaround */
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 :
+ 0x17811200, SEQ_REG(22));
+ clk_osm_write_reg(c, 0x80800, SEQ_REG(23));
+ clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24));
+ clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 :
+ 0x17811290, SEQ_REG(26));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 :
+ 0x17811290, SEQ_REG(20));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 :
+ 0x17911290, SEQ_REG(32));
+ clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35));
+ clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
+ clk_osm_write_reg(c, 0xa, SEQ_REG(86));
+ clk_osm_write_reg(c, 0xe, SEQ_REG(87));
+ clk_osm_write_reg(c, 0x00400000, SEQ_REG(88));
+ clk_osm_write_reg(c, 0x00700000, SEQ_REG(89));
+ } else {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val);
+ val &= ~IGNORE_PLL_LOCK_MASK;
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val);
+
+ /* C2D/C3 + D2D workaround */
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7),
+ cc_hyst);
+
+ /* Droop detector PLL lock detect workaround */
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4),
+ PLL_DD_USER_CTL_LO_ENABLE);
+ }
+
+ if (c->cluster_num == 0) {
+ val = readl_relaxed(c->vbases[PLL_BASE] + PLL_TEST_CTL_HI)
+ | BIT(13);
+ writel_relaxed(val, c->vbases[PLL_BASE] +
+ PLL_TEST_CTL_HI);
+ }
+
+ /* Ensure writes complete before returning */
+ clk_osm_mb(c, OSM_BASE);
+}
+
+static void clk_osm_setup_fsms(struct clk_osm *c)
+{
+ u32 val;
+
+ /* Reduction FSM */
+ if (c->red_fsm_en) {
+ val = clk_osm_read_reg(c, VMIN_REDUC_ENABLE_REG) | BIT(0);
+ clk_osm_write_reg(c, val, VMIN_REDUC_ENABLE_REG);
+ clk_osm_write_reg(c, BVAL(15, 0, clk_osm_count_ns(c, 10000)),
+ VMIN_REDUC_TIMER_REG);
+ }
+
+ /* Boost FSM */
+ if (c->boost_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | CC_BOOST_EN_MASK, PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG0);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS));
+ clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG0);
+
+ val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG1);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG1);
+
+ val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG2);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS));
+ clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG2);
+ }
+
+ /* Safe Freq FSM */
+ if (c->safe_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | DCVS_BOOST_EN_MASK,
+ PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG0);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS));
+ clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG0);
+
+ val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG1);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG1);
+
+ val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG2);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS));
+ clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG2);
+
+ }
+
+ /* PS FSM */
+ if (c->ps_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | PS_BOOST_EN_MASK, PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG0);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS));
+ clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG0);
+
+ val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG1);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG1);
+
+ val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG2);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS));
+ clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG2);
+ }
+
+ /* PLL signal timing control */
+ if (c->boost_fsm_en || c->safe_fsm_en || c->ps_fsm_en)
+ clk_osm_write_reg(c, 0x5, BOOST_PROG_SYNC_DELAY_REG);
+
+ /* Droop FSM */
+ if (c->wfx_fsm_en) {
+ /* WFx FSM */
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | WFX_DROOP_EN_MASK, PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG);
+ val |= BVAL(31, 16, clk_osm_count_ns(c, 500));
+ clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG);
+
+ val = clk_osm_read_reg(c,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ val |= BVAL(31, 16, clk_osm_count_ns(c, 250));
+ clk_osm_write_reg(c, val,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ }
+
+ /* PC/RET FSM */
+ if (c->pc_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | PC_RET_EXIT_DROOP_EN_MASK,
+ PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, 500));
+ clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG);
+
+ val = clk_osm_read_reg(c,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, 250));
+ clk_osm_write_reg(c, val,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ }
+
+ /* DCVS droop FSM - only if RCGwRC is not used for di/dt control */
+ if (c->droop_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | DCVS_DROOP_EN_MASK,
+ PDN_FSM_CTRL_REG);
+ }
+
+ if (c->wfx_fsm_en || c->ps_fsm_en || c->droop_fsm_en) {
+ clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG);
+ clk_osm_write_reg(c, clk_osm_count_ns(c, 5),
+ DROOP_RELEASE_TIMER_CTRL);
+ clk_osm_write_reg(c, clk_osm_count_ns(c, 500),
+ DCVS_DROOP_TIMER_CTRL);
+ val = clk_osm_read_reg(c, DROOP_CTRL_REG);
+ val |= BIT(31) | BVAL(22, 16, 0x2) |
+ BVAL(6, 0, 0x8);
+ clk_osm_write_reg(c, val, DROOP_CTRL_REG);
+ }
+
+ /* Enable the PLL Droop Override */
+ val = clk_osm_read_reg(c, OSM_PLL_SW_OVERRIDE_EN);
+ val |= PLL_SW_OVERRIDE_DROOP_EN;
+ clk_osm_write_reg(c, val, OSM_PLL_SW_OVERRIDE_EN);
+}
+
+static void clk_osm_do_additional_setup(struct clk_osm *c,
+ struct platform_device *pdev)
+{
+ if (!c->secure_init)
+ return;
+
+ dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n",
+ c->cluster_num);
+
+ clk_osm_write_reg(c, BVAL(23, 16, 0xF), SPM_CC_CTRL);
+
+ /* PLL LVAL programming */
+ clk_osm_write_reg(c, c->l_val_base, SEQ_REG(0));
+ clk_osm_write_reg(c, PLL_MIN_LVAL, SEQ_REG(21));
+
+ /* PLL post-div programming */
+ clk_osm_write_reg(c, c->apcs_pll_user_ctl, SEQ_REG(18));
+ clk_osm_write_reg(c, PLL_POST_DIV2, SEQ_REG(19));
+ clk_osm_write_reg(c, PLL_POST_DIV1, SEQ_REG(29));
+
+ /* APM Programming */
+ clk_osm_program_apm_regs(c);
+
+ /* GFMUX Programming */
+ clk_osm_write_reg(c, c->apcs_cfg_rcgr, SEQ_REG(16));
+ clk_osm_write_reg(c, c->apcs_cmd_rcgr, SEQ_REG(33));
+ clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(34));
+ clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17));
+ clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(82));
+ clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(83));
+ clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(84));
+ clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(85));
+
+ /* ITM to OSM handoff */
+ clk_osm_setup_itm_to_osm_handoff();
+
+ pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr),
+ ARRAY_SIZE(seq_br_instr));
+ clk_osm_setup_sequencer(&pwrcl_clk);
+ clk_osm_setup_sequencer(&perfcl_clk);
+}
+
+static void clk_osm_apm_vc_setup(struct clk_osm *c)
+{
+ /*
+ * APM crossover virtual corner corresponds to switching
+ * voltage during APM transition. APM threshold virtual
+ * corner is the first corner which requires switch
+ * sequence of APM from MX to APC.
+ */
+ if (c->secure_init) {
+ clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1));
+ clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1),
+ SEQ_REG(8));
+ clk_osm_write_reg(c, c->apm_threshold_vc,
+ SEQ_REG(15));
+ clk_osm_write_reg(c, c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff,
+ SEQ_REG(31));
+ clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6,
+ SEQ_REG(73));
+ clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6,
+ SEQ_REG(76));
+
+ /* Ensure writes complete before returning */
+ clk_osm_mb(c, OSM_BASE);
+ } else {
+ if (msmcobalt_v1) {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1),
+ c->apm_threshold_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73),
+ 0x3b | c->apm_threshold_vc << 6);
+ } else if (msmcobalt_v2) {
+ clk_osm_write_reg(c, c->apm_threshold_vc,
+ SEQ_REG1_MSMCOBALT_V2);
+ }
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72),
+ c->apm_crossover_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(15),
+ c->apm_threshold_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31),
+ c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76),
+ 0x39 | c->apm_threshold_vc << 6);
+ }
+}
+
+static irqreturn_t clk_osm_debug_irq_cb(int irq, void *data)
+{
+ struct clk_osm *c = data;
+ unsigned long first, second, total_delta = 0;
+ u32 val, factor;
+ int i;
+
+ val = clk_osm_read_reg(c, DCVS_PERF_STATE_DEVIATION_INTR_STAT);
+ if (val & BIT(0)) {
+ pr_info("OS DCVS performance state deviated\n");
+ clk_osm_write_reg(c, BIT(0),
+ DCVS_PERF_STATE_DEVIATION_INTR_CLEAR);
+ }
+
+ val = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT);
+ if (val & BIT(0)) {
+ pr_info("OS DCVS performance state corrected\n");
+ clk_osm_write_reg(c, BIT(0),
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR);
+ }
+
+ val = clk_osm_read_reg(c, DCVS_PERF_STATE_MET_INTR_STAT);
+ if (val & BIT(0)) {
+ pr_info("OS DCVS performance state desired reached\n");
+ clk_osm_write_reg(c, BIT(0), DCVS_PERF_STATE_MET_INTR_CLR);
+ }
+
+ factor = c->cycle_counter_factor ? c->cycle_counter_factor : 1;
+
+ for (i = 0; i < c->cycle_counter_reads; i++) {
+ first = clk_osm_read_reg(c, OSM_CYCLE_COUNTER_STATUS_REG);
+
+ if (c->cycle_counter_delay)
+ udelay(c->cycle_counter_delay);
+
+ second = clk_osm_read_reg(c, OSM_CYCLE_COUNTER_STATUS_REG);
+ total_delta = total_delta + ((second - first) / factor);
+ }
+
+ pr_info("cluster=%d, L_VAL (estimated)=%lu\n",
+ c->cluster_num, total_delta / c->cycle_counter_factor);
+
+ return IRQ_HANDLED;
+}
+
+static int clk_osm_setup_irq(struct platform_device *pdev, struct clk_osm *c,
+ char *irq_name)
+{
+ int rc = 0;
+
+ rc = c->irq = platform_get_irq_byname(pdev, irq_name);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "%s irq not specified\n", irq_name);
+ return rc;
+ }
+
+ rc = devm_request_irq(&pdev->dev, c->irq,
+ clk_osm_debug_irq_cb,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ "OSM IRQ", c);
+ if (rc)
+ dev_err(&pdev->dev, "Request IRQ failed for OSM IRQ\n");
+
+ return rc;
+}
+
+static u32 find_voltage(struct clk_osm *c, unsigned long rate)
+{
+ struct osm_entry *table = c->osm_table;
+ int entries = c->num_entries, i;
+
+ for (i = 0; i < entries; i++) {
+ if (rate == table[i].frequency) {
+ /* OPP table voltages have units of mV */
+ return table[i].open_loop_volt * 1000;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int add_opp(struct clk_osm *c, struct device *dev)
+{
+ unsigned long rate = 0;
+ u32 uv;
+ long rc;
+ int j = 0;
+ unsigned long min_rate = c->c.fmax[0];
+ unsigned long max_rate = c->c.fmax[c->c.num_fmax - 1];
+
+ while (1) {
+ rate = c->c.fmax[j++];
+ uv = find_voltage(c, rate);
+ if (uv <= 0) {
+ pr_warn("No voltage for %lu.\n", rate);
+ return -EINVAL;
+ }
+
+ rc = dev_pm_opp_add(dev, rate, uv);
+ if (rc) {
+ pr_warn("failed to add OPP for %lu\n", rate);
+ return rc;
+ }
+
+ /*
+ * Print the OPP pair for the lowest and highest frequency for
+ * each device that we're populating. This is important since
+ * this information will be used by thermal mitigation and the
+ * scheduler.
+ */
+ if (rate == min_rate)
+ pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n",
+ rate, uv, dev_name(dev));
+
+ if (rate == max_rate && max_rate != min_rate) {
+ pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n",
+ rate, uv, dev_name(dev));
+ break;
+ }
+
+ if (min_rate == max_rate)
+ break;
+ }
+
+ return 0;
+}
+
+static struct clk *logical_cpu_to_clk(int cpu)
+{
+ struct device_node *cpu_node;
+ const u32 *cell;
+ u64 hwid;
+ static struct clk *cpu_clk_map[NR_CPUS];
+
+ if (cpu_clk_map[cpu])
+ return cpu_clk_map[cpu];
+
+ cpu_node = of_get_cpu_node(cpu, NULL);
+ if (!cpu_node)
+ goto fail;
+
+ cell = of_get_property(cpu_node, "reg", NULL);
+ if (!cell) {
+ pr_err("%s: missing reg property\n", cpu_node->full_name);
+ goto fail;
+ }
+
+ hwid = of_read_number(cell, of_n_addr_cells(cpu_node));
+ if ((hwid | pwrcl_clk.cpu_reg_mask) == pwrcl_clk.cpu_reg_mask) {
+ cpu_clk_map[cpu] = &pwrcl_clk.c;
+ return &pwrcl_clk.c;
+ }
+ if ((hwid | perfcl_clk.cpu_reg_mask) == perfcl_clk.cpu_reg_mask) {
+ cpu_clk_map[cpu] = &perfcl_clk.c;
+ return &perfcl_clk.c;
+ }
+
+fail:
+ return NULL;
+}
+
+static u64 clk_osm_get_cpu_cycle_counter(int cpu)
+{
+ struct clk_osm *c;
+ u32 val;
+ unsigned long flags;
+
+ if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c)
+ c = &pwrcl_clk;
+ else if (logical_cpu_to_clk(cpu) == &perfcl_clk.c)
+ c = &perfcl_clk;
+ else {
+ pr_err("no clock device for CPU=%d\n", cpu);
+ return 0;
+ }
+
+ spin_lock_irqsave(&c->lock, flags);
+ val = clk_osm_read_reg_no_log(c, OSM_CYCLE_COUNTER_STATUS_REG);
+
+ if (val < c->prev_cycle_counter) {
+ /* Handle counter overflow */
+ c->total_cycle_counter += UINT_MAX -
+ c->prev_cycle_counter + val;
+ c->prev_cycle_counter = val;
+ } else {
+ c->total_cycle_counter += val - c->prev_cycle_counter;
+ c->prev_cycle_counter = val;
+ }
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ return c->total_cycle_counter;
+}
+
+static void populate_opp_table(struct platform_device *pdev)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) {
+ WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)),
+ "Failed to add OPP levels for power cluster\n");
+ }
+ if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) {
+ WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)),
+ "Failed to add OPP levels for perf cluster\n");
+ }
+ }
+}
+
+static int debugfs_get_trace_enable(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->trace_en;
+ return 0;
+}
+
+static int debugfs_set_trace_enable(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_masked_write_reg(c, val ? TRACE_CTRL_ENABLE :
+ TRACE_CTRL_DISABLE,
+ TRACE_CTRL, TRACE_CTRL_EN_MASK);
+ c->trace_en = val ? true : false;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_enable_fops,
+ debugfs_get_trace_enable,
+ debugfs_set_trace_enable,
+ "%llu\n");
+
+static int debugfs_get_wdog_trace(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->wdog_trace_en;
+ return 0;
+}
+
+static int debugfs_set_wdog_trace(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+ int regval;
+
+ if (c->version >= VERSION_1P1) {
+ regval = clk_osm_read_reg(c, TRACE_CTRL);
+ regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS :
+ regval & ~TRACE_CTRL_ENABLE_WDOG_STATUS;
+ clk_osm_write_reg(c, regval, TRACE_CTRL);
+ c->wdog_trace_en = val ? true : false;
+ } else {
+ pr_info("wdog status registers enabled by default\n");
+ }
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_wdog_enable_fops,
+ debugfs_get_wdog_trace,
+ debugfs_set_wdog_trace,
+ "%llu\n");
+
+#define MAX_DEBUG_BUF_LEN 15
+
+static DEFINE_MUTEX(debug_buf_mutex);
+static char debug_buf[MAX_DEBUG_BUF_LEN];
+
+static ssize_t debugfs_trace_method_set(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct clk_osm *c = file->private_data;
+ u32 val;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!c) {
+ pr_err("invalid clk_osm handle\n");
+ return -EINVAL;
+ }
+
+ if (count < MAX_DEBUG_BUF_LEN) {
+ mutex_lock(&debug_buf_mutex);
+
+ if (copy_from_user(debug_buf, (void __user *) buf, count)) {
+ mutex_unlock(&debug_buf_mutex);
+ return -EFAULT;
+ }
+ debug_buf[count] = '\0';
+ mutex_unlock(&debug_buf_mutex);
+
+ /* check that user entered a supported packet type */
+ if (strcmp(debug_buf, "periodic\n") == 0) {
+ clk_osm_write_reg(c, clk_osm_count_ns(c,
+ PERIODIC_TRACE_DEFAULT_NS),
+ PERIODIC_TRACE_TIMER_CTRL);
+ clk_osm_masked_write_reg(c,
+ TRACE_CTRL_PERIODIC_TRACE_ENABLE,
+ TRACE_CTRL, TRACE_CTRL_PERIODIC_TRACE_EN_MASK);
+ c->trace_method = PERIODIC_PACKET;
+ c->trace_periodic_timer = PERIODIC_TRACE_DEFAULT_NS;
+ return count;
+ } else if (strcmp(debug_buf, "xor\n") == 0) {
+ val = clk_osm_read_reg(c, TRACE_CTRL);
+ val &= ~TRACE_CTRL_PERIODIC_TRACE_ENABLE;
+ clk_osm_write_reg(c, val, TRACE_CTRL);
+ c->trace_method = XOR_PACKET;
+ return count;
+ }
+ }
+
+ pr_err("error, supported trace mode types: 'periodic' or 'xor'\n");
+ return -EINVAL;
+}
+
+static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct clk_osm *c = file->private_data;
+ int len, rc;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!c) {
+ pr_err("invalid clk_osm handle\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&debug_buf_mutex);
+
+ if (c->trace_method == PERIODIC_PACKET)
+ len = snprintf(debug_buf, sizeof(debug_buf), "periodic\n");
+ else if (c->trace_method == XOR_PACKET)
+ len = snprintf(debug_buf, sizeof(debug_buf), "xor\n");
+
+ rc = simple_read_from_buffer((void __user *) buf, len, ppos,
+ (void *) debug_buf, len);
+
+ mutex_unlock(&debug_buf_mutex);
+
+ return rc;
+}
+
+static int debugfs_trace_method_open(struct inode *inode, struct file *file)
+{
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debugfs_trace_method_fops = {
+ .write = debugfs_trace_method_set,
+ .open = debugfs_trace_method_open,
+ .read = debugfs_trace_method_get,
+};
+
+static int debugfs_get_trace_packet_id(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->trace_id;
+ return 0;
+}
+
+static int debugfs_set_trace_packet_id(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ if (val < TRACE_PACKET0 || val > TRACE_PACKET3) {
+ pr_err("supported trace IDs=%d-%d\n",
+ TRACE_PACKET0, TRACE_PACKET3);
+ return 0;
+ }
+
+ clk_osm_masked_write_reg(c, val << TRACE_CTRL_PACKET_TYPE_SHIFT,
+ TRACE_CTRL, TRACE_CTRL_PACKET_TYPE_MASK);
+ c->trace_id = val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_packet_id_fops,
+ debugfs_get_trace_packet_id,
+ debugfs_set_trace_packet_id,
+ "%llu\n");
+
+static int debugfs_get_trace_periodic_timer(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->trace_periodic_timer;
+ return 0;
+}
+
+static int debugfs_set_trace_periodic_timer(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ if (val < PERIODIC_TRACE_MIN_NS || val > PERIODIC_TRACE_MAX_NS) {
+ pr_err("supported periodic trace periods=%d-%ld ns\n",
+ PERIODIC_TRACE_MIN_NS, PERIODIC_TRACE_MAX_NS);
+ return 0;
+ }
+
+ clk_osm_write_reg(c, clk_osm_count_ns(c, val),
+ PERIODIC_TRACE_TIMER_CTRL);
+ c->trace_periodic_timer = val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_periodic_timer_fops,
+ debugfs_get_trace_periodic_timer,
+ debugfs_set_trace_periodic_timer,
+ "%llu\n");
+
+static int debugfs_get_perf_state_met_irq(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = clk_osm_read_reg(c, DCVS_PERF_STATE_MET_INTR_EN);
+ return 0;
+}
+
+static int debugfs_set_perf_state_met_irq(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_write_reg(c, val ? 1 : 0,
+ DCVS_PERF_STATE_MET_INTR_EN);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_met_irq_fops,
+ debugfs_get_perf_state_met_irq,
+ debugfs_set_perf_state_met_irq,
+ "%llu\n");
+
+static int debugfs_get_perf_state_deviation_irq(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DEVIATION_INTR_EN);
+ return 0;
+}
+
+static int debugfs_set_perf_state_deviation_irq(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_write_reg(c, val ? 1 : 0,
+ DCVS_PERF_STATE_DEVIATION_INTR_EN);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_deviation_irq_fops,
+ debugfs_get_perf_state_deviation_irq,
+ debugfs_set_perf_state_deviation_irq,
+ "%llu\n");
+
+static int debugfs_get_perf_state_deviation_corrected_irq(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN);
+ return 0;
+}
+
+static int debugfs_set_perf_state_deviation_corrected_irq(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_write_reg(c, val ? 1 : 0,
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_deviation_corrected_irq_fops,
+ debugfs_get_perf_state_deviation_corrected_irq,
+ debugfs_set_perf_state_deviation_corrected_irq,
+ "%llu\n");
+
+static int debugfs_get_debug_reg(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR)
+ *val = readl_relaxed((char *)c->vbases[ACD_BASE] +
+ c->acd_debugfs_addr);
+ else
+ *val = clk_osm_acd_local_read_reg(c, c->acd_debugfs_addr);
+ return 0;
+}
+
+static int debugfs_set_debug_reg(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR)
+ clk_osm_acd_master_write_reg(c, val, c->acd_debugfs_addr);
+ else
+ clk_osm_acd_master_write_through_reg(c, val,
+ c->acd_debugfs_addr);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_fops,
+ debugfs_get_debug_reg,
+ debugfs_set_debug_reg,
+ "0x%llx\n");
+
+static int debugfs_get_debug_reg_addr(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->acd_debugfs_addr;
+ return 0;
+}
+
+static int debugfs_set_debug_reg_addr(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ c->acd_debugfs_addr = val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_addr_fops,
+ debugfs_get_debug_reg_addr,
+ debugfs_set_debug_reg_addr,
+ "%llu\n");
+
+static void populate_debugfs_dir(struct clk_osm *c)
+{
+ struct dentry *temp;
+
+ if (osm_debugfs_base == NULL) {
+ osm_debugfs_base = debugfs_create_dir("osm", NULL);
+ if (IS_ERR_OR_NULL(osm_debugfs_base)) {
+ pr_err("osm debugfs base directory creation failed\n");
+ osm_debugfs_base = NULL;
+ return;
+ }
+ }
+
+ c->debugfs = debugfs_create_dir(c->c.dbg_name, osm_debugfs_base);
+ if (IS_ERR_OR_NULL(c->debugfs)) {
+ pr_err("osm debugfs directory creation failed\n");
+ return;
+ }
+
+ temp = debugfs_create_file("perf_state_met_irq_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_perf_state_met_irq_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("perf_state_met_irq_enable debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("perf_state_deviation_irq_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_perf_state_deviation_irq_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("perf_state_deviation_irq_enable debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("perf_state_deviation_corrected_irq_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_perf_state_deviation_corrected_irq_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_perf_state_deviation_corrected_irq_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("wdog_trace_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_wdog_enable_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_wdog_enable_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_enable_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_enable_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_method",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_method_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_method_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_packet_id",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_packet_id_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_packet_id_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_periodic_timer",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_periodic_timer_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_periodic_timer_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("acd_debug_reg",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_acd_debug_reg_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_acd_debug_reg_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("acd_debug_reg_addr",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_acd_debug_reg_addr_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_acd_debug_reg_addr_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+exit:
+ if (IS_ERR_OR_NULL(temp))
+ debugfs_remove_recursive(c->debugfs);
+}
+
+static int clk_osm_panic_callback(struct notifier_block *nfb,
+ unsigned long event,
+ void *data)
+{
+ void __iomem *virt_addr;
+ u32 value, reg;
+ struct clk_osm *c = container_of(nfb,
+ struct clk_osm,
+ panic_notifier);
+
+ reg = c->pbases[OSM_BASE] + WDOG_DOMAIN_PSTATE_STATUS;
+ virt_addr = ioremap(reg, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("DOM%d_PSTATE_STATUS[0x%08x]=0x%08x\n", c->cluster_num,
+ reg, value);
+ iounmap(virt_addr);
+ }
+
+ reg = c->pbases[OSM_BASE] + WDOG_PROGRAM_COUNTER;
+ virt_addr = ioremap(reg, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("DOM%d_PROGRAM_COUNTER[0x%08x]=0x%08x\n", c->cluster_num,
+ reg, value);
+ iounmap(virt_addr);
+ }
+
+ virt_addr = ioremap(c->apm_ctrl_status, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("APM_CTLER_STATUS_%d[0x%08x]=0x%08x\n", c->cluster_num,
+ c->apm_ctrl_status, value);
+ iounmap(virt_addr);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int clk_osm_acd_init(struct clk_osm *c)
+{
+
+ int rc = 0;
+ u32 auto_xfer_mask = 0;
+
+ if (!c->acd_init)
+ return 0;
+
+ c->acd_debugfs_addr = ACD_HW_VERSION;
+
+ /* Program ACD tunable-length delay register */
+ clk_osm_acd_master_write_reg(c, c->acd_td, ACDTD);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDTD);
+
+ /* Program ACD control register */
+ clk_osm_acd_master_write_reg(c, c->acd_cr, ACDCR);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDCR);
+
+ /* Program ACD soft start control register */
+ clk_osm_acd_master_write_reg(c, c->acd_sscr, ACDSSCR);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDSSCR);
+
+ /* Program initial ACD external interface configuration register */
+ clk_osm_acd_master_write_reg(c, c->acd_extint0_cfg, ACD_EXTINT_CFG);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACD_EXTINT_CFG);
+
+ /* Program ACD auto-register transfer control register */
+ clk_osm_acd_master_write_reg(c, c->acd_autoxfer_ctl, ACD_AUTOXFER_CTL);
+
+ /* Ensure writes complete before transfers to local copy */
+ clk_osm_acd_mb(c);
+
+ /* Transfer master copies */
+ rc = clk_osm_acd_auto_local_write_reg(c, auto_xfer_mask);
+ if (rc)
+ return rc;
+
+ /* Switch CPUSS clock source to ACD clock */
+ rc = clk_osm_acd_master_write_through_reg(c, ACD_GFMUX_CFG_SELECT,
+ ACD_GFMUX_CFG);
+ if (rc)
+ return rc;
+
+ /* Program ACD_DCVS_SW */
+ rc = clk_osm_acd_master_write_through_reg(c,
+ ACD_DCVS_SW_DCVS_IN_PRGR_SET,
+ ACD_DCVS_SW);
+ if (rc)
+ return rc;
+
+ rc = clk_osm_acd_master_write_through_reg(c,
+ ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR,
+ ACD_DCVS_SW);
+ if (rc)
+ return rc;
+
+ udelay(1);
+
+ /* Program final ACD external interface configuration register */
+ rc = clk_osm_acd_master_write_through_reg(c, c->acd_extint1_cfg,
+ ACD_EXTINT_CFG);
+ if (rc)
+ return rc;
+
+ /*
+ * ACDCR, ACDTD, ACDSSCR, ACD_EXTINT_CFG, ACD_GFMUX_CFG
+ * must be copied from master to local copy on PC exit.
+ */
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACD_GFMUX_CFG);
+ clk_osm_acd_master_write_reg(c, auto_xfer_mask, ACD_AUTOXFER_CFG);
+
+ return 0;
+}
+
+static unsigned long init_rate = 300000000;
+static unsigned long osm_clk_init_rate = 200000000;
+
+static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
+{
+ int rc, cpu;
+ int speedbin = 0, pvs_ver = 0;
+ u32 pte_efuse;
+ char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0";
+ char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0";
+ struct cpu_cycle_counter_cb cb = {
+ .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter,
+ };
+
+ if (of_find_compatible_node(NULL, NULL,
+ "qcom,cpu-clock-osm-msmcobalt-v1")) {
+ msmcobalt_v1 = true;
+ } else if (of_find_compatible_node(NULL, NULL,
+ "qcom,cpu-clock-osm-msmcobalt-v2")) {
+ msmcobalt_v2 = true;
+ }
+
+ rc = clk_osm_resources_init(pdev);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "resources init failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_parse_dt_configs(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse device tree configurations\n");
+ return rc;
+ }
+
+ if ((pwrcl_clk.secure_init || perfcl_clk.secure_init) &&
+ msmcobalt_v2) {
+ pr_err("unsupported configuration for msmcobalt v2\n");
+ return -EINVAL;
+ }
+
+ if (pwrcl_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]);
+ speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) &
+ PWRCL_EFUSE_MASK);
+ snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr),
+ "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver);
+ }
+
+ dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n",
+ speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &pwrcl_clk,
+ pwrclspeedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (perfcl_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
+ speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) &
+ PERFCL_EFUSE_MASK);
+ snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr),
+ "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver);
+ }
+
+ dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n",
+ speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for power cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for perf cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev, "No APM crossover corner programmed\n");
+
+ rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev, "No APM crossover corner programmed\n");
+
+ clk_osm_setup_cycle_counters(&pwrcl_clk);
+ clk_osm_setup_cycle_counters(&perfcl_clk);
+
+ clk_osm_print_osm_table(&pwrcl_clk);
+ clk_osm_print_osm_table(&perfcl_clk);
+
+ rc = clk_osm_setup_hw_table(&pwrcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup power cluster hardware table\n");
+ goto exit;
+ }
+ rc = clk_osm_setup_hw_table(&perfcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n");
+ goto exit;
+ }
+
+ /* Policy tuning */
+ rc = clk_osm_set_cc_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "cc policy setup failed");
+ goto exit;
+ }
+
+ /* LLM Freq Policy Tuning */
+ rc = clk_osm_set_llm_freq_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "LLM Frequency Policy setup failed");
+ goto exit;
+ }
+
+ /* LLM Voltage Policy Tuning */
+ rc = clk_osm_set_llm_volt_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to set LLM voltage Policy");
+ goto exit;
+ }
+
+ clk_osm_setup_fsms(&pwrcl_clk);
+ clk_osm_setup_fsms(&perfcl_clk);
+
+ /*
+ * Perform typical secure-world HW initialization
+ * as necessary.
+ */
+ clk_osm_do_additional_setup(&pwrcl_clk, pdev);
+ clk_osm_do_additional_setup(&perfcl_clk, pdev);
+
+ /* MEM-ACC Programming */
+ clk_osm_program_mem_acc_regs(&pwrcl_clk);
+ clk_osm_program_mem_acc_regs(&perfcl_clk);
+
+ /* Program APM crossover corners */
+ clk_osm_apm_vc_setup(&pwrcl_clk);
+ clk_osm_apm_vc_setup(&perfcl_clk);
+
+ rc = clk_osm_setup_irq(pdev, &pwrcl_clk, "pwrcl-irq");
+ if (rc)
+ pr_err("Debug IRQ not set for pwrcl\n");
+
+ rc = clk_osm_setup_irq(pdev, &perfcl_clk, "perfcl-irq");
+ if (rc)
+ pr_err("Debug IRQ not set for perfcl\n");
+
+ clk_osm_setup_osm_was(&pwrcl_clk);
+ clk_osm_setup_osm_was(&perfcl_clk);
+
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,osm-pll-setup")) {
+ clk_osm_setup_cluster_pll(&pwrcl_clk);
+ clk_osm_setup_cluster_pll(&perfcl_clk);
+ }
+
+ rc = clk_osm_acd_init(&pwrcl_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for pwrcl, rc=%d\n", rc);
+ return rc;
+ }
+ rc = clk_osm_acd_init(&perfcl_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for perfcl, rc=%d\n", rc);
+ return rc;
+ }
+
+ spin_lock_init(&pwrcl_clk.lock);
+ spin_lock_init(&perfcl_clk.lock);
+
+ pwrcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &pwrcl_clk.panic_notifier);
+ perfcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &perfcl_clk.panic_notifier);
+
+ rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm,
+ ARRAY_SIZE(cpu_clocks_osm));
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to register CPU clocks, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /*
+ * The hmss_gpll0 clock runs at 300 MHz. Ensure it is at the correct
+ * frequency before enabling OSM. LUT index 0 is always sourced from
+ * this clock.
+ */
+ rc = clk_set_rate(&sys_apcsaux_clk_gcc.c, init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on hmss_gpll0, rc=%d\n",
+ rc);
+ return rc;
+ }
+ clk_prepare_enable(&sys_apcsaux_clk_gcc.c);
+
+ rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ /* Make sure index zero is selected */
+ rc = clk_set_rate(&pwrcl_clk.c, init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ rc = clk_set_rate(&perfcl_clk.c, init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ get_online_cpus();
+
+ /* Enable OSM */
+ for_each_online_cpu(cpu) {
+ WARN(clk_prepare_enable(logical_cpu_to_clk(cpu)),
+ "Failed to enable clock for cpu %d\n", cpu);
+ }
+
+ /* Set final boot rate */
+ rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ?
+ MSMCOBALTV1_PWRCL_BOOT_RATE :
+ MSMCOBALTV2_PWRCL_BOOT_RATE);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ?
+ MSMCOBALTV1_PERFCL_BOOT_RATE :
+ MSMCOBALTV2_PERFCL_BOOT_RATE);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG);
+ perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG);
+
+ populate_opp_table(pdev);
+ populate_debugfs_dir(&pwrcl_clk);
+ populate_debugfs_dir(&perfcl_clk);
+
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ register_cpu_cycle_counter_cb(&cb);
+
+ pr_info("OSM driver inited\n");
+ put_online_cpus();
+
+ return 0;
+
+exit2:
+ clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
+exit:
+ dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n",
+ rc);
+ panic("Unable to Setup OSM");
+}
+
+static const struct of_device_id match_table[] = {
+ { .compatible = "qcom,cpu-clock-osm-msmcobalt-v1" },
+ { .compatible = "qcom,cpu-clock-osm-msmcobalt-v2" },
+ {}
+};
+
+static struct platform_driver cpu_clock_osm_driver = {
+ .probe = cpu_clock_osm_driver_probe,
+ .driver = {
+ .name = "cpu-clock-osm",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cpu_clock_osm_init(void)
+{
+ return platform_driver_register(&cpu_clock_osm_driver);
+}
+arch_initcall(cpu_clock_osm_init);
+
+static void __exit cpu_clock_osm_exit(void)
+{
+ platform_driver_unregister(&cpu_clock_osm_driver);
+}
+module_exit(cpu_clock_osm_exit);
+
+MODULE_DESCRIPTION("CPU clock driver for OSM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index bc982c9bfa71..c6ea293a8df3 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -250,7 +250,8 @@ static int clk_smd_rpm_set_rate_sleep(struct clk_smd_rpm *r,
static void to_active_sleep(struct clk_smd_rpm *r, unsigned long rate,
unsigned long *active, unsigned long *sleep)
{
- *active = rate;
+ /* Convert the rate (hz) to khz */
+ *active = DIV_ROUND_UP(rate, 1000);
/*
* Active-only clocks don't care what the rate is during sleep. So,
@@ -533,9 +534,9 @@ DEFINE_CLK_SMD_RPM(msm8996, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8996, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM_BRANCH(msm8996, cxo, cxo_a, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 0, 1000);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 1, 1000);
+DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
+ QCOM_SMD_RPM_AGGR_CLK, 2, 1000);
DEFINE_CLK_SMD_RPM_QDSS(msm8996, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk1, bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk2, bb_clk2_a, 2);
@@ -544,7 +545,7 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk2, rf_clk2_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, ln_bb_clk, ln_bb_a_clk, 8);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk1, div_clk1_ao, 0xb);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk2, div_clk2_ao, 0xc);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_ao, 0xc);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_ao, 0xd);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk1_pin, bb_clk1_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4);
@@ -613,13 +614,13 @@ DEFINE_CLK_SMD_RPM(msmfalcon, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 2);
DEFINE_CLK_SMD_RPM_QDSS(msmfalcon, qdss_clk, qdss_a_clk,
QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, rf_clk2, rf_clk2_ao, 5);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, rf_clk1, rf_clk1_ao, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, div_clk1, div_clk1_ao, 0xb);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk1, ln_bb_clk1_ao, 0x1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk2, ln_bb_clk2_ao, 0x2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk3, ln_bb_clk3_ao, 0x3);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, rf_clk2_pin, rf_clk2_a_pin, 5);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, rf_clk1_pin, rf_clk1_ao_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk1_pin,
ln_bb_clk1_pin_ao, 0x1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk2_pin,
@@ -656,8 +657,10 @@ static struct clk_hw *msmfalcon_clks[] = {
[RPM_BIMC_A_CLK] = &msmfalcon_bimc_a_clk.hw,
[RPM_QDSS_CLK] = &msmfalcon_qdss_clk.hw,
[RPM_QDSS_A_CLK] = &msmfalcon_qdss_a_clk.hw,
- [RPM_RF_CLK2_PIN] = &msmfalcon_rf_clk2_pin.hw,
- [RPM_RF_CLK2_A_PIN] = &msmfalcon_rf_clk2_a_pin.hw,
+ [RPM_RF_CLK1] = &msmfalcon_rf_clk1.hw,
+ [RPM_RF_CLK1_A] = &msmfalcon_rf_clk1_ao.hw,
+ [RPM_RF_CLK1_PIN] = &msmfalcon_rf_clk1_pin.hw,
+ [RPM_RF_CLK1_A_PIN] = &msmfalcon_rf_clk1_ao_pin.hw,
[RPM_AGGR2_NOC_CLK] = &msmfalcon_aggre2_noc_clk.hw,
[RPM_AGGR2_NOC_A_CLK] = &msmfalcon_aggre2_noc_a_clk.hw,
[RPM_CNOC_CLK] = &msmfalcon_cnoc_clk.hw,
diff --git a/drivers/clk/qcom/mmcc-msmfalcon.c b/drivers/clk/qcom/mmcc-msmfalcon.c
new file mode 100644
index 000000000000..e4a84765430a
--- /dev/null
+++ b/drivers/clk/qcom/mmcc-msmfalcon.c
@@ -0,0 +1,3036 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "common.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "reset.h"
+#include "vdd-level-falcon.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define F_SLEW(f, s, h, m, n, src_freq) { (f), (s), (2 * (h) - 1), (m), (n), \
+ (src_freq) }
+
+enum vdd_a_levels {
+ VDDA_NONE,
+ VDDA_LOWER, /* SVS2 */
+ VDDA_NUM,
+};
+
+static int vdda_levels[] = {
+ 0,
+ 1800000,
+};
+
+#define VDDA_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdda, \
+ .rate_max = (unsigned long[VDDA_NUM]) { \
+ [VDDA_##l1] = (f1), \
+ }, \
+ .num_rate_max = VDDA_NUM
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdda, VDDA_NUM, 1, vdda_levels);
+
+enum {
+ P_CORE_BI_PLL_TEST_SE,
+ P_CORE_PI_SLEEP_CLK,
+ P_CXO,
+ P_DP_PHY_PLL_LINK_CLK,
+ P_DP_PHY_PLL_VCO_DIV,
+ P_DSI0_PHY_PLL_OUT_BYTECLK,
+ P_DSI0_PHY_PLL_OUT_DSICLK,
+ P_DSI1_PHY_PLL_OUT_BYTECLK,
+ P_DSI1_PHY_PLL_OUT_DSICLK,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_MAIN_DIV,
+ P_MMPLL0_PLL_OUT_MAIN,
+ P_MMPLL10_PLL_OUT_MAIN,
+ P_MMPLL3_PLL_OUT_MAIN,
+ P_MMPLL4_PLL_OUT_MAIN,
+ P_MMPLL5_PLL_OUT_MAIN,
+ P_MMPLL6_PLL_OUT_MAIN,
+ P_MMPLL7_PLL_OUT_MAIN,
+ P_MMPLL8_PLL_OUT_MAIN,
+};
+
+static const struct parent_map mmcc_parent_map_0[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL8_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_0[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll8_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_1[] = {
+ { P_CXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
+ { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_1[] = {
+ "xo",
+ "dsi0_phy_pll_out_byteclk",
+ "dsi1_phy_pll_out_byteclk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_2[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL10_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_2[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_3[] = {
+ { P_CXO, 0 },
+ { P_MMPLL4_PLL_OUT_MAIN, 1 },
+ { P_MMPLL7_PLL_OUT_MAIN, 2 },
+ { P_MMPLL10_PLL_OUT_MAIN, 3 },
+ { P_CORE_PI_SLEEP_CLK, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_3[] = {
+ "xo",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "core_pi_sleep_clk",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_4[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL7_PLL_OUT_MAIN, 2 },
+ { P_MMPLL10_PLL_OUT_MAIN, 3 },
+ { P_CORE_PI_SLEEP_CLK, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_4[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "core_pi_sleep_clk",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_5[] = {
+ { P_CXO, 0 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_5[] = {
+ "xo",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_6[] = {
+ { P_CXO, 0 },
+ { P_DP_PHY_PLL_LINK_CLK, 1 },
+ { P_DP_PHY_PLL_VCO_DIV, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_6[] = {
+ "xo",
+ "dp_phy_pll_link_clk",
+ "dp_phy_pll_vco_div",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_7[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL5_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_7[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll5_pll_out_main",
+ "mmpll7_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_8[] = {
+ { P_CXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
+ { P_DSI1_PHY_PLL_OUT_DSICLK, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_8[] = {
+ "xo",
+ "dsi0_phy_pll_out_dsiclk",
+ "dsi1_phy_pll_out_dsiclk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_9[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL10_PLL_OUT_MAIN, 4 },
+ { P_MMPLL6_PLL_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_9[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "mmpll6_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_10[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_10[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_11[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL10_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_MMPLL6_PLL_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_11[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "mmpll6_pll_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_12[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL8_PLL_OUT_MAIN, 2 },
+ { P_MMPLL3_PLL_OUT_MAIN, 3 },
+ { P_MMPLL6_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_MMPLL7_PLL_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_12[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll8_pll_out_main",
+ "mmpll3_pll_out_main",
+ "mmpll6_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "mmpll7_pll_out_main",
+ "core_bi_pll_test_se",
+};
+
+/* Voteable PLL */
+static struct clk_alpha_pll mmpll0_pll_out_main = {
+ .offset = 0xc000,
+ .clkr = {
+ .enable_reg = 0x1f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll0_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 404000000,
+ LOW, 808000000),
+ },
+ },
+};
+
+static struct clk_alpha_pll mmpll6_pll_out_main = {
+ .offset = 0xf0,
+ .clkr = {
+ .enable_reg = 0x1f0,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll6_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 540000000,
+ LOW_L1, 1080000000),
+ },
+ },
+};
+
+/* APSS controlled PLLs */
+static struct pll_vco vco[] = {
+ { 1000000000, 2000000000, 0 },
+ { 750000000, 1500000000, 1 },
+ { 500000000, 1000000000, 2 },
+ { 250000000, 500000000, 3 },
+};
+
+static const struct pll_config mmpll10_config = {
+ .l = 0x1e,
+ .config_ctl_val = 0x00004289,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll10_pll_out_main = {
+ .offset = 0x190,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll10_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDDA_FMAX_MAP1(LOWER, 576000000),
+ },
+ },
+};
+
+static struct pll_vco mmpll3_vco[] = {
+ { 750000000, 1500000000, 1 },
+};
+
+static const struct pll_config mmpll3_config = {
+ .l = 0x2e,
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x1 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll3_pll_out_main = {
+ .offset = 0x0,
+ .vco_table = mmpll3_vco,
+ .num_vco = ARRAY_SIZE(mmpll3_vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll3_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_slew_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 441600000,
+ NOMINAL, 1036800000),
+ },
+ },
+};
+
+static const struct pll_config mmpll4_config = {
+ .l = 0x28,
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll4_pll_out_main = {
+ .offset = 0x50,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll4_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 384000000,
+ LOW, 768000000),
+ },
+ },
+};
+
+static const struct pll_config mmpll5_config = {
+ .l = 0x2a,
+ .config_ctl_val = 0x4001055b,
+ .alpha_u = 0xf8,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll5_pll_out_main = {
+ .offset = 0xa0,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll5_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 421500000,
+ LOW, 825000000),
+ },
+ },
+};
+
+static const struct pll_config mmpll7_config = {
+ .l = 0x32,
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll7_pll_out_main = {
+ .offset = 0x140,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll7_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 480000000,
+ LOW, 960000000),
+ },
+ },
+};
+
+static const struct pll_config mmpll8_config = {
+ .l = 0x30,
+ .alpha_u = 0x70,
+ .alpha_en_mask = BIT(24),
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll8_pll_out_main = {
+ .offset = 0x1c0,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll8_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 465000000,
+ LOW, 930000000),
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_ahb_clk_src[] = {
+ F(19200000, P_CXO, 1, 0, 0),
+ F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0),
+ F(80800000, P_MMPLL0_PLL_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ahb_clk_src = {
+ .cmd_rcgr = 0x5000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_10,
+ .freq_tbl = ftbl_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ahb_clk_src",
+ .parent_names = mmcc_parent_names_10,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 19200000,
+ LOW, 40000000,
+ NOMINAL, 80800000),
+ },
+};
+
+static struct clk_rcg2 byte0_clk_src = {
+ .cmd_rcgr = 0x2120,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte0_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_byte2_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 131250000,
+ LOW, 210000000,
+ NOMINAL, 262500000),
+ },
+};
+
+static struct clk_rcg2 byte1_clk_src = {
+ .cmd_rcgr = 0x2140,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte1_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_byte2_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 131250000,
+ LOW, 210000000,
+ NOMINAL, 262500000),
+ },
+};
+
+static const struct freq_tbl ftbl_camss_gp0_clk_src[] = {
+ F(10000, P_CXO, 16, 1, 120),
+ F(24000, P_CXO, 16, 1, 50),
+ F(6000000, P_GPLL0_OUT_MAIN_DIV, 10, 1, 5),
+ F(12000000, P_GPLL0_OUT_MAIN_DIV, 10, 2, 5),
+ F(13043478, P_GPLL0_OUT_MAIN_DIV, 1, 1, 23),
+ F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25),
+ F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camss_gp0_clk_src = {
+ .cmd_rcgr = 0x3420,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_4,
+ .freq_tbl = ftbl_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camss_gp0_clk_src",
+ .parent_names = mmcc_parent_names_4,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 50000000,
+ LOW, 100000000,
+ NOMINAL, 200000000),
+ },
+};
+
+static struct clk_rcg2 camss_gp1_clk_src = {
+ .cmd_rcgr = 0x3450,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_4,
+ .freq_tbl = ftbl_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camss_gp1_clk_src",
+ .parent_names = mmcc_parent_names_4,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 50000000,
+ LOW, 100000000,
+ NOMINAL, 200000000),
+ },
+};
+
+static const struct freq_tbl ftbl_cci_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_MAIN_DIV, 8, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cci_clk_src = {
+ .cmd_rcgr = 0x3300,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_4,
+ .freq_tbl = ftbl_cci_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cci_clk_src",
+ .parent_names = mmcc_parent_names_4,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 37500000,
+ LOW, 50000000,
+ NOMINAL, 100000000),
+ },
+};
+
+static const struct freq_tbl ftbl_cpp_clk_src[] = {
+ F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(256000000, P_MMPLL4_PLL_OUT_MAIN, 3, 0, 0),
+ F(384000000, P_MMPLL4_PLL_OUT_MAIN, 2, 0, 0),
+ F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0),
+ F(540000000, P_MMPLL6_PLL_OUT_MAIN, 2, 0, 0),
+ F(576000000, P_MMPLL10_PLL_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cpp_clk_src = {
+ .cmd_rcgr = 0x3640,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_11,
+ .freq_tbl = ftbl_cpp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cpp_clk_src",
+ .parent_names = mmcc_parent_names_11,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 120000000,
+ LOW, 256000000,
+ LOW_L1, 384000000,
+ NOMINAL, 480000000,
+ NOMINAL_L1, 540000000,
+ HIGH, 576000000),
+ },
+};
+
+static const struct freq_tbl ftbl_csi0_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(310000000, P_MMPLL8_PLL_OUT_MAIN, 3, 0, 0),
+ F(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0),
+ F(465000000, P_MMPLL8_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csi0_clk_src = {
+ .cmd_rcgr = 0x3090,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi0_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static const struct freq_tbl ftbl_csi0phytimer_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x3000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi0phytimer_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333),
+ },
+};
+
+static struct clk_rcg2 csi1_clk_src = {
+ .cmd_rcgr = 0x3100,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi1_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static struct clk_rcg2 csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x3030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi1phytimer_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333),
+ },
+};
+
+static struct clk_rcg2 csi2_clk_src = {
+ .cmd_rcgr = 0x3160,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static struct clk_rcg2 csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x3060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2phytimer_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333),
+ },
+};
+
+static struct clk_rcg2 csi3_clk_src = {
+ .cmd_rcgr = 0x31c0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi3_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static const struct freq_tbl ftbl_csiphy_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0),
+ F(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csiphy_clk_src = {
+ .cmd_rcgr = 0x3800,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csiphy_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csiphy_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333,
+ NOMINAL, 320000000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_aux_clk_src[] = {
+ F(19200000, P_CXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_aux_clk_src = {
+ .cmd_rcgr = 0x2260,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_5,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_aux_clk_src",
+ .parent_names = mmcc_parent_names_5,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_crypto_clk_src[] = {
+ F(101250000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0),
+ F(168750000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0),
+ F(337500000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_crypto_clk_src = {
+ .cmd_rcgr = 0x2220,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_6,
+ .freq_tbl = ftbl_dp_crypto_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_crypto_clk_src",
+ .parent_names = mmcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 101250000,
+ LOW, 168750000,
+ NOMINAL, 337500000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_gtc_clk_src[] = {
+ F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN_DIV, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_gtc_clk_src = {
+ .cmd_rcgr = 0x2280,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_5,
+ .freq_tbl = ftbl_dp_gtc_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_gtc_clk_src",
+ .parent_names = mmcc_parent_names_5,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 40000000,
+ LOW, 300000000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_link_clk_src[] = {
+ F(162000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0),
+ F(270000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0),
+ F(540000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_link_clk_src = {
+ .cmd_rcgr = 0x2200,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_6,
+ .freq_tbl = ftbl_dp_link_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_link_clk_src",
+ .parent_names = mmcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 162000000,
+ LOW, 270000000,
+ NOMINAL, 540000000),
+ },
+};
+
+static struct clk_rcg2 dp_pixel_clk_src = {
+ .cmd_rcgr = 0x2240,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_6,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_pixel_clk_src",
+ .parent_names = mmcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_dp_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 148380000,
+ LOW, 296740000,
+ NOMINAL, 593470000),
+ },
+};
+
+static struct clk_rcg2 esc0_clk_src = {
+ .cmd_rcgr = 0x2160,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc0_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static struct clk_rcg2 esc1_clk_src = {
+ .cmd_rcgr = 0x2180,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc1_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static const struct freq_tbl ftbl_jpeg0_clk_src[] = {
+ F(66666667, P_GPLL0_OUT_MAIN_DIV, 4.5, 0, 0),
+ F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(219428571, P_MMPLL4_PLL_OUT_MAIN, 3.5, 0, 0),
+ F(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0),
+ F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 jpeg0_clk_src = {
+ .cmd_rcgr = 0x3500,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_jpeg0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "jpeg0_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 66666667,
+ LOW, 133333333,
+ LOW_L1, 219428571,
+ NOMINAL, 320000000,
+ NOMINAL_L1, 480000000),
+ },
+};
+
+static const struct freq_tbl ftbl_mclk0_clk_src[] = {
+ F(4800000, P_CXO, 4, 0, 0),
+ F(6000000, P_GPLL0_OUT_MAIN_DIV, 10, 1, 5),
+ F(8000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 75),
+ F(9600000, P_CXO, 2, 0, 0),
+ F(16666667, P_GPLL0_OUT_MAIN_DIV, 2, 1, 9),
+ F(19200000, P_CXO, 1, 0, 0),
+ F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25),
+ F(33333333, P_GPLL0_OUT_MAIN_DIV, 1, 1, 9),
+ F(48000000, P_GPLL0_OUT_MAIN, 1, 2, 25),
+ F(66666667, P_GPLL0_OUT_MAIN, 1, 1, 9),
+ { }
+};
+
+static struct clk_rcg2 mclk0_clk_src = {
+ .cmd_rcgr = 0x3360,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk0_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static struct clk_rcg2 mclk1_clk_src = {
+ .cmd_rcgr = 0x3390,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk1_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static struct clk_rcg2 mclk2_clk_src = {
+ .cmd_rcgr = 0x33c0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk2_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static struct clk_rcg2 mclk3_clk_src = {
+ .cmd_rcgr = 0x33f0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk3_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static const struct freq_tbl ftbl_mdp_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN_DIV, 2, 0, 0),
+ F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0),
+ F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 mdp_clk_src = {
+ .cmd_rcgr = 0x2040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_7,
+ .freq_tbl = ftbl_mdp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mdp_clk_src",
+ .parent_names = mmcc_parent_names_7,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(
+ LOWER, 171428571,
+ LOW, 275000000,
+ NOMINAL, 330000000,
+ HIGH, 412500000),
+ },
+};
+
+static struct clk_rcg2 pclk0_clk_src = {
+ .cmd_rcgr = 0x2000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_8,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk0_clk_src",
+ .parent_names = mmcc_parent_names_8,
+ .num_parents = 4,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 175000000,
+ LOW, 280000000,
+ NOMINAL, 350000000),
+ },
+};
+
+static struct clk_rcg2 pclk1_clk_src = {
+ .cmd_rcgr = 0x2020,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_8,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk1_clk_src",
+ .parent_names = mmcc_parent_names_8,
+ .num_parents = 4,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 175000000,
+ LOW, 280000000,
+ NOMINAL, 350000000),
+ },
+};
+
+static const struct freq_tbl ftbl_rot_clk_src[] = {
+ F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0),
+ F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0),
+ F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 rot_clk_src = {
+ .cmd_rcgr = 0x21a0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_7,
+ .freq_tbl = ftbl_rot_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "rot_clk_src",
+ .parent_names = mmcc_parent_names_7,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(
+ LOWER, 171428571,
+ LOW, 275000000,
+ NOMINAL, 330000000,
+ HIGH, 412500000),
+ },
+};
+
+static const struct freq_tbl ftbl_vfe0_clk_src[] = {
+ F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(256000000, P_MMPLL4_PLL_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0),
+ F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0),
+ F(540000000, P_MMPLL6_PLL_OUT_MAIN, 2, 0, 0),
+ F(576000000, P_MMPLL10_PLL_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 vfe0_clk_src = {
+ .cmd_rcgr = 0x3600,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_9,
+ .freq_tbl = ftbl_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vfe0_clk_src",
+ .parent_names = mmcc_parent_names_9,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 120000000,
+ LOW, 256000000,
+ LOW_L1, 404000000,
+ NOMINAL, 480000000,
+ NOMINAL_L1, 540000000,
+ HIGH, 576000000),
+ },
+};
+
+static struct clk_rcg2 vfe1_clk_src = {
+ .cmd_rcgr = 0x3620,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_9,
+ .freq_tbl = ftbl_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vfe1_clk_src",
+ .parent_names = mmcc_parent_names_9,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 120000000,
+ LOW, 256000000,
+ LOW_L1, 404000000,
+ NOMINAL, 480000000,
+ NOMINAL_L1, 540000000,
+ HIGH, 576000000),
+ },
+};
+
+static const struct freq_tbl ftbl_video_core_clk_src[] = {
+ F_SLEW(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(441600000, P_MMPLL3_PLL_OUT_MAIN, 2, 0, 0, 883200000),
+ F_SLEW(518400000, P_MMPLL3_PLL_OUT_MAIN, 2, 0, 0, 1036800000),
+ { }
+};
+
+static struct clk_rcg2 video_core_clk_src = {
+ .cmd_rcgr = 0x1000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_12,
+ .freq_tbl = ftbl_video_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "video_core_clk_src",
+ .parent_names = mmcc_parent_names_12,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 133333333,
+ LOW, 269333333,
+ LOW_L1, 320000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 441600000,
+ HIGH, 518400000),
+ },
+};
+
+static struct clk_rcg2 vsync_clk_src = {
+ .cmd_rcgr = 0x2080,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_5,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vsync_clk_src",
+ .parent_names = mmcc_parent_names_5,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static struct clk_branch mmss_bimc_smmu_ahb_clk = {
+ .halt_reg = 0xe004,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0xe004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_bimc_smmu_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_bimc_smmu_axi_clk = {
+ .halt_reg = 0xe008,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0xe008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_bimc_smmu_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_ahb_clk = {
+ .halt_reg = 0x348c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x348c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cci_ahb_clk = {
+ .halt_reg = 0x3348,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3348,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cci_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cci_clk = {
+ .halt_reg = 0x3344,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3344,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cci_clk",
+ .parent_names = (const char *[]){
+ "cci_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid0_clk = {
+ .halt_reg = 0x3730,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3730,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid0_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid1_clk = {
+ .halt_reg = 0x3734,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3734,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid1_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid2_clk = {
+ .halt_reg = 0x3738,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3738,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid2_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid3_clk = {
+ .halt_reg = 0x373c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x373c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid3_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_ahb_clk = {
+ .halt_reg = 0x36b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_axi_clk = {
+ .halt_reg = 0x36c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_clk = {
+ .halt_reg = 0x36b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_clk",
+ .parent_names = (const char *[]){
+ "cpp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_vbif_ahb_clk = {
+ .halt_reg = 0x36c8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_vbif_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0_ahb_clk = {
+ .halt_reg = 0x30bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0_clk = {
+ .halt_reg = 0x30b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0_clk",
+ .parent_names = (const char *[]){
+ "csi0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0phytimer_clk = {
+ .halt_reg = 0x3024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0phytimer_clk",
+ .parent_names = (const char *[]){
+ "csi0phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0pix_clk = {
+ .halt_reg = 0x30e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0pix_clk",
+ .parent_names = (const char *[]){
+ "csi0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0rdi_clk = {
+ .halt_reg = 0x30d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0rdi_clk",
+ .parent_names = (const char *[]){
+ "csi0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1_ahb_clk = {
+ .halt_reg = 0x3128,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3128,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1_clk = {
+ .halt_reg = 0x3124,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3124,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1_clk",
+ .parent_names = (const char *[]){
+ "csi1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1phytimer_clk = {
+ .halt_reg = 0x3054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1phytimer_clk",
+ .parent_names = (const char *[]){
+ "csi1phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1pix_clk = {
+ .halt_reg = 0x3154,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3154,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1pix_clk",
+ .parent_names = (const char *[]){
+ "csi1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1rdi_clk = {
+ .halt_reg = 0x3144,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3144,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1rdi_clk",
+ .parent_names = (const char *[]){
+ "csi1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2_ahb_clk = {
+ .halt_reg = 0x3188,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3188,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2_clk = {
+ .halt_reg = 0x3184,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3184,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2_clk",
+ .parent_names = (const char *[]){
+ "csi2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2phytimer_clk = {
+ .halt_reg = 0x3084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2phytimer_clk",
+ .parent_names = (const char *[]){
+ "csi2phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2pix_clk = {
+ .halt_reg = 0x31b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2pix_clk",
+ .parent_names = (const char *[]){
+ "csi2_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2rdi_clk = {
+ .halt_reg = 0x31a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2rdi_clk",
+ .parent_names = (const char *[]){
+ "csi2_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3_ahb_clk = {
+ .halt_reg = 0x31e8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3_clk = {
+ .halt_reg = 0x31e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3_clk",
+ .parent_names = (const char *[]){
+ "csi3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3pix_clk = {
+ .halt_reg = 0x3214,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3214,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3pix_clk",
+ .parent_names = (const char *[]){
+ "csi3_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3rdi_clk = {
+ .halt_reg = 0x3204,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3204,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3rdi_clk",
+ .parent_names = (const char *[]){
+ "csi3_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi_vfe0_clk = {
+ .halt_reg = 0x3704,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3704,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi_vfe0_clk",
+ .parent_names = (const char *[]){
+ "vfe0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi_vfe1_clk = {
+ .halt_reg = 0x3714,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3714,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi_vfe1_clk",
+ .parent_names = (const char *[]){
+ "vfe1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csiphy0_clk = {
+ .halt_reg = 0x3740,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3740,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csiphy0_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csiphy1_clk = {
+ .halt_reg = 0x3744,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3744,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csiphy1_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csiphy2_clk = {
+ .halt_reg = 0x3748,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3748,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csiphy2_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_gp0_clk = {
+ .halt_reg = 0x3444,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3444,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_gp0_clk",
+ .parent_names = (const char *[]){
+ "camss_gp0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_gp1_clk = {
+ .halt_reg = 0x3474,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3474,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_gp1_clk",
+ .parent_names = (const char *[]){
+ "camss_gp1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_ispif_ahb_clk = {
+ .halt_reg = 0x3224,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3224,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_ispif_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_jpeg0_clk = {
+ .halt_reg = 0x35a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x35a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_jpeg0_clk",
+ .parent_names = (const char *[]){
+ "jpeg0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_jpeg_ahb_clk = {
+ .halt_reg = 0x35b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x35b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_jpeg_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_jpeg_axi_clk = {
+ .halt_reg = 0x35b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x35b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_jpeg_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk0_clk = {
+ .halt_reg = 0x3384,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3384,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk0_clk",
+ .parent_names = (const char *[]){
+ "mclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk1_clk = {
+ .halt_reg = 0x33b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk1_clk",
+ .parent_names = (const char *[]){
+ "mclk1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk2_clk = {
+ .halt_reg = 0x33e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk2_clk",
+ .parent_names = (const char *[]){
+ "mclk2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk3_clk = {
+ .halt_reg = 0x3414,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3414,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk3_clk",
+ .parent_names = (const char *[]){
+ "mclk3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_micro_ahb_clk = {
+ .halt_reg = 0x3494,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3494,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_micro_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_top_ahb_clk = {
+ .halt_reg = 0x3484,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3484,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_top_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe0_ahb_clk = {
+ .halt_reg = 0x3668,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3668,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe0_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe0_clk = {
+ .halt_reg = 0x36a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe0_clk",
+ .parent_names = (const char *[]){
+ "vfe0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe0_stream_clk = {
+ .halt_reg = 0x3720,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3720,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe0_stream_clk",
+ .parent_names = (const char *[]){
+ "vfe0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe1_ahb_clk = {
+ .halt_reg = 0x3678,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3678,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe1_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe1_clk = {
+ .halt_reg = 0x36ac,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe1_clk",
+ .parent_names = (const char *[]){
+ "vfe1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe1_stream_clk = {
+ .halt_reg = 0x3724,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3724,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe1_stream_clk",
+ .parent_names = (const char *[]){
+ "vfe1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe_vbif_ahb_clk = {
+ .halt_reg = 0x36b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe_vbif_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe_vbif_axi_clk = {
+ .halt_reg = 0x36bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe_vbif_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_csiphy_ahb2crif_clk = {
+ .halt_reg = 0x374c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x374c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_csiphy_ahb2crif_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_ahb_clk = {
+ .halt_reg = 0x2308,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2308,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_axi_clk = {
+ .halt_reg = 0x2310,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2310,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte0_clk = {
+ .halt_reg = 0x233c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x233c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte0_clk",
+ .parent_names = (const char *[]){
+ "byte0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte0_intf_clk = {
+ .halt_reg = 0x2374,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2374,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte0_intf_clk",
+ .parent_names = (const char *[]){
+ "mmss_mdss_byte0_intf_div_clk",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div mmss_mdss_byte0_intf_div_clk = {
+ .reg = 0x237c,
+ .shift = 0,
+ .width = 2,
+ /*
+ * NOTE: Op does not work for div-3. Current assumption is that div-3
+ * is not a recommended setting for this divider.
+ */
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte0_intf_div_clk",
+ .parent_names = (const char *[]){
+ "byte0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte1_clk = {
+ .halt_reg = 0x2340,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2340,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte1_clk",
+ .parent_names = (const char *[]){
+ "byte1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte1_intf_clk = {
+ .halt_reg = 0x2378,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2378,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte1_intf_clk",
+ .parent_names = (const char *[]){
+ "byte1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_aux_clk = {
+ .halt_reg = 0x2364,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2364,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_aux_clk",
+ .parent_names = (const char *[]){
+ "dp_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_crypto_clk = {
+ .halt_reg = 0x235c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x235c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_crypto_clk",
+ .parent_names = (const char *[]){
+ "dp_crypto_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_gtc_clk = {
+ .halt_reg = 0x2368,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2368,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_gtc_clk",
+ .parent_names = (const char *[]){
+ "dp_gtc_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_link_clk = {
+ .halt_reg = 0x2354,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2354,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_link_clk",
+ .parent_names = (const char *[]){
+ "dp_link_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+/* Reset state of MMSS_MDSS_DP_LINK_INTF_DIV is 0x3 (div-4) */
+static struct clk_branch mmss_mdss_dp_link_intf_clk = {
+ .halt_reg = 0x2358,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2358,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_link_intf_clk",
+ .parent_names = (const char *[]){
+ "dp_link_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_pixel_clk = {
+ .halt_reg = 0x2360,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2360,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_pixel_clk",
+ .parent_names = (const char *[]){
+ "dp_pixel_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_esc0_clk = {
+ .halt_reg = 0x2344,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2344,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_esc0_clk",
+ .parent_names = (const char *[]){
+ "esc0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_esc1_clk = {
+ .halt_reg = 0x2348,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2348,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_esc1_clk",
+ .parent_names = (const char *[]){
+ "esc1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_hdmi_dp_ahb_clk = {
+ .halt_reg = 0x230c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x230c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_hdmi_dp_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_mdp_clk = {
+ .halt_reg = 0x231c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x231c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_mdp_clk",
+ .parent_names = (const char *[]){
+ "mdp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_pclk0_clk = {
+ .halt_reg = 0x2314,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2314,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_pclk0_clk",
+ .parent_names = (const char *[]){
+ "pclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_pclk1_clk = {
+ .halt_reg = 0x2318,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2318,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_pclk1_clk",
+ .parent_names = (const char *[]){
+ "pclk1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_rot_clk = {
+ .halt_reg = 0x2350,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2350,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_rot_clk",
+ .parent_names = (const char *[]){
+ "rot_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_vsync_clk = {
+ .halt_reg = 0x2328,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2328,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_vsync_clk",
+ .parent_names = (const char *[]){
+ "vsync_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_misc_ahb_clk = {
+ .halt_reg = 0x328,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x328,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_misc_ahb_clk",
+ /*
+ * Dependency to be enabled before the branch is
+ * enabled.
+ */
+ .parent_names = (const char *[]){
+ "mmss_mnoc_ahb_clk",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_misc_cxo_clk = {
+ .halt_reg = 0x324,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x324,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_misc_cxo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mnoc_ahb_clk = {
+ .halt_reg = 0x5024,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x5024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mnoc_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_snoc_dvm_axi_clk = {
+ .halt_reg = 0xe040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_snoc_dvm_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_ahb_clk = {
+ .halt_reg = 0x1030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_axi_clk = {
+ .halt_reg = 0x1034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_core_clk = {
+ .halt_reg = 0x1028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_core_clk",
+ .parent_names = (const char *[]){
+ "video_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_subcore0_clk = {
+ .halt_reg = 0x1048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_subcore0_clk",
+ .parent_names = (const char *[]){
+ "video_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *mmcc_falcon_clocks[] = {
+ [AHB_CLK_SRC] = &ahb_clk_src.clkr,
+ [BYTE0_CLK_SRC] = &byte0_clk_src.clkr,
+ [BYTE1_CLK_SRC] = &byte1_clk_src.clkr,
+ [CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr,
+ [CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr,
+ [CCI_CLK_SRC] = &cci_clk_src.clkr,
+ [CPP_CLK_SRC] = &cpp_clk_src.clkr,
+ [CSI0_CLK_SRC] = &csi0_clk_src.clkr,
+ [CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr,
+ [CSI1_CLK_SRC] = &csi1_clk_src.clkr,
+ [CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr,
+ [CSI2_CLK_SRC] = &csi2_clk_src.clkr,
+ [CSI2PHYTIMER_CLK_SRC] = &csi2phytimer_clk_src.clkr,
+ [CSI3_CLK_SRC] = &csi3_clk_src.clkr,
+ [CSIPHY_CLK_SRC] = &csiphy_clk_src.clkr,
+ [DP_AUX_CLK_SRC] = &dp_aux_clk_src.clkr,
+ [DP_CRYPTO_CLK_SRC] = &dp_crypto_clk_src.clkr,
+ [DP_GTC_CLK_SRC] = &dp_gtc_clk_src.clkr,
+ [DP_LINK_CLK_SRC] = &dp_link_clk_src.clkr,
+ [DP_PIXEL_CLK_SRC] = &dp_pixel_clk_src.clkr,
+ [ESC0_CLK_SRC] = &esc0_clk_src.clkr,
+ [ESC1_CLK_SRC] = &esc1_clk_src.clkr,
+ [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr,
+ [MCLK0_CLK_SRC] = &mclk0_clk_src.clkr,
+ [MCLK1_CLK_SRC] = &mclk1_clk_src.clkr,
+ [MCLK2_CLK_SRC] = &mclk2_clk_src.clkr,
+ [MCLK3_CLK_SRC] = &mclk3_clk_src.clkr,
+ [MDP_CLK_SRC] = &mdp_clk_src.clkr,
+ [MMPLL0_PLL] = &mmpll0_pll_out_main.clkr,
+ [MMPLL10_PLL] = &mmpll10_pll_out_main.clkr,
+ [MMPLL3_PLL] = &mmpll3_pll_out_main.clkr,
+ [MMPLL4_PLL] = &mmpll4_pll_out_main.clkr,
+ [MMPLL5_PLL] = &mmpll5_pll_out_main.clkr,
+ [MMPLL6_PLL] = &mmpll6_pll_out_main.clkr,
+ [MMPLL7_PLL] = &mmpll7_pll_out_main.clkr,
+ [MMPLL8_PLL] = &mmpll8_pll_out_main.clkr,
+ [MMSS_BIMC_SMMU_AHB_CLK] = &mmss_bimc_smmu_ahb_clk.clkr,
+ [MMSS_BIMC_SMMU_AXI_CLK] = &mmss_bimc_smmu_axi_clk.clkr,
+ [MMSS_CAMSS_AHB_CLK] = &mmss_camss_ahb_clk.clkr,
+ [MMSS_CAMSS_CCI_AHB_CLK] = &mmss_camss_cci_ahb_clk.clkr,
+ [MMSS_CAMSS_CCI_CLK] = &mmss_camss_cci_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID0_CLK] = &mmss_camss_cphy_csid0_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID1_CLK] = &mmss_camss_cphy_csid1_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID2_CLK] = &mmss_camss_cphy_csid2_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID3_CLK] = &mmss_camss_cphy_csid3_clk.clkr,
+ [MMSS_CAMSS_CPP_AHB_CLK] = &mmss_camss_cpp_ahb_clk.clkr,
+ [MMSS_CAMSS_CPP_AXI_CLK] = &mmss_camss_cpp_axi_clk.clkr,
+ [MMSS_CAMSS_CPP_CLK] = &mmss_camss_cpp_clk.clkr,
+ [MMSS_CAMSS_CPP_VBIF_AHB_CLK] = &mmss_camss_cpp_vbif_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI0_AHB_CLK] = &mmss_camss_csi0_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI0_CLK] = &mmss_camss_csi0_clk.clkr,
+ [MMSS_CAMSS_CSI0PHYTIMER_CLK] = &mmss_camss_csi0phytimer_clk.clkr,
+ [MMSS_CAMSS_CSI0PIX_CLK] = &mmss_camss_csi0pix_clk.clkr,
+ [MMSS_CAMSS_CSI0RDI_CLK] = &mmss_camss_csi0rdi_clk.clkr,
+ [MMSS_CAMSS_CSI1_AHB_CLK] = &mmss_camss_csi1_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI1_CLK] = &mmss_camss_csi1_clk.clkr,
+ [MMSS_CAMSS_CSI1PHYTIMER_CLK] = &mmss_camss_csi1phytimer_clk.clkr,
+ [MMSS_CAMSS_CSI1PIX_CLK] = &mmss_camss_csi1pix_clk.clkr,
+ [MMSS_CAMSS_CSI1RDI_CLK] = &mmss_camss_csi1rdi_clk.clkr,
+ [MMSS_CAMSS_CSI2_AHB_CLK] = &mmss_camss_csi2_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI2_CLK] = &mmss_camss_csi2_clk.clkr,
+ [MMSS_CAMSS_CSI2PHYTIMER_CLK] = &mmss_camss_csi2phytimer_clk.clkr,
+ [MMSS_CAMSS_CSI2PIX_CLK] = &mmss_camss_csi2pix_clk.clkr,
+ [MMSS_CAMSS_CSI2RDI_CLK] = &mmss_camss_csi2rdi_clk.clkr,
+ [MMSS_CAMSS_CSI3_AHB_CLK] = &mmss_camss_csi3_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI3_CLK] = &mmss_camss_csi3_clk.clkr,
+ [MMSS_CAMSS_CSI3PIX_CLK] = &mmss_camss_csi3pix_clk.clkr,
+ [MMSS_CAMSS_CSI3RDI_CLK] = &mmss_camss_csi3rdi_clk.clkr,
+ [MMSS_CAMSS_CSI_VFE0_CLK] = &mmss_camss_csi_vfe0_clk.clkr,
+ [MMSS_CAMSS_CSI_VFE1_CLK] = &mmss_camss_csi_vfe1_clk.clkr,
+ [MMSS_CAMSS_CSIPHY0_CLK] = &mmss_camss_csiphy0_clk.clkr,
+ [MMSS_CAMSS_CSIPHY1_CLK] = &mmss_camss_csiphy1_clk.clkr,
+ [MMSS_CAMSS_CSIPHY2_CLK] = &mmss_camss_csiphy2_clk.clkr,
+ [MMSS_CAMSS_GP0_CLK] = &mmss_camss_gp0_clk.clkr,
+ [MMSS_CAMSS_GP1_CLK] = &mmss_camss_gp1_clk.clkr,
+ [MMSS_CAMSS_ISPIF_AHB_CLK] = &mmss_camss_ispif_ahb_clk.clkr,
+ [MMSS_CAMSS_JPEG0_CLK] = &mmss_camss_jpeg0_clk.clkr,
+ [MMSS_CAMSS_JPEG_AHB_CLK] = &mmss_camss_jpeg_ahb_clk.clkr,
+ [MMSS_CAMSS_JPEG_AXI_CLK] = &mmss_camss_jpeg_axi_clk.clkr,
+ [MMSS_CAMSS_MCLK0_CLK] = &mmss_camss_mclk0_clk.clkr,
+ [MMSS_CAMSS_MCLK1_CLK] = &mmss_camss_mclk1_clk.clkr,
+ [MMSS_CAMSS_MCLK2_CLK] = &mmss_camss_mclk2_clk.clkr,
+ [MMSS_CAMSS_MCLK3_CLK] = &mmss_camss_mclk3_clk.clkr,
+ [MMSS_CAMSS_MICRO_AHB_CLK] = &mmss_camss_micro_ahb_clk.clkr,
+ [MMSS_CAMSS_TOP_AHB_CLK] = &mmss_camss_top_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE0_AHB_CLK] = &mmss_camss_vfe0_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE0_CLK] = &mmss_camss_vfe0_clk.clkr,
+ [MMSS_CAMSS_VFE0_STREAM_CLK] = &mmss_camss_vfe0_stream_clk.clkr,
+ [MMSS_CAMSS_VFE1_AHB_CLK] = &mmss_camss_vfe1_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE1_CLK] = &mmss_camss_vfe1_clk.clkr,
+ [MMSS_CAMSS_VFE1_STREAM_CLK] = &mmss_camss_vfe1_stream_clk.clkr,
+ [MMSS_CAMSS_VFE_VBIF_AHB_CLK] = &mmss_camss_vfe_vbif_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE_VBIF_AXI_CLK] = &mmss_camss_vfe_vbif_axi_clk.clkr,
+ [MMSS_CSIPHY_AHB2CRIF_CLK] = &mmss_csiphy_ahb2crif_clk.clkr,
+ [MMSS_MDSS_AHB_CLK] = &mmss_mdss_ahb_clk.clkr,
+ [MMSS_MDSS_AXI_CLK] = &mmss_mdss_axi_clk.clkr,
+ [MMSS_MDSS_BYTE0_CLK] = &mmss_mdss_byte0_clk.clkr,
+ [MMSS_MDSS_BYTE0_INTF_CLK] = &mmss_mdss_byte0_intf_clk.clkr,
+ [MMSS_MDSS_BYTE0_INTF_DIV_CLK] = &mmss_mdss_byte0_intf_div_clk.clkr,
+ [MMSS_MDSS_BYTE1_CLK] = &mmss_mdss_byte1_clk.clkr,
+ [MMSS_MDSS_BYTE1_INTF_CLK] = &mmss_mdss_byte1_intf_clk.clkr,
+ [MMSS_MDSS_DP_AUX_CLK] = &mmss_mdss_dp_aux_clk.clkr,
+ [MMSS_MDSS_DP_CRYPTO_CLK] = &mmss_mdss_dp_crypto_clk.clkr,
+ [MMSS_MDSS_DP_GTC_CLK] = &mmss_mdss_dp_gtc_clk.clkr,
+ [MMSS_MDSS_DP_LINK_CLK] = &mmss_mdss_dp_link_clk.clkr,
+ [MMSS_MDSS_DP_LINK_INTF_CLK] = &mmss_mdss_dp_link_intf_clk.clkr,
+ [MMSS_MDSS_DP_PIXEL_CLK] = &mmss_mdss_dp_pixel_clk.clkr,
+ [MMSS_MDSS_ESC0_CLK] = &mmss_mdss_esc0_clk.clkr,
+ [MMSS_MDSS_ESC1_CLK] = &mmss_mdss_esc1_clk.clkr,
+ [MMSS_MDSS_HDMI_DP_AHB_CLK] = &mmss_mdss_hdmi_dp_ahb_clk.clkr,
+ [MMSS_MDSS_MDP_CLK] = &mmss_mdss_mdp_clk.clkr,
+ [MMSS_MDSS_PCLK0_CLK] = &mmss_mdss_pclk0_clk.clkr,
+ [MMSS_MDSS_PCLK1_CLK] = &mmss_mdss_pclk1_clk.clkr,
+ [MMSS_MDSS_ROT_CLK] = &mmss_mdss_rot_clk.clkr,
+ [MMSS_MDSS_VSYNC_CLK] = &mmss_mdss_vsync_clk.clkr,
+ [MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr,
+ [MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr,
+ [MMSS_MNOC_AHB_CLK] = &mmss_mnoc_ahb_clk.clkr,
+ [MMSS_SNOC_DVM_AXI_CLK] = &mmss_snoc_dvm_axi_clk.clkr,
+ [MMSS_VIDEO_AHB_CLK] = &mmss_video_ahb_clk.clkr,
+ [MMSS_VIDEO_AXI_CLK] = &mmss_video_axi_clk.clkr,
+ [MMSS_VIDEO_CORE_CLK] = &mmss_video_core_clk.clkr,
+ [MMSS_VIDEO_SUBCORE0_CLK] = &mmss_video_subcore0_clk.clkr,
+ [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr,
+ [PCLK1_CLK_SRC] = &pclk1_clk_src.clkr,
+ [ROT_CLK_SRC] = &rot_clk_src.clkr,
+ [VFE0_CLK_SRC] = &vfe0_clk_src.clkr,
+ [VFE1_CLK_SRC] = &vfe1_clk_src.clkr,
+ [VIDEO_CORE_CLK_SRC] = &video_core_clk_src.clkr,
+ [VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
+};
+
+static const struct qcom_reset_map mmcc_falcon_resets[] = {
+ [CAMSS_MICRO_BCR] = { 0x3490 },
+};
+
+static const struct regmap_config mmcc_falcon_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x10004,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc mmcc_falcon_desc = {
+ .config = &mmcc_falcon_regmap_config,
+ .clks = mmcc_falcon_clocks,
+ .num_clks = ARRAY_SIZE(mmcc_falcon_clocks),
+ .resets = mmcc_falcon_resets,
+ .num_resets = ARRAY_SIZE(mmcc_falcon_resets),
+};
+
+static const struct of_device_id mmcc_falcon_match_table[] = {
+ { .compatible = "qcom,mmcc-msmfalcon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mmcc_falcon_match_table);
+
+static int mmcc_falcon_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &mmcc_falcon_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* PLLs connected on Mx rails of MMSS_CC */
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx_mmss");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_mx_mmss regulator\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_mmss");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_dig regulator\n");
+ return PTR_ERR(vdd_dig.regulator[0]);
+ }
+
+ /* MMPLL10 connected to the Analog Rail */
+ vdda.regulator[0] = devm_regulator_get(&pdev->dev, "vdda");
+ if (IS_ERR(vdda.regulator[0])) {
+ if (!(PTR_ERR(vdda.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdda regulator\n");
+ return PTR_ERR(vdda.regulator[0]);
+ }
+
+ clk_alpha_pll_configure(&mmpll3_pll_out_main, regmap, &mmpll3_config);
+ clk_alpha_pll_configure(&mmpll4_pll_out_main, regmap, &mmpll4_config);
+ clk_alpha_pll_configure(&mmpll5_pll_out_main, regmap, &mmpll5_config);
+ clk_alpha_pll_configure(&mmpll7_pll_out_main, regmap, &mmpll7_config);
+ clk_alpha_pll_configure(&mmpll8_pll_out_main, regmap, &mmpll8_config);
+ clk_alpha_pll_configure(&mmpll10_pll_out_main, regmap, &mmpll10_config);
+
+ ret = qcom_cc_really_probe(pdev, &mmcc_falcon_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register MMSS clocks\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Registered MMSS clocks\n");
+
+ return ret;
+}
+
+static struct platform_driver mmcc_falcon_driver = {
+ .probe = mmcc_falcon_probe,
+ .driver = {
+ .name = "mmcc-msmfalcon",
+ .of_match_table = mmcc_falcon_match_table,
+ },
+};
+
+static int __init mmcc_falcon_init(void)
+{
+ return platform_driver_register(&mmcc_falcon_driver);
+}
+core_initcall_sync(mmcc_falcon_init);
+
+static void __exit mmcc_falcon_exit(void)
+{
+ platform_driver_unregister(&mmcc_falcon_driver);
+}
+module_exit(mmcc_falcon_exit);
diff --git a/drivers/clk/qcom/vdd-level-falcon.h b/drivers/clk/qcom/vdd-level-falcon.h
index d54e801ecc67..8f9eefe3a89c 100644
--- a/drivers/clk/qcom/vdd-level-falcon.h
+++ b/drivers/clk/qcom/vdd-level-falcon.h
@@ -116,6 +116,21 @@
}, \
.num_rate_max = VDD_DIG_NUM
+#define VDD_MMSS_PLL_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_mx, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_MMSS_PLL_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_mx, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
enum vdd_dig_levels {
VDD_DIG_NONE,
VDD_DIG_MIN, /* MIN SVS */
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index e2099c4e7877..433e4783d1d1 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -603,7 +603,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
while (len > 0) {
user_src =
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
- if (user_src && __copy_from_user(k_src,
+ if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len))
return -EFAULT;
@@ -639,7 +639,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
/* Copy data from user src(s) */
user_src = (void __user *)qcedev_areq->sha_op_req.data[0].vaddr;
- if (user_src && __copy_from_user(k_src,
+ if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[0].len)) {
kzfree(k_buf_src);
@@ -648,7 +648,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
k_src += qcedev_areq->sha_op_req.data[0].len;
for (i = 1; i < qcedev_areq->sha_op_req.entries; i++) {
user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
- if (user_src && __copy_from_user(k_src,
+ if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len)) {
kzfree(k_buf_src);
@@ -702,13 +702,6 @@ static int qcedev_sha_update(struct qcedev_async_req *qcedev_areq,
return -EINVAL;
}
- /* verify address src(s) */
- for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
- if (!access_ok(VERIFY_READ,
- (void __user *)qcedev_areq->sha_op_req.data[i].vaddr,
- qcedev_areq->sha_op_req.data[i].len))
- return -EFAULT;
-
if (qcedev_areq->sha_op_req.data_len > QCE_MAX_OPER_DATA) {
struct qcedev_sha_op_req *saved_req;
@@ -868,19 +861,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq,
total = qcedev_areq->sha_op_req.data_len;
- /* verify address src(s) */
- for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
- if (!access_ok(VERIFY_READ,
- (void __user *)qcedev_areq->sha_op_req.data[i].vaddr,
- qcedev_areq->sha_op_req.data[i].len))
- return -EFAULT;
-
- /* Verify Source Address */
- if (!access_ok(VERIFY_READ,
- (void __user *)qcedev_areq->sha_op_req.authkey,
- qcedev_areq->sha_op_req.authklen))
- return -EFAULT;
- if (__copy_from_user(&handle->sha_ctxt.authkey[0],
+ if (copy_from_user(&handle->sha_ctxt.authkey[0],
(void __user *)qcedev_areq->sha_op_req.authkey,
qcedev_areq->sha_op_req.authklen))
return -EFAULT;
@@ -900,7 +881,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq,
for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) {
user_src =
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
- if (user_src && __copy_from_user(k_src, (void __user *)user_src,
+ if (user_src && copy_from_user(k_src, (void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len)) {
kzfree(k_buf_src);
return -EFAULT;
@@ -928,12 +909,7 @@ static int qcedev_set_hmac_auth_key(struct qcedev_async_req *areq,
if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) {
qcedev_sha_init(areq, handle);
- /* Verify Source Address */
- if (!access_ok(VERIFY_READ,
- (void __user *)areq->sha_op_req.authkey,
- areq->sha_op_req.authklen))
- return -EFAULT;
- if (__copy_from_user(&handle->sha_ctxt.authkey[0],
+ if (copy_from_user(&handle->sha_ctxt.authkey[0],
(void __user *)areq->sha_op_req.authkey,
areq->sha_op_req.authklen))
return -EFAULT;
@@ -1146,7 +1122,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
byteoffset = areq->cipher_op_req.byteoffset;
user_src = (void __user *)areq->cipher_op_req.vbuf.src[0].vaddr;
- if (user_src && __copy_from_user((k_align_src + byteoffset),
+ if (user_src && copy_from_user((k_align_src + byteoffset),
(void __user *)user_src,
areq->cipher_op_req.vbuf.src[0].len))
return -EFAULT;
@@ -1156,7 +1132,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
for (i = 1; i < areq->cipher_op_req.entries; i++) {
user_src =
(void __user *)areq->cipher_op_req.vbuf.src[i].vaddr;
- if (user_src && __copy_from_user(k_align_src,
+ if (user_src && copy_from_user(k_align_src,
(void __user *)user_src,
areq->cipher_op_req.vbuf.src[i].len)) {
return -EFAULT;
@@ -1188,7 +1164,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
while (creq->data_len > 0) {
if (creq->vbuf.dst[dst_i].len <= creq->data_len) {
- if (err == 0 && __copy_to_user(
+ if (err == 0 && copy_to_user(
(void __user *)creq->vbuf.dst[dst_i].vaddr,
(k_align_dst + byteoffset),
creq->vbuf.dst[dst_i].len))
@@ -1199,7 +1175,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
creq->data_len -= creq->vbuf.dst[dst_i].len;
dst_i++;
} else {
- if (err == 0 && __copy_to_user(
+ if (err == 0 && copy_to_user(
(void __user *)creq->vbuf.dst[dst_i].vaddr,
(k_align_dst + byteoffset),
creq->data_len))
@@ -1531,36 +1507,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
__func__, total, req->data_len);
goto error;
}
- /* Verify Source Address's */
- for (i = 0, total = 0; i < req->entries; i++) {
- if (total < req->data_len) {
- if (!access_ok(VERIFY_READ,
- (void __user *)req->vbuf.src[i].vaddr,
- req->vbuf.src[i].len)) {
- pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n",
- __func__, i, (uintptr_t)
- req->vbuf.src[i].vaddr);
- goto error;
- }
- total += req->vbuf.src[i].len;
- }
- }
-
- /* Verify Destination Address's */
- for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) {
- if ((req->vbuf.dst[i].vaddr != 0) &&
- (total < req->data_len)) {
- if (!access_ok(VERIFY_WRITE,
- (void __user *)req->vbuf.dst[i].vaddr,
- req->vbuf.dst[i].len)) {
- pr_err("%s:DST WR_VERIFY err %d=0x%lx\n",
- __func__, i, (uintptr_t)
- req->vbuf.dst[i].vaddr);
- goto error;
- }
- total += req->vbuf.dst[i].len;
- }
- }
return 0;
error:
return -EINVAL;
@@ -1656,11 +1602,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
switch (cmd) {
case QCEDEV_IOCTL_ENC_REQ:
case QCEDEV_IOCTL_DEC_REQ:
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_cipher_op_req)))
- return -EFAULT;
-
- if (__copy_from_user(&qcedev_areq.cipher_op_req,
+ if (copy_from_user(&qcedev_areq.cipher_op_req,
(void __user *)arg,
sizeof(struct qcedev_cipher_op_req)))
return -EFAULT;
@@ -1673,20 +1615,17 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
if (err)
return err;
- if (__copy_to_user((void __user *)arg,
+ if (copy_to_user((void __user *)arg,
&qcedev_areq.cipher_op_req,
sizeof(struct qcedev_cipher_op_req)))
- return -EFAULT;
+ return -EFAULT;
break;
case QCEDEV_IOCTL_SHA_INIT_REQ:
{
struct scatterlist sg_src;
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1696,9 +1635,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
if (err)
return err;
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
+ return -EFAULT;
}
handle->sha_ctxt.init_done = true;
break;
@@ -1708,11 +1647,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_SHA_UPDATE_REQ:
{
struct scatterlist sg_src;
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1734,10 +1670,15 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return err;
}
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ return -EINVAL;
+ }
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
}
@@ -1749,11 +1690,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_err("%s Init was not called\n", __func__);
return -EINVAL;
}
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
-
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1767,7 +1704,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
handle->sha_ctxt.init_done = false;
@@ -1776,11 +1713,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_GET_SHA_REQ:
{
struct scatterlist sg_src;
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1798,7 +1732,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
}
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index a02ed40ba9d5..e6163384f9c1 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -269,7 +269,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
.patchid = ANY_ID,
.features = ADRENO_PREEMPTION | ADRENO_64BIT |
ADRENO_CONTENT_PROTECTION |
- ADRENO_GPMU | ADRENO_SPTP_PC | ADRENO_LM,
+ ADRENO_GPMU | ADRENO_SPTP_PC,
.pm4fw_name = "a530_pm4.fw",
.pfpfw_name = "a530_pfp.fw",
.zap_name = "a540_zap",
@@ -283,4 +283,18 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
.gpmu_tsens = 0x000C000D,
.max_power = 5448,
},
+ {
+ .gpurev = ADRENO_REV_A512,
+ .core = 5,
+ .major = 1,
+ .minor = 2,
+ .patchid = ANY_ID,
+ .features = ADRENO_64BIT,
+ .pm4fw_name = "a530_pm4.fw",
+ .pfpfw_name = "a530_pfp.fw",
+ .gpudev = &adreno_a5xx_gpudev,
+ .gmem_size = (SZ_256K + SZ_16K),
+ .num_protected_regs = 0x20,
+ .busy_mask = 0xFFFFFFFE,
+ },
};
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index d81142db5b58..1c30b43fdfcf 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -170,6 +170,7 @@ enum adreno_gpurev {
ADRENO_REV_A505 = 505,
ADRENO_REV_A506 = 506,
ADRENO_REV_A510 = 510,
+ ADRENO_REV_A512 = 512,
ADRENO_REV_A530 = 530,
ADRENO_REV_A540 = 540,
};
@@ -998,6 +999,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev)
ADRENO_TARGET(a505, ADRENO_REV_A505)
ADRENO_TARGET(a506, ADRENO_REV_A506)
ADRENO_TARGET(a510, ADRENO_REV_A510)
+ADRENO_TARGET(a512, ADRENO_REV_A512)
ADRENO_TARGET(a530, ADRENO_REV_A530)
ADRENO_TARGET(a540, ADRENO_REV_A540)
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index dc35c0080d11..90b833888d9d 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -57,6 +57,7 @@ static const struct adreno_vbif_data a540_vbif[] = {
static const struct adreno_vbif_platform a5xx_vbif_platforms[] = {
{ adreno_is_a540, a540_vbif },
{ adreno_is_a530, a530_vbif },
+ { adreno_is_a512, a540_vbif },
{ adreno_is_a510, a530_vbif },
{ adreno_is_a505, a530_vbif },
{ adreno_is_a506, a530_vbif },
@@ -1884,7 +1885,7 @@ static void a5xx_start(struct adreno_device *adreno_dev)
if (adreno_is_a505_or_a506(adreno_dev))
kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL,
(0x100 << 11 | 0x100 << 22));
- else if (adreno_is_a510(adreno_dev))
+ else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev))
kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL,
(0x200 << 11 | 0x200 << 22));
else
@@ -1976,8 +1977,8 @@ static void a5xx_start(struct adreno_device *adreno_dev)
kgsl_regwrite(device, A5XX_TPL1_MODE_CNTL, bit << 7);
kgsl_regwrite(device, A5XX_RB_MODE_CNTL, bit << 1);
-
- if (adreno_is_a540(adreno_dev))
+ if (adreno_is_a540(adreno_dev) ||
+ adreno_is_a512(adreno_dev))
kgsl_regwrite(device, A5XX_UCHE_DBG_ECO_CNTL_2,
bit);
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 9dc9f93f4e36..577183bea07c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1251,6 +1251,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
/* Ignore report if ErrorRollOver */
if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
value[n] >= min && value[n] <= max &&
+ value[n] - min < field->maxusage &&
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
goto exit;
}
@@ -1263,11 +1264,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
}
if (field->value[n] >= min && field->value[n] <= max
+ && field->value[n] - min < field->maxusage
&& field->usage[field->value[n] - min].hid
&& search(value, field->value[n], count))
hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
if (value[n] >= min && value[n] <= max
+ && value[n] - min < field->maxusage
&& field->usage[value[n] - min].hid
&& search(field->value, value[n], count))
hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 2282fe005bc7..f001706236ab 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -1606,6 +1606,13 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
{
+ if (count > (fwu->image_size - fwu->data_pos)) {
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "%s: Not enough space in buffer\n",
+ __func__);
+ return -EINVAL;
+ }
+
memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
(const void *)buf,
count);
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
index feede3a14e07..d6b32036f31c 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/dma-buf.h>
#include <asm/dma-iommu.h>
+#include <asm/cacheflush.h>
#include <linux/dma-direction.h>
#include <linux/dma-attrs.h>
#include <linux/of_platform.h>
@@ -23,6 +24,8 @@
#include <linux/dma-mapping.h>
#include <linux/msm_dma_iommu_mapping.h>
#include <linux/workqueue.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/secure_buffer.h>
#include "cam_smmu_api.h"
#define SCRATCH_ALLOC_START SZ_128K
@@ -35,10 +38,15 @@
#define COOKIE_MASK ((1<<COOKIE_SIZE)-1)
#define HANDLE_INIT (-1)
#define CAM_SMMU_CB_MAX 2
+#define CAM_SMMU_SID_MAX 4
+
#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK))
#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK)
+#define CAMERA_DEVICE_ID 0x16
+#define SECURE_SYSCALL_ID 0x18
+
#ifdef CONFIG_CAM_SMMU_DBG
#define CDBG(fmt, args...) pr_err(fmt, ##args)
#else
@@ -104,6 +112,8 @@ struct cam_context_bank_info {
int, void*);
void *token[CAM_SMMU_CB_MAX];
int cb_count;
+ int ref_cnt;
+ int sids[CAM_SMMU_SID_MAX];
};
struct cam_iommu_cb_set {
@@ -136,6 +146,17 @@ struct cam_dma_buff_info {
size_t phys_len;
};
+struct cam_sec_buff_info {
+ struct ion_handle *i_hdl;
+ struct ion_client *i_client;
+ enum dma_data_direction dir;
+ int ref_count;
+ dma_addr_t paddr;
+ struct list_head list;
+ int ion_fd;
+ size_t len;
+};
+
static struct cam_iommu_cb_set iommu_cb_set;
static enum dma_data_direction cam_smmu_translate_dir(
@@ -151,6 +172,9 @@ static int cam_smmu_create_add_handle_in_table(char *name,
static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
int ion_fd);
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+ int ion_fd);
+
static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
dma_addr_t base, size_t size,
int order);
@@ -477,10 +501,14 @@ void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops)
iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH;
iommu_cb_set.cb_info[i].dev = NULL;
iommu_cb_set.cb_info[i].cb_count = 0;
+ iommu_cb_set.cb_info[i].ref_cnt = 0;
for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
iommu_cb_set.cb_info[i].token[j] = NULL;
iommu_cb_set.cb_info[i].handler[j] = NULL;
}
+ for (j = 0; j < CAM_SMMU_SID_MAX; j++)
+ iommu_cb_set.cb_info[i].sids[j] = -1;
+
if (ops == CAM_SMMU_TABLE_INIT)
mutex_init(&iommu_cb_set.cb_info[i].lock);
else
@@ -549,6 +577,8 @@ static int cam_smmu_create_add_handle_in_table(char *name,
pr_err("Error: %s already got handle 0x%x\n",
name,
iommu_cb_set.cb_info[i].handle);
+ *hdl = iommu_cb_set.cb_info[i].handle;
+ iommu_cb_set.cb_info[i].ref_cnt++;
mutex_unlock(&iommu_cb_set.cb_info[i].lock);
return -EINVAL;
}
@@ -561,6 +591,7 @@ static int cam_smmu_create_add_handle_in_table(char *name,
/* put handle in the table */
iommu_cb_set.cb_info[i].handle = handle;
iommu_cb_set.cb_info[i].cb_count = 0;
+ iommu_cb_set.cb_info[i].ref_cnt++;
*hdl = handle;
CDBG("%s creates handle 0x%x\n", name, handle);
mutex_unlock(&iommu_cb_set.cb_info[i].lock);
@@ -698,6 +729,23 @@ static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
return NULL;
}
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+ int ion_fd)
+{
+ struct cam_sec_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->ion_fd == ion_fd) {
+ CDBG("[sec_cam] find ion_fd %d\n", ion_fd);
+ return mapping;
+ }
+ }
+ pr_err("Error: Cannot find fd %d by index %d\n",
+ ion_fd, idx);
+ return NULL;
+}
+
static void cam_smmu_clean_buffer_list(int idx)
{
int ret;
@@ -754,6 +802,148 @@ static int cam_smmu_attach(int idx)
return ret;
}
+static int cam_smmu_send_syscall_cpp_intf(int vmid, int idx)
+{
+ int rc = 0;
+ struct scm_desc desc = {0};
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+ uint32_t sid_info;
+
+
+ sid_info = cb->sids[0]; /* CPP SID */
+
+ desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+ desc.args[0] = CAMERA_DEVICE_ID;
+ desc.args[1] = SCM_BUFFER_PHYS(&sid_info);
+ desc.args[2] = sizeof(uint32_t);
+ desc.args[3] = vmid;
+ /*
+ * Syscall to hypervisor to switch CPP SID's
+ * between secure and non-secure contexts
+ */
+ dmac_flush_range(&sid_info, &sid_info + 1);
+ if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID),
+ &desc)){
+ pr_err("call to hypervisor failed\n");
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int cam_smmu_send_syscall_pix_intf(int vmid, int idx)
+{
+ int rc = 0;
+ struct scm_desc desc = {0};
+ uint32_t *sid_info = NULL;
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ sid_info = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL);
+ if (!sid_info)
+ return -ENOMEM;
+
+ sid_info[0] = cb->sids[0]; /* VFE 0 Image SID */
+ sid_info[1] = cb->sids[2]; /* VFE 1 Image SID */
+
+ desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+ desc.args[0] = CAMERA_DEVICE_ID;
+ desc.args[1] = SCM_BUFFER_PHYS(sid_info);
+ desc.args[2] = sizeof(uint32_t) * 2;
+ desc.args[3] = vmid;
+ /*
+ * Syscall to hypervisor to switch VFE SID's
+ * between secure and non-secure contexts
+ */
+ dmac_flush_range(sid_info, sid_info + 2);
+ if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID),
+ &desc)){
+ pr_err("call to hypervisor failed\n");
+ kfree(sid_info);
+ return -EINVAL;
+ }
+
+ kfree(sid_info);
+ return rc;
+}
+
+static int cam_smmu_detach_device(int idx)
+{
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ /* detach the mapping to device */
+ arm_iommu_detach_device(cb->dev);
+ iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+ return 0;
+}
+
+static int cam_smmu_attach_sec_cpp(int idx)
+{
+ /*
+ * When switching to secure, detach CPP NS, do scm call
+ * with CPP SID and no need of attach again, because
+ * all cpp sids are shared in SCM call. so no need of
+ * attach again.
+ */
+
+ if (cam_smmu_send_syscall_cpp_intf(VMID_CP_CAMERA, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cam_smmu_detach_sec_cpp(int idx)
+{
+ /*
+ * When exiting secure, do scm call to attach
+ * with CPP SID in NS mode.
+ */
+ if (cam_smmu_send_syscall_cpp_intf(VMID_HLOS, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cam_smmu_attach_sec_vfe_ns_stats(int idx)
+{
+ /*
+ *When switching to secure, for secure pixel and non-secure stats
+ *localizing scm/attach of non-secure SID's in attach secure
+ */
+ if (cam_smmu_send_syscall_pix_intf(VMID_CP_CAMERA, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ if (cam_smmu_attach(idx)) {
+ pr_err("error: failed to attach\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int cam_smmu_detach_sec_vfe_ns_stats(int idx)
+{
+ /*
+ *While exiting from secure mode for secure pixel and non-secure stats,
+ *localizing detach/scm of non-secure SID's to detach secure
+ */
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_DETACH) {
+ if (cam_smmu_detach_device(idx) < 0) {
+ pr_err("Error: ARM IOMMU detach failed\n");
+ return -ENODEV;
+ }
+ }
+
+ if (cam_smmu_send_syscall_pix_intf(VMID_HLOS, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
size_t *len_ptr)
@@ -805,7 +995,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
} else {
rc = -EINVAL;
pr_err("Error: table sgl is null\n");
- goto err_unmap_sg;
+ goto err_map_addr;
}
/* fill up mapping_info */
@@ -813,7 +1003,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
if (!mapping_info) {
pr_err("Error: No enough space!\n");
rc = -ENOSPC;
- goto err_unmap_sg;
+ goto err_map_addr;
}
mapping_info->ion_fd = ion_fd;
mapping_info->buf = buf;
@@ -831,7 +1021,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
if (!*paddr_ptr || !*len_ptr) {
pr_err("Error: Space Allocation failed!\n");
rc = -ENOSPC;
- goto err_unmap_sg;
+ goto err_mapping_info;
}
CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
(void *)iommu_cb_set.cb_info[idx].dev,
@@ -841,6 +1031,12 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
return 0;
+err_mapping_info:
+ kzfree(mapping_info);
+err_map_addr:
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ table->sgl, table->nents,
+ dma_dir, buf);
err_unmap_sg:
dma_buf_unmap_attachment(attach, table, dma_dir);
err_detach:
@@ -851,6 +1047,98 @@ err_out:
return rc;
}
+static int cam_smmu_map_secure_buffer_and_add_to_list(int idx,
+ struct dma_buf *buf,
+ enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *table = NULL;
+
+ attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ rc = PTR_ERR(attach);
+ pr_err("Error: dma buf attach failed\n");
+ goto err_put;
+ }
+
+ table = dma_buf_map_attachment(attach, dma_dir);
+ if (IS_ERR_OR_NULL(table)) {
+ rc = PTR_ERR(table);
+ pr_err("Error: dma buf map attachment failed\n");
+ goto err_detach;
+ }
+
+ rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, table->sgl,
+ table->nents, dma_dir, buf);
+ if (!rc) {
+ pr_err("Error: msm_dma_map_sg_lazy failed\n");
+ goto err_unmap_sg;
+ }
+
+ if (table->sgl) {
+ CDBG("DMA buf: %p, device: %p, attach: %p, table: %p\n",
+ (void *)buf,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)attach, (void *)table);
+ CDBG("table sgl: %p, rc: %d, dma_address: 0x%x\n",
+ (void *)table->sgl, rc,
+ (unsigned int)table->sgl->dma_address);
+ } else {
+ rc = -EINVAL;
+ pr_err("Error: table sgl is null\n");
+ goto err_map_addr;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+ if (!mapping_info) {
+ rc = -ENOSPC;
+ goto err_map_addr;
+ }
+ mapping_info->ion_fd = 0;
+ mapping_info->buf = buf;
+ mapping_info->attach = attach;
+ mapping_info->table = table;
+ mapping_info->paddr = sg_dma_address(table->sgl);
+ mapping_info->len = (size_t)sg_dma_len(table->sgl);
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+
+ /* return paddr and len to client */
+ *paddr_ptr = sg_dma_address(table->sgl);
+ *len_ptr = (size_t)sg_dma_len(table->sgl);
+
+ if (!*paddr_ptr || !*len_ptr) {
+ pr_err("Error: Invalid dma address/length\n");
+ rc = -ENOSPC;
+ goto err_mapping_info;
+ }
+ CDBG("dev = %p, paddr= %p, len = %u\n",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ return 0;
+
+err_mapping_info:
+ kzfree(mapping_info);
+err_map_addr:
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ table->sgl, table->nents,
+ dma_dir, buf);
+err_unmap_sg:
+ dma_buf_unmap_attachment(attach, table, dma_dir);
+err_detach:
+ dma_buf_detach(buf, attach);
+err_put:
+ return rc;
+}
+
static int cam_smmu_unmap_buf_and_remove_from_list(
struct cam_dma_buff_info *mapping_info,
int idx)
@@ -951,7 +1239,23 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
break;
}
case CAM_SMMU_DETACH: {
- ret = 0;
+ ret = cam_smmu_detach_device(idx);
+ break;
+ }
+ case CAM_SMMU_ATTACH_SEC_VFE_NS_STATS: {
+ ret = cam_smmu_attach_sec_vfe_ns_stats(idx);
+ break;
+ }
+ case CAM_SMMU_DETACH_SEC_VFE_NS_STATS: {
+ ret = cam_smmu_detach_sec_vfe_ns_stats(idx);
+ break;
+ }
+ case CAM_SMMU_ATTACH_SEC_CPP: {
+ ret = cam_smmu_attach_sec_cpp(idx);
+ break;
+ }
+ case CAM_SMMU_DETACH_SEC_CPP: {
+ ret = cam_smmu_detach_sec_cpp(idx);
break;
}
case CAM_SMMU_VOTE:
@@ -1126,7 +1430,7 @@ int cam_smmu_get_phy_addr_scratch(int handle,
size_t virt_len,
size_t phys_len)
{
- int idx, rc;
+ int idx, rc = 0;
unsigned int iommu_dir;
if (!paddr_ptr || !virt_len || !phys_len) {
@@ -1250,12 +1554,384 @@ int cam_smmu_put_phy_addr_scratch(int handle,
pr_err("Error: unmap or remove list fail\n");
goto handle_err;
}
+handle_err:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_get_phy_addr_secure_scratch(int handle,
+ enum cam_smmu_map_dir dir,
+ struct dma_buf *scratch_buf,
+ dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Error: Input pointer or lengths invalid\n");
+ return -EINVAL;
+ }
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n",
+ __func__, handle, idx, dir);
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = cam_smmu_map_secure_buffer_and_add_to_list(idx,
+ scratch_buf,
+ dma_dir,
+ paddr_ptr,
+ len_ptr);
+ if (rc < 0) {
+ pr_err("Error: mapping or add list fail\n");
+ goto error;
+ }
+
+ CDBG("Mapped scratch buffer physical address is %lx\n",
+ (unsigned long)*paddr_ptr);
+error:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_put_phy_addr_secure_scratch(int handle,
+ dma_addr_t paddr)
+{
+ int idx;
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ /* Based on virtual address and index, we can find mapping info
+ * of the scratch buffer
+ */
+ mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params\n");
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc < 0) {
+ pr_err("Error: unmap or remove list fail\n");
+ goto handle_err;
+ }
+ CDBG("Unmap secure scratch buffer %lx success fully\n",
+ (unsigned long)paddr);
handle_err:
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
return rc;
}
+int cam_smmu_alloc_get_stage2_scratch_mem(int handle,
+ enum cam_smmu_map_dir dir, struct ion_client *client,
+ struct ion_handle **sc_handle, ion_phys_addr_t *addr,
+ size_t *len_ptr)
+{
+ int idx, rc = 0;
+ enum dma_data_direction dma_dir;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ return -EINVAL;
+ }
+ *sc_handle = ion_alloc(client, SZ_2M, SZ_2M,
+ ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID),
+ ION_FLAG_SECURE | ION_FLAG_CP_CAMERA);
+ if (IS_ERR_OR_NULL((void *) (*sc_handle))) {
+ rc = -ENOMEM;
+ goto err_ion_handle;
+ }
+
+ /* return addr and len to client */
+ rc = ion_phys(client, *sc_handle, addr, len_ptr);
+ if (rc) {
+ pr_err("%s: ION Get Physical failed, rc = %d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto err_ion_phys;
+ }
+
+ CDBG("dev = %pK, paddr= %pK, len = %u\n",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*addr, (unsigned int)*len_ptr);
+ return rc;
+
+err_ion_phys:
+ ion_free(client, *sc_handle);
+
+err_ion_handle:
+ *sc_handle = NULL;
+ return rc;
+}
+
+int cam_smmu_free_stage2_scratch_mem(int handle,
+ struct ion_client *client, struct ion_handle *sc_handle)
+{
+ int idx = 0;
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+ ion_free(client, sc_handle);
+ return 0;
+}
+
+static int cam_smmu_secure_unmap_buf_and_remove_from_list(
+ struct cam_sec_buff_info *mapping_info,
+ int idx)
+{
+ if (!mapping_info) {
+ pr_err("Error: List doesn't exist\n");
+ return -EINVAL;
+ }
+ ion_free(mapping_info->i_client, mapping_info->i_hdl);
+ list_del_init(&mapping_info->list);
+
+ /* free one buffer */
+ kfree(mapping_info);
+ return 0;
+}
+
+int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd)
+{
+ int idx, rc;
+ struct cam_sec_buff_info *mapping_info;
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ /* based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ mapping_info->ref_count--;
+ if (mapping_info->ref_count > 0) {
+ CDBG("There are still %u buffer(s) with same fd %d",
+ mapping_info->ref_count, mapping_info->ion_fd);
+ rc = 0;
+ goto put_addr_end;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc < 0) {
+ pr_err("Error: unmap or remove list fail\n");
+ goto put_addr_end;
+ }
+
+put_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_stage2_phy_addr);
+
+static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, struct ion_client *client,
+ dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int rc = 0;
+ struct ion_handle *i_handle = NULL;
+ struct cam_sec_buff_info *mapping_info;
+
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ return -EINVAL;
+ }
+
+ i_handle = ion_import_dma_buf(client, ion_fd);
+ if (IS_ERR_OR_NULL((void *)(i_handle))) {
+ pr_err("%s: ion import dma buffer failed\n", __func__);
+ return -EINVAL;
+ }
+
+ /* return addr and len to client */
+ rc = ion_phys(client, i_handle, paddr_ptr, len_ptr);
+ if (rc) {
+ pr_err("%s: ION Get Physical failed, rc = %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL);
+ if (!mapping_info)
+ return -ENOSPC;
+
+ mapping_info->ion_fd = ion_fd;
+ mapping_info->paddr = *paddr_ptr;
+ mapping_info->len = *len_ptr;
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->i_hdl = i_handle;
+ mapping_info->i_client = client;
+
+ CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ return rc;
+}
+
+int cam_smmu_get_stage2_phy_addr(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ struct ion_client *client, ion_phys_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Error: Input pointers are invalid\n");
+ return -EINVAL;
+ }
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_EXIST) {
+ CDBG("ion_fd:%d already in the list, give same addr back",
+ ion_fd);
+ rc = 0;
+ goto get_addr_end;
+ }
+ rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+ client, paddr_ptr, len_ptr);
+ if (rc < 0) {
+ pr_err("Error: mapping or add list fail\n");
+ goto get_addr_end;
+ }
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+
int cam_smmu_get_phy_addr(int handle, int ion_fd,
enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
size_t *len_ptr)
@@ -1383,6 +2059,11 @@ int cam_smmu_destroy_handle(int handle)
}
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (--iommu_cb_set.cb_info[idx].ref_cnt != 0) {
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return 0;
+ }
+
if (iommu_cb_set.cb_info[idx].handle != handle) {
pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
iommu_cb_set.cb_info[idx].handle, handle);
@@ -1469,6 +2150,28 @@ end:
return rc;
}
+static int cam_smmu_populate_sids(struct device *dev,
+ struct cam_context_bank_info *cb)
+{
+ int i, j, rc = 0;
+ unsigned int cnt = 0;
+ const void *property;
+
+ /* set the name of the context bank */
+ property = of_get_property(dev->of_node, "iommus", &cnt);
+ cnt /= 4;
+ for (i = 0, j = 0; i < cnt; i = i + 2, j++) {
+ rc = of_property_read_u32_index(dev->of_node,
+ "iommus", i + 1, &cb->sids[j]);
+ if (rc < 0)
+ pr_err("misconfiguration, can't fetch SID\n");
+
+ pr_err("__debug cnt = %d, cb->name: :%s sid [%d] = %d\n,",
+ cnt, cb->name, j, cb->sids[j]);
+ }
+ return rc;
+}
+
static int cam_alloc_smmu_context_banks(struct device *dev)
{
struct device_node *domains_child_node = NULL;
@@ -1541,6 +2244,11 @@ static int cam_populate_smmu_context_banks(struct device *dev,
goto cb_init_fail;
}
+ /* populate SID's for each cb */
+ rc = cam_smmu_populate_sids(dev, cb);
+ if (rc < 0)
+ pr_err("Error: failed to populate sids : %s\n", cb->name);
+
/* Check if context bank supports scratch buffers */
if (of_property_read_bool(dev->of_node, "qcom,scratch-buf-support"))
cb->scratch_buf_support = 1;
@@ -1549,9 +2257,9 @@ static int cam_populate_smmu_context_banks(struct device *dev,
/* set the secure/non secure domain type */
if (of_property_read_bool(dev->of_node, "qcom,secure-context"))
- cb->is_secure = CAM_SECURE;
+ cb->is_secure = true;
else
- cb->is_secure = CAM_NON_SECURE;
+ cb->is_secure = false;
CDBG("cb->name :%s, cb->is_secure :%d, cb->scratch_support :%d\n",
cb->name, cb->is_secure, cb->scratch_buf_support);
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
index 59d085989a9c..3b8481f8bf7e 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
@@ -23,6 +23,8 @@
#include <linux/random.h>
#include <linux/spinlock_types.h>
#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+
/*
* Enum for possible CAM SMMU operations
@@ -31,6 +33,10 @@
enum cam_smmu_ops_param {
CAM_SMMU_ATTACH,
CAM_SMMU_DETACH,
+ CAM_SMMU_ATTACH_SEC_VFE_NS_STATS,
+ CAM_SMMU_DETACH_SEC_VFE_NS_STATS,
+ CAM_SMMU_ATTACH_SEC_CPP,
+ CAM_SMMU_DETACH_SEC_CPP,
CAM_SMMU_VOTE,
CAM_SMMU_DEVOTE,
CAM_SMMU_OPS_INVALID
@@ -87,6 +93,59 @@ int cam_smmu_get_phy_addr(int handle,
int cam_smmu_put_phy_addr(int handle, int ion_fd);
/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ * DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @client : Client has to pass the ion_client pointer created by the client.
+ * @phys_addr : Pointer to physical address where mapped address will be
+ * returned.
+ * @len : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_stage2_phy_addr(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ struct ion_client *client, ion_phys_addr_t *addr,
+ size_t *len_ptr);
+
+/**
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd);
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ * DMA_TO_DEVICE or DMA_FROM_DEVICE, client has to pass.
+ * @client : Client has to pass the ion_client pointer created by the client.
+ * @ion_handle : handle to the buffer returned by CAM SMMU driver.
+ * @phys_addr : Pointer to physical address where mapped address will be
+ * returned.
+ * @len : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_get_stage2_scratch_mem(int handle,
+ enum cam_smmu_map_dir dir, struct ion_client *client,
+ struct ion_handle **sc_handle, ion_phys_addr_t *addr,
+ size_t *len_ptr);
+
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @client : Client has to pass the ion_client pointer provided by SMMU
+ * driver.
+ * @ion_handle : Client has to pass the ion_handle provided by SMMU
+ * driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_free_stage2_scratch_mem(int handle,
+ struct ion_client *client, struct ion_handle *sc_handle);
+
+/**
* @brief : Allocates a scratch buffer
*
* This function allocates a scratch virtual buffer of length virt_len in the
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 4e86a3ff820d..eaf35733b38a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2013,15 +2013,18 @@ static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr,
}
}
- fmt = sde_get_format_params(item->output.format);
- /* Tiled format downscale support not applied to AYUV tiled */
- if (sde_mdp_is_tilea5x_format(fmt) && (entry->dnsc_factor_h > 4)) {
- SDEROT_DBG("max downscale for tiled format is 4\n");
+ fmt = sde_get_format_params(item->input.format);
+ /*
+ * Rotator downscale support max 4 times for UBWC format and
+ * max 2 times for TP10/TP10_UBWC format
+ */
+ if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 4)) {
+ SDEROT_DBG("max downscale for UBWC format is 4\n");
ret = -EINVAL;
goto dnsc_err;
}
- if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 2)) {
- SDEROT_DBG("downscale with ubwc cannot be more than 2\n");
+ if (sde_mdp_is_tp10_format(fmt) && (entry->dnsc_factor_h > 2)) {
+ SDEROT_DBG("downscale with TP10 cannot be more than 2\n");
ret = -EINVAL;
}
goto dnsc_err;
@@ -2076,6 +2079,7 @@ static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr,
struct device_attribute *attr, char *buf, ssize_t len)
{
struct sde_hw_rotator *hw_data;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
int cnt = 0;
if (!mgr || !buf)
@@ -2087,6 +2091,10 @@ static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr,
(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
/* insert capabilities here */
+ if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map))
+ SPRINT("min_downscale=1.5\n");
+ else
+ SPRINT("min_downscale=2.0\n");
#undef SPRINT
return cnt;
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c
index dded8a25961a..98d9eb733371 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c
@@ -24,6 +24,7 @@ enum bus_profile {
VIDC_BUS_PROFILE_NORMAL = BIT(0),
VIDC_BUS_PROFILE_LOW = BIT(1),
VIDC_BUS_PROFILE_UBWC = BIT(2),
+ VIDC_BUS_PROFILE_UBWC_10_BIT = BIT(3),
};
struct bus_profile_entry {
@@ -53,7 +54,7 @@ static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
load = NUM_MBS_PER_SEC(data->width, data->height, data->fps);
sess_type = VIDC_VOTE_DATA_SESSION_VAL(data->codec, data->domain);
- /* check if ubwc bus profile is present */
+ /* check if appropriate bus profile is present */
for (i = 0; i < gov->count; i++) {
entry = &gov->bus_prof_entries[i];
if (!entry->bus_table || !entry->bus_table_size)
@@ -119,18 +120,23 @@ static int msm_vidc_table_get_target_freq(struct devfreq *dev,
}
profile = VIDC_BUS_PROFILE_NORMAL;
- if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_TP10_UBWC ||
- data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
+ if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
profile = VIDC_BUS_PROFILE_UBWC;
+ else if (data->color_formats[0] ==
+ HAL_COLOR_FORMAT_NV12_TP10_UBWC)
+ profile = VIDC_BUS_PROFILE_UBWC_10_BIT;
freq = __get_bus_freq(gov, data, profile);
/*
* chose frequency from normal profile
* if specific profile frequency was not found.
*/
- if (!freq)
+ if (!freq) {
+ dprintk(VIDC_WARN,
+ "appropriate bus table not found, voting with Normal Profile\n");
freq = __get_bus_freq(gov, data,
VIDC_BUS_PROFILE_NORMAL);
+ }
*frequency += (unsigned long)freq;
@@ -260,6 +266,8 @@ static int msm_vidc_load_bus_table(struct platform_device *pdev,
entry->profile = VIDC_BUS_PROFILE_LOW;
else if (of_find_property(child_node, "qcom,ubwc-mode", NULL))
entry->profile = VIDC_BUS_PROFILE_UBWC;
+ else if (of_find_property(child_node, "qcom,ubwc-10bit", NULL))
+ entry->profile = VIDC_BUS_PROFILE_UBWC_10_BIT;
else
entry->profile = VIDC_BUS_PROFILE_NORMAL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index c4d06b658b30..7bc1fe1af26d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1320,11 +1320,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst)
msm_comm_ctrl_deinit(inst);
- mutex_destroy(&inst->sync_lock);
- mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
- mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
- mutex_destroy(&inst->lock);
-
DEINIT_MSM_VIDC_LIST(&inst->pendingq);
DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
@@ -1338,6 +1333,11 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst)
for (i = 0; i < MAX_PORT_NUM; i++)
vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ mutex_destroy(&inst->sync_lock);
+ mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
+ mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
+ mutex_destroy(&inst->lock);
+
pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n",
VIDC_MSG_PRIO2STRING(VIDC_INFO), inst);
kfree(inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index fa2ad1754e77..73c52841fd34 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -298,6 +298,11 @@ static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
rc = msm_comm_g_ctrl(inst, &ctrl);
if (!rc && ctrl.value) {
fps = (ctrl.value >> 16) ? ctrl.value >> 16 : 1;
+ /*
+ * Check if operating rate is less than fps.
+ * If Yes, then use fps to scale clocks
+ */
+ fps = fps > inst->prop.fps ? fps : inst->prop.fps;
return max(output_port_mbs, capture_port_mbs) * fps;
} else
return max(output_port_mbs, capture_port_mbs) * inst->prop.fps;
@@ -1666,7 +1671,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
*/
mutex_lock(&core->lock);
- inst = list_first_entry(&core->instances,
+ inst = list_first_entry_or_null(&core->instances,
struct msm_vidc_inst, list);
mutex_unlock(&core->lock);
@@ -5359,10 +5364,10 @@ static void msm_comm_print_debug_info(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "Venus core frequency = %lu",
msm_comm_get_clock_rate(core));
+ mutex_lock(&core->lock);
dprintk(VIDC_ERR, "Printing instance info that caused Error\n");
msm_comm_print_inst_info(inst);
dprintk(VIDC_ERR, "Printing remaining instances info\n");
- mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
/* inst already printed above. Hence don't repeat.*/
if (temp == inst)
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 787ee43ccbd2..0055e22b40b4 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -75,7 +75,7 @@ const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = {
.imem_size = 0,
};
-const int max_packets = 250;
+const int max_packets = 1000;
static void venus_hfi_pm_handler(struct work_struct *work);
static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler);
@@ -3576,6 +3576,7 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
struct venus_hfi_device *device = list_first_entry(
&hal_ctxt.dev_head, struct venus_hfi_device, list);
int num_responses = 0, i = 0;
+ u32 intr_status;
mutex_lock(&device->lock);
@@ -3601,10 +3602,9 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
num_responses = __response_handler(device);
err_no_work:
- /* We need re-enable the irq which was disabled in ISR handler */
- if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
- enable_irq(device->hal_data->irq);
+ /* Keep the interrupt status before releasing device lock */
+ intr_status = device->intr_status;
mutex_unlock(&device->lock);
/*
@@ -3619,6 +3619,10 @@ err_no_work:
device->callback(r->response_type, &r->response);
}
+ /* We need re-enable the irq which was disabled in ISR handler */
+ if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+ enable_irq(device->hal_data->irq);
+
/*
* XXX: Don't add any code beyond here. Reacquiring locks after release
* it above doesn't guarantee the atomicity that we're aiming for.
@@ -4548,7 +4552,7 @@ static struct venus_hfi_device *__add_device(u32 device_id,
}
hdevice->response_pkt = kmalloc_array(max_packets,
- sizeof(*hdevice->response_pkt), GFP_TEMPORARY);
+ sizeof(*hdevice->response_pkt), GFP_KERNEL);
if (!hdevice->response_pkt) {
dprintk(VIDC_ERR, "failed to allocate response_pkt\n");
goto err_cleanup;
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 4e941f00b600..082ff5608455 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1403,11 +1403,12 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
* in order to avoid troubles during device release.
*/
kfree(priv->ctrl.fname);
+ priv->ctrl.fname = NULL;
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (p->fname) {
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL)
- rc = -ENOMEM;
+ return -ENOMEM;
}
/*
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 7accaa3a1673..039ffcc24c23 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -214,7 +214,6 @@ static struct smb_params v1_params = {
#define STEP_CHARGING_MAX_STEPS 5
struct smb_dt_props {
- bool no_battery;
int fcc_ua;
int usb_icl_ua;
int otg_cl_ua;
@@ -226,7 +225,9 @@ struct smb_dt_props {
struct device_node *revid_dev_node;
int float_option;
int chg_inhibit_thr_mv;
+ bool no_battery;
bool hvdcp_disable;
+ bool auto_recharge_soc;
};
struct smb2 {
@@ -344,6 +345,8 @@ static int smb2_parse_dt(struct smb2 *chip)
return -EINVAL;
}
+ chip->dt.auto_recharge_soc = of_property_read_bool(node,
+ "qcom,auto-recharge-soc");
return 0;
}
@@ -1295,6 +1298,28 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
+ if (chip->dt.auto_recharge_soc) {
+ rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG,
+ SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT |
+ VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT,
+ VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ } else {
+ rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG,
+ SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT |
+ VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT,
+ SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
return rc;
}
@@ -1837,8 +1862,13 @@ static void smb2_shutdown(struct platform_device *pdev)
struct smb2 *chip = platform_get_drvdata(pdev);
struct smb_charger *chg = &chip->chg;
+ /* configure power role for UFP */
+ smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT);
+
+ /* force HVDCP to 5V */
smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
- HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
+ HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
}
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index 3403474565be..52805357ef92 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -505,15 +505,14 @@ static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
{
- const struct apsd_result *apsd_result;
+ const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
/* if PD is active, APSD is disabled so won't have a valid result */
if (chg->pd_active) {
chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
- return 0;
+ return apsd_result;
}
- apsd_result = smblib_get_apsd_result(chg);
chg->usb_psy_desc.type = apsd_result->pst;
return apsd_result;
}
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index d3f967319d21..21733633cb6c 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -628,12 +628,10 @@ config MSM_PERFORMANCE
config MSM_PERFORMANCE_HOTPLUG_ON
bool "Hotplug functionality through msm_performance turned on"
depends on MSM_PERFORMANCE
- default y
help
- If some other core-control driver is present turn off the core-control
- capability of msm_performance driver. Setting this flag to false will
- compile out the nodes needed for core-control functionality through
- msm_performance.
+ Setting this flag to true will enable the nodes needed for core-control
+ functionality of hot plugging cores through msm_performance if there is
+ no default core-control driver available.
endif # ARCH_QCOM
diff --git a/drivers/soc/qcom/gladiator_erp_v2.c b/drivers/soc/qcom/gladiator_erp_v2.c
index 25c7bd77ae96..91b5d39be242 100644
--- a/drivers/soc/qcom/gladiator_erp_v2.c
+++ b/drivers/soc/qcom/gladiator_erp_v2.c
@@ -628,9 +628,11 @@ static irqreturn_t msm_gladiator_isr(int irq, void *dev_id)
msm_gld_data->gladiator_virt_base +
get_gld_offset(err_log));
}
- pr_alert("Main log register data:\n%08x %08x %08x %08x\n%08x %08x %08x %08x\n%08x %08x %08x\n",
- err_buf[0], err_buf[1], err_buf[2], err_buf[3], err_buf[4], err_buf[5], err_buf[6],
- err_buf[7], err_buf[8], err_buf[9], err_buf[10]);
+ pr_alert("Main log register data:\n%08x %08x %08x %08x\n"
+ "%08x %08x %08x %08x\n%08x %08x %08x %08x\n",
+ err_buf[2], err_buf[3], err_buf[4], err_buf[5],
+ err_buf[6], err_buf[7], err_buf[8], err_buf[9],
+ err_buf[10], err_buf[11], err_buf[12], err_buf[13]);
}
if (obsrv_err_valid) {
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
index deb7231a4ed1..10fb4cc8ebff 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
@@ -869,7 +869,7 @@ static void unregister_client_adhoc(uint32_t cl)
}
curr = client->curr;
- if (curr >= pdata->num_usecases) {
+ if ((curr < 0) || (curr >= pdata->num_usecases)) {
MSM_BUS_ERR("Invalid index Defaulting curr to 0");
curr = 0;
}
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index b4713ac1b68b..f2216f968319 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -665,10 +665,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
desc->ret[0] = desc->ret[1] = desc->ret[2] = 0;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
trace_scm_call_start(x0, desc);
if (scm_version == SCM_ARMV8_64)
@@ -698,10 +694,8 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
} while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
- desc->ret[1], desc->ret[2]);
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
kfree(desc->extra_arg_buf);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 826a22355429..f93ee29123fe 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -42,8 +42,8 @@
#define SMEM_IMAGE_VERSION_NAME_SIZE 75
#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
#define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75
-#define SMEM_IMAGE_VERSION_OEM_SIZE 32
-#define SMEM_IMAGE_VERSION_OEM_OFFSET 96
+#define SMEM_IMAGE_VERSION_OEM_SIZE 33
+#define SMEM_IMAGE_VERSION_OEM_OFFSET 95
#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
enum {
@@ -974,7 +974,7 @@ msm_get_image_crm_version(struct device *dev,
}
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
- return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n",
+ return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s\n",
string_address);
}
@@ -995,7 +995,7 @@ msm_set_image_crm_version(struct device *dev,
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
- snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf);
+ snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s", buf);
return count;
}
@@ -1049,7 +1049,8 @@ msm_get_images(struct device *dev,
image_address);
pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVariant:\t%-.20s\n",
image_address + SMEM_IMAGE_VERSION_VARIANT_OFFSET);
- pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVersion:\t%-.32s\n\n",
+ pos += snprintf(buf + pos, PAGE_SIZE - pos,
+ "\tVersion:\t%-.33s\n",
image_address + SMEM_IMAGE_VERSION_OEM_OFFSET);
image_address += SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index b2e1a4c1b170..b5905fc81147 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -274,11 +274,16 @@ static int ion_secure_cma_allocate(struct ion_heap *heap,
source_vm = VMID_HLOS;
dest_vm = get_secure_vmid(flags);
+
if (dest_vm < 0) {
pr_err("%s: Failed to get secure vmid\n", __func__);
return -EINVAL;
}
- dest_perms = PERM_READ | PERM_WRITE;
+
+ if (dest_vm == VMID_CP_SEC_DISPLAY)
+ dest_perms = PERM_READ;
+ else
+ dest_perms = PERM_READ | PERM_WRITE;
ret = ion_cma_allocate(heap, buffer, len, align, flags);
if (ret) {
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 629e3c865072..9bee25cfa0be 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -417,6 +417,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do
* any harm.
*
+ * The line discipline-related tty_struct fields are reset to
+ * prevent the ldisc driver from re-using stale information for
+ * the new ldisc instance.
+ *
* Locking: takes termios_rwsem
*/
@@ -425,6 +429,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
down_write(&tty->termios_rwsem);
tty->termios.c_line = num;
up_write(&tty->termios_rwsem);
+
+ tty->disc_data = NULL;
+ tty->receive_room = 0;
}
/**
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index eb2409dda50d..19d6a997ee6c 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -760,8 +760,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
ssize_t ret, data_len = -EINVAL;
int halt;
- ffs_log("enter: epfile name %s epfile err %d", epfile->name,
- atomic_read(&epfile->error));
+ ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name,
+ atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE");
smp_mb__before_atomic();
if (atomic_read(&epfile->error))
@@ -781,6 +781,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
goto error;
}
+ /* Don't wait on write if device is offline */
+ if (!io_data->read) {
+ ret = -EINTR;
+ goto error;
+ }
+
/*
* If ep is disabled, this fails all current IOs
* and wait for next epfile open to happen.
diff --git a/drivers/usb/pd/Kconfig b/drivers/usb/pd/Kconfig
index dd2813000dec..cc88df495f6e 100644
--- a/drivers/usb/pd/Kconfig
+++ b/drivers/usb/pd/Kconfig
@@ -9,6 +9,7 @@ config USB_PD
config USB_PD_POLICY
tristate "USB Power Delivery Protocol and Policy Engine"
depends on EXTCON
+ depends on DUAL_ROLE_USB_INTF
select USB_PD
help
Say Y here to enable USB PD protocol and policy engine.
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index aa2e1d9f3c70..2fbe4c8faa79 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/ipc_logging.h>
@@ -24,6 +25,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/extcon.h>
+#include <linux/usb/class-dual-role.h>
#include <linux/usb/usbpd.h>
#include "usbpd.h"
@@ -163,11 +165,11 @@ static void *usbpd_ipc_log;
/* Timeouts (in ms) */
#define ERROR_RECOVERY_TIME 25
#define SENDER_RESPONSE_TIME 26
-#define SINK_WAIT_CAP_TIME 620
+#define SINK_WAIT_CAP_TIME 500
#define PS_TRANSITION_TIME 450
#define SRC_CAP_TIME 120
#define SRC_TRANSITION_TIME 25
-#define SRC_RECOVER_TIME 660
+#define SRC_RECOVER_TIME 750
#define PS_HARD_RESET_TIME 25
#define PS_SOURCE_ON 400
#define PS_SOURCE_OFF 750
@@ -175,8 +177,11 @@ static void *usbpd_ipc_log;
#define VDM_BUSY_TIME 50
#define VCONN_ON_TIME 100
-/* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */
-#define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275)
+/* tPSHardReset + tSafe0V */
+#define SNK_HARD_RESET_VBUS_OFF_TIME (35 + 650)
+
+/* tSrcRecover + tSrcTurnOn */
+#define SNK_HARD_RESET_VBUS_ON_TIME (1000 + 275)
#define PD_CAPS_COUNT 50
@@ -308,15 +313,23 @@ struct usbpd {
enum power_supply_typec_mode typec_mode;
enum power_supply_type psy_type;
+ enum power_supply_typec_power_role forced_pr;
bool vbus_present;
enum data_role current_dr;
enum power_role current_pr;
bool in_pr_swap;
bool pd_phy_opened;
+ struct completion swap_complete;
+
+ struct dual_role_phy_instance *dual_role;
+ struct dual_role_phy_desc dr_desc;
+ bool send_pr_swap;
+ bool send_dr_swap;
struct regulator *vbus;
struct regulator *vconn;
+ bool vbus_enabled;
bool vconn_enabled;
bool vconn_is_external;
@@ -409,6 +422,17 @@ static struct usbpd_svid_handler *find_svid_handler(struct usbpd *pd, u16 svid)
return NULL;
}
+/* Reset protocol layer */
+static inline void pd_reset_protocol(struct usbpd *pd)
+{
+ /*
+ * first Rx ID should be 0; set this to a sentinel of -1 so that in
+ * phy_msg_received() we can check if we had seen it before.
+ */
+ pd->rx_msgid = -1;
+ pd->tx_msgid = 0;
+}
+
static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
size_t num_data, enum pd_msg_type type)
{
@@ -423,7 +447,9 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
/* MessageID incremented regardless of Tx error */
pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
- if (ret != num_data * sizeof(u32))
+ if (ret < 0)
+ return ret;
+ else if (ret != num_data * sizeof(u32))
return -EIO;
return 0;
}
@@ -631,6 +657,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
switch (next_state) {
case PE_ERROR_RECOVERY: /* perform hard disconnect/reconnect */
pd->in_pr_swap = false;
+ pd->current_pr = PR_NONE;
set_power_role(pd, PR_NONE);
pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
kick_sm(pd, 0);
@@ -646,12 +673,14 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
*/
}
+ dual_role_instance_changed(pd->dual_role);
+
/* Set CC back to DRP toggle for the next disconnect */
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
if (pd->pd_phy_opened) {
@@ -677,6 +706,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->current_state = PE_SRC_SEND_CAPABILITIES;
if (pd->in_pr_swap) {
kick_sm(pd, SWAP_SOURCE_START_TIME);
+ pd->in_pr_swap = false;
break;
}
@@ -758,6 +788,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
+ complete(&pd->swap_complete);
+ dual_role_instance_changed(pd->dual_role);
break;
case PE_SRC_HARD_RESET:
@@ -768,9 +800,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_SEND_SOFT_RESET:
case PE_SNK_SEND_SOFT_RESET:
- /* Reset protocol layer */
- pd->tx_msgid = 0;
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
ret = pd_send_msg(pd, MSG_SOFT_RESET, NULL, 0, SOP_MSG);
if (ret) {
@@ -801,6 +831,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
}
+ dual_role_instance_changed(pd->dual_role);
+
ret = power_supply_get_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_ALLOWED, &val);
if (ret) {
@@ -812,9 +844,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
if (!val.intval)
break;
- /* Reset protocol layer */
- pd->tx_msgid = 0;
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
if (pd->pd_phy_opened) {
@@ -837,7 +867,17 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->pd_phy_opened = true;
}
- pd->current_voltage = 5000000;
+ pd->current_voltage = pd->requested_voltage = 5000000;
+ val.intval = pd->requested_voltage; /* set max range to 5V */
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX, &val);
+
+ if (!pd->vbus_present) {
+ pd->current_state = PE_SNK_DISCOVERY;
+ /* max time for hard reset to turn vbus back on */
+ kick_sm(pd, SNK_HARD_RESET_VBUS_ON_TIME);
+ break;
+ }
pd->current_state = PE_SNK_WAIT_FOR_CAPABILITIES;
/* fall-through */
@@ -882,6 +922,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SNK_READY:
pd->in_explicit_contract = true;
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
+ complete(&pd->swap_complete);
+ dual_role_instance_changed(pd->dual_role);
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
@@ -901,13 +943,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->vconn_enabled = false;
}
- val.intval = pd->requested_voltage; /* set range back to 5V */
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_VOLTAGE_MAX, &val);
- pd->current_voltage = pd->requested_voltage;
-
- /* max time for hard reset to toggle vbus off/on */
- kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME);
+ /* max time for hard reset to turn vbus off */
+ kick_sm(pd, SNK_HARD_RESET_VBUS_OFF_TIME);
break;
case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
@@ -996,7 +1033,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos)
pd->vdm_tx = vdm_tx;
/* slight delay before queuing to prioritize handling of incoming VDM */
- kick_sm(pd, 5);
+ kick_sm(pd, 2);
return 0;
}
@@ -1214,21 +1251,32 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
static void handle_vdm_tx(struct usbpd *pd)
{
int ret;
+ unsigned long flags;
/* only send one VDM at a time */
if (pd->vdm_tx) {
u32 vdm_hdr = pd->vdm_tx->data[0];
+ /* bail out and try again later if a message just arrived */
+ spin_lock_irqsave(&pd->rx_lock, flags);
+ if (!list_empty(&pd->rx_q)) {
+ spin_unlock_irqrestore(&pd->rx_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&pd->rx_lock, flags);
+
ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data,
pd->vdm_tx->size, SOP_MSG);
if (ret) {
- usbpd_err(&pd->dev, "Error sending VDM command %d\n",
- SVDM_HDR_CMD(pd->vdm_tx->data[0]));
- usbpd_set_state(pd, pd->current_pr == PR_SRC ?
+ usbpd_err(&pd->dev, "Error (%d) sending VDM command %d\n",
+ ret, SVDM_HDR_CMD(pd->vdm_tx->data[0]));
+
+ /* retry when hitting PE_SRC/SNK_Ready again */
+ if (ret != -EBUSY)
+ usbpd_set_state(pd, pd->current_pr == PR_SRC ?
PE_SRC_SEND_SOFT_RESET :
PE_SNK_SEND_SOFT_RESET);
- /* retry when hitting PE_SRC/SNK_Ready again */
return;
}
@@ -1240,7 +1288,7 @@ static void handle_vdm_tx(struct usbpd *pd)
SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR &&
SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) {
if (pd->vdm_tx_retry) {
- usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n",
+ usbpd_dbg(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n",
SVDM_HDR_CMD(
pd->vdm_tx_retry->data[0]));
kfree(pd->vdm_tx_retry);
@@ -1319,6 +1367,13 @@ static void vconn_swap(struct usbpd *pd)
pd->vconn_enabled = true;
+ /*
+ * Small delay to ensure Vconn has ramped up. This is well
+ * below tVCONNSourceOn (100ms) so we still send PS_RDY within
+ * the allowed time.
+ */
+ usleep_range(5000, 10000);
+
ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending PS_RDY\n");
@@ -1366,7 +1421,7 @@ static void usbpd_sm(struct work_struct *w)
spin_unlock_irqrestore(&pd->rx_lock, flags);
/* Disconnect? */
- if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE && !pd->in_pr_swap) {
+ if (pd->current_pr == PR_NONE) {
if (pd->current_state == PE_UNKNOWN)
goto sm_done;
@@ -1400,8 +1455,10 @@ static void usbpd_sm(struct work_struct *w)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_ACTIVE, &val);
- if (pd->current_pr == PR_SRC)
+ if (pd->vbus_enabled) {
regulator_disable(pd->vbus);
+ pd->vbus_enabled = false;
+ }
if (pd->vconn_enabled) {
regulator_disable(pd->vconn);
@@ -1423,13 +1480,22 @@ static void usbpd_sm(struct work_struct *w)
usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
(ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
- /* Set CC back to DRP toggle */
- val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+ /* set due to dual_role class "mode" change */
+ if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
+ val.intval = pd->forced_pr;
+ else
+ /* Set CC back to DRP toggle */
+ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
+ pd->forced_pr = POWER_SUPPLY_TYPEC_PR_NONE;
pd->current_state = PE_UNKNOWN;
+ kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
+ dual_role_instance_changed(pd->dual_role);
+
goto sm_done;
}
@@ -1473,6 +1539,8 @@ static void usbpd_sm(struct work_struct *w)
ret = regulator_enable(pd->vbus);
if (ret)
usbpd_err(&pd->dev, "Unable to enable vbus\n");
+ else
+ pd->vbus_enabled = true;
if (!pd->vconn_enabled &&
pd->typec_mode ==
@@ -1521,10 +1589,6 @@ static void usbpd_sm(struct work_struct *w)
break;
}
- val.intval = 1;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_ACTIVE, &val);
-
/* transmit was successful if GoodCRC was received */
pd->caps_count = 0;
pd->hard_reset_count = 0;
@@ -1533,6 +1597,10 @@ static void usbpd_sm(struct work_struct *w)
/* wait for REQUEST */
pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT;
kick_sm(pd, SENDER_RESPONSE_TIME);
+
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_ACTIVE, &val);
break;
case PE_SRC_SEND_CAPABILITIES_WAIT:
@@ -1582,7 +1650,6 @@ static void usbpd_sm(struct work_struct *w)
}
dr_swap(pd);
- kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
} else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) {
/* lock in current mode */
set_power_role(pd, pd->current_pr);
@@ -1607,18 +1674,40 @@ static void usbpd_sm(struct work_struct *w)
}
vconn_swap(pd);
+ } else if (IS_DATA(rx_msg, MSG_VDM)) {
+ handle_vdm_rx(pd, rx_msg);
+ } else if (pd->send_pr_swap) {
+ pd->send_pr_swap = false;
+ ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending PR Swap\n");
+ usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_PRS_SRC_SNK_SEND_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
+ } else if (pd->send_dr_swap) {
+ pd->send_dr_swap = false;
+ ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending DR Swap\n");
+ usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_DRS_SEND_DR_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
} else {
- if (IS_DATA(rx_msg, MSG_VDM))
- handle_vdm_rx(pd, rx_msg);
- else
- handle_vdm_tx(pd);
+ handle_vdm_tx(pd);
}
break;
case PE_SRC_TRANSITION_TO_DEFAULT:
if (pd->vconn_enabled)
regulator_disable(pd->vconn);
- regulator_disable(pd->vbus);
+ if (pd->vbus_enabled)
+ regulator_disable(pd->vbus);
if (pd->current_dr != DR_DFP) {
extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0);
@@ -1628,9 +1717,12 @@ static void usbpd_sm(struct work_struct *w)
msleep(SRC_RECOVER_TIME);
+ pd->vbus_enabled = false;
ret = regulator_enable(pd->vbus);
if (ret)
usbpd_err(&pd->dev, "Unable to enable vbus\n");
+ else
+ pd->vbus_enabled = true;
if (pd->vconn_enabled) {
ret = regulator_enable(pd->vconn);
@@ -1665,23 +1757,48 @@ static void usbpd_sm(struct work_struct *w)
usbpd_set_state(pd, PE_SNK_STARTUP);
break;
+ case PE_SNK_DISCOVERY:
+ if (!rx_msg) {
+ if (pd->vbus_present)
+ usbpd_set_state(pd,
+ PE_SNK_WAIT_FOR_CAPABILITIES);
+
+ /*
+ * Handle disconnection in the middle of PR_Swap.
+ * Since in psy_changed() if pd->in_pr_swap is true
+ * we ignore the typec_mode==NONE change since that is
+ * expected to happen. However if the cable really did
+ * get disconnected we need to check for it here after
+ * waiting for VBUS presence times out.
+ */
+ if (!pd->typec_mode) {
+ pd->current_pr = PR_NONE;
+ kick_sm(pd, 0);
+ }
+
+ break;
+ }
+ /* else fall-through */
+
case PE_SNK_WAIT_FOR_CAPABILITIES:
+ pd->in_pr_swap = false;
+
if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) {
val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
&val);
- val.intval = 1;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_ACTIVE, &val);
-
/* save the PDOs so userspace can further evaluate */
memcpy(&pd->received_pdos, rx_msg->payload,
sizeof(pd->received_pdos));
pd->src_cap_id++;
usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY);
+
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_ACTIVE, &val);
} else if (pd->hard_reset_count < 3) {
usbpd_set_state(pd, PE_SNK_HARD_RESET);
} else if (pd->pd_connected) {
@@ -1821,7 +1938,6 @@ static void usbpd_sm(struct work_struct *w)
}
dr_swap(pd);
- kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
} else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) {
/* lock in current mode */
set_power_role(pd, pd->current_pr);
@@ -1863,37 +1979,42 @@ static void usbpd_sm(struct work_struct *w)
}
vconn_swap(pd);
+ } else if (IS_DATA(rx_msg, MSG_VDM)) {
+ handle_vdm_rx(pd, rx_msg);
+ } else if (pd->send_pr_swap) {
+ pd->send_pr_swap = false;
+ ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending PR Swap\n");
+ usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_PRS_SNK_SRC_SEND_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
+ } else if (pd->send_dr_swap) {
+ pd->send_dr_swap = false;
+ ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending DR Swap\n");
+ usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_DRS_SEND_DR_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
} else {
- if (IS_DATA(rx_msg, MSG_VDM))
- handle_vdm_rx(pd, rx_msg);
- else
- handle_vdm_tx(pd);
+ handle_vdm_tx(pd);
}
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
- val.intval = 0;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
-
- if (pd->vbus_present) {
- usbpd_set_state(pd, PE_SNK_STARTUP);
- } else {
- /* Hard reset and VBUS didn't come back? */
- power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_TYPEC_MODE, &val);
- if (val.intval == POWER_SUPPLY_TYPEC_NONE) {
- pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
- kick_sm(pd, 0);
- }
- }
+ usbpd_set_state(pd, PE_SNK_STARTUP);
break;
case PE_SRC_SOFT_RESET:
case PE_SNK_SOFT_RESET:
- /* Reset protocol layer */
- pd->tx_msgid = 0;
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
if (ret) {
@@ -1969,7 +2090,10 @@ static void usbpd_sm(struct work_struct *w)
pd->in_pr_swap = true;
pd->in_explicit_contract = false;
- regulator_disable(pd->vbus);
+ if (pd->vbus_enabled) {
+ regulator_disable(pd->vbus);
+ pd->vbus_enabled = false;
+ }
/* PE_PRS_SRC_SNK_Assert_Rd */
pd->current_pr = PR_SINK;
@@ -2024,6 +2148,8 @@ static void usbpd_sm(struct work_struct *w)
ret = regulator_enable(pd->vbus);
if (ret)
usbpd_err(&pd->dev, "Unable to enable vbus\n");
+ else
+ pd->vbus_enabled = true;
msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */
@@ -2134,6 +2260,21 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
pd->psy_type = val.intval;
+ /*
+ * For sink hard reset, state machine needs to know when VBUS changes
+ * - when in PE_SNK_TRANSITION_TO_DEFAULT, notify when VBUS falls
+ * - when in PE_SNK_DISCOVERY, notify when VBUS rises
+ */
+ if (typec_mode && ((!pd->vbus_present &&
+ pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) ||
+ (pd->vbus_present && pd->current_state == PE_SNK_DISCOVERY))) {
+ usbpd_dbg(&pd->dev, "hard reset: typec mode:%d present:%d\n",
+ typec_mode, pd->vbus_present);
+ pd->typec_mode = typec_mode;
+ kick_sm(pd, 0);
+ return 0;
+ }
+
if (pd->typec_mode == typec_mode)
return 0;
@@ -2151,32 +2292,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
return 0;
}
- /*
- * Workaround for PMIC HW bug.
- *
- * During hard reset when VBUS goes to 0 the CC logic
- * will report this as a disconnection. In those cases
- * it can be ignored, however the downside is that
- * we can also happen to be in the SNK_Transition_to_default
- * state due to a hard reset attempt even with a non-PD
- * capable source, in which a physical disconnect may get
- * masked. In that case, allow for the common case of
- * disconnecting from an SDP.
- *
- * The less common case is a PD-capable SDP which will
- * result in a hard reset getting treated like a
- * disconnect. We can live with this until the HW bug
- * is fixed: in which disconnection won't be reported
- * on VBUS loss alone unless pullup is also removed
- * from CC.
- */
- if (pd->psy_type != POWER_SUPPLY_TYPE_USB &&
- pd->current_state ==
- PE_SNK_TRANSITION_TO_DEFAULT) {
- usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n");
- return 0;
- }
-
+ pd->current_pr = PR_NONE;
break;
/* Sink states */
@@ -2185,8 +2301,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
usbpd_info(&pd->dev, "Type-C Source (%s) connected\n",
src_current(typec_mode));
+
+ if (pd->current_pr == PR_SINK)
+ return 0;
+
pd->current_pr = PR_SINK;
- pd->in_pr_swap = false;
break;
/* Source states */
@@ -2195,8 +2314,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
usbpd_info(&pd->dev, "Type-C Sink%s connected\n",
typec_mode == POWER_SUPPLY_TYPEC_SINK ?
"" : " (powered)");
+
+ if (pd->current_pr == PR_SRC)
+ return 0;
+
pd->current_pr = PR_SRC;
- pd->in_pr_swap = false;
break;
case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY:
@@ -2216,6 +2338,198 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
return 0;
}
+static enum dual_role_property usbpd_dr_properties[] = {
+ DUAL_ROLE_PROP_SUPPORTED_MODES,
+ DUAL_ROLE_PROP_MODE,
+ DUAL_ROLE_PROP_PR,
+ DUAL_ROLE_PROP_DR,
+};
+
+static int usbpd_dr_get_property(struct dual_role_phy_instance *dual_role,
+ enum dual_role_property prop, unsigned int *val)
+{
+ struct usbpd *pd = dual_role_get_drvdata(dual_role);
+
+ if (!pd)
+ return -ENODEV;
+
+ switch (prop) {
+ case DUAL_ROLE_PROP_MODE:
+ /* For now associate UFP/DFP with data role only */
+ if (pd->current_dr == DR_UFP)
+ *val = DUAL_ROLE_PROP_MODE_UFP;
+ else if (pd->current_dr == DR_DFP)
+ *val = DUAL_ROLE_PROP_MODE_DFP;
+ else
+ *val = DUAL_ROLE_PROP_MODE_NONE;
+ break;
+ case DUAL_ROLE_PROP_PR:
+ if (pd->current_pr == PR_SRC)
+ *val = DUAL_ROLE_PROP_PR_SRC;
+ else if (pd->current_pr == PR_SINK)
+ *val = DUAL_ROLE_PROP_PR_SNK;
+ else
+ *val = DUAL_ROLE_PROP_PR_NONE;
+ break;
+ case DUAL_ROLE_PROP_DR:
+ if (pd->current_dr == DR_UFP)
+ *val = DUAL_ROLE_PROP_DR_DEVICE;
+ else if (pd->current_dr == DR_DFP)
+ *val = DUAL_ROLE_PROP_DR_HOST;
+ else
+ *val = DUAL_ROLE_PROP_DR_NONE;
+ break;
+ default:
+ usbpd_warn(&pd->dev, "unsupported property %d\n", prop);
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role,
+ enum dual_role_property prop, const unsigned int *val)
+{
+ struct usbpd *pd = dual_role_get_drvdata(dual_role);
+ bool do_swap = false;
+
+ if (!pd)
+ return -ENODEV;
+
+ switch (prop) {
+ case DUAL_ROLE_PROP_MODE:
+ usbpd_dbg(&pd->dev, "Setting mode to %d\n", *val);
+
+ /*
+ * Forces disconnect on CC and re-establishes connection.
+ * This does not use PD-based PR/DR swap
+ */
+ if (*val == DUAL_ROLE_PROP_MODE_UFP)
+ pd->forced_pr = POWER_SUPPLY_TYPEC_PR_SINK;
+ else if (*val == DUAL_ROLE_PROP_MODE_DFP)
+ pd->forced_pr = POWER_SUPPLY_TYPEC_PR_SOURCE;
+
+ /* new mode will be applied in disconnect handler */
+ set_power_role(pd, PR_NONE);
+
+ /* wait until it takes effect */
+ while (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
+ msleep(20);
+
+ break;
+
+ case DUAL_ROLE_PROP_DR:
+ usbpd_dbg(&pd->dev, "Setting data_role to %d\n", *val);
+
+ if (*val == DUAL_ROLE_PROP_DR_HOST) {
+ if (pd->current_dr == DR_UFP)
+ do_swap = true;
+ } else if (*val == DUAL_ROLE_PROP_DR_DEVICE) {
+ if (pd->current_dr == DR_DFP)
+ do_swap = true;
+ } else {
+ usbpd_warn(&pd->dev, "setting data_role to 'none' unsupported\n");
+ return -ENOTSUPP;
+ }
+
+ if (do_swap) {
+ if (pd->current_state != PE_SRC_READY &&
+ pd->current_state != PE_SNK_READY) {
+ usbpd_err(&pd->dev, "data_role swap not allowed: PD not in Ready state\n");
+ return -EAGAIN;
+ }
+
+ reinit_completion(&pd->swap_complete);
+ pd->send_dr_swap = true;
+ kick_sm(pd, 0);
+
+ /* wait for operation to complete */
+ if (!wait_for_completion_timeout(&pd->swap_complete,
+ msecs_to_jiffies(100))) {
+ usbpd_err(&pd->dev, "data_role swap timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((*val == DUAL_ROLE_PROP_DR_HOST &&
+ pd->current_dr != DR_DFP) ||
+ (*val == DUAL_ROLE_PROP_DR_DEVICE &&
+ pd->current_dr != DR_UFP)) {
+ usbpd_err(&pd->dev, "incorrect state (%s) after data_role swap\n",
+ pd->current_dr == DR_DFP ?
+ "dfp" : "ufp");
+ return -EPROTO;
+ }
+ }
+
+ break;
+
+ case DUAL_ROLE_PROP_PR:
+ usbpd_dbg(&pd->dev, "Setting power_role to %d\n", *val);
+
+ if (*val == DUAL_ROLE_PROP_PR_SRC) {
+ if (pd->current_pr == PR_SINK)
+ do_swap = true;
+ } else if (*val == DUAL_ROLE_PROP_PR_SNK) {
+ if (pd->current_pr == PR_SRC)
+ do_swap = true;
+ } else {
+ usbpd_warn(&pd->dev, "setting power_role to 'none' unsupported\n");
+ return -ENOTSUPP;
+ }
+
+ if (do_swap) {
+ if (pd->current_state != PE_SRC_READY &&
+ pd->current_state != PE_SNK_READY) {
+ usbpd_err(&pd->dev, "power_role swap not allowed: PD not in Ready state\n");
+ return -EAGAIN;
+ }
+
+ reinit_completion(&pd->swap_complete);
+ pd->send_pr_swap = true;
+ kick_sm(pd, 0);
+
+ /* wait for operation to complete */
+ if (!wait_for_completion_timeout(&pd->swap_complete,
+ msecs_to_jiffies(2000))) {
+ usbpd_err(&pd->dev, "power_role swap timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((*val == DUAL_ROLE_PROP_PR_SRC &&
+ pd->current_pr != PR_SRC) ||
+ (*val == DUAL_ROLE_PROP_PR_SNK &&
+ pd->current_pr != PR_SINK)) {
+ usbpd_err(&pd->dev, "incorrect state (%s) after power_role swap\n",
+ pd->current_pr == PR_SRC ?
+ "source" : "sink");
+ return -EPROTO;
+ }
+ }
+ break;
+
+ default:
+ usbpd_warn(&pd->dev, "unsupported property %d\n", prop);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int usbpd_dr_prop_writeable(struct dual_role_phy_instance *dual_role,
+ enum dual_role_property prop)
+{
+ switch (prop) {
+ case DUAL_ROLE_PROP_MODE:
+ case DUAL_ROLE_PROP_DR:
+ case DUAL_ROLE_PROP_PR:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int usbpd_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usbpd *pd = dev_get_drvdata(dev);
@@ -2698,6 +3012,30 @@ struct usbpd *usbpd_create(struct device *parent)
pd->vconn_is_external = device_property_present(parent,
"qcom,vconn-uses-external-source");
+ /*
+ * Register the Android dual-role class (/sys/class/dual_role_usb/).
+ * The first instance should be named "otg_default" as that's what
+ * Android expects.
+ * Note this is different than the /sys/class/usbpd/ created above.
+ */
+ pd->dr_desc.name = (num_pd_instances == 1) ?
+ "otg_default" : dev_name(&pd->dev);
+ pd->dr_desc.supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP;
+ pd->dr_desc.properties = usbpd_dr_properties;
+ pd->dr_desc.num_properties = ARRAY_SIZE(usbpd_dr_properties);
+ pd->dr_desc.get_property = usbpd_dr_get_property;
+ pd->dr_desc.set_property = usbpd_dr_set_property;
+ pd->dr_desc.property_is_writeable = usbpd_dr_prop_writeable;
+
+ pd->dual_role = devm_dual_role_instance_register(&pd->dev,
+ &pd->dr_desc);
+ if (IS_ERR(pd->dual_role)) {
+ usbpd_err(&pd->dev, "could not register dual_role instance\n");
+ goto unreg_psy;
+ } else {
+ pd->dual_role->drv_data = pd;
+ }
+
pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE;
list_add_tail(&pd->instance, &_usbpd);
@@ -2705,6 +3043,7 @@ struct usbpd *usbpd_create(struct device *parent)
spin_lock_init(&pd->rx_lock);
INIT_LIST_HEAD(&pd->rx_q);
INIT_LIST_HEAD(&pd->svid_handlers);
+ init_completion(&pd->swap_complete);
/* force read initial power_supply values */
psy_changed(&pd->psy_nb, PSY_EVENT_PROP_CHANGED, pd->usb_psy);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index b90ac82049c6..0a316fa19909 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -134,6 +134,7 @@ struct hdmi_edid_ctrl {
u8 it_scan_info;
u8 ce_scan_info;
u8 cea_blks;
+ /* DC: MSB -> LSB: Y420_48|Y420_36|Y420_30|RGB48|RGB36|RGB30|Y444 */
u8 deep_color;
u16 physical_address;
u32 video_resolution; /* selected by user */
@@ -858,6 +859,43 @@ static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
return NULL;
} /* hdmi_edid_find_block */
+static const u8 *hdmi_edid_find_hfvsdb(const u8 *in_buf)
+{
+ u8 len = 0, i = 0;
+ const u8 *vsd = NULL;
+ u32 vsd_offset = DBC_START_OFFSET;
+ u32 hf_ieee_oui = 0;
+
+ /* Find HF-VSDB with HF-OUI */
+ do {
+ vsd = hdmi_edid_find_block(in_buf, vsd_offset,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+ if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) {
+ if (i == 0)
+ pr_debug("%s: VSDB not found\n", __func__);
+ else
+ pr_debug("%s: no more VSDB found\n", __func__);
+
+ return NULL;
+ }
+
+ hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3];
+
+ if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) {
+ pr_debug("%s: found HF-VSDB\n", __func__);
+ break;
+ }
+
+ pr_debug("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui);
+
+ i++;
+ vsd_offset = vsd - in_buf + len + 1;
+ } while (1);
+
+ return vsd;
+}
+
static void hdmi_edid_set_y420_support(struct hdmi_edid_ctrl *edid_ctrl,
u32 video_format)
{
@@ -1251,62 +1289,32 @@ static void hdmi_edid_extract_speaker_allocation_data(
static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl,
const u8 *in_buf)
{
- u8 len = 0, i = 0;
const u8 *vsd = NULL;
- u32 vsd_offset = DBC_START_OFFSET;
- u32 hf_ieee_oui = 0;
if (!edid_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("%s: invalid input\n", __func__);
return;
}
- /* Find HF-VSDB with HF-OUI */
- do {
- vsd = hdmi_edid_find_block(in_buf, vsd_offset,
- VENDOR_SPECIFIC_DATA_BLOCK, &len);
-
- if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) {
- if (i == 0)
- DEV_ERR("%s: VSDB not found\n", __func__);
- else
- DEV_DBG("%s: no more VSDB found\n", __func__);
- break;
- }
-
- hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3];
-
- if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) {
- DEV_DBG("%s: found HF-VSDB\n", __func__);
- break;
- }
-
- DEV_DBG("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui);
-
- i++;
- vsd_offset = vsd - in_buf + len + 1;
- } while (1);
-
- if (!vsd) {
- DEV_DBG("%s: HF-VSDB not found\n", __func__);
- return;
+ vsd = hdmi_edid_find_hfvsdb(in_buf);
+
+ if (vsd) {
+ /* Max pixel clock is in multiples of 5Mhz. */
+ edid_ctrl->sink_caps.max_pclk_in_hz =
+ vsd[5]*5000000;
+ edid_ctrl->sink_caps.scdc_present =
+ (vsd[6] & 0x80) ? true : false;
+ edid_ctrl->sink_caps.scramble_support =
+ (vsd[6] & 0x08) ? true : false;
+ edid_ctrl->sink_caps.read_req_support =
+ (vsd[6] & 0x40) ? true : false;
+ edid_ctrl->sink_caps.osd_disparity =
+ (vsd[6] & 0x01) ? true : false;
+ edid_ctrl->sink_caps.dual_view_support =
+ (vsd[6] & 0x02) ? true : false;
+ edid_ctrl->sink_caps.ind_view_support =
+ (vsd[6] & 0x04) ? true : false;
}
-
- /* Max pixel clock is in multiples of 5Mhz. */
- edid_ctrl->sink_caps.max_pclk_in_hz =
- vsd[5]*5000000;
- edid_ctrl->sink_caps.scdc_present =
- (vsd[6] & 0x80) ? true : false;
- edid_ctrl->sink_caps.scramble_support =
- (vsd[6] & 0x08) ? true : false;
- edid_ctrl->sink_caps.read_req_support =
- (vsd[6] & 0x40) ? true : false;
- edid_ctrl->sink_caps.osd_disparity =
- (vsd[6] & 0x01) ? true : false;
- edid_ctrl->sink_caps.dual_view_support =
- (vsd[6] & 0x02) ? true : false;
- edid_ctrl->sink_caps.ind_view_support =
- (vsd[6] & 0x04) ? true : false;
}
static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
@@ -1404,12 +1412,19 @@ static void hdmi_edid_extract_dc(struct hdmi_edid_ctrl *edid_ctrl,
edid_ctrl->deep_color = (vsd[6] >> 0x3) & 0xF;
- DEV_DBG("%s: deep color: Y444|RGB30|RGB36|RGB48: (%d|%d|%d|%d)\n",
- __func__,
+ vsd = hdmi_edid_find_hfvsdb(in_buf);
+
+ if (vsd)
+ edid_ctrl->deep_color |= (vsd[7] & 0x07) << 4;
+
+ pr_debug("deep color: Y444|RGB30|RGB36|RGB48|Y420_30|Y420_36|Y420_48: (%d|%d|%d|%d|%d|%d|%d)\n",
(int) (edid_ctrl->deep_color & BIT(0)) >> 0,
(int) (edid_ctrl->deep_color & BIT(1)) >> 1,
(int) (edid_ctrl->deep_color & BIT(2)) >> 2,
- (int) (edid_ctrl->deep_color & BIT(3)) >> 3);
+ (int) (edid_ctrl->deep_color & BIT(3)) >> 3,
+ (int) (edid_ctrl->deep_color & BIT(4)) >> 4,
+ (int) (edid_ctrl->deep_color & BIT(5)) >> 5,
+ (int) (edid_ctrl->deep_color & BIT(6)) >> 6);
}
static u32 hdmi_edid_check_header(const u8 *edid_buf)
@@ -2398,8 +2413,8 @@ u32 hdmi_edid_get_sink_mode(void *input)
*
* This API returns deep color for different formats supported by sink.
* Deep color support for Y444 (BIT(0)), RGB30 (BIT(1)), RGB36 (BIT(2),
- * RGB 48 (BIT(3)) is provided in a 8 bit integer. The MSB 8 bits are
- * not used.
+ * RGB 48 (BIT(3)), Y420_30 (BIT(4)), Y420_36 (BIT(5)), Y420_48 (BIT(6))
+ * is provided in a 8 bit integer. The MSB 8 bits are not used.
*
* Return: deep color data.
*/
@@ -2416,6 +2431,25 @@ u8 hdmi_edid_get_deep_color(void *input)
}
/**
+ * hdmi_edid_get_max_pclk() - get max pclk supported. Sink side's limitation
+ * should be concerned as well.
+ * @input: edid parser data
+ *
+ * Return: max pclk rate
+ */
+u32 hdmi_edid_get_max_pclk(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return 0;
+ }
+
+ return edid_ctrl->init_data.max_pclk_khz;
+}
+
+/**
* hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink
* @input: edid parser data
*
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index ce6cecbb2e03..43e1adb1f139 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -60,6 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
bool hdmi_edid_is_s3d_mode_supported(void *input,
u32 video_mode, u32 s3d_mode);
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
+u32 hdmi_edid_get_max_pclk(void *edid_ctrl);
void hdmi_edid_get_hdr_data(void *edid_ctrl,
struct hdmi_edid_hdr_data **hdr_data);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
index 522debfba8ce..a8a56e3a8745 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
@@ -602,14 +602,51 @@ end:
return rc;
}
+static int hdmi_panel_setup_dc(struct hdmi_panel *panel)
+{
+ u32 hdmi_ctrl_reg;
+ u32 vbi_pkt_reg;
+ int rc = 0;
+
+ pr_debug("Deep Color: %s\n", panel->data->dc_enable ? "ON" : "OFF");
+
+ /* enable deep color if supported */
+ if (panel->data->dc_enable) {
+ hdmi_ctrl_reg = DSS_REG_R(panel->io, HDMI_CTRL);
+
+ /* GC CD override */
+ hdmi_ctrl_reg |= BIT(27);
+
+ /* enable deep color for RGB888 30 bits */
+ hdmi_ctrl_reg |= BIT(24);
+ DSS_REG_W(panel->io, HDMI_CTRL, hdmi_ctrl_reg);
+
+ /* Enable GC_CONT and GC_SEND in General Control Packet
+ * (GCP) register so that deep color data is
+ * transmitted to the sink on every frame, allowing
+ * the sink to decode the data correctly.
+ *
+ * GC_CONT: 0x1 - Send GCP on every frame
+ * GC_SEND: 0x1 - Enable GCP Transmission
+ */
+ vbi_pkt_reg = DSS_REG_R(panel->io, HDMI_VBI_PKT_CTRL);
+ vbi_pkt_reg |= BIT(5) | BIT(4);
+ DSS_REG_W(panel->io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg);
+ }
+
+ return rc;
+}
+
static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel)
{
int rc = 0;
int timeout_hsync;
u32 reg_val = 0;
u32 tmds_clock_ratio = 0;
+ u32 tmds_clock = 0;
bool scrambler_on = false;
struct msm_hdmi_mode_timing_info *timing = NULL;
+ struct mdss_panel_info *pinfo = NULL;
if (!panel) {
pr_err("invalid input\n");
@@ -622,13 +659,22 @@ static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel)
return -EINVAL;
}
+ pinfo = panel->data->pinfo;
+ if (!pinfo) {
+ pr_err("invalid panel data\n");
+ return -EINVAL;
+ }
+
/* Scrambling is supported from HDMI TX 4.0 */
if (panel->version < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) {
pr_debug("scrambling not supported by tx\n");
return 0;
}
- if (timing->pixel_freq > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
+ tmds_clock = hdmi_tx_setup_tmds_clk_rate(timing->pixel_freq,
+ pinfo->out_format, panel->data->dc_enable);
+
+ if (tmds_clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
scrambler_on = true;
tmds_clock_ratio = 1;
} else {
@@ -798,6 +844,12 @@ static int hdmi_panel_power_on(void *input)
pr_err("scrambler setup failed. rc=%d\n", rc);
goto err;
}
+
+ rc = hdmi_panel_setup_dc(panel);
+ if (rc) {
+ pr_err("Deep Color setup failed. rc=%d\n", rc);
+ goto err;
+ }
end:
panel->on = true;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
index 6fa9af13d46e..cb40f0cad55e 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
@@ -28,6 +28,7 @@
* @infoframe: set to true if infoframes should be sent to sink
* @is_it_content: set to true if content is IT
* @scrambler: set to true if scrambler needs to be enabled
+ * @dc_enable: set to true if deep color is enabled
*/
struct hdmi_panel_data {
struct mdss_panel_info *pinfo;
@@ -39,6 +40,7 @@ struct hdmi_panel_data {
bool infoframe;
bool is_it_content;
bool scrambler;
+ bool dc_enable;
};
/**
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index d01d163af5fa..ff44d0ae4ac5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -35,6 +35,7 @@
#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_hdmi_mhl.h"
+#include "mdss_hdmi_util.h"
#define DRV_NAME "hdmi-tx"
#define COMPATIBLE_NAME "qcom,hdmi-tx"
@@ -58,13 +59,6 @@
#define AUDIO_POLL_SLEEP_US (5 * 1000)
#define AUDIO_POLL_TIMEOUT_US (AUDIO_POLL_SLEEP_US * 1000)
-#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2
-#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
-#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
-
-#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000
-#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200
-
/* Maximum pixel clock rates for hdmi tx */
#define HDMI_DEFAULT_MAX_PCLK_RATE 148500
#define HDMI_TX_3_MAX_PCLK_RATE 297000
@@ -111,7 +105,6 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data);
static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
enum hdmi_tx_power_module_type module, int enable);
-static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl);
static void hdmi_tx_fps_work(struct work_struct *work);
static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl,
enum hdmi_tx_power_module_type module, bool active);
@@ -318,11 +311,29 @@ static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl)
return hdr_data->metadata_type_one;
}
+static inline bool hdmix_tx_sink_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+
+ if (hdmi_ctrl->panel_data.panel_info.out_format == MDP_Y_CBCR_H2V2)
+ return (hdmi_edid_get_deep_color(edid_fd) & BIT(4));
+ else
+ return (hdmi_edid_get_deep_color(edid_fd) & BIT(1));
+}
+
static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support &&
- (hdmi_edid_get_deep_color(
- hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)) & BIT(1));
+ /* actual pixel clock if deep color is enabled */
+ void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+ u32 tmds_clk_with_dc = hdmi_tx_setup_tmds_clk_rate(
+ hdmi_ctrl->timing.pixel_freq,
+ hdmi_ctrl->panel.pinfo->out_format,
+ true);
+
+ return hdmi_ctrl->dc_feature_on &&
+ hdmi_ctrl->dc_support &&
+ hdmix_tx_sink_dc_support(hdmi_ctrl) &&
+ (tmds_clk_with_dc <= hdmi_edid_get_max_pclk(edid_fd));
}
static const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
@@ -349,7 +360,10 @@ static const char *hdmi_tx_io_name(u32 type)
static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
{
if (hdmi_ctrl && hdmi_ctrl->audio_ops.on) {
- u32 pclk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl);
+ u32 pclk = hdmi_tx_setup_tmds_clk_rate(
+ hdmi_ctrl->timing.pixel_freq,
+ hdmi_ctrl->panel.pinfo->out_format,
+ hdmi_ctrl->panel.dc_enable);
hdmi_ctrl->audio_ops.on(hdmi_ctrl->audio_data,
pclk, &hdmi_ctrl->audio_params);
@@ -2345,7 +2359,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
struct dss_io_data *io = NULL;
/* Defaults: Disable block, HDMI mode */
u32 hdmi_ctrl_reg = BIT(1);
- u32 vbi_pkt_reg;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2383,27 +2396,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
* longer be used
*/
hdmi_ctrl_reg |= BIT(31);
-
- /* enable deep color if supported */
- if (hdmi_tx_dc_support(hdmi_ctrl)) {
- /* GC CD override */
- hdmi_ctrl_reg |= BIT(27);
-
- /* enable deep color for RGB888 30 bits */
- hdmi_ctrl_reg |= BIT(24);
-
- /* Enable GC_CONT and GC_SEND in General Control Packet
- * (GCP) register so that deep color data is
- * transmitted to the sink on every frame, allowing
- * the sink to decode the data correctly.
- *
- * GC_CONT: 0x1 - Send GCP on every frame
- * GC_SEND: 0x1 - Enable GCP Transmission
- */
- vbi_pkt_reg = DSS_REG_R(io, HDMI_VBI_PKT_CTRL);
- vbi_pkt_reg |= BIT(5) | BIT(4);
- DSS_REG_W(io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg);
- }
}
DSS_REG_W(io, HDMI_CTRL, hdmi_ctrl_reg);
@@ -2973,44 +2965,6 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote)
return hpd;
}
-static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl)
-{
- u32 rate = 0;
- struct msm_hdmi_mode_timing_info *timing = NULL;
- u32 rate_ratio;
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: Bad input parameters\n", __func__);
- goto end;
- }
-
- timing = &hdmi_ctrl->timing;
- if (!timing) {
- DEV_ERR("%s: Invalid timing info\n", __func__);
- goto end;
- }
-
- switch (hdmi_ctrl->panel_data.panel_info.out_format) {
- case MDP_Y_CBCR_H2V2:
- rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO;
- break;
- case MDP_Y_CBCR_H2V1:
- rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO;
- break;
- default:
- rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO;
- break;
- }
-
- rate = timing->pixel_freq / rate_ratio;
-
- if (hdmi_tx_dc_support(hdmi_ctrl))
- rate += rate >> 2;
-
-end:
- return rate;
-}
-
static inline bool hdmi_tx_hw_is_cable_connected(struct hdmi_tx_ctrl *hdmi_ctrl)
{
return DSS_REG_R(&hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO],
@@ -3117,7 +3071,7 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
void *edata = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
- hdmi_panel_get_vic(&panel_data->panel_info,
+ hdmi_ctrl->vic = hdmi_panel_get_vic(&panel_data->panel_info,
&hdmi_ctrl->ds_data);
if (hdmi_ctrl->vic <= 0) {
@@ -3144,16 +3098,14 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->vic);
hdmi_ctrl->panel.scrambler = hdmi_edid_get_sink_scrambler_support(
edata);
+ hdmi_ctrl->panel.dc_enable = hdmi_tx_dc_support(hdmi_ctrl);
if (hdmi_ctrl->panel_ops.on)
hdmi_ctrl->panel_ops.on(pdata);
- pixel_clk = hdmi_ctrl->timing.pixel_freq * 1000;
-
- if (panel_data->panel_info.out_format == MDP_Y_CBCR_H2V2)
- pixel_clk >>= 1;
- else if (hdmi_tx_dc_support(hdmi_ctrl))
- pixel_clk += pixel_clk >> 2;
+ pixel_clk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl->timing.pixel_freq,
+ hdmi_ctrl->panel.pinfo->out_format,
+ hdmi_ctrl->panel.dc_enable) * 1000;
DEV_DBG("%s: setting pixel clk %d\n", __func__, pixel_clk);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index c9fc8ba8bfdb..89890bcf68df 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/msm_mdp.h>
#include "mdss_hdmi_util.h"
#define RESOLUTION_NAME_STR_LEN 30
@@ -26,6 +27,10 @@
#define HDMI_SCDC_UNKNOWN_REGISTER "Unknown register"
+#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2
+#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
+#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
+
static char res_buf[RESOLUTION_NAME_STR_LEN];
enum trigger_mode {
@@ -738,6 +743,30 @@ ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size)
return len;
} /* hdmi_get_video_3d_fmt_2string */
+int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable)
+{
+ u32 rate_ratio;
+
+ switch (out_format) {
+ case MDP_Y_CBCR_H2V2:
+ rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO;
+ break;
+ case MDP_Y_CBCR_H2V1:
+ rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO;
+ break;
+ default:
+ rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO;
+ break;
+ }
+
+ pixel_freq /= rate_ratio;
+
+ if (dc_enable)
+ pixel_freq += pixel_freq >> 2;
+
+ return pixel_freq;
+}
+
static void hdmi_ddc_trigger(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
enum trigger_mode mode, bool seg)
{
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h
index 8a7e4d1ebafc..4fd659616bcc 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h
@@ -16,6 +16,7 @@
#include "video/msm_hdmi_modes.h"
#include "mdss_panel.h"
+#include "mdss_hdmi_panel.h"
/* HDMI_TX Registers */
#define HDMI_CTRL (0x00000000)
@@ -495,6 +496,7 @@ bool hdmi_is_valid_resv_timing(int mode);
void hdmi_reset_resv_timing_info(void);
int hdmi_panel_get_vic(struct mdss_panel_info *pinfo,
struct hdmi_util_ds_data *ds_data);
+int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable);
/* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 298b8743f0a6..6ba5828479f5 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1453,6 +1453,21 @@ static void mdss_mdp_overlay_update_pm(struct mdss_overlay_private *mdp5_data)
activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time);
}
+static void __unstage_pipe_and_clean_buf(struct msm_fb_data_type *mfd,
+ struct mdss_mdp_pipe *pipe, struct mdss_mdp_data *buf)
+{
+
+ pr_debug("unstaging pipe:%d rect:%d buf:%d\n",
+ pipe->num, pipe->multirect.num, !buf);
+ MDSS_XLOG(pipe->num, pipe->multirect.num, !buf);
+ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left);
+ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
+ pipe->dirty = true;
+
+ if (buf)
+ __pipe_buf_mark_cleanup(mfd, buf);
+}
+
static int __overlay_queue_pipes(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -1573,14 +1588,36 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd)
ret = mdss_mdp_pipe_queue_data(pipe, buf);
if (IS_ERR_VALUE(ret)) {
- pr_warn("Unable to queue data for pnum=%d\n",
- pipe->num);
- mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left);
- mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
- pipe->dirty = true;
+ pr_warn("Unable to queue data for pnum=%d rect=%d\n",
+ pipe->num, pipe->multirect.num);
+
+ /*
+ * If we fail for a multi-rect pipe, unstage both rects
+ * so we don't leave the pipe configured in multi-rect
+ * mode with only one rectangle staged.
+ */
+ if (pipe->multirect.mode !=
+ MDSS_MDP_PIPE_MULTIRECT_NONE) {
+ struct mdss_mdp_pipe *next_pipe =
+ (struct mdss_mdp_pipe *)
+ pipe->multirect.next;
+
+ if (next_pipe) {
+ struct mdss_mdp_data *next_buf =
+ list_first_entry_or_null(
+ &next_pipe->buf_queue,
+ struct mdss_mdp_data,
+ pipe_list);
+
+ __unstage_pipe_and_clean_buf(mfd,
+ next_pipe, next_buf);
+ } else {
+ pr_warn("cannot find rect pnum=%d\n",
+ pipe->num);
+ }
+ }
- if (buf)
- __pipe_buf_mark_cleanup(mfd, buf);
+ __unstage_pipe_and_clean_buf(mfd, pipe, buf);
}
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index bcf5309993b9..d7678e4d2ae5 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -2702,8 +2702,8 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
if (ret) {
pr_err("pipe pp setup error for pnum=%d\n", pipe->num);
- MDSS_XLOG(pipe->num, pipe->mixer_left->num,
- pipe->play_cnt, 0xbad);
+ MDSS_XLOG(pipe->num, pipe->multirect.num,
+ pipe->mixer_left->num, pipe->play_cnt, 0xbad);
goto done;
}
@@ -2714,13 +2714,14 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
pipe->params_changed = 0;
mdss_mdp_pipe_solidfill_setup(pipe);
- MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt,
- 0x111);
+ MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num,
+ pipe->play_cnt, 0x111);
goto update_nobuf;
}
- MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt, 0x222);
+ MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num,
+ pipe->play_cnt, 0x222);
if (params_changed) {
pipe->params_changed = 0;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index b6c00ce0e29e..d5c6f5b38617 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -171,15 +171,15 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
seq_printf(m,
"State:\t%s\n"
"Tgid:\t%d\n"
- "Ngid:\t%d\n"
"Pid:\t%d\n"
"PPid:\t%d\n"
"TracerPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n"
+ "Ngid:\t%d\n"
"FDSize:\t%d\nGroups:\t",
get_task_state(p),
- tgid, ngid, pid_nr_ns(pid, ns), ppid, tpid,
+ tgid, pid_nr_ns(pid, ns), ppid, tpid,
from_kuid_munged(user_ns, cred->uid),
from_kuid_munged(user_ns, cred->euid),
from_kuid_munged(user_ns, cred->suid),
@@ -188,7 +188,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
from_kgid_munged(user_ns, cred->egid),
from_kgid_munged(user_ns, cred->sgid),
from_kgid_munged(user_ns, cred->fsgid),
- max_fds);
+ ngid, max_fds);
group_info = cred->group_info;
for (g = 0; g < group_info->ngroups; g++)
diff --git a/include/dt-bindings/clock/audio-ext-clk.h b/include/dt-bindings/clock/audio-ext-clk.h
index 6e4932342751..c9a8286d7c7f 100644
--- a/include/dt-bindings/clock/audio-ext-clk.h
+++ b/include/dt-bindings/clock/audio-ext-clk.h
@@ -14,9 +14,19 @@
#define __AUDIO_EXT_CLK_H
/* Audio External Clocks */
+#ifdef CONFIG_COMMON_CLK_QCOM
+#define AUDIO_PMI_CLK 0
+#define AUDIO_PMIC_LNBB_CLK 1
+#define AUDIO_AP_CLK 2
+#define AUDIO_AP_CLK2 3
+#define AUDIO_LPASS_MCLK 4
+#define AUDIO_LPASS_MCLK2 5
+#else
#define clk_audio_ap_clk 0x9b5727cb
#define clk_audio_pmi_clk 0xcbfe416d
#define clk_audio_ap_clk2 0x454d1e91
#define clk_audio_lpass_mclk 0xf0f2a284
#define clk_audio_pmi_lnbb_clk 0x57312343
#endif
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h
index ffb80a128dd6..7a6ec2bf2418 100644
--- a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h
+++ b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h
@@ -159,46 +159,47 @@
#define MMSS_MDSS_AXI_CLK 142
#define MMSS_MDSS_BYTE0_CLK 143
#define MMSS_MDSS_BYTE0_INTF_CLK 144
-#define MMSS_MDSS_BYTE1_CLK 145
-#define MMSS_MDSS_BYTE1_INTF_CLK 146
-#define MMSS_MDSS_DP_AUX_CLK 147
-#define MMSS_MDSS_DP_CRYPTO_CLK 148
-#define MMSS_MDSS_DP_GTC_CLK 149
-#define MMSS_MDSS_DP_LINK_CLK 150
-#define MMSS_MDSS_DP_LINK_INTF_CLK 151
-#define MMSS_MDSS_DP_PIXEL_CLK 152
-#define MMSS_MDSS_ESC0_CLK 153
-#define MMSS_MDSS_ESC1_CLK 154
-#define MMSS_MDSS_HDMI_DP_AHB_CLK 155
-#define MMSS_MDSS_MDP_CLK 156
-#define MMSS_MDSS_PCLK0_CLK 157
-#define MMSS_MDSS_PCLK1_CLK 158
-#define MMSS_MDSS_ROT_CLK 159
-#define MMSS_MDSS_VSYNC_CLK 160
-#define MMSS_MISC_AHB_CLK 161
-#define MMSS_MISC_CXO_CLK 162
-#define MMSS_MNOC_AHB_CLK 163
-#define MMSS_SNOC_DVM_AXI_CLK 164
-#define MMSS_THROTTLE_CAMSS_AHB_CLK 165
-#define MMSS_THROTTLE_CAMSS_AXI_CLK 166
-#define MMSS_THROTTLE_CAMSS_CXO_CLK 167
-#define MMSS_THROTTLE_MDSS_AHB_CLK 168
-#define MMSS_THROTTLE_MDSS_AXI_CLK 169
-#define MMSS_THROTTLE_MDSS_CXO_CLK 170
-#define MMSS_THROTTLE_VIDEO_AHB_CLK 171
-#define MMSS_THROTTLE_VIDEO_AXI_CLK 172
-#define MMSS_THROTTLE_VIDEO_CXO_CLK 173
-#define MMSS_VIDEO_AHB_CLK 174
-#define MMSS_VIDEO_AXI_CLK 175
-#define MMSS_VIDEO_CORE_CLK 176
-#define MMSS_VIDEO_SUBCORE0_CLK 177
-#define PCLK0_CLK_SRC 178
-#define PCLK1_CLK_SRC 179
-#define ROT_CLK_SRC 180
-#define VFE0_CLK_SRC 181
-#define VFE1_CLK_SRC 182
-#define VIDEO_CORE_CLK_SRC 183
-#define VSYNC_CLK_SRC 184
+#define MMSS_MDSS_BYTE0_INTF_DIV_CLK 145
+#define MMSS_MDSS_BYTE1_CLK 146
+#define MMSS_MDSS_BYTE1_INTF_CLK 147
+#define MMSS_MDSS_DP_AUX_CLK 148
+#define MMSS_MDSS_DP_CRYPTO_CLK 149
+#define MMSS_MDSS_DP_GTC_CLK 150
+#define MMSS_MDSS_DP_LINK_CLK 151
+#define MMSS_MDSS_DP_LINK_INTF_CLK 152
+#define MMSS_MDSS_DP_PIXEL_CLK 153
+#define MMSS_MDSS_ESC0_CLK 154
+#define MMSS_MDSS_ESC1_CLK 155
+#define MMSS_MDSS_HDMI_DP_AHB_CLK 156
+#define MMSS_MDSS_MDP_CLK 157
+#define MMSS_MDSS_PCLK0_CLK 158
+#define MMSS_MDSS_PCLK1_CLK 159
+#define MMSS_MDSS_ROT_CLK 160
+#define MMSS_MDSS_VSYNC_CLK 161
+#define MMSS_MISC_AHB_CLK 162
+#define MMSS_MISC_CXO_CLK 163
+#define MMSS_MNOC_AHB_CLK 164
+#define MMSS_SNOC_DVM_AXI_CLK 165
+#define MMSS_THROTTLE_CAMSS_AHB_CLK 166
+#define MMSS_THROTTLE_CAMSS_AXI_CLK 167
+#define MMSS_THROTTLE_CAMSS_CXO_CLK 168
+#define MMSS_THROTTLE_MDSS_AHB_CLK 169
+#define MMSS_THROTTLE_MDSS_AXI_CLK 170
+#define MMSS_THROTTLE_MDSS_CXO_CLK 171
+#define MMSS_THROTTLE_VIDEO_AHB_CLK 172
+#define MMSS_THROTTLE_VIDEO_AXI_CLK 173
+#define MMSS_THROTTLE_VIDEO_CXO_CLK 174
+#define MMSS_VIDEO_AHB_CLK 175
+#define MMSS_VIDEO_AXI_CLK 176
+#define MMSS_VIDEO_CORE_CLK 177
+#define MMSS_VIDEO_SUBCORE0_CLK 178
+#define PCLK0_CLK_SRC 179
+#define PCLK1_CLK_SRC 180
+#define ROT_CLK_SRC 181
+#define VFE0_CLK_SRC 182
+#define VFE1_CLK_SRC 183
+#define VIDEO_CORE_CLK_SRC 184
+#define VSYNC_CLK_SRC 185
#define BIMC_SMMU_GDSC 0
#define CAMSS_CPP_GDSC 1
@@ -209,5 +210,6 @@
#define VIDEO_SUBCORE0_GDSC 6
#define VIDEO_TOP_GDSC 7
+#define CAMSS_MICRO_BCR 0
#endif
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b89c9c2f7f6e..cc1e8d6b3454 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -796,19 +796,15 @@ struct cfg80211_csa_settings {
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
- * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
- * the GCD of a single value is considered the value itself, so for
- * a single interface this should be set to that interface's beacon
- * interval
- * @beacon_int_different: a flag indicating whether or not all beacon
- * intervals (of beaconing interfaces) are different or not.
+ * @new_beacon_int: set this to the beacon interval of a new interface
+ * that's not operating yet, if such is to be checked as part of
+ * the verification
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
- u32 beacon_int_gcd;
- bool beacon_int_different;
+ u32 new_beacon_int;
};
/**
@@ -3219,6 +3215,9 @@ struct wiphy_iftype_ext_capab {
* @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden.
* If null, then none can be over-ridden.
*
+ * @wdev_list: the list of associated (virtual) interfaces; this list must
+ * not be modified by the driver, but can be read with RTNL/RCU protection.
+ *
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
* supports for ACL.
*
@@ -3363,6 +3362,8 @@ struct wiphy {
const struct ieee80211_ht_cap *ht_capa_mod_mask;
const struct ieee80211_vht_cap *vht_capa_mod_mask;
+ struct list_head wdev_list;
+
/* the network namespace this phy lives in currently */
possible_net_t _net;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 213601d620e0..52402ab90c57 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1528,6 +1528,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli
{
if (sk->sk_send_head == skb_unlinked)
sk->sk_send_head = NULL;
+ if (tcp_sk(sk)->highest_sack == skb_unlinked)
+ tcp_sk(sk)->highest_sack = NULL;
}
static inline void tcp_init_send_head(struct sock *sk)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b86cc04959de..48f45987dc6c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -73,6 +73,7 @@
#include <linux/compat.h>
#include <linux/ctype.h>
#include <linux/string.h>
+#include <linux/uaccess.h>
#include <uapi/linux/limits.h>
#include "audit.h"
@@ -82,7 +83,8 @@
#define AUDITSC_SUCCESS 1
#define AUDITSC_FAILURE 2
-/* no execve audit message should be longer than this (userspace limits) */
+/* no execve audit message should be longer than this (userspace limits),
+ * see the note near the top of audit_log_execve_info() about this value */
#define MAX_EXECVE_AUDIT_LEN 7500
/* max length to print of cmdline/proctitle value during audit */
@@ -988,184 +990,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
return rc;
}
-/*
- * to_send and len_sent accounting are very loose estimates. We aren't
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundary)
- *
- * why snprintf? an int is up to 12 digits long. if we just assumed when
- * logging that a[%d]= was going to be 16 characters long we would be wasting
- * space in every audit message. In one 7500 byte message we can log up to
- * about 1000 min size arguments. That comes down to about 50% waste of space
- * if we didn't do the snprintf to find out how long arg_num_len was.
- */
-static int audit_log_single_execve_arg(struct audit_context *context,
- struct audit_buffer **ab,
- int arg_num,
- size_t *len_sent,
- const char __user *p,
- char *buf)
+static void audit_log_execve_info(struct audit_context *context,
+ struct audit_buffer **ab)
{
- char arg_num_len_buf[12];
- const char __user *tmp_p = p;
- /* how many digits are in arg_num? 5 is the length of ' a=""' */
- size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
- size_t len, len_left, to_send;
- size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
- unsigned int i, has_cntl = 0, too_long = 0;
- int ret;
-
- /* strnlen_user includes the null we don't want to send */
- len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
-
- /*
- * We just created this mm, if we can't find the strings
- * we just copied into it something is _very_ wrong. Similar
- * for strings that are too long, we should not have created
- * any.
- */
- if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
- send_sig(SIGKILL, current, 0);
- return -1;
+ long len_max;
+ long len_rem;
+ long len_full;
+ long len_buf;
+ long len_abuf;
+ long len_tmp;
+ bool require_data;
+ bool encode;
+ unsigned int iter;
+ unsigned int arg;
+ char *buf_head;
+ char *buf;
+ const char __user *p = (const char __user *)current->mm->arg_start;
+
+ /* NOTE: this buffer needs to be large enough to hold all the non-arg
+ * data we put in the audit record for this argument (see the
+ * code below) ... at this point in time 96 is plenty */
+ char abuf[96];
+
+ /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
+ * current value of 7500 is not as important as the fact that it
+ * is less than 8k, a setting of 7500 gives us plenty of wiggle
+ * room if we go over a little bit in the logging below */
+ WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
+ len_max = MAX_EXECVE_AUDIT_LEN;
+
+ /* scratch buffer to hold the userspace args */
+ buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+ if (!buf_head) {
+ audit_panic("out of memory for argv string");
+ return;
}
+ buf = buf_head;
- /* walk the whole argument looking for non-ascii chars */
+ audit_log_format(*ab, "argc=%d", context->execve.argc);
+
+ len_rem = len_max;
+ len_buf = 0;
+ len_full = 0;
+ require_data = true;
+ encode = false;
+ iter = 0;
+ arg = 0;
do {
- if (len_left > MAX_EXECVE_AUDIT_LEN)
- to_send = MAX_EXECVE_AUDIT_LEN;
- else
- to_send = len_left;
- ret = copy_from_user(buf, tmp_p, to_send);
- /*
- * There is no reason for this copy to be short. We just
- * copied them here, and the mm hasn't been exposed to user-
- * space yet.
- */
- if (ret) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
- }
- buf[to_send] = '\0';
- has_cntl = audit_string_contains_control(buf, to_send);
- if (has_cntl) {
- /*
- * hex messages get logged as 2 bytes, so we can only
- * send half as much in each message
- */
- max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
- break;
- }
- len_left -= to_send;
- tmp_p += to_send;
- } while (len_left > 0);
-
- len_left = len;
-
- if (len > max_execve_audit_len)
- too_long = 1;
-
- /* rewalk the argument actually logging the message */
- for (i = 0; len_left > 0; i++) {
- int room_left;
-
- if (len_left > max_execve_audit_len)
- to_send = max_execve_audit_len;
- else
- to_send = len_left;
-
- /* do we have space left to send this argument in this ab? */
- room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
- if (has_cntl)
- room_left -= (to_send * 2);
- else
- room_left -= to_send;
- if (room_left < 0) {
- *len_sent = 0;
- audit_log_end(*ab);
- *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
- if (!*ab)
- return 0;
- }
+ /* NOTE: we don't ever want to trust this value for anything
+ * serious, but the audit record format insists we
+ * provide an argument length for really long arguments,
+ * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
+ * to use strncpy_from_user() to obtain this value for
+ * recording in the log, although we don't use it
+ * anywhere here to avoid a double-fetch problem */
+ if (len_full == 0)
+ len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+
+ /* read more data from userspace */
+ if (require_data) {
+ /* can we make more room in the buffer? */
+ if (buf != buf_head) {
+ memmove(buf_head, buf, len_buf);
+ buf = buf_head;
+ }
+
+ /* fetch as much as we can of the argument */
+ len_tmp = strncpy_from_user(&buf_head[len_buf], p,
+ len_max - len_buf);
+ if (len_tmp == -EFAULT) {
+ /* unable to copy from userspace */
+ send_sig(SIGKILL, current, 0);
+ goto out;
+ } else if (len_tmp == (len_max - len_buf)) {
+ /* buffer is not large enough */
+ require_data = true;
+ /* NOTE: if we are going to span multiple
+ * buffers force the encoding so we stand
+ * a chance at a sane len_full value and
+ * consistent record encoding */
+ encode = true;
+ len_full = len_full * 2;
+ p += len_tmp;
+ } else {
+ require_data = false;
+ if (!encode)
+ encode = audit_string_contains_control(
+ buf, len_tmp);
+ /* try to use a trusted value for len_full */
+ if (len_full < len_max)
+ len_full = (encode ?
+ len_tmp * 2 : len_tmp);
+ p += len_tmp + 1;
+ }
+ len_buf += len_tmp;
+ buf_head[len_buf] = '\0';
- /*
- * first record needs to say how long the original string was
- * so we can be sure nothing was lost.
- */
- if ((i == 0) && (too_long))
- audit_log_format(*ab, " a%d_len=%zu", arg_num,
- has_cntl ? 2*len : len);
-
- /*
- * normally arguments are small enough to fit and we already
- * filled buf above when we checked for control characters
- * so don't bother with another copy_from_user
- */
- if (len >= max_execve_audit_len)
- ret = copy_from_user(buf, p, to_send);
- else
- ret = 0;
- if (ret) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
+ /* length of the buffer in the audit record? */
+ len_abuf = (encode ? len_buf * 2 : len_buf + 2);
}
- buf[to_send] = '\0';
-
- /* actually log it */
- audit_log_format(*ab, " a%d", arg_num);
- if (too_long)
- audit_log_format(*ab, "[%d]", i);
- audit_log_format(*ab, "=");
- if (has_cntl)
- audit_log_n_hex(*ab, buf, to_send);
- else
- audit_log_string(*ab, buf);
-
- p += to_send;
- len_left -= to_send;
- *len_sent += arg_num_len;
- if (has_cntl)
- *len_sent += to_send * 2;
- else
- *len_sent += to_send;
- }
- /* include the null we didn't log */
- return len + 1;
-}
-static void audit_log_execve_info(struct audit_context *context,
- struct audit_buffer **ab)
-{
- int i, len;
- size_t len_sent = 0;
- const char __user *p;
- char *buf;
+ /* write as much as we can to the audit log */
+ if (len_buf > 0) {
+ /* NOTE: some magic numbers here - basically if we
+ * can't fit a reasonable amount of data into the
+ * existing audit buffer, flush it and start with
+ * a new buffer */
+ if ((sizeof(abuf) + 8) > len_rem) {
+ len_rem = len_max;
+ audit_log_end(*ab);
+ *ab = audit_log_start(context,
+ GFP_KERNEL, AUDIT_EXECVE);
+ if (!*ab)
+ goto out;
+ }
- p = (const char __user *)current->mm->arg_start;
+ /* create the non-arg portion of the arg record */
+ len_tmp = 0;
+ if (require_data || (iter > 0) ||
+ ((len_abuf + sizeof(abuf)) > len_rem)) {
+ if (iter == 0) {
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d_len=%lu",
+ arg, len_full);
+ }
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d[%d]=", arg, iter++);
+ } else
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d=", arg);
+ WARN_ON(len_tmp >= sizeof(abuf));
+ abuf[sizeof(abuf) - 1] = '\0';
+
+ /* log the arg in the audit record */
+ audit_log_format(*ab, "%s", abuf);
+ len_rem -= len_tmp;
+ len_tmp = len_buf;
+ if (encode) {
+ if (len_abuf > len_rem)
+ len_tmp = len_rem / 2; /* encoding */
+ audit_log_n_hex(*ab, buf, len_tmp);
+ len_rem -= len_tmp * 2;
+ len_abuf -= len_tmp * 2;
+ } else {
+ if (len_abuf > len_rem)
+ len_tmp = len_rem - 2; /* quotes */
+ audit_log_n_string(*ab, buf, len_tmp);
+ len_rem -= len_tmp + 2;
+ /* don't subtract the "2" because we still need
+ * to add quotes to the remaining string */
+ len_abuf -= len_tmp;
+ }
+ len_buf -= len_tmp;
+ buf += len_tmp;
+ }
- audit_log_format(*ab, "argc=%d", context->execve.argc);
+ /* ready to move to the next argument? */
+ if ((len_buf == 0) && !require_data) {
+ arg++;
+ iter = 0;
+ len_full = 0;
+ require_data = true;
+ encode = false;
+ }
+ } while (arg < context->execve.argc);
- /*
- * we need some kernel buffer to hold the userspace args. Just
- * allocate one big one rather than allocating one of the right size
- * for every single argument inside audit_log_single_execve_arg()
- * should be <8k allocation so should be pretty safe.
- */
- buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
- if (!buf) {
- audit_panic("out of memory for argv string");
- return;
- }
+ /* NOTE: the caller handles the final audit_log_end() call */
- for (i = 0; i < context->execve.argc; i++) {
- len = audit_log_single_execve_arg(context, ab, i,
- &len_sent, p, buf);
- if (len <= 0)
- break;
- p += len;
- }
- kfree(buf);
+out:
+ kfree(buf_head);
}
static void show_special(struct audit_context *context, int *call_panic)
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index ae83d9602aa0..8c9823947c7a 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6002,7 +6002,7 @@ static int cgroup_css_links_read(struct seq_file *seq, void *v)
struct task_struct *task;
int count = 0;
- seq_printf(seq, "css_set %p\n", cset);
+ seq_printf(seq, "css_set %pK\n", cset);
list_for_each_entry(task, &cset->tasks, cg_list) {
if (count++ > MAX_TASKS_SHOWN_PER_CSS)
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 77afe913d03d..9adedba78eea 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -326,10 +326,12 @@ replay:
nlh = nlmsg_hdr(skb);
err = 0;
- if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) ||
- skb->len < nlh->nlmsg_len) {
- err = -EINVAL;
- goto ack;
+ if (nlh->nlmsg_len < NLMSG_HDRLEN ||
+ skb->len < nlh->nlmsg_len ||
+ nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
+ nfnl_err_reset(&err_list);
+ status |= NFNL_BATCH_FAILURE;
+ goto done;
}
/* Only requests are handled by the kernel */
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index cf14c7e22fb3..d5ccaeaa76e0 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -749,7 +749,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
* and thus fail the GO instantiation, consider only the interfaces of
* the current registered device.
*/
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
struct ieee80211_channel *other_chan = NULL;
int r1, r2;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6d3402434a63..16043faba52c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -3,6 +3,7 @@
*
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2015 Intel Deutschland GmbH
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -157,7 +158,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
return -EOPNOTSUPP;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
@@ -171,7 +172,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
/* failed -- clean up to old netns */
net = wiphy_net(&rdev->wiphy);
- list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list,
+ list_for_each_entry_continue_reverse(wdev,
+ &rdev->wiphy.wdev_list,
list) {
if (!wdev->netdev)
continue;
@@ -230,7 +232,7 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
ASSERT_RTNL();
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->netdev) {
dev_close(wdev->netdev);
continue;
@@ -298,7 +300,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
kfree(item);
spin_unlock_irq(&rdev->destroy_list_lock);
- list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) {
+ list_for_each_entry_safe(wdev, tmp,
+ &rdev->wiphy.wdev_list, list) {
if (nlportid == wdev->owner_nlportid)
rdev_del_virtual_intf(rdev, wdev);
}
@@ -400,7 +403,7 @@ use_default_name:
dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
}
- INIT_LIST_HEAD(&rdev->wdev_list);
+ INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations);
spin_lock_init(&rdev->beacon_registrations_lock);
spin_lock_init(&rdev->bss_lock);
@@ -812,7 +815,7 @@ void wiphy_unregister(struct wiphy *wiphy)
nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
rdev->wiphy.registered = false;
- WARN_ON(!list_empty(&rdev->wdev_list));
+ WARN_ON(!list_empty(&rdev->wiphy.wdev_list));
/*
* First remove the hardware from everywhere, this makes
@@ -949,7 +952,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
spin_lock_init(&wdev->mgmt_registrations_lock);
wdev->identifier = ++rdev->wdev_id;
- list_add_rcu(&wdev->list, &rdev->wdev_list);
+ list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
rdev->devlist_generation++;
/* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index fcd59e76a8e5..a06a1056f726 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -50,8 +50,7 @@ struct cfg80211_registered_device {
/* wiphy index, internal only */
int wiphy_idx;
- /* associated wireless interfaces, protected by rtnl or RCU */
- struct list_head wdev_list;
+ /* protected by RTNL */
int devlist_generation, wdev_id;
int opencount; /* also protected by devlist_mtx */
wait_queue_head_t dev_wait;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 40299f19c09b..375d6c1732fa 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -103,7 +103,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
continue;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (have_ifidx && wdev->netdev &&
wdev->netdev->ifindex == ifidx) {
result = wdev;
@@ -149,7 +149,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
if (tmp) {
/* make sure wdev exists */
- list_for_each_entry(wdev, &tmp->wdev_list, list) {
+ list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
if (wdev->identifier != (u32)wdev_id)
continue;
found = true;
@@ -524,7 +524,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
*rdev = wiphy_to_rdev(wiphy);
*wdev = NULL;
- list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+ list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
if (tmp->identifier == cb->args[1]) {
*wdev = tmp;
break;
@@ -2504,7 +2504,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
}
if_idx = 0;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (if_idx < if_start) {
if_idx++;
continue;
@@ -2776,7 +2776,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
spin_lock_init(&wdev->mgmt_registrations_lock);
wdev->identifier = ++rdev->wdev_id;
- list_add_rcu(&wdev->list, &rdev->wdev_list);
+ list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
rdev->devlist_generation++;
break;
default:
@@ -3585,7 +3585,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev;
bool ret = false;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue;
@@ -7770,12 +7770,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.beacon_interval = 100;
- if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
ibss.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
- return -EINVAL;
- }
+
+ err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
+ ibss.beacon_interval);
+ if (err)
+ return err;
if (!rdev->ops->join_ibss)
return -EOPNOTSUPP;
@@ -9013,9 +9015,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- if (setup.beacon_interval < 10 ||
- setup.beacon_interval > 10000)
- return -EINVAL;
+
+ err = cfg80211_validate_beacon_int(rdev,
+ NL80211_IFTYPE_MESH_POINT,
+ setup.beacon_interval);
+ if (err)
+ return err;
}
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
@@ -10328,7 +10333,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
*wdev = NULL;
if (cb->args[1]) {
- list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+ list_for_each_entry(tmp, &wiphy->wdev_list, list) {
if (tmp->identifier == cb->args[1] - 1) {
*wdev = tmp;
break;
@@ -13339,7 +13344,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
sched_scan_req->owner_nlportid == notify->portid)
schedule_scan_stop = true;
- list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
if (wdev->owner_nlportid == notify->portid)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2fed05f2edf8..050d7948dd68 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1685,7 +1685,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy)
struct cfg80211_sched_scan_request *sched_scan_req;
ASSERT_RTNL();
- list_for_each_entry(wdev, &rdev->wdev_list, list)
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
if (!reg_wdev_chan_valid(wiphy, wdev)) {
dev = wdev->netdev;
switch (wdev->iftype) {
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 37d8ab3a71be..e5b962d2ffe7 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -54,7 +54,7 @@ static bool cfg80211_is_all_countryie_ignore(void)
bool is_all_countryie_ignore = true;
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev);
if (!(wdev->wiphy->regulatory_flags &
REGULATORY_COUNTRY_IE_IGNORE)) {
@@ -246,7 +246,7 @@ void cfg80211_conn_work(struct work_struct *work)
rtnl_lock();
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev)
continue;
@@ -630,7 +630,7 @@ static bool cfg80211_is_all_idle(void)
* count as new regulatory hints.
*/
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev);
if (wdev->conn || wdev->current_bss)
is_all_idle = false;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index acff02fcc281..ef394e8a42bc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -13,6 +13,7 @@
#include <net/dsfield.h>
#include <linux/if_vlan.h>
#include <linux/mpls.h>
+#include <linux/gcd.h>
#include "core.h"
#include "rdev-ops.h"
@@ -910,7 +911,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
ASSERT_RTNL();
- list_for_each_entry(wdev, &rdev->wdev_list, list)
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
cfg80211_process_wdev_events(wdev);
}
@@ -1482,47 +1483,53 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
}
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
-int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- enum nl80211_iftype iftype, u32 beacon_int)
+static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
+ u32 *beacon_int_gcd,
+ bool *beacon_int_different)
{
struct wireless_dev *wdev;
- struct iface_combination_params params = {
- .beacon_int_gcd = beacon_int, /* GCD(n) = n */
- };
- if (!beacon_int)
- return -EINVAL;
+ *beacon_int_gcd = 0;
+ *beacon_int_different = false;
- params.iftype_num[iftype] = 1;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
- params.iftype_num[wdev->iftype]++;
- }
-
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
- u32 bi_prev = wdev->beacon_interval;
-
- if (!wdev->beacon_interval)
+ if (!*beacon_int_gcd) {
+ *beacon_int_gcd = wdev->beacon_interval;
continue;
+ }
- /* slight optimisation - skip identical BIs */
- if (wdev->beacon_interval == beacon_int)
+ if (wdev->beacon_interval == *beacon_int_gcd)
continue;
- params.beacon_int_different = true;
-
- /* Get the GCD */
- while (bi_prev != 0) {
- u32 tmp_bi = bi_prev;
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
+ }
- bi_prev = params.beacon_int_gcd % bi_prev;
- params.beacon_int_gcd = tmp_bi;
- }
+ if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
+ if (*beacon_int_gcd)
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
}
+}
- return cfg80211_check_combinations(&rdev->wiphy, &params);
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+ enum nl80211_iftype iftype, u32 beacon_int)
+{
+ /*
+ * This is just a basic pre-condition check; if interface combinations
+ * are possible the driver must already be checking those with a call
+ * to cfg80211_check_combinations(), in which case we'll validate more
+ * through the cfg80211_calculate_bi_data() call and code in
+ * cfg80211_iter_combinations().
+ */
+
+ if (beacon_int < 10 || beacon_int > 10000)
+ return -EINVAL;
+
+ return 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@@ -1536,6 +1543,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
+
+ /*
+ * This is a bit strange, since the iteration used to rely only on
+ * the data given by the driver, but here it now relies on context,
+ * in form of the currently operating interfaces.
+ * This is OK for all current users, and saves us from having to
+ * push the GCD calculations into all the drivers.
+ * In the future, this should probably rely more on data that's in
+ * cfg80211 already - the only thing not would appear to be any new
+ * interfaces (while being brought up) and channel/radar data.
+ */
+ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
+ &beacon_int_gcd, &beacon_int_different);
if (params->radar_detect) {
rcu_read_lock();
@@ -1598,14 +1620,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
- if (params->beacon_int_gcd) {
+ if (beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
- params->beacon_int_gcd < c->beacon_int_min_gcd) {
- kfree(limits);
- return -EINVAL;
- }
- if (!c->beacon_int_min_gcd &&
- params->beacon_int_different)
+ beacon_int_gcd < c->beacon_int_min_gcd)
+ goto cont;
+ if (!c->beacon_int_min_gcd && beacon_int_different)
goto cont;
}
@@ -1701,7 +1720,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
break;
}
- list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev_iter, &rdev->wiphy.wdev_list, list) {
if (wdev_iter == wdev)
continue;
if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 06e00fdfe6a1..71858e268232 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -13681,6 +13681,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
snd_soc_dapm_ignore_suspend(dapm, "AIF Mix Playback");
snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX");
snd_soc_dapm_ignore_suspend(dapm, "VIfeed");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF5 CPE TX");
}
snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index aa036d352f40..9c720acf8ef8 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -2449,6 +2449,63 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.name = "VoiceMMode2",
.probe = fe_dai_probe,
},
+ {
+ .capture = {
+ .stream_name = "MultiMedia17 Capture",
+ .aif_name = "MM_UL17",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia17",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia18 Capture",
+ .aif_name = "MM_UL18",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia18",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia19 Capture",
+ .aif_name = "MM_UL19",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia19",
+ .probe = fe_dai_probe,
+ },
};
static int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index a2cd6c6f98db..90371b8e27f4 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -127,6 +127,11 @@ struct msm_compr_audio {
uint64_t bytes_received; /* from userspace */
uint64_t bytes_sent; /* to DSP */
+ uint64_t received_total; /* bytes received from DSP */
+ uint64_t bytes_copied; /* to userspace */
+ uint64_t bytes_read; /* from DSP */
+ uint32_t bytes_read_offset; /* bytes read offset*/
+
int32_t first_buffer;
int32_t last_buffer;
int32_t partial_drain_delay;
@@ -362,6 +367,49 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd)
return 0;
}
+static int msm_compr_read_buffer(struct msm_compr_audio *prtd)
+{
+ int buffer_length;
+ uint64_t bytes_available;
+ uint64_t buffer_sent;
+ struct audio_aio_read_param param;
+ int ret;
+
+ if (!atomic_read(&prtd->start)) {
+ pr_err("%s: stream is not in started state\n", __func__);
+ return -EINVAL;
+ }
+
+ buffer_length = prtd->codec_param.buffer.fragment_size;
+ bytes_available = prtd->received_total - prtd->bytes_copied;
+ buffer_sent = prtd->bytes_read - prtd->bytes_copied;
+ if (buffer_sent + buffer_length > prtd->buffer_size) {
+ pr_debug(" %s : Buffer is Full bytes_available: %llu\n",
+ __func__, bytes_available);
+ return 0;
+ }
+
+ memset(&param, 0x0, sizeof(struct audio_aio_read_param));
+ param.paddr = prtd->buffer_paddr + prtd->bytes_read_offset;
+ param.len = buffer_length;
+ param.uid = buffer_length;
+
+ pr_debug("%s: reading %d bytes from DSP byte_offset = %llu\n",
+ __func__, buffer_length, prtd->bytes_read);
+ ret = q6asm_async_read(prtd->audio_client, &param);
+ if (ret < 0) {
+ pr_err("%s: q6asm_async_read failed - %d\n",
+ __func__, ret);
+ return ret;
+ }
+ prtd->bytes_read += buffer_length;
+ prtd->bytes_read_offset += buffer_length;
+ if (prtd->bytes_read_offset >= prtd->buffer_size)
+ prtd->bytes_read_offset -= prtd->buffer_size;
+
+ return 0;
+}
+
static void compr_event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -374,6 +422,7 @@ static void compr_event_handler(uint32_t opcode,
int stream_id;
uint32_t stream_index;
unsigned long flags;
+ uint64_t read_size;
if (!prtd) {
pr_err("%s: prtd is NULL\n", __func__);
@@ -459,6 +508,32 @@ static void compr_event_handler(uint32_t opcode,
spin_unlock_irqrestore(&prtd->lock, flags);
break;
+
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ pr_debug("ASM_DATA_EVENT_READ_DONE_V2 offset %d, length %d\n",
+ prtd->byte_offset, payload[4]);
+ /* Always assume read_size is same as fragment_size */
+ read_size = prtd->codec_param.buffer.fragment_size;
+ prtd->byte_offset += read_size;
+ prtd->received_total += read_size;
+ if (prtd->byte_offset >= prtd->buffer_size)
+ prtd->byte_offset -= prtd->buffer_size;
+
+ snd_compr_fragment_elapsed(cstream);
+
+ if (!atomic_read(&prtd->start)) {
+ pr_debug("read_done received while not started, treat as xrun");
+ atomic_set(&prtd->xrun, 1);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ msm_compr_read_buffer(prtd);
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
case ASM_DATA_EVENT_RENDERED_EOS:
spin_lock_irqsave(&prtd->lock, flags);
pr_debug("%s: ASM_DATA_CMDRSP_EOS token 0x%x,stream id %d\n",
@@ -511,6 +586,14 @@ static void compr_event_handler(uint32_t opcode,
/* FIXME: A state is a better way, dealing with this*/
spin_lock_irqsave(&prtd->lock, flags);
+
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ atomic_set(&prtd->start, 1);
+ msm_compr_read_buffer(prtd);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
if (!prtd->bytes_sent) {
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < cstream->runtime->fragment_size) {
@@ -958,7 +1041,8 @@ static int msm_compr_init_pp_params(struct snd_compr_stream *cstream,
return ret;
}
-static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
+static int msm_compr_configure_dsp_for_playback
+ (struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -1096,7 +1180,103 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
return ret;
}
-static int msm_compr_open(struct snd_compr_stream *cstream)
+static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_compr_audio *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
+ uint16_t bits_per_sample;
+ uint16_t sample_word_size;
+ int dir = OUT, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
+ uint32_t stream_index;
+
+ switch (prtd->codec_param.codec.format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bits_per_sample = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bits_per_sample = 16;
+ sample_word_size = 16;
+ break;
+ }
+
+ pr_debug("%s: stream_id %d bits_per_sample %d\n",
+ __func__, ac->stream_id, bits_per_sample);
+
+ ret = q6asm_open_read_v3(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ ac->perf_mode,
+ prtd->session_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret) {
+ pr_err("%s: stream reg failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE));
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -EINVAL;
+ }
+
+ stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
+ if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) {
+ pr_err("%s: Invalid stream index:%d", __func__, stream_index);
+ return -EINVAL;
+ }
+
+ runtime->fragments = prtd->codec_param.buffer.fragments;
+ runtime->fragment_size = prtd->codec_param.buffer.fragment_size;
+ pr_debug("%s: allocate %d buffers each of size %d\n",
+ __func__, runtime->fragments,
+ runtime->fragment_size);
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
+ runtime->fragment_size,
+ runtime->fragments);
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+ return -ENOMEM;
+ }
+
+ prtd->byte_offset = 0;
+ prtd->received_total = 0;
+ prtd->app_pointer = 0;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->buffer = ac->port[dir].buf[0].data;
+ prtd->buffer_paddr = ac->port[dir].buf[0].phys;
+ prtd->buffer_size = runtime->fragments * runtime->fragment_size;
+
+
+ pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n",
+ __func__, prtd->sample_rate, prtd->num_channels,
+ bits_per_sample, sample_word_size);
+ ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client,
+ prtd->sample_rate, prtd->num_channels,
+ bits_per_sample, sample_word_size);
+
+ return ret;
+}
+
+static int msm_compr_playback_open(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -1181,15 +1361,80 @@ static int msm_compr_open(struct snd_compr_stream *cstream)
kfree(prtd);
return -ENOMEM;
}
+ pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+ prtd->audio_client->perf_mode = false;
+ prtd->session_id = prtd->audio_client->session;
+
+ return 0;
+}
+static int msm_compr_capture_open(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct msm_compr_audio *prtd;
+ struct msm_compr_pdata *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+
+ pr_debug("%s\n", __func__);
+ prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
+ if (prtd == NULL) {
+ pr_err("Failed to allocate memory for msm_compr_audio\n");
+ return -ENOMEM;
+ }
+
+ runtime->private_data = NULL;
+ prtd->cstream = cstream;
+ pdata->cstream[rtd->dai_link->be_id] = cstream;
+
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)compr_event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_err("%s: Could not allocate memory for client\n", __func__);
+ pdata->cstream[rtd->dai_link->be_id] = NULL;
+ kfree(prtd);
+ return -ENOMEM;
+ }
pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->audio_client->perf_mode = false;
prtd->session_id = prtd->audio_client->session;
+ prtd->codec = FORMAT_LINEAR_PCM;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->received_total = 0;
+ prtd->byte_offset = 0;
+ prtd->sample_rate = 48000;
+ prtd->num_channels = 2;
+ prtd->first_buffer = 0;
+
+ spin_lock_init(&prtd->lock);
+
+ atomic_set(&prtd->eos, 0);
+ atomic_set(&prtd->start, 0);
+ atomic_set(&prtd->drain, 0);
+ atomic_set(&prtd->xrun, 0);
+ atomic_set(&prtd->close, 0);
+ atomic_set(&prtd->wait_on_close, 0);
+ atomic_set(&prtd->error, 0);
+
+ runtime->private_data = prtd;
return 0;
}
-static int msm_compr_free(struct snd_compr_stream *cstream)
+static int msm_compr_open(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_open(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_open(cstream);
+ return ret;
+}
+
+static int msm_compr_playback_free(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime;
struct msm_compr_audio *prtd;
@@ -1284,6 +1529,76 @@ static int msm_compr_free(struct snd_compr_stream *cstream)
return 0;
}
+static int msm_compr_capture_free(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime;
+ struct msm_compr_audio *prtd;
+ struct snd_soc_pcm_runtime *soc_prtd;
+ struct msm_compr_pdata *pdata;
+ struct audio_client *ac;
+ int dir = OUT, stream_id;
+ unsigned long flags;
+ uint32_t stream_index;
+
+ if (!cstream) {
+ pr_err("%s cstream is null\n", __func__);
+ return 0;
+ }
+ runtime = cstream->runtime;
+ soc_prtd = cstream->private_data;
+ if (!runtime || !soc_prtd || !(soc_prtd->platform)) {
+ pr_err("%s runtime or soc_prtd or platform is null\n",
+ __func__);
+ return 0;
+ }
+ prtd = runtime->private_data;
+ if (!prtd) {
+ pr_err("%s prtd is null\n", __func__);
+ return 0;
+ }
+ pdata = snd_soc_platform_get_drvdata(soc_prtd->platform);
+ ac = prtd->audio_client;
+ if (!pdata || !ac) {
+ pr_err("%s pdata or ac is null\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ stream_id = ac->stream_id;
+
+ stream_index = STREAM_ARRAY_INDEX(stream_id);
+ if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0)) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ pr_debug("close stream %d", stream_id);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
+
+ q6asm_audio_client_free(ac);
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int msm_compr_free(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_free(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_free(cstream);
+ return ret;
+}
+
static bool msm_compr_validate_codec_compr(__u32 codec_id)
{
int32_t i;
@@ -1449,7 +1764,10 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream,
prtd->partial_drain_delay =
msm_compr_get_partial_drain_delay(frame_sz, prtd->sample_rate);
- ret = msm_compr_configure_dsp(cstream);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_configure_dsp_for_playback(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_configure_dsp_for_capture(cstream);
return ret;
}
@@ -1539,11 +1857,6 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
uint32_t stream_index;
uint16_t bits_per_sample = 16;
- if (cstream->direction != SND_COMPRESS_PLAYBACK) {
- pr_err("%s: Unsupported stream type\n", __func__);
- return -EINVAL;
- }
-
spin_lock_irqsave(&prtd->lock, flags);
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification, return immediately",
@@ -1566,7 +1879,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
* compress passthrough volume is controlled in
* ADM by adm_send_compressed_device_mute()
*/
- if (prtd->compr_passthr == LEGACY_PCM) {
+ if (prtd->compr_passthr == LEGACY_PCM &&
+ cstream->direction == SND_COMPRESS_PLAYBACK) {
/* set volume for the stream before RUN */
rc = msm_compr_set_volume(cstream,
volume[0], volume[1]);
@@ -1578,8 +1892,9 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
if (rc)
pr_err("%s : init PP params failed : %d\n",
__func__, rc);
+ } else {
+ msm_compr_read_buffer(prtd);
}
-
/* issue RUN command for the stream */
q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
break;
@@ -1589,6 +1904,18 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
prtd->gapless_state.gapless_transition);
stream_id = ac->stream_id;
atomic_set(&prtd->start, 0);
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->xrun, 0);
+ prtd->received_total = 0;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->byte_offset = 0;
+ prtd->app_pointer = 0;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
if (prtd->next_stream) {
pr_debug("%s: interrupt next track wait queues\n",
__func__);
@@ -1979,7 +2306,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
}
static int msm_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *arg)
+ struct snd_compr_tstamp *arg)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -1998,7 +2325,10 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream,
spin_lock_irqsave(&prtd->lock, flags);
tstamp.sampling_rate = prtd->sample_rate;
tstamp.byte_offset = prtd->byte_offset;
- tstamp.copied_total = prtd->copied_total;
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ tstamp.copied_total = prtd->copied_total;
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ tstamp.copied_total = prtd->received_total;
first_buffer = prtd->first_buffer;
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification, return error\n",
@@ -2012,37 +2342,39 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream,
spin_unlock_irqrestore(&prtd->lock, flags);
return -ENETRESET;
}
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- gapless_transition = prtd->gapless_state.gapless_transition;
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- if (gapless_transition)
- pr_debug("%s session time in gapless transition",
- __func__);
-
- /*
- - Do not query if no buffer has been given.
- - Do not query on a gapless transition.
- Playback for the 2nd stream can start (thus returning time
- starting from 0) before the driver knows about EOS of first stream.
- */
-
- if (!first_buffer && !gapless_transition) {
- if (pdata->use_legacy_api)
- rc = q6asm_get_session_time_legacy(prtd->audio_client,
- &prtd->marker_timestamp);
- else
- rc = q6asm_get_session_time(prtd->audio_client,
- &prtd->marker_timestamp);
+ gapless_transition = prtd->gapless_state.gapless_transition;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ if (gapless_transition)
+ pr_debug("%s session time in gapless transition",
+ __func__);
+ /*
+ *- Do not query if no buffer has been given.
+ *- Do not query on a gapless transition.
+ * Playback for the 2nd stream can start (thus returning time
+ * starting from 0) before the driver knows about EOS of first
+ * stream.
+ */
+ if (!first_buffer || gapless_transition) {
- if (rc < 0) {
- pr_err("%s: Get Session Time return value =%lld\n",
- __func__, timestamp);
- if (atomic_read(&prtd->error))
- return -ENETRESET;
+ if (pdata->use_legacy_api)
+ rc = q6asm_get_session_time_legacy(
+ prtd->audio_client, &prtd->marker_timestamp);
else
- return -EAGAIN;
+ rc = q6asm_get_session_time(
+ prtd->audio_client, &prtd->marker_timestamp);
+ if (rc < 0) {
+ pr_err("%s: Get Session Time return =%lld\n",
+ __func__, timestamp);
+ if (atomic_read(&prtd->error))
+ return -ENETRESET;
+ else
+ return -EAGAIN;
+ }
}
+ } else {
+ spin_unlock_irqrestore(&prtd->lock, flags);
}
timestamp = prtd->marker_timestamp;
@@ -2103,8 +2435,8 @@ static int msm_compr_ack(struct snd_compr_stream *cstream,
return 0;
}
-static int msm_compr_copy(struct snd_compr_stream *cstream,
- char __user *buf, size_t count)
+static int msm_compr_playback_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -2166,6 +2498,60 @@ static int msm_compr_copy(struct snd_compr_stream *cstream,
return count;
}
+static int msm_compr_capture_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_compr_audio *prtd = runtime->private_data;
+ void *source;
+ unsigned long flags;
+
+ pr_debug("%s: count = %zd\n", __func__, count);
+ if (!prtd->buffer) {
+ pr_err("%s: Buffer is not allocated yet ??", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s Got RESET EVENTS notification", __func__);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return -ENETRESET;
+ }
+
+ source = prtd->buffer + prtd->app_pointer;
+ /* check if we have requested amount of data to copy to user*/
+ if (count <= prtd->received_total - prtd->bytes_copied) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ if (copy_to_user(buf, source, count)) {
+ pr_err("copy_to_user failed");
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->app_pointer += count;
+ if (prtd->app_pointer >= prtd->buffer_size)
+ prtd->app_pointer -= prtd->buffer_size;
+ prtd->bytes_copied += count;
+ }
+ msm_compr_read_buffer(prtd);
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return count;
+}
+
+static int msm_compr_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ int ret = 0;
+
+ pr_debug(" In %s\n", __func__);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_copy(cstream, buf, count);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_copy(cstream, buf, count);
+ return ret;
+}
+
static int msm_compr_get_caps(struct snd_compr_stream *cstream,
struct snd_compr_caps *arg)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 718f7017342b..f1f2fd908eca 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -2645,8 +2645,10 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_rx_dai = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
@@ -2667,8 +2669,10 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_tx_dai = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 9164475386ff..a456cc2ab857 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -548,6 +548,15 @@ static struct msm_pcm_routing_fdai_data
/* MULTIMEDIA16 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA17 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA18 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA19 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
};
static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2]
@@ -2288,6 +2297,21 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 =
msm_route_ec_ref_rx_enum[0],
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul18 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL18 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul19 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL19 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2417,6 +2441,15 @@ static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -2468,6 +2501,15 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = {
@@ -2519,6 +2561,16 @@ static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SPDIF_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+
};
static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = {
@@ -2621,6 +2673,15 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_5_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -2672,6 +2733,15 @@ static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -2723,6 +2793,15 @@ static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -2774,6 +2853,15 @@ static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = {
@@ -2825,6 +2913,15 @@ static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
@@ -2870,6 +2967,15 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = {
@@ -2927,6 +3033,15 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
@@ -2978,6 +3093,15 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = {
@@ -3131,6 +3255,15 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new display_port_mixer_controls[] = {
@@ -3432,6 +3565,15 @@ static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = {
@@ -3534,6 +3676,15 @@ static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -3585,6 +3736,15 @@ static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -3636,6 +3796,15 @@ static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -3687,6 +3856,15 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = {
@@ -5018,6 +5196,77 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul17_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul18_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul19_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -8098,6 +8347,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
@@ -8796,6 +9048,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul18_mixer_controls, ARRAY_SIZE(mmul18_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia19 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -9060,6 +9318,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
&ext_ec_ref_mux_ul8),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul9),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul17),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul18),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL19 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul19),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -9287,9 +9551,15 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia8 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
{"MultiMedia8 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia17 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -9884,10 +10154,16 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
@@ -9895,6 +10171,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
@@ -9905,6 +10184,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL17", NULL, "MultiMedia17 Mixer"},
+ {"MM_UL18", NULL, "MultiMedia18 Mixer"},
+ {"MM_UL19", NULL, "MultiMedia19 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -10284,6 +10566,21 @@ static const struct snd_soc_dapm_route intercon[] = {
{"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
{"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL18 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL19 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
{"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"},
{"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"},
{"MM_UL3", NULL, "AUDIO_REF_EC_UL3 MUX"},
@@ -10292,6 +10589,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
{"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
{"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+ {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"},
+ {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"},
+ {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4fdfd6bb936d..d64fd640618e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -182,6 +182,9 @@ enum {
MSM_FRONTEND_DAI_MULTIMEDIA14,
MSM_FRONTEND_DAI_MULTIMEDIA15,
MSM_FRONTEND_DAI_MULTIMEDIA16,
+ MSM_FRONTEND_DAI_MULTIMEDIA17,
+ MSM_FRONTEND_DAI_MULTIMEDIA18,
+ MSM_FRONTEND_DAI_MULTIMEDIA19,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
@@ -207,8 +210,8 @@ enum {
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA16 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA16
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA19 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA19
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,