aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,kryocc.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wcd9335.txt20
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi52
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi9
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi149
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-pins.dtsi46
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi958
-rw-r--r--arch/arm64/boot/dts/qcom/pmi8994.dtsi14
-rw-r--r--arch/arm64/configs/defconfig2
-rw-r--r--drivers/clk/clk-fixed-factor.c2
-rw-r--r--drivers/clk/qcom/Kconfig10
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h6
-rw-r--r--drivers/clk/qcom/clk-cpu-8996.c510
-rw-r--r--drivers/misc/fastrpc.c235
-rw-r--r--drivers/perf/Kconfig1
-rw-r--r--drivers/perf/qcom_l2_pmu.c90
-rw-r--r--drivers/slimbus/core.c5
-rw-r--r--drivers/soc/qcom/Kconfig3
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/apr.c65
-rw-r--r--drivers/soc/qcom/kryo-l2-accessors.c56
-rw-r--r--include/soc/qcom/kryo-l2-accessors.h12
-rw-r--r--sound/soc/codecs/wcd9335.c296
-rw-r--r--sound/soc/qcom/apq8096.c53
-rw-r--r--sound/soc/qcom/common.c1
26 files changed, 2468 insertions, 146 deletions
diff --git a/Documentation/devicetree/bindings/clock/qcom,kryocc.txt b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt
new file mode 100644
index 000000000000..8458783c5a1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt
@@ -0,0 +1,17 @@
+Qualcomm CPUSS clock controller for Kryo CPUs
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+ "qcom,msm8996-apcc"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+
+Example:
+ kryocc: clock-controller@6400000 {
+ compatible = "qcom,msm8996-apcc";
+ reg = <0x6400000 0x90000>;
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
index 5d6ea66a863f..4d56c3ca9fa8 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
@@ -55,6 +55,26 @@ Required properties with SLIMbus Interface:
Value type: <string>
Definition: Must contain "mclk", "mclk2" and "slimbus" strings.
+- qcom,mbhc-vthreshold:
+ Usage: Optional, only required if headset button support required.
+ Value type: <u32 array>
+ Definition: Must contain an array of 8 threshold voltages in mV for
+ 8 buttons detection on headset.
+
+- qcom,hphl-jack-type-normally-open:
+ Usage: Optional, only required if headset button support required.
+ Value type: <boolean>
+ Definition: present if hphl pin on jack is a NO (Normally Open).
+ If not specified, then its assumed that hphl pin on jack
+ is NC (Normally Closed).
+
+- qcom,gnd-jack-type-normally-open:
+ Usage: Optional, only required if headset button support required.
+ Value type: <boolean>
+ Definition: present if gnd pin on jack is NO (Normally Open).
+ If not specified, then its assumed that gnd pin on
+ jack is NC (Normally Closed).
+
- vdd-buck-supply:
Usage: required
Value type: <phandle>
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
index 6a573875d45a..1c0d06f59d00 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
@@ -62,4 +62,56 @@
bias-disable;
};
};
+
+ hdmi_hpd_active: hdmi_hpd_active {
+ mux {
+ pins = "gpio34";
+ function = "hdmi_hot";
+ };
+
+ config {
+ pins = "gpio34";
+ bias-pull-down;
+ drive-strength = <16>;
+ };
+ };
+
+ hdmi_hpd_suspend: hdmi_hpd_suspend {
+ mux {
+ pins = "gpio34";
+ function = "hdmi_hot";
+ };
+
+ config {
+ pins = "gpio34";
+ bias-pull-down;
+ drive-strength = <2>;
+ };
+ };
+
+ hdmi_ddc_active: hdmi_ddc_active {
+ mux {
+ pins = "gpio32", "gpio33";
+ function = "hdmi_ddc";
+ };
+
+ config {
+ pins = "gpio32", "gpio33";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ hdmi_ddc_suspend: hdmi_ddc_suspend {
+ mux {
+ pins = "gpio32", "gpio33";
+ function = "hdmi_ddc";
+ };
+
+ config {
+ pins = "gpio32", "gpio33";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
index a6ad3d7fe655..7c5045949c01 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
@@ -36,6 +36,15 @@
};
};
+
+ audio_mclk: clk_div1 {
+ pinconf {
+ pins = "gpio15";
+ function = "func1";
+ power-source = <PM8994_GPIO_S4>; // 1.8V
+ };
+ };
+
volume_up_gpio: pm8996_gpio2 {
pinconf {
pins = "gpio2";
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
index 6d50449fbcdf..946bb2be3038 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
@@ -18,6 +18,8 @@
#include "apq8096-db820c-pmic-pins.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
/*
* GPIO name legend: proper name = the GPIO line is used as GPIO
@@ -63,6 +65,7 @@
};
clocks {
+ compatible = "simple-bus";
divclk4: divclk4 {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -72,6 +75,16 @@
pinctrl-names = "default";
pinctrl-0 = <&divclk4_pin_a>;
};
+
+ div1_mclk: divclk1 {
+ compatible = "gpio-gate-clock";
+ pinctrl-0 = <&audio_mclk>;
+ pinctrl-names = "default";
+ clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
+ #clock-cells = <0>;
+ enable-gpios = <&pm8994_gpios 15 0>;
+ };
+
};
soc {
@@ -452,6 +465,43 @@
perst-gpio = <&msmgpio 114 GPIO_ACTIVE_LOW>;
};
};
+
+ slim_msm: slim@91c0000 {
+ ngd@1 {
+ wcd9335: codec@1{
+ clock-names = "mclk", "slimbus";
+ clocks = <&div1_mclk>,
+ <&rpmcc RPM_SMD_BB_CLK1>;
+ };
+ };
+ };
+
+ mdss@900000 {
+ status = "okay";
+
+ mdp@901000 {
+ status = "okay";
+ };
+
+ hdmi-phy@9a0600 {
+ status = "okay";
+
+ vddio-supply = <&pm8994_l12>;
+ vcca-supply = <&pm8994_l28>;
+ #phy-cells = <0>;
+ };
+
+ hdmi-tx@9a0000 {
+ status = "okay";
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&hdmi_hpd_active &hdmi_ddc_active>;
+ pinctrl-1 = <&hdmi_hpd_suspend &hdmi_ddc_suspend>;
+
+ core-vdda-supply = <&pm8994_l12>;
+ core-vcc-supply = <&pm8994_s4>;
+ };
+ };
};
@@ -639,3 +689,102 @@
};
};
};
+
+&sound {
+ compatible = "qcom,apq8096-sndcard";
+ model = "DB820c";
+ audio-routing =
+ "RX_BIAS", "MCLK",
+ "MIC BIAS1", "MCLK",
+ "MIC BIAS2", "MCLK",
+ "MIC BIAS3", "MCLK",
+ "MIC BIAS4", "MCLK",
+ "AMIC1", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC5", "MIC BIAS2",
+ "MIC BIAS2", "Analog Mic6",
+ "AMIC6", "MIC BIAS2",
+ "MIC BIAS2", "Analog Mic7",
+ "DMIC2", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic2",
+ "DMIC3", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic3",
+ "DMIC4", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic4",
+ "DMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ mm1-dai-link {
+ link-name = "MultiMedia1";
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
+ };
+ };
+
+ mm2-dai-link {
+ link-name = "MultiMedia2";
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>;
+ };
+ };
+
+ mm3-dai-link {
+ link-name = "MultiMedia3";
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>;
+ };
+ };
+
+ hdmi-dai-link {
+ link-name = "HDMI";
+ cpu {
+ sound-dai = <&q6afedai HDMI_RX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&hdmi 0>;
+ };
+ };
+
+ slim-dai-link {
+ link-name = "SLIM Playback";
+ cpu {
+ sound-dai = <&q6afedai SLIMBUS_6_RX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&wcd9335 6>;
+ };
+ };
+
+ slimcap-dai-link {
+ link-name = "SLIM Capture";
+ cpu {
+ sound-dai = <&q6afedai SLIMBUS_0_TX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&wcd9335 1>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
index 131878db9852..c7ae88100cb6 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
@@ -13,6 +13,52 @@
&msmgpio {
+ wcd9xxx_intr {
+ wcd_intr_default: wcd_intr_default{
+ mux {
+ pins = "gpio54";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio54";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ input-enable;
+ };
+ };
+ };
+
+
+ cdc_reset_ctrl {
+ cdc_reset_sleep: cdc_reset_sleep {
+ mux {
+ pins = "gpio64";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio64";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+ };
+ cdc_reset_active:cdc_reset_active {
+ mux {
+ pins = "gpio64";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio64";
+ drive-strength = <16>;
+ bias-pull-down;
+ output-high;
+ };
+ };
+ };
+
+
+
blsp1_spi0_default: blsp1_spi0_default {
pinmux {
function = "blsp_spi1";
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index c761269caf80..75a522a91ba2 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -1,19 +1,14 @@
-/* Copyright (c) 2014-2015, 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.
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/soc/qcom,apr.h>
/ {
interrupt-parent = <&intc>;
@@ -39,11 +34,6 @@
no-map;
};
- slpi_region: slpi@90b00000 {
- reg = <0x0 0x90b00000 0x0 0xa00000>;
- no-map;
- };
-
venus_region: venus@90400000 {
reg = <0x0 0x90400000 0x0 0x700000>;
no-map;
@@ -84,6 +74,12 @@
qcom,client-id = <1>;
qcom,vmid = <15>;
};
+
+ zap_shader_region: gpu@8f200000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x90b00000 0x0 0xa00000>;
+ no-map;
+ };
};
cpus {
@@ -95,6 +91,9 @@
compatible = "qcom,kryo";
reg = <0x0 0x0>;
enable-method = "psci";
+ clocks = <&kryocc 0>;
+ operating-points-v2 = <&cluster0_opp>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
compatible = "cache";
@@ -107,6 +106,9 @@
compatible = "qcom,kryo";
reg = <0x0 0x1>;
enable-method = "psci";
+ clocks = <&kryocc 0>;
+ operating-points-v2 = <&cluster0_opp>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
};
@@ -115,6 +117,9 @@
compatible = "qcom,kryo";
reg = <0x0 0x100>;
enable-method = "psci";
+ clocks = <&kryocc 1>;
+ operating-points-v2 = <&cluster1_opp>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
compatible = "cache";
@@ -127,6 +132,9 @@
compatible = "qcom,kryo";
reg = <0x0 0x101>;
enable-method = "psci";
+ clocks = <&kryocc 1>;
+ operating-points-v2 = <&cluster1_opp>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_1>;
};
@@ -153,6 +161,441 @@
};
};
+ cluster0_opp: opp_table0 {
+ compatible = "operating-points-v2-kryo-cpu",
+ "operating-points-v2";
+ nvmem-cells = <&speedbin_efuse>;
+ opp-shared;
+
+ opp-307200000 {
+ opp-hz = /bits/ 64 <307200000>;
+ opp-supported-hw = <0x77>;
+ clock-latency-ns = <200000>;
+ };
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-422400000 {
+ opp-hz = /bits/ 64 <422400000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-460800000 {
+ opp-hz = /bits/ 64 <460800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-480000000 {
+ opp-hz = /bits/ 64 <480000000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-537600000 {
+ opp-hz = /bits/ 64 <537600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-556800000 {
+ opp-hz = /bits/ 64 <556800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-614400000 {
+ opp-hz = /bits/ 64 <614400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-652800000 {
+ opp-hz = /bits/ 64 <652800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-691200000 {
+ opp-hz = /bits/ 64 <691200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-729600000 {
+ opp-hz = /bits/ 64 <729600000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-768000000 {
+ opp-hz = /bits/ 64 <768000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-844800000 {
+ opp-hz = /bits/ 64 <844800000>;
+ opp-supported-hw = <0x77>;
+ clock-latency-ns = <200000>;
+ };
+ opp-902400000 {
+ opp-hz = /bits/ 64 <902400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-960000000 {
+ opp-hz = /bits/ 64 <960000000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-979200000 {
+ opp-hz = /bits/ 64 <979200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1036800000 {
+ opp-hz = /bits/ 64 <1036800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1056000000 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1113600000 {
+ opp-hz = /bits/ 64 <1113600000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1132800000 {
+ opp-hz = /bits/ 64 <1132800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1190400000 {
+ opp-hz = /bits/ 64 <1190400000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1209600000 {
+ opp-hz = /bits/ 64 <1209600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1228800000 {
+ opp-hz = /bits/ 64 <1228800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1286400000 {
+ opp-hz = /bits/ 64 <1286400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1324800000 {
+ opp-hz = /bits/ 64 <1324800000>;
+ opp-supported-hw = <0x5>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1363200000 {
+ opp-hz = /bits/ 64 <1363200000>;
+ opp-supported-hw = <0x72>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1401600000 {
+ opp-hz = /bits/ 64 <1401600000>;
+ opp-supported-hw = <0x5>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1440000000 {
+ opp-hz = /bits/ 64 <1440000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1478400000 {
+ opp-hz = /bits/ 64 <1478400000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1497600000 {
+ opp-hz = /bits/ 64 <1497600000>;
+ opp-supported-hw = <0x4>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1516800000 {
+ opp-hz = /bits/ 64 <1516800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1593600000 {
+ opp-hz = /bits/ 64 <1593600000>;
+ opp-supported-hw = <0x71>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1996800000 {
+ opp-hz = /bits/ 64 <1996800000>;
+ opp-supported-hw = <0x20>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2188800000 {
+ opp-hz = /bits/ 64 <2188800000>;
+ opp-supported-hw = <0x10>;
+ clock-latency-ns = <200000>;
+ };
+ };
+
+ cluster1_opp: opp_table1 {
+ compatible = "operating-points-v2-kryo-cpu";
+ nvmem-cells = <&speedbin_efuse>;
+ opp-shared;
+
+ opp-307200000 {
+ opp-hz = /bits/ 64 <307200000>;
+ opp-supported-hw = <0x77>;
+ clock-latency-ns = <200000>;
+ };
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-403200000 {
+ opp-hz = /bits/ 64 <403200000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-460800000 {
+ opp-hz = /bits/ 64 <460800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-480000000 {
+ opp-hz = /bits/ 64 <480000000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-537600000 {
+ opp-hz = /bits/ 64 <537600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-556800000 {
+ opp-hz = /bits/ 64 <556800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-614400000 {
+ opp-hz = /bits/ 64 <614400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-652800000 {
+ opp-hz = /bits/ 64 <652800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-691200000 {
+ opp-hz = /bits/ 64 <691200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-729600000 {
+ opp-hz = /bits/ 64 <729600000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-748800000 {
+ opp-hz = /bits/ 64 <748800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-806400000 {
+ opp-hz = /bits/ 64 <806400000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-825600000 {
+ opp-hz = /bits/ 64 <825600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-883200000 {
+ opp-hz = /bits/ 64 <883200000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-902400000 {
+ opp-hz = /bits/ 64 <902400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-940800000 {
+ opp-hz = /bits/ 64 <940800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-979200000 {
+ opp-hz = /bits/ 64 <979200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1036800000 {
+ opp-hz = /bits/ 64 <1036800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1056000000 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1113600000 {
+ opp-hz = /bits/ 64 <1113600000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1132800000 {
+ opp-hz = /bits/ 64 <1132800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1190400000 {
+ opp-hz = /bits/ 64 <1190400000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1209600000 {
+ opp-hz = /bits/ 64 <1209600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1248000000 {
+ opp-hz = /bits/ 64 <1248000000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1286400000 {
+ opp-hz = /bits/ 64 <1286400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1324800000 {
+ opp-hz = /bits/ 64 <1324800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1363200000 {
+ opp-hz = /bits/ 64 <1363200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1401600000 {
+ opp-hz = /bits/ 64 <1401600000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1440000000 {
+ opp-hz = /bits/ 64 <1440000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1478400000 {
+ opp-hz = /bits/ 64 <1478400000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1516800000 {
+ opp-hz = /bits/ 64 <1516800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1555200000 {
+ opp-hz = /bits/ 64 <1555200000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1593600000 {
+ opp-hz = /bits/ 64 <1593600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1632000000 {
+ opp-hz = /bits/ 64 <1632000000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1670400000 {
+ opp-hz = /bits/ 64 <1670400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1708800000 {
+ opp-hz = /bits/ 64 <1708800000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1747200000 {
+ opp-hz = /bits/ 64 <1747200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1785600000 {
+ opp-hz = /bits/ 64 <1785600000>;
+ opp-supported-hw = <0x7>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1804800000 {
+ opp-hz = /bits/ 64 <1804800000>;
+ opp-supported-hw = <0x6>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1824000000 {
+ opp-hz = /bits/ 64 <1824000000>;
+ opp-supported-hw = <0x71>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1900800000 {
+ opp-hz = /bits/ 64 <1900800000>;
+ opp-supported-hw = <0x74>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1920000000 {
+ opp-hz = /bits/ 64 <1920000000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1977600000 {
+ opp-hz = /bits/ 64 <1977600000>;
+ opp-supported-hw = <0x30>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1996800000 {
+ opp-hz = /bits/ 64 <1996800000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2054400000 {
+ opp-hz = /bits/ 64 <2054400000>;
+ opp-supported-hw = <0x30>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2073600000 {
+ opp-hz = /bits/ 64 <2073600000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2150400000 {
+ opp-hz = /bits/ 64 <2150400000>;
+ opp-supported-hw = <0x31>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2246400000 {
+ opp-hz = /bits/ 64 <2246400000>;
+ opp-supported-hw = <0x10>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2342400000 {
+ opp-hz = /bits/ 64 <2342400000>;
+ opp-supported-hw = <0x10>;
+ clock-latency-ns = <200000>;
+ };
+ };
+
thermal-zones {
cpu-thermal0 {
polling-delay-passive = <250>;
@@ -161,18 +604,34 @@
thermal-sensors = <&tsens0 3>;
trips {
- cpu_alert0: trip0 {
+ cpu_alert0: cpu_alert0 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn0: cpu_warn0 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
- cpu_crit0: trip1 {
+ cpu_crit0: cpu_crit0 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn0>;
+ cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal1 {
@@ -182,18 +641,34 @@
thermal-sensors = <&tsens0 5>;
trips {
- cpu_alert1: trip0 {
+ cpu_alert1: cpu_alert1 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn1: cpu_warn1 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
- cpu_crit1: trip1 {
+ cpu_crit1: cpu_crit1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn1>;
+ cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal2 {
@@ -203,18 +678,33 @@
thermal-sensors = <&tsens0 8>;
trips {
- cpu_alert2: trip0 {
+ cpu_alert2: cpu_alert2 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn2: cpu_warn2 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
- cpu_crit2: trip1 {
+ cpu_crit2: cpu_crit2 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert2>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn2>;
+ cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal3 {
@@ -224,9 +714,14 @@
thermal-sensors = <&tsens0 10>;
trips {
- cpu_alert3: trip0 {
+ cpu_alert3: cpu_alert3 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn3: cpu_warn3 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
@@ -236,6 +731,16 @@
type = "critical";
};
};
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert3>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn3>;
+ cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
};
@@ -464,7 +969,7 @@
};
kryocc: clock-controller@6400000 {
- compatible = "qcom,apcc-msm8996";
+ compatible = "qcom,msm8996-apcc";
reg = <0x6400000 0x90000>;
#clock-cells = <1>;
};
@@ -796,6 +1301,11 @@
reg = <0x24f 0x1>;
bits = <1 4>;
};
+
+ speedbin_efuse: speedbin@133 {
+ reg = <0x133 0x1>;
+ bits = <5 3>;
+ };
};
phy@34000 {
@@ -1285,7 +1795,7 @@
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pcie2_clkreq_default &pcie2_perst_default &pcie2_wake_default>;
- pinctrl-1 = <&pcie2_clkreq_sleep &pcie2_perst_default &pcie2_wake_sleep >;
+ pinctrl-1 = <&pcie2_clkreq_sleep &pcie2_perst_default &pcie2_wake_sleep>;
vdda-supply = <&pm8994_l28>;
@@ -1303,6 +1813,303 @@
"bus_slave";
};
};
+
+ slimbam:dma@9184000
+ {
+ compatible = "qcom,bam-v1.7.0";
+ qcom,controlled-remotely;
+ reg = <0x9184000 0x32000>;
+ num-channels = <31>;
+ interrupts = <0 164 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ qcom,ee = <1>;
+ qcom,num-ees = <2>;
+ };
+
+ slim_msm: slim@91c0000 {
+ compatible = "qcom,slim-ngd-v1.5.0";
+ reg = <0x91c0000 0x2C000>;
+ reg-names = "ctrl";
+ interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,apps-ch-pipes = <0x60000000>;
+ qcom,ea-pc = <0x160>;
+ dmas = <&slimbam 3>, <&slimbam 4>,
+ <&slimbam 5>, <&slimbam 6>;
+ dma-names = "rx", "tx", "tx2", "rx2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ngd@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ tasha_ifd: tas-ifd {
+ compatible = "slim217,1a0";
+ reg = <0 0>;
+ };
+
+ wcd9335: codec@1{
+ pinctrl-0 = <&cdc_reset_active &wcd_intr_default>;
+ pinctrl-names = "default";
+
+ compatible = "slim217,1a0";
+ reg = <1 0>;
+
+ interrupt-parent = <&msmgpio>;
+ interrupts = <54 IRQ_TYPE_LEVEL_HIGH>,
+ <53 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "intr1", "intr2";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reset-gpios = <&msmgpio 64 0>;
+
+ slim-ifc-dev = <&tasha_ifd>;
+
+ vdd-buck-supply = <&pm8994_s4>;
+ vdd-buck-sido-supply = <&pm8994_s4>;
+ vdd-tx-supply = <&pm8994_s4>;
+ vdd-rx-supply = <&pm8994_s4>;
+ vdd-io-supply = <&pm8994_s4>;
+
+ #sound-dai-cells = <1>;
+ };
+ };
+ };
+
+ adreno_smmu: arm,smmu@b40000 {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0xb40000 0x10000>;
+
+ #global-interrupts = <1>;
+ interrupts = <0 334 IRQ_TYPE_LEVEL_HIGH>,
+ <0 329 IRQ_TYPE_LEVEL_HIGH>,
+ <0 330 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+
+ clocks = <&mmcc GPU_AHB_CLK>,
+ <&gcc GCC_MMSS_BIMC_GFX_CLK>;
+ clock-names = "bus", "iface";
+
+ power-domains = <&mmcc GPU_GDSC>;
+
+ status = "okay";
+ };
+
+ gpu@b00000 {
+ compatible = "qcom,adreno-530.2", "qcom,adreno";
+ #stream-id-cells = <16>;
+
+ reg = <0xb00000 0x3f000>;
+ reg-names = "kgsl_3d0_reg_memory";
+
+ interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "kgsl_3d0_irq";
+
+ clocks = <&mmcc GPU_GX_GFX3D_CLK>,
+ <&mmcc GPU_AHB_CLK>,
+ <&mmcc GPU_GX_RBBMTIMER_CLK>,
+ <&gcc GCC_BIMC_GFX_CLK>,
+ <&gcc GCC_MMSS_BIMC_GFX_CLK>;
+
+ clock-names = "core",
+ "iface",
+ "rbbmtimer",
+ "mem",
+ "mem_iface";
+
+ power-domains = <&mmcc GPU_GDSC>;
+ iommus = <&adreno_smmu 0>;
+
+ qcom,gpu-quirk-two-pass-use-wfi;
+ qcom,gpu-quirk-fault-detect-mask;
+
+ /* This is a safe speed for bring up in all bin levels.
+ * This isn't the fastest the chip can go, but we can
+ * get there eventually */
+ qcom,gpu-pwrlevels {
+ compatible = "qcom,gpu-pwrlevels";
+ qcom,gpu-pwrlevel@0 {
+ qcom,gpu-freq = <510000000>;
+ };
+ qcom,gpu-pwrlevel@1 {
+ qcom,gpu-freq = <27000000>;
+ };
+ };
+
+ zap-shader {
+ memory-region = <&zap_shader_region>;
+ };
+ };
+
+ mdp_smmu: arm,smmu@d00000 {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0xd00000 0x10000>;
+
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+
+ power-domains = <&mmcc MDSS_GDSC>;
+
+ clocks = <&mmcc SMMU_MDP_AHB_CLK>,
+ <&mmcc SMMU_MDP_AXI_CLK>;
+ clock-names = "iface", "bus";
+
+ status = "okay";
+ };
+
+ mdss: mdss@900000 {
+ compatible = "qcom,mdss";
+
+ reg = <0x900000 0x1000>,
+ <0x9b0000 0x1040>,
+ <0x9b8000 0x1040>;
+ reg-names = "mdss_phys",
+ "vbif_phys",
+ "vbif_nrt_phys";
+
+ power-domains = <&mmcc MDSS_GDSC>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>;
+ clock-names = "iface";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ mdp: mdp@901000 {
+ compatible = "qcom,mdp5";
+ reg = <0x901000 0x90000>;
+ reg-names = "mdp_phys";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MDSS_MDP_CLK>,
+ <&mmcc SMMU_MDP_AXI_CLK>,
+ <&mmcc MDSS_VSYNC_CLK>;
+ clock-names = "iface",
+ "bus",
+ "core",
+ "iommu",
+ "vsync";
+
+ iommus = <&mdp_smmu 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ mdp5_intf3_out: endpoint {
+ remote-endpoint = <&hdmi_in>;
+ };
+ };
+ };
+ };
+
+ hdmi: hdmi-tx@9a0000 {
+ compatible = "qcom,hdmi-tx-8996";
+ reg = <0x009a0000 0x50c>,
+ <0x00070000 0x6158>,
+ <0x009e0000 0xfff>;
+ reg-names = "core_physical",
+ "qfprom_physical",
+ "hdcp_physical";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&mmcc MDSS_MDP_CLK>,
+ <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_HDMI_CLK>,
+ <&mmcc MDSS_HDMI_AHB_CLK>,
+ <&mmcc MDSS_EXTPCLK_CLK>;
+ clock-names =
+ "mdp_core",
+ "iface",
+ "core",
+ "alt_iface",
+ "extp";
+
+ phys = <&hdmi_phy>;
+ phy-names = "hdmi_phy";
+ #sound-dai-cells = <1>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ hdmi_in: endpoint {
+ remote-endpoint = <&mdp5_intf3_out>;
+ };
+ };
+ };
+ };
+
+ hdmi_phy: hdmi-phy@9a0600 {
+ compatible = "qcom,hdmi-phy-8996";
+ reg = <0x9a0600 0x1c4>,
+ <0x9a0a00 0x124>,
+ <0x9a0c00 0x124>,
+ <0x9a0e00 0x124>,
+ <0x9a1000 0x124>,
+ <0x9a1200 0x0c8>;
+ reg-names = "hdmi_pll",
+ "hdmi_tx_l0",
+ "hdmi_tx_l1",
+ "hdmi_tx_l2",
+ "hdmi_tx_l3",
+ "hdmi_phy";
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&gcc GCC_HDMI_CLKREF_CLK>;
+ clock-names = "iface",
+ "ref";
+ };
+ };
+
+ lpass_q6_smmu: arm,smmu-lpass_q6@1600000 {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0x1600000 0x20000>;
+ #iommu-cells = <1>;
+ power-domains = <&gcc HLOS1_VOTE_LPASS_CORE_GDSC>;
+
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK>,
+ <&gcc GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>;
+ clock-names = "iface", "bus";
+ status = "okay";
+ };
+ };
+
+ sound: sound {
+
};
adsp-pil {
@@ -1331,6 +2138,107 @@
mboxes = <&apcs_glb 8>;
qcom,smd-edge = <1>;
qcom,remote-pid = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fastrpc {
+ compatible = "qcom,fastrpc";
+ qcom,smd-channels = "fastrpcsmd-apps-dsp";
+ /* DOMAIN_ADSP */
+ label = "adsp";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cb@8 {
+ compatible = "qcom,fastrpc-compute-cb";
+ reg = <8>;
+ iommus = <&lpass_q6_smmu 8>;
+ };
+ cb@9 {
+ compatible = "qcom,fastrpc-compute-cb";
+ reg = <9>;
+ iommus = <&lpass_q6_smmu 9>;
+ };
+ cb@10 {
+ compatible = "qcom,fastrpc-compute-cb";
+ reg = <10>;
+ iommus = <&lpass_q6_smmu 10>;
+ };
+ cb@11 {
+ reg = <11>;
+ compatible = "qcom,fastrpc-compute-cb";
+ iommus = <&lpass_q6_smmu 11>;
+ };
+ cb@12 {
+ reg = <12>;
+ compatible = "qcom,fastrpc-compute-cb";
+ iommus = <&lpass_q6_smmu 12>;
+ };
+ cb@5 {
+ reg = <5>;
+ compatible = "qcom,fastrpc-compute-cb";
+ iommus = <&lpass_q6_smmu 5>;
+ };
+ cb@6 {
+ reg = <6>;
+ compatible = "qcom,fastrpc-compute-cb";
+ iommus = <&lpass_q6_smmu 6>;
+ };
+ cb@7 {
+ reg = <7>;
+ compatible = "qcom,fastrpc-compute-cb";
+ iommus = <&lpass_q6_smmu 7>;
+ };
+
+ };
+
+ apr {
+ power-domains = <&gcc HLOS1_VOTE_LPASS_ADSP_GDSC>;
+ compatible = "qcom,apr-v2";
+ qcom,smd-channels = "apr_audio_svc";
+ reg = <APR_DOMAIN_ADSP>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ q6core {
+ reg = <APR_SVC_ADSP_CORE>;
+ compatible = "qcom,q6core";
+ };
+
+ q6afe: q6afe {
+ compatible = "qcom,q6afe";
+ reg = <APR_SVC_AFE>;
+ q6afedai: dais {
+ compatible = "qcom,q6afe-dais";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ hdmi@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ q6asm: q6asm {
+ compatible = "qcom,q6asm";
+ reg = <APR_SVC_ASM>;
+ q6asmdai: dais {
+ compatible = "qcom,q6asm-dais";
+ #sound-dai-cells = <1>;
+ iommus = <&lpass_q6_smmu 1>;
+ };
+ };
+
+ q6adm: q6adm {
+ compatible = "qcom,q6adm";
+ reg = <APR_SVC_ADM>;
+ q6routing: routing {
+ compatible = "qcom,q6adm-routing";
+ #sound-dai-cells = <0>;
+ };
+ };
+
+ };
};
};
@@ -1407,3 +2315,5 @@
};
#include "msm8996-pins.dtsi"
+#include "pm8994.dtsi"
+#include "pmi8994.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pmi8994.dtsi b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
index 3aee10e3f921..8bfcd138c3c1 100644
--- a/arch/arm64/boot/dts/qcom/pmi8994.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
@@ -25,5 +25,19 @@
reg = <0x3 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ regulators {
+ compatible = "qcom,pmi8994-regulators";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pmi8994_s2: s2@1700 {
+ reg = <0x1700 0x100>;
+ status = "ok";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1015000>;
+ regulator-always-on;
+ };
+ };
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 2d9c39033c1a..b3aca4d84f3b 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -109,6 +109,7 @@ CONFIG_CPUFREQ_DT=y
CONFIG_ACPI_CPPC_CPUFREQ=m
CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
CONFIG_ARM_SCPI_CPUFREQ=y
+CONFIG_ARM_QCOM_CPUFREQ_KRYO=y
CONFIG_ARM_TEGRA186_CPUFREQ=y
CONFIG_ARM_SCPI_PROTOCOL=y
CONFIG_RASPBERRYPI_FIRMWARE=y
@@ -646,6 +647,7 @@ CONFIG_CLK_IMX8MQ=y
CONFIG_CLK_IMX8QXP=y
CONFIG_TI_SCI_CLK=y
CONFIG_COMMON_CLK_QCOM=y
+CONFIG_QCOM_CLK_APCC_MSM8996=y
CONFIG_QCOM_CLK_SMD_RPM=y
CONFIG_QCOM_CLK_RPMH=y
CONFIG_IPQ_GCC_8074=y
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index 241b3f8c61a9..95edc00d2c59 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -89,7 +89,7 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
init.num_parents = 1;
hw = &fix->hw;
- ret = clk_hw_register(dev, hw);
+ ret = devm_clk_hw_register(dev, hw);
if (ret) {
kfree(fix);
hw = ERR_PTR(ret);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 1c04575c118f..95b7139dfe34 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -37,6 +37,16 @@ config QCOM_CLK_APCS_MSM8916
Say Y if you want to support CPU frequency scaling on devices
such as msm8916.
+config QCOM_CLK_APCC_MSM8996
+ tristate "MSM8996 CPU Clock Controller"
+ depends on ARM64
+ depends on COMMON_CLK_QCOM
+ select QCOM_KRYO_L2_ACCESSORS
+ help
+ Support for the CPU clock controller on msm8996 devices.
+ Say Y if you want to support CPU clock scaling using CPUfreq
+ drivers for dyanmic power management.
+
config QCOM_CLK_RPM
tristate "RPM based Clock Controller"
depends on MFD_QCOM_RPM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index ee8d0698e370..4c59e31de1b0 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
+obj-$(CONFIG_QCOM_CLK_APCC_MSM8996) += clk-cpu-8996.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 66755f0f84fc..db4918360b03 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -40,6 +40,12 @@ struct pll_vco {
u32 val;
};
+#define VCO(a, b, c) { \
+ .val = a,\
+ .min_freq = b,\
+ .max_freq = c,\
+}
+
/**
* struct clk_alpha_pll - phase locked loop (PLL)
* @offset: base address of registers
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
new file mode 100644
index 000000000000..0a908d849cda
--- /dev/null
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * Each of the CPU clusters (Power and Perf) on msm8996 are
+ * clocked via 2 PLLs, a primary and alternate. There are also
+ * 2 Mux'es, a primary and secondary all connected together
+ * as shown below
+ *
+ * +-------+
+ * XO | |
+ * +------------------>0 |
+ * | |
+ * PLL/2 | SMUX +----+
+ * +------->1 | |
+ * | | | |
+ * | +-------+ | +-------+
+ * | +---->0 |
+ * | | |
+ * +---------------+ | +----------->1 | CPU clk
+ * |Primary PLL +----+ PLL_EARLY | | +------>
+ * | +------+-----------+ +------>2 PMUX |
+ * +---------------+ | | | |
+ * | +------+ | +-->3 |
+ * +--^+ ACD +-----+ | +-------+
+ * +---------------+ +------+ |
+ * |Alt PLL | |
+ * | +---------------------------+
+ * +---------------+ PLL_EARLY
+ *
+ * The primary PLL is what drives the CPU clk, except for times
+ * when we are reprogramming the PLL itself (for rate changes) when
+ * we temporarily switch to an alternate PLL. A subsequent patch adds
+ * support to switch between primary and alternate PLL during rate
+ * changes.
+ *
+ * The primary PLL operates on a single VCO range, between 600MHz
+ * and 3GHz. However the CPUs do support OPPs with frequencies
+ * between 300MHz and 600MHz. In order to support running the CPUs
+ * at those frequencies we end up having to lock the PLL at twice
+ * the rate and drive the CPU clk via the PLL/2 output and SMUX.
+ *
+ * So for frequencies above 600MHz we follow the following path
+ * Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
+ * and for frequencies between 300MHz and 600MHz we follow
+ * Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
+ * Support for this is added in a subsequent patch as well.
+ *
+ * ACD stands for Adaptive Clock Distribution and is used to
+ * detect voltage droops.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-regmap.h"
+
+enum _pmux_input {
+ DIV_2_INDEX = 0,
+ PLL_INDEX,
+ ACD_INDEX,
+ ALT_INDEX,
+ NUM_OF_PMUX_INPUTS
+};
+
+#define DIV_2_THRESHOLD 600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000
+#define MUX_OFFSET 0x40
+#define ALT_PLL_OFFSET 0x100
+#define SSSCTL_OFFSET 0x160
+
+static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_USER_CTL] = 0x10,
+ [PLL_OFF_CONFIG_CTL] = 0x18,
+ [PLL_OFF_CONFIG_CTL_U] = 0x1c,
+ [PLL_OFF_TEST_CTL] = 0x20,
+ [PLL_OFF_TEST_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+ [PLL_OFF_USER_CTL] = 0x10,
+ [PLL_OFF_USER_CTL_U] = 0x14,
+ [PLL_OFF_CONFIG_CTL] = 0x18,
+ [PLL_OFF_TEST_CTL] = 0x20,
+ [PLL_OFF_TEST_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+ .l = 60,
+ .config_ctl_val = 0x200d4aa8,
+ .config_ctl_hi_val = 0x006,
+ .pre_div_mask = BIT(12),
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+ .offset = PERFCL_REG_OFFSET,
+ .regs = prim_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "perfcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+ .offset = PWRCL_REG_OFFSET,
+ .regs = prim_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pwrcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+ VCO(3, 250000000, 500000000),
+ VCO(2, 500000000, 750000000),
+ VCO(1, 750000000, 1000000000),
+ VCO(0, 1000000000, 2150400000),
+};
+
+static const struct alpha_pll_config altpll_config = {
+ .l = 16,
+ .vco_val = 0x3 << 20,
+ .vco_mask = 0x3 << 20,
+ .config_ctl_val = 0x4001051b,
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+ .offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
+ .regs = alt_pll_regs,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+ .offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
+ .regs = alt_pll_regs,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+void __iomem *base;
+static void qcom_cpu_clk_msm8996_acd_init(void __iomem *base);
+
+/* Mux'es */
+
+struct clk_cpu_8996_mux {
+ u32 reg;
+ u8 shift;
+ u8 width;
+ struct notifier_block nb;
+ struct clk_hw *pll;
+ struct clk_hw *pll_div_2;
+ struct clk_regmap clkr;
+};
+
+#define to_clk_cpu_8996_mux_nb(_nb) \
+ container_of(_nb, struct clk_cpu_8996_mux, nb)
+
+static inline
+struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr);
+}
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw)
+{
+ u32 val;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ u32 mask = (u32)GENMASK(cpuclk->width - 1, 0);
+
+ regmap_read(clkr->regmap, cpuclk->reg, &val);
+ val >>= (u32)(cpuclk->shift);
+
+ return (u8)(val & mask);
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ u32 val;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+ cpuclk->shift);
+
+ val = (u32)index;
+ val <<= (u32)(cpuclk->shift);
+
+ return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);
+}
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ struct clk_hw *parent = cpuclk->pll;
+
+ if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) {
+ if (req->rate < (DIV_2_THRESHOLD / 2))
+ return -EINVAL;
+
+ parent = cpuclk->pll_div_2;
+ }
+
+ req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+ req->best_parent_hw = parent;
+
+ return 0;
+}
+
+int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ int ret;
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+ struct clk_notifier_data *cnd = data;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+ qcom_cpu_clk_msm8996_acd_init(base);
+ break;
+ case POST_RATE_CHANGE:
+ if (cnd->new_rate < DIV_2_THRESHOLD)
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+ DIV_2_INDEX);
+ else
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+ ACD_INDEX);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return notifier_from_errno(ret);
+};
+const struct clk_ops clk_cpu_8996_mux_ops = {
+ .set_parent = clk_cpu_8996_mux_set_parent,
+ .get_parent = clk_cpu_8996_mux_get_parent,
+ .determine_rate = clk_cpu_8996_mux_determine_rate,
+};
+
+static struct clk_cpu_8996_mux pwrcl_smux = {
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "pwrcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_smux = {
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "perfcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 0,
+ .width = 2,
+ .pll = &pwrcl_pll.clkr.hw,
+ .pll_div_2 = &pwrcl_smux.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_pmux",
+ .parent_names = (const char *[]){
+ "pwrcl_smux",
+ "pwrcl_pll",
+ "pwrcl_pll_acd",
+ "pwrcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 0,
+ .width = 2,
+ .pll = &perfcl_pll.clkr.hw,
+ .pll_div_2 = &perfcl_smux.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_pmux",
+ .parent_names = (const char *[]){
+ "perfcl_smux",
+ "perfcl_pll",
+ "perfcl_pll_acd",
+ "perfcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x80210,
+ .fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+struct clk_regmap *clks[] = {
+ &perfcl_pll.clkr,
+ &pwrcl_pll.clkr,
+ &perfcl_alt_pll.clkr,
+ &pwrcl_alt_pll.clkr,
+ &perfcl_smux.clkr,
+ &pwrcl_smux.clkr,
+ &perfcl_pmux.clkr,
+ &pwrcl_pmux.clkr,
+};
+
+static int
+qcom_cpu_clk_msm8996_register_clks(struct device *dev, struct regmap *regmap)
+{
+ int i, ret;
+
+ perfcl_smux.pll = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",
+ "perfcl_pll",
+ CLK_SET_RATE_PARENT, 1, 2);
+
+ pwrcl_smux.pll = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
+ "pwrcl_pll",
+ CLK_SET_RATE_PARENT, 1, 2);
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ ret = devm_clk_register_regmap(dev, clks[i]);
+ if (ret)
+ return ret;
+ }
+
+ clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+ clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
+
+ /* Enable alt PLLs */
+ clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+ clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+
+ ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
+ if (ret)
+ return ret;
+
+ ret = clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
+
+ return ret;
+}
+
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103
+
+#define L2ACDCR_REG 0x580ULL
+#define L2ACDTD_REG 0x581ULL
+#define L2ACDDVMRC_REG 0x584ULL
+#define L2ACDSSCR_REG 0x589ULL
+
+static DEFINE_SPINLOCK(acd_lock);
+
+static void qcom_cpu_clk_msm8996_acd_init(void __iomem *base)
+{
+ u64 hwid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acd_lock, flags);
+
+ hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+
+ kryo_l2_set_indirect_reg(L2ACDTD_REG, 0x00006A11);
+ kryo_l2_set_indirect_reg(L2ACDDVMRC_REG, 0x000E0F0F);
+ kryo_l2_set_indirect_reg(L2ACDSSCR_REG, 0x00000601);
+
+ if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+ writel(0xF, base + PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+ wmb();
+ kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002C5FFD);
+ }
+
+ if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) {
+ kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002C5FFD);
+ writel(0xF, base + PERFCL_REG_OFFSET + SSSCTL_OFFSET);
+ wmb();
+ }
+
+ spin_unlock_irqrestore(&acd_lock, flags);
+}
+
+static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+ struct regmap *regmap;
+ struct clk_hw_onecell_data *data;
+ struct device *dev = &pdev->dev;
+
+ data = devm_kzalloc(dev, sizeof(*data) + 2 * sizeof(struct clk_hw *),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &cpu_msm8996_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = qcom_cpu_clk_msm8996_register_clks(dev, regmap);
+ if (ret)
+ return ret;
+
+ qcom_cpu_clk_msm8996_acd_init(base);
+
+ data->hws[0] = &pwrcl_pmux.clkr.hw;
+ data->hws[1] = &perfcl_pmux.clkr.hw;
+ data->num = 2;
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
+}
+
+static const struct of_device_id qcom_cpu_clk_msm8996_match_table[] = {
+ { .compatible = "qcom,msm8996-apcc" },
+ {}
+};
+
+static struct platform_driver qcom_cpu_clk_msm8996_driver = {
+ .probe = qcom_cpu_clk_msm8996_driver_probe,
+ .driver = {
+ .name = "qcom-msm8996-apcc",
+ .of_match_table = qcom_cpu_clk_msm8996_match_table,
+ },
+};
+module_platform_driver(qcom_cpu_clk_msm8996_driver);
+
+MODULE_ALIAS("platform:msm8996-apcc");
+MODULE_DESCRIPTION("QCOM MSM8996 CPU Clock Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 39f832d27288..c4cc8e53243d 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of.h>
+#include <linux/sort.h>
#include <linux/of_platform.h>
#include <linux/rpmsg.h>
#include <linux/scatterlist.h>
@@ -31,7 +32,7 @@
#define FASTRPC_CTX_MAX (256)
#define FASTRPC_INIT_HANDLE 1
#define FASTRPC_CTXID_MASK (0xFF0)
-#define INIT_FILELEN_MAX (2 * 1024 * 1024)
+#define INIT_FILELEN_MAX (64 * 1024 * 1024)
#define INIT_MEMLEN_MAX (8 * 1024 * 1024)
#define FASTRPC_DEVICE_NAME "fastrpc"
@@ -104,6 +105,15 @@ struct fastrpc_invoke_rsp {
int retval; /* invoke return value */
};
+struct fastrpc_buf_overlap {
+ u64 start;
+ u64 end;
+ int raix;
+ u64 mstart;
+ u64 mend;
+ u64 offset;
+};
+
struct fastrpc_buf {
struct fastrpc_user *fl;
struct dma_buf *dmabuf;
@@ -149,12 +159,14 @@ struct fastrpc_invoke_ctx {
struct kref refcount;
struct list_head node; /* list of ctxs */
struct completion work;
+ struct work_struct put_work;
struct fastrpc_msg msg;
struct fastrpc_user *fl;
struct fastrpc_remote_arg *rpra;
struct fastrpc_map **maps;
struct fastrpc_buf *buf;
struct fastrpc_invoke_args *args;
+ struct fastrpc_buf_overlap *olaps;
struct fastrpc_channel_ctx *cctx;
};
@@ -282,6 +294,7 @@ static void fastrpc_context_free(struct kref *ref)
{
struct fastrpc_invoke_ctx *ctx;
struct fastrpc_channel_ctx *cctx;
+ unsigned long flags;
int i;
ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
@@ -293,11 +306,12 @@ static void fastrpc_context_free(struct kref *ref)
if (ctx->buf)
fastrpc_buf_free(ctx->buf);
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
kfree(ctx->maps);
+ kfree(ctx->olaps);
kfree(ctx);
}
@@ -311,12 +325,70 @@ static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx)
kref_put(&ctx->refcount, fastrpc_context_free);
}
+static void fastrpc_context_put_wq(struct work_struct *work)
+{
+ struct fastrpc_invoke_ctx *ctx =
+ container_of(work, struct fastrpc_invoke_ctx, put_work);
+
+ fastrpc_context_put(ctx);
+}
+
+#define CMP(aa, bb) ((aa) == (bb) ? 0 : (aa) < (bb) ? -1 : 1)
+static int olaps_cmp(const void *a, const void *b)
+{
+ struct fastrpc_buf_overlap *pa = (struct fastrpc_buf_overlap *)a;
+ struct fastrpc_buf_overlap *pb = (struct fastrpc_buf_overlap *)b;
+ /* sort with lowest starting buffer first */
+ int st = CMP(pa->start, pb->start);
+ /* sort with highest ending buffer first */
+ int ed = CMP(pb->end, pa->end);
+
+ return st == 0 ? ed : st;
+}
+
+static void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx)
+{
+ u64 max_end = 0;
+ int i;
+
+ for (i = 0; i < ctx->nbufs; ++i) {
+ ctx->olaps[i].start = ctx->args[i].ptr;
+ ctx->olaps[i].end = ctx->olaps[i].start + ctx->args[i].length;
+ ctx->olaps[i].raix = i;
+ }
+
+ sort(ctx->olaps, ctx->nbufs, sizeof(*ctx->olaps), olaps_cmp, NULL);
+
+ for (i = 0; i < ctx->nbufs; ++i) {
+ /* Falling inside previous range */
+ if (ctx->olaps[i].start < max_end) {
+ ctx->olaps[i].mstart = max_end;
+ ctx->olaps[i].mend = ctx->olaps[i].end;
+ ctx->olaps[i].offset = max_end - ctx->olaps[i].start;
+
+ if (ctx->olaps[i].end > max_end) {
+ max_end = ctx->olaps[i].end;
+ } else {
+ ctx->olaps[i].mend = 0;
+ ctx->olaps[i].mstart = 0;
+ }
+
+ } else {
+ ctx->olaps[i].mend = ctx->olaps[i].end;
+ ctx->olaps[i].mstart = ctx->olaps[i].start;
+ ctx->olaps[i].offset = 0;
+ max_end = ctx->olaps[i].end;
+ }
+ }
+}
+
static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
struct fastrpc_user *user, u32 kernel, u32 sc,
struct fastrpc_invoke_args *args)
{
struct fastrpc_channel_ctx *cctx = user->cctx;
struct fastrpc_invoke_ctx *ctx = NULL;
+ unsigned long flags;
int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -336,7 +408,15 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
kfree(ctx);
return ERR_PTR(-ENOMEM);
}
+ ctx->olaps = kcalloc(ctx->nscalars,
+ sizeof(*ctx->olaps), GFP_KERNEL);
+ if (!ctx->olaps) {
+ kfree(ctx->maps);
+ kfree(ctx);
+ return ERR_PTR(-ENOMEM);
+ }
ctx->args = args;
+ fastrpc_get_buff_overlaps(ctx);
}
ctx->sc = sc;
@@ -345,20 +425,21 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
ctx->tgid = user->tgid;
ctx->cctx = cctx;
init_completion(&ctx->work);
+ INIT_WORK(&ctx->put_work, fastrpc_context_put_wq);
spin_lock(&user->lock);
list_add_tail(&ctx->node, &user->pending);
spin_unlock(&user->lock);
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
ret = idr_alloc_cyclic(&cctx->ctx_idr, ctx, 1,
FASTRPC_CTX_MAX, GFP_ATOMIC);
if (ret < 0) {
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
goto err_idr;
}
ctx->ctxid = ret << 4;
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
kref_init(&ctx->refcount);
@@ -368,6 +449,7 @@ err_idr:
list_del(&ctx->node);
spin_unlock(&user->lock);
kfree(ctx->maps);
+ kfree(ctx->olaps);
kfree(ctx);
return ERR_PTR(ret);
@@ -586,8 +668,11 @@ static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen)
size = ALIGN(metalen, FASTRPC_ALIGN);
for (i = 0; i < ctx->nscalars; i++) {
if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) {
- size = ALIGN(size, FASTRPC_ALIGN);
- size += ctx->args[i].length;
+
+ if (ctx->olaps[i].offset == 0)
+ size = ALIGN(size, FASTRPC_ALIGN);
+
+ size += (ctx->olaps[i].mend - ctx->olaps[i].mstart);
}
}
@@ -625,12 +710,12 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
struct fastrpc_remote_arg *rpra;
struct fastrpc_invoke_buf *list;
struct fastrpc_phy_page *pages;
- int inbufs, i, err = 0;
- u64 rlen, pkt_size;
+ int inbufs, i, oix, err = 0;
+ u64 len, rlen, pkt_size;
+ u64 pg_start, pg_end;
uintptr_t args;
int metalen;
-
inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
metalen = fastrpc_get_meta_size(ctx);
pkt_size = fastrpc_get_payload_size(ctx, metalen);
@@ -653,8 +738,11 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
rlen = pkt_size - metalen;
ctx->rpra = rpra;
- for (i = 0; i < ctx->nbufs; ++i) {
- u64 len = ctx->args[i].length;
+ for (oix = 0; oix < ctx->nbufs; ++oix) {
+ int mlen;
+
+ i = ctx->olaps[oix].raix;
+ len = ctx->args[i].length;
rpra[i].pv = 0;
rpra[i].len = len;
@@ -664,22 +752,45 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
if (!len)
continue;
- pages[i].size = roundup(len, PAGE_SIZE);
-
if (ctx->maps[i]) {
+ struct vm_area_struct *vma = NULL;
+
rpra[i].pv = (u64) ctx->args[i].ptr;
pages[i].addr = ctx->maps[i]->phys;
+
+ vma = find_vma(current->mm, ctx->args[i].ptr);
+ if (vma)
+ pages[i].addr += ctx->args[i].ptr -
+ vma->vm_start;
+
+ pg_start = (ctx->args[i].ptr & PAGE_MASK) >> PAGE_SHIFT;
+ pg_end = ((ctx->args[i].ptr + len - 1) & PAGE_MASK) >>
+ PAGE_SHIFT;
+ pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
+
} else {
- rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
- args = ALIGN(args, FASTRPC_ALIGN);
- if (rlen < len)
+
+ if (ctx->olaps[oix].offset == 0) {
+ rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
+ args = ALIGN(args, FASTRPC_ALIGN);
+ }
+
+ mlen = ctx->olaps[oix].mend - ctx->olaps[oix].mstart;
+
+ if (rlen < mlen)
goto bail;
- rpra[i].pv = args;
- pages[i].addr = ctx->buf->phys + (pkt_size - rlen);
+ rpra[i].pv = args - ctx->olaps[oix].offset;
+ pages[i].addr = ctx->buf->phys -
+ ctx->olaps[oix].offset +
+ (pkt_size - rlen);
pages[i].addr = pages[i].addr & PAGE_MASK;
- args = args + len;
- rlen -= len;
+
+ pg_start = (args & PAGE_MASK) >> PAGE_SHIFT;
+ pg_end = ((args + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+ pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
+ args = args + mlen;
+ rlen -= mlen;
}
if (i < inbufs && !ctx->maps[i]) {
@@ -782,6 +893,9 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
if (err)
goto bail;
}
+
+ /* make sure that all CPU memory writes are seen by DSP */
+ dma_wmb();
/* Send invoke buffer to remote dsp */
err = fastrpc_invoke_send(fl->sctx, ctx, kernel, handle);
if (err)
@@ -798,6 +912,8 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
goto bail;
if (ctx->nscalars) {
+ /* make sure that all memory writes by DSP are seen by CPU */
+ dma_rmb();
/* populate all the output buffers with results */
err = fastrpc_put_args(ctx, kernel);
if (err)
@@ -843,12 +959,12 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
if (copy_from_user(&init, argp, sizeof(init))) {
err = -EFAULT;
- goto bail;
+ goto err;
}
if (init.filelen > INIT_FILELEN_MAX) {
err = -EINVAL;
- goto bail;
+ goto err;
}
inbuf.pgid = fl->tgid;
@@ -862,17 +978,15 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
if (init.filelen && init.filefd) {
err = fastrpc_map_create(fl, init.filefd, init.filelen, &map);
if (err)
- goto bail;
+ goto err;
}
memlen = ALIGN(max(INIT_FILELEN_MAX, (int)init.filelen * 4),
1024 * 1024);
err = fastrpc_buf_alloc(fl, fl->sctx->dev, memlen,
&imem);
- if (err) {
- fastrpc_map_put(map);
- goto bail;
- }
+ if (err)
+ goto err_alloc;
fl->init_mem = imem;
args[0].ptr = (u64)(uintptr_t)&inbuf;
@@ -908,13 +1022,24 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
sc, args);
+ if (err)
+ goto err_invoke;
- if (err) {
+ kfree(args);
+
+ return 0;
+
+err_invoke:
+ fl->init_mem = NULL;
+ fastrpc_buf_free(imem);
+err_alloc:
+ if (map) {
+ spin_lock(&fl->lock);
+ list_del(&map->node);
+ spin_unlock(&fl->lock);
fastrpc_map_put(map);
- fastrpc_buf_free(imem);
}
-
-bail:
+err:
kfree(args);
return err;
@@ -924,9 +1049,10 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc(
struct fastrpc_channel_ctx *cctx)
{
struct fastrpc_session_ctx *session = NULL;
+ unsigned long flags;
int i;
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
for (i = 0; i < cctx->sesscount; i++) {
if (!cctx->session[i].used && cctx->session[i].valid) {
cctx->session[i].used = true;
@@ -934,7 +1060,7 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc(
break;
}
}
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
return session;
}
@@ -942,9 +1068,11 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc(
static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
struct fastrpc_session_ctx *session)
{
- spin_lock(&cctx->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&cctx->lock, flags);
session->used = false;
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
}
static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
@@ -970,12 +1098,13 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
struct fastrpc_channel_ctx *cctx = fl->cctx;
struct fastrpc_invoke_ctx *ctx, *n;
struct fastrpc_map *map, *m;
+ unsigned long flags;
fastrpc_release_current_dsp_process(fl);
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
list_del(&fl->user);
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
if (fl->init_mem)
fastrpc_buf_free(fl->init_mem);
@@ -1003,6 +1132,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
{
struct fastrpc_channel_ctx *cctx = miscdev_to_cctx(filp->private_data);
struct fastrpc_user *fl = NULL;
+ unsigned long flags;
fl = kzalloc(sizeof(*fl), GFP_KERNEL);
if (!fl)
@@ -1026,9 +1156,9 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
return -EBUSY;
}
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
list_add_tail(&fl->user, &cctx->users);
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
return 0;
}
@@ -1184,6 +1314,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
struct fastrpc_session_ctx *sess;
struct device *dev = &pdev->dev;
int i, sessions = 0;
+ unsigned long flags;
cctx = dev_get_drvdata(dev->parent);
if (!cctx)
@@ -1191,7 +1322,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions);
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
sess = &cctx->session[cctx->sesscount];
sess->used = false;
sess->valid = true;
@@ -1212,7 +1343,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
}
}
cctx->sesscount++;
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
dma_set_mask(dev, DMA_BIT_MASK(32));
return 0;
@@ -1222,16 +1353,17 @@ static int fastrpc_cb_remove(struct platform_device *pdev)
{
struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent);
struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
int i;
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
for (i = 1; i < FASTRPC_MAX_SESSIONS; i++) {
if (cctx->session[i].sid == sess->sid) {
cctx->session[i].valid = false;
cctx->sesscount--;
}
}
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
return 0;
}
@@ -1313,11 +1445,12 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
{
struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
struct fastrpc_user *user;
+ unsigned long flags;
- spin_lock(&cctx->lock);
+ spin_lock_irqsave(&cctx->lock, flags);
list_for_each_entry(user, &cctx->users, user)
fastrpc_notify_users(user);
- spin_unlock(&cctx->lock);
+ spin_unlock_irqrestore(&cctx->lock, flags);
misc_deregister(&cctx->miscdev);
of_platform_depopulate(&rpdev->dev);
@@ -1349,7 +1482,13 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
ctx->retval = rsp->retval;
complete(&ctx->work);
- fastrpc_context_put(ctx);
+
+ /*
+ * The DMA buffer associated with the context cannot be freed in
+ * interrupt context so schedule it through a worker thread to
+ * avoid a kernel BUG.
+ */
+ schedule_work(&ctx->put_work);
return 0;
}
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index af9bc178495d..f71537ca23d5 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -71,6 +71,7 @@ config HISI_PMU
config QCOM_L2_PMU
bool "Qualcomm Technologies L2-cache PMU"
depends on ARCH_QCOM && ARM64 && ACPI
+ select QCOM_KRYO_L2_ACCESSORS
help
Provides support for the L2 cache performance monitor unit (PMU)
in Qualcomm Technologies processors.
diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c
index 091b4d7d32c4..ed3b85321896 100644
--- a/drivers/perf/qcom_l2_pmu.c
+++ b/drivers/perf/qcom_l2_pmu.c
@@ -31,6 +31,7 @@
#include <asm/barrier.h>
#include <asm/local64.h>
#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
#define MAX_L2_CTRS 9
@@ -87,8 +88,6 @@
#define L2_COUNTER_RELOAD BIT_ULL(31)
#define L2_CYCLE_COUNTER_RELOAD BIT_ULL(63)
-#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
-#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
#define reg_idx(reg, i) (((i) * IA_L2_REG_OFFSET) + reg##_BASE)
@@ -107,48 +106,7 @@
#define L2_EVENT_STREX 0x421
#define L2_EVENT_CLREX 0x422
-static DEFINE_RAW_SPINLOCK(l2_access_lock);
-/**
- * set_l2_indirect_reg: write value to an L2 register
- * @reg: Address of L2 register.
- * @value: Value to be written to register.
- *
- * Use architecturally required barriers for ordering between system register
- * accesses
- */
-static void set_l2_indirect_reg(u64 reg, u64 val)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&l2_access_lock, flags);
- write_sysreg_s(reg, L2CPUSRSELR_EL1);
- isb();
- write_sysreg_s(val, L2CPUSRDR_EL1);
- isb();
- raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-}
-
-/**
- * get_l2_indirect_reg: read an L2 register value
- * @reg: Address of L2 register.
- *
- * Use architecturally required barriers for ordering between system register
- * accesses
- */
-static u64 get_l2_indirect_reg(u64 reg)
-{
- u64 val;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&l2_access_lock, flags);
- write_sysreg_s(reg, L2CPUSRSELR_EL1);
- isb();
- val = read_sysreg_s(L2CPUSRDR_EL1);
- raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-
- return val;
-}
struct cluster_pmu;
@@ -219,28 +177,28 @@ static inline struct cluster_pmu *get_cluster_pmu(
static void cluster_pmu_reset(void)
{
/* Reset all counters */
- set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
- set_l2_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask);
- set_l2_indirect_reg(L2PMINTENCLR, l2_counter_present_mask);
- set_l2_indirect_reg(L2PMOVSCLR, l2_counter_present_mask);
+ kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
+ kryo_l2_set_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask);
+ kryo_l2_set_indirect_reg(L2PMINTENCLR, l2_counter_present_mask);
+ kryo_l2_set_indirect_reg(L2PMOVSCLR, l2_counter_present_mask);
}
static inline void cluster_pmu_enable(void)
{
- set_l2_indirect_reg(L2PMCR, L2PMCR_COUNTERS_ENABLE);
+ kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_COUNTERS_ENABLE);
}
static inline void cluster_pmu_disable(void)
{
- set_l2_indirect_reg(L2PMCR, L2PMCR_COUNTERS_DISABLE);
+ kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_COUNTERS_DISABLE);
}
static inline void cluster_pmu_counter_set_value(u32 idx, u64 value)
{
if (idx == l2_cycle_ctr_idx)
- set_l2_indirect_reg(L2PMCCNTR, value);
+ kryo_l2_set_indirect_reg(L2PMCCNTR, value);
else
- set_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx), value);
+ kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx), value);
}
static inline u64 cluster_pmu_counter_get_value(u32 idx)
@@ -248,46 +206,46 @@ static inline u64 cluster_pmu_counter_get_value(u32 idx)
u64 value;
if (idx == l2_cycle_ctr_idx)
- value = get_l2_indirect_reg(L2PMCCNTR);
+ value = kryo_l2_get_indirect_reg(L2PMCCNTR);
else
- value = get_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx));
+ value = kryo_l2_get_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx));
return value;
}
static inline void cluster_pmu_counter_enable(u32 idx)
{
- set_l2_indirect_reg(L2PMCNTENSET, idx_to_reg_bit(idx));
+ kryo_l2_set_indirect_reg(L2PMCNTENSET, idx_to_reg_bit(idx));
}
static inline void cluster_pmu_counter_disable(u32 idx)
{
- set_l2_indirect_reg(L2PMCNTENCLR, idx_to_reg_bit(idx));
+ kryo_l2_set_indirect_reg(L2PMCNTENCLR, idx_to_reg_bit(idx));
}
static inline void cluster_pmu_counter_enable_interrupt(u32 idx)
{
- set_l2_indirect_reg(L2PMINTENSET, idx_to_reg_bit(idx));
+ kryo_l2_set_indirect_reg(L2PMINTENSET, idx_to_reg_bit(idx));
}
static inline void cluster_pmu_counter_disable_interrupt(u32 idx)
{
- set_l2_indirect_reg(L2PMINTENCLR, idx_to_reg_bit(idx));
+ kryo_l2_set_indirect_reg(L2PMINTENCLR, idx_to_reg_bit(idx));
}
static inline void cluster_pmu_set_evccntcr(u32 val)
{
- set_l2_indirect_reg(L2PMCCNTCR, val);
+ kryo_l2_set_indirect_reg(L2PMCCNTCR, val);
}
static inline void cluster_pmu_set_evcntcr(u32 ctr, u32 val)
{
- set_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTCR, ctr), val);
+ kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVCNTCR, ctr), val);
}
static inline void cluster_pmu_set_evtyper(u32 ctr, u32 val)
{
- set_l2_indirect_reg(reg_idx(IA_L2PMXEVTYPER, ctr), val);
+ kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVTYPER, ctr), val);
}
static void cluster_pmu_set_resr(struct cluster_pmu *cluster,
@@ -303,11 +261,11 @@ static void cluster_pmu_set_resr(struct cluster_pmu *cluster,
spin_lock_irqsave(&cluster->pmu_lock, flags);
- resr_val = get_l2_indirect_reg(L2PMRESR);
+ resr_val = kryo_l2_get_indirect_reg(L2PMRESR);
resr_val &= ~(L2PMRESR_GROUP_MASK << shift);
resr_val |= field;
resr_val |= L2PMRESR_EN;
- set_l2_indirect_reg(L2PMRESR, resr_val);
+ kryo_l2_set_indirect_reg(L2PMRESR, resr_val);
spin_unlock_irqrestore(&cluster->pmu_lock, flags);
}
@@ -323,14 +281,14 @@ static inline void cluster_pmu_set_evfilter_sys_mode(u32 ctr)
L2PMXEVFILTER_ORGFILTER_IDINDEP |
L2PMXEVFILTER_ORGFILTER_ALL;
- set_l2_indirect_reg(reg_idx(IA_L2PMXEVFILTER, ctr), val);
+ kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVFILTER, ctr), val);
}
static inline u32 cluster_pmu_getreset_ovsr(void)
{
- u32 result = get_l2_indirect_reg(L2PMOVSSET);
+ u32 result = kryo_l2_get_indirect_reg(L2PMOVSSET);
- set_l2_indirect_reg(L2PMOVSCLR, result);
+ kryo_l2_set_indirect_reg(L2PMOVSCLR, result);
return result;
}
@@ -775,7 +733,7 @@ static int get_num_counters(void)
{
int val;
- val = get_l2_indirect_reg(L2PMCR);
+ val = kryo_l2_get_indirect_reg(L2PMCR);
/*
* Read number of counters from L2PMCR and add 1
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index b2f07d2043eb..526e3215d8fe 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -98,11 +98,6 @@ static int slim_device_remove(struct device *dev)
static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct slim_device *sbdev = to_slim_device(dev);
- int ret;
-
- ret = of_device_uevent_modalias(dev, env);
- if (ret != -ENODEV)
- return ret;
return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
}
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 1ee298f6bf17..a84b43df0830 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -57,6 +57,9 @@ config QCOM_SDM845_LLCC
data required to configure LLCC so that clients can start using the
LLCC slices.
+config QCOM_KRYO_L2_ACCESSORS
+ bool
+
config QCOM_MDT_LOADER
tristate
select QCOM_SCM
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index ffe519b0cb66..be1fef6c99f1 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
+obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index 74f8b9607daa..c033e15b2de4 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -8,6 +8,7 @@
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <linux/of_device.h>
#include <linux/soc/qcom/apr.h>
#include <linux/rpmsg.h>
@@ -17,8 +18,18 @@ struct apr {
struct rpmsg_endpoint *ch;
struct device *dev;
spinlock_t svcs_lock;
+ spinlock_t rx_lock;
struct idr svcs_idr;
int dest_domain_id;
+ struct workqueue_struct *rxwq;
+ struct work_struct rx_work;
+ struct list_head rx_list;
+};
+
+struct apr_rx_buf {
+ struct list_head node;
+ int len;
+ uint8_t buf[];
};
/**
@@ -62,6 +73,36 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
int len, void *priv, u32 addr)
{
struct apr *apr = dev_get_drvdata(&rpdev->dev);
+ struct apr_rx_buf *abuf;
+ unsigned long flags;
+
+ if (len <= APR_HDR_SIZE) {
+ dev_err(apr->dev, "APR: Improper apr pkt received:%p %d\n",
+ buf, len);
+ return -EINVAL;
+ }
+
+ abuf = kzalloc(sizeof(*abuf) + len, GFP_ATOMIC);
+ if (!abuf)
+ return -ENOMEM;
+
+ abuf->len = len;
+ memcpy(abuf->buf, buf, len);
+
+ spin_lock_irqsave(&apr->rx_lock, flags);
+ list_add_tail(&abuf->node, &apr->rx_list);
+ spin_unlock_irqrestore(&apr->rx_lock, flags);
+
+ queue_work(apr->rxwq, &apr->rx_work);
+
+ return 0;
+}
+
+
+static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)
+{
+ void *buf = abuf->buf;
+ int len = abuf->len;
uint16_t hdr_size, msg_type, ver, svc_id;
struct apr_device *svc = NULL;
struct apr_driver *adrv = NULL;
@@ -132,6 +173,19 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
return 0;
}
+static void apr_rxwq(struct work_struct *work) {
+ struct apr *apr = container_of(work, struct apr, rx_work);
+ struct apr_rx_buf *abuf, *b;
+
+ if (!list_empty(&apr->rx_list)) {
+ list_for_each_entry_safe(abuf, b, &apr->rx_list, node) {
+ apr_do_rx_callback(apr, abuf);
+ list_del(&abuf->node);
+ kfree(abuf);
+ }
+ }
+}
+
static int apr_device_match(struct device *dev, struct device_driver *drv)
{
struct apr_device *adev = to_apr_device(dev);
@@ -285,6 +339,14 @@ static int apr_probe(struct rpmsg_device *rpdev)
dev_set_drvdata(dev, apr);
apr->ch = rpdev->ept;
apr->dev = dev;
+ apr->rxwq = create_singlethread_workqueue("qcom_apr_rx");
+ if (!apr->rxwq) {
+ dev_err(apr->dev, "Failed to start Rx WQ\n");
+ return -ENOMEM;
+ }
+ INIT_WORK(&apr->rx_work, apr_rxwq);
+ INIT_LIST_HEAD(&apr->rx_list);
+ spin_lock_init(&apr->rx_lock);
spin_lock_init(&apr->svcs_lock);
idr_init(&apr->svcs_idr);
of_register_apr_devices(dev);
@@ -303,6 +365,9 @@ static int apr_remove_device(struct device *dev, void *null)
static void apr_remove(struct rpmsg_device *rpdev)
{
+ struct apr *apr = dev_get_drvdata(&rpdev->dev);
+
+ destroy_workqueue(apr->rxwq);
device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
}
diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c
new file mode 100644
index 000000000000..75fd07a5a886
--- /dev/null
+++ b/drivers/soc/qcom/kryo-l2-accessors.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/spinlock.h>
+#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
+#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
+
+static DEFINE_RAW_SPINLOCK(l2_access_lock);
+
+/**
+ * kryo_l2_set_indirect_reg() - write value to an L2 register
+ * @reg: Address of L2 register.
+ * @value: Value to be written to register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+void kryo_l2_set_indirect_reg(u64 reg, u64 val)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ write_sysreg_s(val, L2CPUSRDR_EL1);
+ isb();
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+}
+EXPORT_SYMBOL(kryo_l2_set_indirect_reg);
+
+/**
+ * kryo_l2_get_indirect_reg() - read an L2 register value
+ * @reg: Address of L2 register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+u64 kryo_l2_get_indirect_reg(u64 reg)
+{
+ u64 val;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ val = read_sysreg_s(L2CPUSRDR_EL1);
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL(kryo_l2_get_indirect_reg);
diff --git a/include/soc/qcom/kryo-l2-accessors.h b/include/soc/qcom/kryo-l2-accessors.h
new file mode 100644
index 000000000000..673c5344afe3
--- /dev/null
+++ b/include/soc/qcom/kryo-l2-accessors.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H
+#define __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H
+
+void kryo_l2_set_indirect_reg(u64 reg, u64 val);
+u64 kryo_l2_get_indirect_reg(u64 reg);
+
+#endif
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 981f88a5f615..6f205638a8b8 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -11,6 +11,7 @@
#include <linux/regulator/consumer.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <sound/jack.h>
#include <linux/kernel.h>
#include <linux/slimbus.h>
#include <sound/soc.h>
@@ -91,12 +92,18 @@
#define CF_MIN_3DB_75HZ 0x1
#define CF_MIN_3DB_150HZ 0x2
+#define WCD9335_MBHC_MAX_BUTTONS (8)
+
#define WCD9335_SLIM_RX_CH(p) \
{.port = p + WCD9335_RX_START, .shift = p,}
#define WCD9335_SLIM_TX_CH(p) \
{.port = p, .shift = p,}
+static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
+static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
+
/* vout step value */
#define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
@@ -324,6 +331,16 @@ struct wcd9335_codec {
u32 num_rx_port;
u32 num_tx_port;
+ struct snd_soc_jack *jack;
+ bool hphl_jack_type_normally_open;
+ bool gnd_jack_type_normally_open;
+ bool mbhc_btn_enabled;
+ int mbhc_btn0_released;
+ bool detect_accessory_type;
+ int accessory_type;
+ /* Voltage threshold for button detection */
+ u32 vref_btn[WCD9335_MBHC_MAX_BUTTONS];
+
int sido_input_src;
enum wcd9335_sido_voltage sido_voltage;
@@ -2814,7 +2831,6 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(comp, hpf_gate_reg, 0x01, 0x00);
-
if (decimator == 0) {
snd_soc_component_write(comp,
WCD9335_MBHC_ZDET_RAMP_CTL, 0x83);
@@ -2825,7 +2841,6 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
snd_soc_component_write(comp,
WCD9335_MBHC_ZDET_RAMP_CTL, 0x03);
}
-
snd_soc_component_update_bits(comp, hpf_gate_reg,
0x01, 0x01);
snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
@@ -3971,6 +3986,131 @@ static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
return ret;
}
+static irqreturn_t wcd9335_mbhc_sw_irq(int irq, void *data)
+{
+ struct wcd9335_codec *wcd = data;
+ struct snd_soc_component *component = wcd->component;
+ bool ins = false;
+
+ if (snd_soc_component_read32(component, WCD9335_ANA_MBHC_MECH) &
+ WCD9335_MBHC_MECH_DETECT_TYPE_MASK)
+ ins = true;
+
+ /* Set the detection type appropriately */
+ snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_MECH,
+ WCD9335_MBHC_MECH_DETECT_TYPE_MASK,
+ (!ins << WCD9335_MBHC_MECH_DETECT_TYPE_SHIFT));
+
+ if (ins) { /* hs insertion */
+ u32 btndet_curr_src;
+
+ /*
+ * If no micbias is enabled, then enable 100uA internal
+ * current source for Button detection
+ */
+ if (snd_soc_component_read32(component, WCD9335_ANA_MICB2) &
+ WCD9335_ANA_MICB2_ENABLE)
+ btndet_curr_src = WCD9335_ANA_MBHC_BD_ISRC_OFF;
+ else
+ btndet_curr_src = WCD9335_ANA_MBHC_BD_ISRC_100UA;
+
+ snd_soc_component_update_bits(component,
+ WCD9335_ANA_MBHC_ELECT,
+ WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK,
+ btndet_curr_src);
+
+ /*
+ * if only a btn0 press event is receive just before
+ * insert event then its a 3 pole headphone else if
+ * both press and release event received then its
+ * a headset.
+ */
+ if (wcd->mbhc_btn0_released) {
+ snd_soc_jack_report(wcd->jack,
+ SND_JACK_HEADSET, hs_jack_mask);
+ wcd->accessory_type = SND_JACK_HEADSET;
+ } else {
+ snd_soc_jack_report(wcd->jack,
+ SND_JACK_HEADPHONE, hs_jack_mask);
+ wcd->accessory_type = SND_JACK_HEADPHONE;
+ }
+
+ wcd->detect_accessory_type = false;
+
+ } else { /* removal */
+ snd_soc_jack_report(wcd->jack, 0, hs_jack_mask);
+ wcd->detect_accessory_type = true;
+ wcd->mbhc_btn0_released = false;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd9335_mbhc_btn_press_irq(int irq, void *data)
+{
+ struct wcd9335_codec *wcd = data;
+ struct snd_soc_component *comp = wcd->component;
+ u32 btn_result, result;
+
+ /* do not handle any button events for headset without buttons */
+ if (wcd->accessory_type == SND_JACK_HEADPHONE)
+ return IRQ_HANDLED;
+
+ result = snd_soc_component_read32(comp, WCD9335_ANA_MBHC_RESULT_3);
+ btn_result = result & WCD9335_MBHC_BTN_RESULT_MASK;
+
+ switch (btn_result) {
+ case 0xf:
+ snd_soc_jack_report(wcd->jack, SND_JACK_BTN_4, btn_mask);
+ break;
+ case 0x4:
+ snd_soc_jack_report(wcd->jack, SND_JACK_BTN_4, btn_mask);
+ break;
+ case 0x3:
+ snd_soc_jack_report(wcd->jack, SND_JACK_BTN_3, btn_mask);
+ break;
+ case 0x2:
+ snd_soc_jack_report(wcd->jack, SND_JACK_BTN_2, btn_mask);
+ break;
+ case 0x1:
+ snd_soc_jack_report(wcd->jack, SND_JACK_BTN_1, btn_mask);
+ break;
+ case 0x0:
+ /* handle BTN_0 specially for type detection */
+ if (!wcd->detect_accessory_type)
+ snd_soc_jack_report(wcd->jack,
+ SND_JACK_BTN_0, btn_mask);
+ break;
+ default:
+ dev_err(comp->dev,
+ "Unexpected button press result (%x)", btn_result);
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd9335_mbhc_bt_rel_irq(int irq, void *data)
+{
+ struct wcd9335_codec *wcd = data;
+
+
+ if (wcd->detect_accessory_type) {
+ u32 result = snd_soc_component_read32(wcd->component,
+ WCD9335_ANA_MBHC_RESULT_3);
+
+ /* check if its BTN0 thats released */
+ if (!(result & WCD9335_MBHC_BTN_RESULT_MASK))
+ wcd->mbhc_btn0_released = true;
+
+ } else {
+ if (wcd->accessory_type != SND_JACK_HEADPHONE)
+ snd_soc_jack_report(wcd->jack, 0, btn_mask);
+ }
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
{
struct wcd9335_codec *wcd = data;
@@ -4045,11 +4185,95 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
return ret;
}
+static void wcd9335_program_btn_threshold(struct wcd9335_codec *wcd)
+{
+ int i, vth;
+
+ for (i = 0; i < WCD9335_MBHC_MAX_BUTTONS; i++) {
+ vth = ((wcd->vref_btn[i] * 2) / 25) & 0x3F;
+ snd_soc_component_update_bits(wcd->component,
+ WCD9335_ANA_MBHC_BTN0 + i,
+ 0xFC, vth << 2);
+ }
+}
+
+static void wcd9335_mbhc_initialise(struct wcd9335_codec *wcd)
+{
+ struct snd_soc_component *comp = wcd->component;
+ u32 plug_type = 0;
+
+ snd_soc_component_update_bits(comp, WCD9335_MBHC_PLUG_DETECT_CTL,
+ WCD9335_MBHC_HSDET_PULLUP_CTL_MASK,
+ WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA);
+
+ if (wcd->hphl_jack_type_normally_open)
+ plug_type |= WCD9335_MBHC_HPHL_PLUG_TYPE_NO;
+
+ if (wcd->gnd_jack_type_normally_open)
+ plug_type |= WCD9335_MBHC_GND_PLUG_TYPE_NO;
+
+ snd_soc_component_write(wcd->component, WCD9335_ANA_MBHC_MECH,
+ plug_type |
+ WCD9335_MBHC_L_DET_EN |
+ WCD9335_MBHC_HSL_PULLUP_COMP_EN |
+ WCD9335_MBHC_HPHL_100K_TO_GND_EN);
+
+ /* Insertion debounce set to 96ms */
+ snd_soc_component_write(wcd->component,
+ WCD9335_MBHC_PLUG_DETECT_CTL,
+ WCD9335_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS|
+ WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA);
+ /* Button Debounce set to 16ms */
+ snd_soc_component_update_bits(wcd->component, WCD9335_MBHC_CTL_1,
+ WCD9335_MBHC_BTN_DBNC_MASK,
+ WCD9335_MBHC_BTN_DBNC_T_16_MS);
+
+ /* enable bias distribution control */
+ snd_soc_component_update_bits(comp, WCD9335_ANA_MBHC_ELECT,
+ WCD9335_ANA_MBHC_BIAS_EN_MASK,
+ WCD9335_ANA_MBHC_BIAS_EN);
+
+ snd_soc_component_update_bits(wcd->component,
+ WCD9335_ANA_MBHC_ELECT,
+ WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK,
+ WCD9335_ANA_MBHC_BD_ISRC_100UA);
+
+ /* enable MBHC clock */
+ snd_soc_component_update_bits(wcd->component, WCD9335_MBHC_CTL_1,
+ WCD9335_MBHC_CTL_RCO_EN_MASK,
+ WCD9335_MBHC_CTL_RCO_EN);
+
+ snd_soc_component_update_bits(wcd->component, WCD9335_MBHC_CTL_2,
+ WCD9335_MBHC_HS_VREF_CTL_MASK,
+ WCD9335_MBHC_HS_VREF_1P5_V);
+
+ /* program HS_VREF value */
+ wcd9335_program_btn_threshold(wcd);
+ /* Start FSM */
+ snd_soc_component_update_bits(wcd->component, WCD9335_ANA_MBHC_ELECT,
+ BIT(7), BIT(7));
+
+ wcd->mbhc_btn0_released = false;
+ wcd->detect_accessory_type = true;
+}
+
static struct wcd9335_irq wcd9335_irqs[] = {
{
.irq = WCD9335_IRQ_SLIMBUS,
.handler = wcd9335_slimbus_irq,
.name = "SLIM Slave",
+ }, {
+ .irq = WCD9335_IRQ_MBHC_SW_DET,
+ .handler = wcd9335_mbhc_sw_irq,
+ .name = "Headset Mech Insert Removal",
+ }, {
+ .irq = WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+ .handler = wcd9335_mbhc_btn_press_irq,
+ .name = "Headset Button Press",
+ }, {
+ .irq = WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+ .handler = wcd9335_mbhc_bt_rel_irq,
+ .name = "Headset Button Release",
},
};
@@ -4847,6 +5071,7 @@ static void wcd9335_codec_init(struct snd_soc_component *component)
wcd9335_codec_reg_init[i].val);
wcd9335_enable_efuse_sensing(component);
+ wcd9335_mbhc_initialise(wcd);
}
static int wcd9335_codec_probe(struct snd_soc_component *component)
@@ -4902,10 +5127,21 @@ static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp,
return clk_set_rate(wcd->mclk, freq);
}
+static int wcd9335_codec_set_jack(struct snd_soc_component *comp,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+
+ wcd->jack = jack;
+
+ return 0;
+}
+
static const struct snd_soc_component_driver wcd9335_component_drv = {
.probe = wcd9335_codec_probe,
.remove = wcd9335_codec_remove,
.set_sysclk = wcd9335_codec_set_sysclk,
+ .set_jack = wcd9335_codec_set_jack,
.controls = wcd9335_snd_controls,
.num_controls = ARRAY_SIZE(wcd9335_snd_controls),
.dapm_widgets = wcd9335_dapm_widgets,
@@ -4914,10 +5150,39 @@ static const struct snd_soc_component_driver wcd9335_component_drv = {
.num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map),
};
+static void of_parse_mbhc_data(struct device *dev, struct wcd9335_codec *wcd)
+{
+ int rval;
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,hphl-jack-type-normally-open"))
+ wcd->hphl_jack_type_normally_open = true;
+ else
+ wcd->hphl_jack_type_normally_open = false;
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,gnd-jack-type-normally-open"))
+ wcd->gnd_jack_type_normally_open = true;
+ else
+ wcd->gnd_jack_type_normally_open = false;
+
+ wcd->mbhc_btn_enabled = true;
+ rval = of_property_read_u32_array(dev->of_node,
+ "qcom,mbhc-vthreshold",
+ &wcd->vref_btn[0],
+ WCD9335_MBHC_MAX_BUTTONS);
+ if (rval < 0) {
+ wcd->mbhc_btn_enabled = false;
+ dev_err(dev, "MBHC btn detection disabled\n");
+ }
+}
+
static int wcd9335_probe(struct wcd9335_codec *wcd)
{
struct device *dev = wcd->dev;
+ of_parse_mbhc_data(dev, wcd);
+
memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs));
memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs));
@@ -5005,6 +5270,33 @@ static const struct regmap_irq wcd9335_codec_irqs[] = {
.type_reg_mask = BIT(0),
},
},
+ [WCD9335_IRQ_MBHC_SW_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(0),
+ .type = {
+ .type_reg_offset = 1,
+ .types_supported = IRQ_TYPE_EDGE_BOTH,
+ .type_reg_mask = BIT(0),
+ },
+ },
+ [WCD9335_IRQ_MBHC_BUTTON_PRESS_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(2),
+ .type = {
+ .type_reg_offset = 1,
+ .types_supported = IRQ_TYPE_EDGE_BOTH,
+ .type_reg_mask = BIT(2),
+ },
+ },
+ [WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(3),
+ .type = {
+ .type_reg_offset = 1,
+ .types_supported = IRQ_TYPE_EDGE_BOTH,
+ .type_reg_mask = BIT(3),
+ },
+ }
};
static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 94363fd6846a..2bc43618dcc2 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -5,14 +5,21 @@
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <sound/soc.h>
+#include <sound/jack.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <uapi/linux/input-event-codes.h>
#include "common.h"
#define SLIM_MAX_TX_PORTS 16
#define SLIM_MAX_RX_PORTS 16
#define WCD9335_DEFAULT_MCLK_RATE 9600000
+struct apq8096_card_data {
+ struct snd_soc_jack jack;
+ bool jack_setup;
+};
+
static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -67,6 +74,7 @@ static struct snd_soc_ops apq8096_ops = {
static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct apq8096_card_data *data = snd_soc_card_get_drvdata(rtd->card);
/*
* Codec SLIMBUS configuration
@@ -79,6 +87,8 @@ static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
134, 135, 136, 137, 138, 139,
140, 141, 142, 143};
+ struct snd_soc_card *card = rtd->card;
+ int rval;
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
@@ -86,6 +96,38 @@ static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE,
SNDRV_PCM_STREAM_PLAYBACK);
+ if (!data->jack_setup) {
+ struct snd_jack *jack;
+
+ rval = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4,
+ &data->jack, NULL, 0);
+
+ if (rval < 0) {
+ dev_err(card->dev, "Unable to add Headphone Jack\n");
+ return rval;
+ }
+
+ jack = data->jack.jack;
+
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ data->jack_setup = true;
+ }
+
+ rval = snd_soc_component_set_jack(codec_dai->component,
+ &data->jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
+
return 0;
}
@@ -105,6 +147,7 @@ static void apq8096_add_be_ops(struct snd_soc_card *card)
static int apq8096_platform_probe(struct platform_device *pdev)
{
+ struct apq8096_card_data *data;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
int ret;
@@ -113,8 +156,15 @@ static int apq8096_platform_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ kfree(card);
+ return -ENOMEM;
+ }
+
card->dev = dev;
dev_set_drvdata(dev, card);
+ snd_soc_card_set_drvdata(card, data);
ret = qcom_snd_parse_of(card);
if (ret) {
dev_err(dev, "Error parsing OF data\n");
@@ -132,16 +182,19 @@ err_card_register:
kfree(card->dai_link);
err:
kfree(card);
+ kfree(data);
return ret;
}
static int apq8096_platform_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
+ struct apq8096_card_data *data = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card);
kfree(card->dai_link);
kfree(card);
+ kfree(data);
return 0;
}
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 5661025e8cec..231e10b7bb5d 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -90,6 +90,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
link->dynamic = 1;
}
+ link->nonatomic = 1;
link->ignore_suspend = 1;
ret = of_property_read_string(np, "link-name", &link->name);
if (ret) {