Merge "defconfig: msm: Add perf configuration support for sdm670"
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
index 790da12..c811c28 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -25,7 +25,46 @@
- qcom,aux-en-gpio: Specifies the aux-channel enable gpio.
- qcom,aux-sel-gpio: Specifies the aux-channel select gpio.
- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio.
-- qcom,aux-cfg-settings: An array that specifies the DP AUX configuration settings.
+- qcom,aux-cfg0-settings: Specifies the DP AUX configuration 0 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg1-settings: Specifies the DP AUX configuration 1 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg2-settings: Specifies the DP AUX configuration 2 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg3-settings: Specifies the DP AUX configuration 3 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg4-settings: Specifies the DP AUX configuration 4 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg5-settings: Specifies the DP AUX configuration 5 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg6-settings: Specifies the DP AUX configuration 6 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg7-settings: Specifies the DP AUX configuration 7 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg8-settings: Specifies the DP AUX configuration 8 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
+- qcom,aux-cfg9-settings: Specifies the DP AUX configuration 9 settings. The first
+ entry in this array corresponds to the register offset
+ within DP AUX, while the remaining entries indicate the
+ programmable values.
- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port.
- qcom,dp-usbpd-detection: Phandle for the PMI regulator node for USB PHY PD detection.
- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the a particular "type" of DSI module. The module "types"
@@ -93,7 +132,16 @@
qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
- qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+ qcom,aux-cfg0-settings = [1c 00];
+ qcom,aux-cfg1-settings = [20 13 23 1d];
+ qcom,aux-cfg2-settings = [24 00];
+ qcom,aux-cfg3-settings = [28 00];
+ qcom,aux-cfg4-settings = [2c 0a];
+ qcom,aux-cfg5-settings = [30 26];
+ qcom,aux-cfg6-settings = [34 0a];
+ qcom,aux-cfg7-settings = [38 03];
+ qcom,aux-cfg8-settings = [3c bb];
+ qcom,aux-cfg9-settings = [40 03];
qcom,max-pclk-frequency-khz = <593470>;
pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index 1e6aac5..42e97f7 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -78,6 +78,8 @@
- qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be
controlled dynamically when WLED module is enabled
or disabled.
+- qcom,auto-calibration-enable : A boolean property which enables auto-calibration
+ of the WLED sink configuration.
Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
- qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320.
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 0123682..d0d878b 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -385,6 +385,11 @@
property "qcom,slope-limit-temp-threshold" to make dynamic
slope limit adjustment functional.
+- qcom,fg-bmd-en-delay-ms
+ Usage: optional
+ Value type: <u32>
+ Definition: The delay in ms for FG to enable BMD after reading RID.
+
==========================================================
Second Level Nodes - Peripherals managed by FG Gen3 driver
==========================================================
diff --git a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
index 8bead0d..be50d45 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
+++ b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
@@ -31,12 +31,29 @@
Definition: Should specify the cluster affinity this hardware
corresponds to.
+- isens_vref-supply:
+ Usage: optional
+ Value type: <phandle>
+ Definition: Should specify the phandle of the vref regulator used by
+ the isens hardware. This active only regulator will be
+ enabled by LMH DCVSh.
+
+- isens-vref-settings:
+ Usage: optional
+ Value type: <u32 array>
+ Definition: Should specify the min voltage(uV), max voltage(uV) and
+ max load(uA) for the isens vref regulator. This
+ property is valid only if there is valid entry for
+ isens_vref-supply.
+
Example:
lmh_dcvs0: qcom,limits-dcvs@0 {
compatible = "qcom,msm-hw-limits";
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
qcom,affinity = <0>;
+ isens_vref-supply = <&pm8998_l1_ao>;
+ isens-vref-settings = <880000 880000 36000>;
};
CPU0: cpu@0 {
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 9bf3f79..cb2c9f4 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -116,6 +116,21 @@
static void __dma_page_dev_to_cpu(struct page *, unsigned long,
size_t, enum dma_data_direction);
+static void *
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
+ const void *caller);
+
+static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn);
+
+static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot);
+
+static void *arm_dma_remap(struct device *dev, void *cpu_addr,
+ dma_addr_t handle, size_t size,
+ unsigned long attrs);
+
+static void arm_dma_unremap(struct device *dev, void *remapped_addr,
+ size_t size);
+
/**
* arm_dma_map_page - map a portion of a page for streaming DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -197,6 +212,8 @@
.sync_single_for_device = arm_dma_sync_single_for_device,
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
.sync_sg_for_device = arm_dma_sync_sg_for_device,
+ .remap = arm_dma_remap,
+ .unremap = arm_dma_unremap,
};
EXPORT_SYMBOL(arm_dma_ops);
@@ -917,6 +934,38 @@
return ret;
}
+static void *arm_dma_remap(struct device *dev, void *cpu_addr,
+ dma_addr_t handle, size_t size,
+ unsigned long attrs)
+{
+ void *ptr;
+ struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
+ unsigned long offset = handle & ~PAGE_MASK;
+
+ size = PAGE_ALIGN(size + offset);
+ ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot,
+ __builtin_return_address(0));
+ return ptr ? ptr + offset : ptr;
+}
+
+static void arm_dma_unremap(struct device *dev, void *remapped_addr,
+ size_t size)
+{
+ unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
+ struct vm_struct *area;
+
+ remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK);
+
+ area = find_vm_area(remapped_addr);
+ if (!area || (area->flags & flags) != flags) {
+ WARN(1, "trying to free invalid coherent area: %p\n",
+ remapped_addr);
+ return;
+ }
+
+ vunmap(remapped_addr);
+}
/*
* Create userspace mapping for the DMA-coherent memory.
*/
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 40fa801..56e74be 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -24,7 +24,6 @@
#global-interrupts = <2>;
qcom,regulator-names = "vdd";
vdd-supply = <&gpu_cx_gdsc>;
- qcom,deferred-regulator-disable-delay = <80>;
interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
index bc0b118..0d2f9e8 100644
--- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -85,7 +85,7 @@
compatible = "qcom,msm-pcm-loopback";
};
- qcom,msm-dai-mi2s {
+ msm_dai_mi2s: qcom,msm-dai-mi2s {
compatible = "qcom,msm-dai-mi2s";
dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
compatible = "qcom,msm-dai-q6-mi2s";
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 9cd117c..075eaef2 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -269,6 +269,7 @@
qcom,led-strings-list = [00 01 02];
qcom,loop-auto-gm-en;
qcom,pmic-revid = <&pm660l_revid>;
+ qcom,auto-calibration-enable;
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 09405ee..12b469c 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -563,6 +563,7 @@
qcom,en-ext-pfet-sc-pro;
qcom,pmic-revid = <&pmi8998_revid>;
qcom,loop-auto-gm-en;
+ qcom,auto-calibration-enable;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
new file mode 100644
index 0000000..3bd0350
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm-audio-lpass.dtsi"
+#include "sdm670-wsa881x.dtsi"
+#include "sdm670-wcd.dtsi"
+#include "sdm670-lpi.dtsi"
+#include <dt-bindings/clock/qcom,audio-ext-clk.h>
+
+&msm_audio_ion {
+ iommus = <&apps_smmu 0x1801 0x0>;
+ qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&soc {
+ qcom,avtimer@62cf700c {
+ compatible = "qcom,avtimer";
+ reg = <0x62cf700c 0x4>,
+ <0x62cf7010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <192>;
+ qcom,clk-mult = <10>;
+ };
+
+ tavil_snd: sound-tavil {
+ status = "disabled";
+ compatible = "qcom,sdm670-asoc-snd-tavil";
+ qcom,model = "sdm670-tavil-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "hifi amp", "LINEOUT1",
+ "hifi amp", "LINEOUT2",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,hph-en0-gpio = <&tavil_hph_en0>;
+ qcom,hph-en1-gpio = <&tavil_hph_en1>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_rx>, <&sb_5_tx>,
+ <&sb_6_rx>, <&sb_7_rx>, <&sb_7_tx>,
+ <&sb_8_rx>, <&sb_8_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16394", "msm-dai-q6-dev.16395",
+ "msm-dai-q6-dev.16396",
+ "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399",
+ "msm-dai-q6-dev.16400", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+int_codec: sound {
+ status = "okay";
+ compatible = "qcom,sdm670-asoc-snd";
+ qcom,model = "sdm670-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,msm-micbias2-ext-cap;
+ qcom,msm-hs-micbias-type = "external";
+ qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
+ qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+ qcom,audio-routing =
+ "RX_BIAS", "INT_MCLK0",
+ "SPK_RX_BIAS", "INT_MCLK0",
+ "INT_LDO_H", "INT_MCLK0",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS External2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS External2",
+ "AMIC3", "MIC BIAS External",
+ "DMIC1", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic1",
+ "DMIC2", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic2",
+ "DMIC3", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic3",
+ "DMIC4", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic4",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT",
+ "PDM_IN_RX1", "PDM_OUT_RX1",
+ "PDM_IN_RX2", "PDM_OUT_RX2",
+ "PDM_IN_RX3", "PDM_OUT_RX3",
+ "ADC1_IN", "ADC1_OUT",
+ "ADC2_IN", "ADC2_OUT",
+ "ADC3_IN", "ADC3_OUT";
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_int_mi2s0>, <&dai_int_mi2s1>,
+ <&dai_int_mi2s2>, <&dai_int_mi2s3>,
+ <&dai_int_mi2s4>, <&dai_int_mi2s5>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_7_rx>, <&sb_7_tx>,
+ <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.7", "msm-dai-q6-mi2s.8",
+ "msm-dai-q6-mi2s.9", "msm-dai-q6-mi2s.10",
+ "msm-dai-q6-mi2s.11", "msm-dai-q6-mi2s.12",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399",
+ "msm-dai-q6-dev.16401", "msm-dai-q6-dev.16400",
+ "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+ <&pmic_analog_codec>, <&msm_sdw_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+ "analog-codec", "msm_sdw_codec";
+
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>,
+ <&wsa881x_213_en>, <&wsa881x_214_en>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ cdc_pdm_gpios: cdc_pdm_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active
+ &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active
+ &cdc_pdm_2_gpios_active>;
+ pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep
+ &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep
+ &cdc_pdm_2_gpios_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_comp_gpios: cdc_comp_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>;
+ pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_dmic_gpios: cdc_dmic_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_dmic12_gpios_active
+ &cdc_dmic34_gpios_active>;
+ pinctrl-1 = <&cdc_dmic12_gpios_sleep
+ &cdc_dmic34_gpios_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_sdw_gpios: sdw_clk_data_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&sdw_clk_active &sdw_data_active>;
+ pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>;
+ };
+
+ wsa_spkr_en1: wsa_spkr_en1_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_sd_n_active>;
+ pinctrl-1 = <&spkr_1_sd_n_sleep>;
+ };
+
+ wsa_spkr_en2: wsa_spkr_en2_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_sd_n_active>;
+ pinctrl-1 = <&spkr_2_sd_n_sleep>;
+ };
+
+ msm_sdw_codec: msm-sdw-codec@62ec1000 {
+ status = "okay";
+ compatible = "qcom,msm-sdw-codec";
+ reg = <0x62ec1000 0x0>;
+ interrupts = <0 161 0>;
+ interrupt-names = "swr_master_irq";
+ qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
+
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211_en: wsa881x_en@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
+ };
+
+ wsa881x_212_en: wsa881x_en@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
+ };
+
+ wsa881x_213_en: wsa881x_en@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
+ };
+
+ wsa881x_214_en: wsa881x_en@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
+ };
+ };
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ status = "disabled";
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ qcom,gpio-connect = <&tlmm 80 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
+ };
+
+ clock_audio_lnbb: audio_ext_clk_lnbb {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ clocks = <&clock_rpmh RPMH_LN_BB_CLK2>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ };
+
+ wcd_rst_gpio: msm_cdc_pinctrl@64 {
+ status = "disabled";
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&lpi_cdc_reset_active>;
+ pinctrl-1 = <&lpi_cdc_reset_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
+ cpe3: qcom,msm-cpe-lsm@3 {
+ compatible = "qcom,msm-cpe-lsm";
+ qcom,msm-cpe-lsm-id = <3>;
+ };
+
+ wdsp_mgr: qcom,wcd-dsp-mgr {
+ compatible = "qcom,wcd-dsp-mgr";
+ qcom,wdsp-components = <&wcd934x_cdc 0>,
+ <&wcd_spi_0 1>,
+ <&glink_spi_xprt_wdsp 2>;
+ qcom,img-filename = "cpe_9340";
+ };
+
+ wdsp_glink: qcom,wcd-dsp-glink {
+ compatible = "qcom,wcd-dsp-glink";
+ };
+};
+
+&slim_aud {
+ status = "disabled";
+ dai_slim: msm_dai_slim {
+ status = "disabled";
+ compatible = "qcom,msm-dai-slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ wcd934x_cdc: tavil_codec {
+ status = "disabled";
+ compatible = "qcom,tavil-slim-pgd";
+ elemental-addr = [00 01 50 02 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30 31>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk";
+ clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>;
+
+ cdc-vdd-mic-bias-supply = <&pm660l_bob>;
+ qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>;
+ qcom,cdc-vdd-mic-bias-current = <30400>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-mic-bias";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tavil-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+
+ qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+
+ wcd_spi_0: wcd_spi {
+ compatible = "qcom,wcd-spi-v2";
+ qcom,master-bus-num = <8>;
+ qcom,chip-select = <0>;
+ qcom,max-frequency = <24000000>;
+ qcom,mem-base-addr = <0x100000>;
+ };
+
+ wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wcd_usbc_analog_en1_active>;
+ pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
+ };
+ };
+};
+
+&msm_dai_mi2s {
+ dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <7>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <8>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <9>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <10>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <11>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <12>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <13>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+};
+
+&pm660l_3 {
+ pmic_analog_codec: analog-codec@f000 {
+ status = "okay";
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x3 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int",
+ "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+
+
+ cdc-vdda-cp-supply = <&pm660_s4>;
+ qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+ qcom,cdc-vdda-cp-current = <50000>;
+
+ cdc-vdd-pa-supply = <&pm660_s4>;
+ qcom,cdc-vdd-pa-voltage = <2040000 2040000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm660l_l7>;
+ qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdda-cp",
+ "cdc-vdd-pa";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+ /*
+ * Not marking address @ as driver searches this child
+ * with name msm-dig-codec
+ */
+ msm_digital_codec: msm-dig-codec {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0x62ec0000 0x0>;
+ };
+ };
+};
+
+&pm660_gpios {
+ gpio@c200 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <4>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
new file mode 100644
index 0000000..6e92f0e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
@@ -0,0 +1,284 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ lpi_tlmm: lpi_pinctrl@62b40000 {
+ compatible = "qcom,lpi-pinctrl";
+ reg = <0x62b40000 0x0>;
+ qcom,num-gpios = <32>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ cdc_pdm_clk_active: cdc_pdm_clk_active {
+ mux {
+ pins = "gpio18";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio18";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_clk_sleep: cdc_pdm_clk_sleep {
+ mux {
+ pins = "gpio18";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio18";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_sync_active: cdc_pdm_sync_active {
+ mux {
+ pins = "gpio19";
+ function = "func3";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_sync_sleep: cdc_pdm_sync_sleep {
+ mux {
+ pins = "gpio19";
+ function = "func3";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_rx0_active: cdc_pdm_rx0_active {
+ mux {
+ pins = "gpio21";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_rx0_sleep: cdc_pdm_rx0_sleep {
+ mux {
+ pins = "gpio21";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_rx1_2_active: cdc_pdm_rx1_2_active {
+ mux {
+ pins = "gpio23", "gpio25";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio23", "gpio25";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_pdm_rx1_2_sleep: cdc_pdm_rx1_2_sleep {
+ mux {
+ pins = "gpio23", "gpio25";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio23", "gpio25";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_pdm_2_gpios_active: cdc_pdm_2_gpios_active {
+ mux {
+ pins = "gpio20";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_pdm_2_gpios_sleep: cdc_pdm_2_gpios_sleep {
+ mux {
+ pins = "gpio20";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cdc_rx0_comp_active: cdc_pdm_rx0_comp_active {
+ mux {
+ pins = "gpio22";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_rx0_comp_sleep: cdc_pdm_rx0_comp_sleep {
+ mux {
+ pins = "gpio22";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cdc_rx1_comp_active: cdc_pdm_rx1_comp_active {
+ mux {
+ pins = "gpio24";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio24";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_rx1_comp_sleep: cdc_pdm_rx1_comp_sleep {
+ mux {
+ pins = "gpio24";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio24";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ lpi_cdc_reset_active: lpi_cdc_reset_active {
+ mux {
+ pins = "gpio29";
+ function = "func2";
+ };
+ config {
+ pins = "gpio29";
+ drive-strength = <16>;
+ output-high;
+ };
+ };
+
+ lpi_cdc_reset_sleep: lpi_cdc_reset_sleep {
+ mux {
+ pins = "gpio29";
+ function = "func2";
+ };
+
+ config {
+ pins = "gpio29";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_dmic12_gpios_active: dmic12_gpios_active {
+ mux {
+ pins = "gpio26", "gpio28";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio26", "gpio28";
+ drive-strength = <8>;
+ output-high;
+ };
+ };
+
+ cdc_dmic12_gpios_sleep: dmic12_gpios_sleep {
+ mux {
+ pins = "gpio26", "gpio28";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio26", "gpio28";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+
+ cdc_dmic34_gpios_active: dmic34_gpios_active {
+ mux {
+ pins = "gpio27", "gpio29";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio27", "gpio29";
+ drive-strength = <8>;
+ input-enable;
+ };
+ };
+
+ cdc_dmic34_gpios_sleep: dmic34_gpios_sleep {
+ mux {
+ pins = "gpio27", "gpio29";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio27", "gpio29";
+ drive-strength = <2>;
+ pull-down;
+ input-enable;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index 46d4aa6..73df253 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -1244,5 +1244,198 @@
};
};
+ /* USB C analog configuration */
+ wcd_usbc_analog_en1 {
+ wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle {
+ mux {
+ pins = "gpio49";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio49";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+ };
+
+ wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active {
+ mux {
+ pins = "gpio49";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio49";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ sdw_clk_pin {
+ sdw_clk_sleep: sdw_clk_sleep {
+ mux {
+ pins = "gpio65";
+ function = "wsa_clk";
+ };
+
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+ };
+
+ sdw_clk_active: sdw_clk_active {
+ mux {
+ pins = "gpio65";
+ function = "wsa_clk";
+ };
+
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+ };
+ };
+
+ sdw_data_pin {
+ sdw_data_sleep: sdw_data_sleep {
+ mux {
+ pins = "gpio66";
+ function = "wsa_data";
+ };
+
+ config {
+ pins = "gpio66";
+ drive-strength = <4>;
+ bias-bus-hold;
+ };
+ };
+
+ sdw_data_active: sdw_data_active {
+ mux {
+ pins = "gpio66";
+ function = "wsa_data";
+ };
+
+ config {
+ pins = "gpio66";
+ drive-strength = <4>;
+ bias-bus-hold;
+ };
+ };
+ };
+
+ /* WSA speaker reset pins */
+ spkr_1_sd_n {
+ spkr_1_sd_n_sleep: spkr_1_sd_n_sleep {
+ mux {
+ pins = "gpio67";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_1_sd_n_active: spkr_1_sd_n_active {
+ mux {
+ pins = "gpio67";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ spkr_2_sd_n {
+ spkr_2_sd_n_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_2_sd_n_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ wcd_gnd_mic_swap {
+ wcd_gnd_mic_swap_idle: wcd_gnd_mic_swap_idle {
+ mux {
+ pins = "gpio40";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+ };
+
+ wcd_gnd_mic_swap_active: wcd_gnd_mic_swap_active {
+ mux {
+ pins = "gpio40";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ wcd9xxx_intr {
+ wcd_intr_default: wcd_intr_default{
+ mux {
+ pins = "gpio80";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio80";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ input-enable;
+ };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi
new file mode 100644
index 0000000..f8d2a04
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi
@@ -0,0 +1,167 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&slim_aud {
+ tavil_codec {
+ wcd: wcd_pinctrl@5 {
+ compatible = "qcom,wcd-pinctrl";
+ qcom,num-gpios = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ us_euro_sw_wcd_active: us_euro_sw_wcd_active {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-high;
+ };
+ };
+
+ us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-low;
+ };
+ };
+
+ spkr_1_wcd_en_active: spkr_1_wcd_en_active {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ output-high;
+ };
+ };
+
+ spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ input-enable;
+ };
+ };
+
+ spkr_2_wcd_en_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ output-high;
+ };
+ };
+
+ spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ input-enable;
+ };
+ };
+
+ hph_en0_wcd_active: hph_en0_wcd_active {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-high;
+ };
+ };
+
+ hph_en0_wcd_sleep: hph_en0_wcd_sleep {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-low;
+ };
+ };
+
+ hph_en1_wcd_active: hph_en1_wcd_active {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-high;
+ };
+ };
+
+ hph_en1_wcd_sleep: hph_en1_wcd_sleep {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-low;
+ };
+ };
+ };
+
+ wsa_spkr_wcd_sd1: msm_cdc_pinctrll {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_wcd_en_active>;
+ pinctrl-1 = <&spkr_1_wcd_en_sleep>;
+ };
+
+ wsa_spkr_wcd_sd2: msm_cdc_pinctrlr {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_wcd_en_active>;
+ pinctrl-1 = <&spkr_2_wcd_en_sleep>;
+ };
+
+ tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&us_euro_sw_wcd_active>;
+ pinctrl-1 = <&us_euro_sw_wcd_sleep>;
+ };
+
+ tavil_hph_en0: msm_cdc_pinctrl_hph_en0 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en0_wcd_active>;
+ pinctrl-1 = <&hph_en0_wcd_sleep>;
+ };
+
+ tavil_hph_en1: msm_cdc_pinctrl_hph_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en1_wcd_active>;
+ pinctrl-1 = <&hph_en1_wcd_sleep>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi
new file mode 100644
index 0000000..c35850d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi
@@ -0,0 +1,45 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&slim_aud {
+ tavil_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_0211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+
+ wsa881x_0213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 9cdb4ce..0dec428 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -1815,6 +1815,89 @@
qcom,scaling-lower-bus-speed-mode = "DDR52";
status = "disabled";
};
+
+ qcom,msm-cdsp-loader {
+ compatible = "qcom,cdsp-loader";
+ qcom,proc-img-to-load = "cdsp";
+ };
+
+ qcom,msm-adsprpc-mem {
+ compatible = "qcom,msm-adsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
+ qcom,msm_fastrpc {
+ compatible = "qcom,msm-fastrpc-compute";
+
+ qcom,msm_fastrpc_compute_cb1 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1421 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb2 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1422 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb3 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1423 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb4 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1424 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb5 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1425 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb6 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ iommus = <&apps_smmu 0x1426 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb7 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ qcom,secure-context-bank;
+ iommus = <&apps_smmu 0x1429 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb8 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ qcom,secure-context-bank;
+ iommus = <&apps_smmu 0x142A 0x30>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb9 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1803 0x0>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb10 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1804 0x0>;
+ dma-coherent;
+ };
+ qcom,msm_fastrpc_compute_cb11 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1805 0x0>;
+ dma-coherent;
+ };
+ };
};
#include "sdm670-pinctrl.dtsi"
@@ -1911,3 +1994,4 @@
#include "pm660.dtsi"
#include "pm660l.dtsi"
#include "sdm670-regulator.dtsi"
+#include "sdm670-audio.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 941e94d..a2c3450 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -104,18 +104,18 @@
qcom,msm-bus,vectors-KBps =
<26 512 0 0>,
- <26 512 0 800000>, // 1 bus=100
- <26 512 0 1200000>, // 2 bus=150
- <26 512 0 1600000>, // 3 bus=200
- <26 512 0 2400000>, // 4 bus=300
- <26 512 0 3296000>, // 5 bus=412
- <26 512 0 4376000>, // 6 bus=547
- <26 512 0 5448000>, // 7 bus=681
- <26 512 0 6144000>, // 8 bus=768
- <26 512 0 8136000>, // 9 bus=1017
- <26 512 0 10368000>, // 10 bus=1296
- <26 512 0 12440000>, // 11 bus=1555
- <26 512 0 14432000>; // 12 bus=1804
+ <26 512 0 400000>, // 1 bus=100
+ <26 512 0 600000>, // 2 bus=150
+ <26 512 0 800000>, // 3 bus=200
+ <26 512 0 1200000>, // 4 bus=300
+ <26 512 0 1648000>, // 5 bus=412
+ <26 512 0 2188000>, // 6 bus=547
+ <26 512 0 2724000>, // 7 bus=681
+ <26 512 0 3072000>, // 8 bus=768
+ <26 512 0 4068000>, // 9 bus=1017
+ <26 512 0 5184000>, // 10 bus=1296
+ <26 512 0 6220000>, // 11 bus=1555
+ <26 512 0 7216000>; // 12 bus=1804
/* GDSC regulator names */
regulator-names = "vddcx", "vdd";
@@ -214,7 +214,7 @@
qcom,gpu-pwrlevel@5 {
reg = <5>;
qcom,gpu-freq = <280000000>;
- qcom,bus-freq = <6>;
+ qcom,bus-freq = <5>;
qcom,bus-min = <5>;
qcom,bus-max = <7>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 7049eb9..b9e9c34 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -31,27 +31,40 @@
};
&dsi_dual_nt35597_truly_video_display {
- /delete-property/ vddio-supply;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
};
&dsi_dual_nt35597_truly_cmd_display {
- /delete-property/ vddio-supply;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
};
&dsi_nt35597_truly_dsc_cmd_display {
- /delete-property/ vddio-supply;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
};
&dsi_nt35597_truly_dsc_video_display {
- /delete-property/ vddio-supply;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
};
&sde_dp {
+ status = "disabled";
/delete-property/ vdda-1p2-supply;
/delete-property/ vdda-0p9-supply;
/delete-property/ qcom,dp-usbpd-detection;
};
+&mdss_dp_pll {
+ status = "disabled";
+};
+
&bluetooth {
/delete-property/ qca,bt-vdd-io-supply;
/delete-property/ qca,bt-vdd-xtal-supply;
@@ -245,19 +258,19 @@
};
qcom,mdss_dsi_ctrl0@ae94000 {
- /delete-property/ vdda-1p2-supply;
+ vdda-1p2-supply = <&pm660_l1>;
};
qcom,mdss_dsi_ctrl1@ae96000 {
- /delete-property/ vdda-1p2-supply;
+ vdda-1p2-supply = <&pm660_l1>;
};
qcom,mdss_dsi_phy0@ae94400 {
- /delete-property/ vdda-0p9-supply;
+ vdda-0p9-supply = <&pm660l_l1>;
};
qcom,mdss_dsi_phy0@ae96400 {
- /delete-property/ vdda-0p9-supply;
+ vdda-0p9-supply = <&pm660l_l1>;
};
gpio-regulator@1 {
@@ -374,3 +387,7 @@
&soc {
/delete-node/ thermal-zones;
};
+
+&pm660l_wled {
+ qcom,led-strings-list = [01 02];
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 9b683cc..c0afb74 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -84,6 +84,7 @@
&pmi8998_fg {
qcom,battery-data = <&qrd_batterydata>;
+ qcom,fg-bmd-en-delay-ms = <300>;
};
&smb1355_charger {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index d569b52..21aedbf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -411,7 +411,17 @@
qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
- qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+ qcom,aux-cfg0-settings = [20 00];
+ qcom,aux-cfg1-settings = [24 13 23 1d];
+ qcom,aux-cfg2-settings = [28 24];
+ qcom,aux-cfg3-settings = [2c 00];
+ qcom,aux-cfg4-settings = [30 0a];
+ qcom,aux-cfg5-settings = [34 26];
+ qcom,aux-cfg6-settings = [38 0a];
+ qcom,aux-cfg7-settings = [3c 03];
+ qcom,aux-cfg8-settings = [40 bb];
+ qcom,aux-cfg9-settings = [44 03];
+
qcom,max-pclk-frequency-khz = <576000>;
qcom,core-supply-entries {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index 8c3ac9c..40c677f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -21,6 +21,8 @@
reg = <0x0a600000 0xf8c00>,
<0x088ee000 0x400>;
reg-names = "core_base", "ahb2phy_base";
+ iommus = <&apps_smmu 0x740 0x0>;
+ qcom,smmu-s1-bypass;
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -331,6 +333,8 @@
reg = <0x0a800000 0xf8c00>,
<0x088ee000 0x400>;
reg-names = "core_base", "ahb2phy_base";
+ iommus = <&apps_smmu 0x760 0x0>;
+ qcom,smmu-s1-bypass;
#address-cells = <1>;
#size-cells = <1>;
ranges;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 41164cd..fe29336 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -935,10 +935,9 @@
qcom,core-dev-table =
< 300000 762 >,
< 748800 1720 >,
- < 979200 2929 >,
- < 1209600 3879 >,
- < 1516800 4943 >,
- < 1593600 5931 >;
+ < 1132800 2086 >,
+ < 1440000 2929 >,
+ < 1593600 3879 >;
};
devfreq_memlat_4: qcom,cpu4-memlat-mon {
@@ -948,10 +947,12 @@
qcom,cachemiss-ev = <0x2A>;
qcom,core-dev-table =
< 300000 762 >,
+ < 499200 1720 >,
+ < 806400 2086 >,
< 1036800 2929 >,
< 1190400 3879 >,
< 1574400 4943 >,
- < 1804800 5931 >,
+ < 1728000 5931 >,
< 1958400 6881 >;
};
@@ -1337,8 +1338,6 @@
<1000 1000 1000>;
qcom,down-timer =
<100000 100000 100000>;
- qcom,pc-override-index =
- <0 0 0>;
qcom,set-ret-inactive;
qcom,enable-llm-freq-vote;
qcom,llm-freq-up-timer =
@@ -2543,18 +2542,6 @@
qcom,fragmented-data;
};
- qcom,qsee_ipc_irq_bridge {
- compatible = "qcom,qsee-ipc-irq-bridge";
-
- qcom,qsee-ipq-irq-spss {
- qcom,rx-irq-clr = <0x1888008 0x4>;
- qcom,rx-irq-clr-mask = <0x2>;
- qcom,dev-name = "qsee_ipc_irq_spss";
- interrupts = <0 349 4>;
- label = "spss";
- };
- };
-
qcom,spcom {
compatible = "qcom,spcom";
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index cd1d361..a1c5710 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -529,7 +529,6 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
-CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index c26a3c4..0940b48 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -550,7 +550,6 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
-CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index aa5e22c..7c8f6bf 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -306,7 +306,7 @@
unsigned long vm_flags,
pgprot_t prot, const void *caller)
{
- int i;
+ unsigned long i;
struct page **pages;
void *ptr;
unsigned long pfn;
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index b5c42fcc..e4ee2a7 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -26,6 +26,9 @@
#include <sound/tlv.h>
#include <btfm_slim.h>
+static int bt_soc_enable_status;
+
+
static int btfm_slim_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -38,8 +41,31 @@
return 0;
}
+static int bt_soc_status_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = bt_soc_enable_status;
+ return 1;
+}
+
+static int bt_soc_status_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 1;
+}
+
+static const struct snd_kcontrol_new status_controls[] = {
+ SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0,
+ bt_soc_status_get,
+ bt_soc_status_put)
+
+};
+
+
static int btfm_slim_codec_probe(struct snd_soc_codec *codec)
{
+ snd_soc_add_codec_controls(codec, status_controls,
+ ARRAY_SIZE(status_controls));
return 0;
}
@@ -130,6 +156,7 @@
struct btfmslim *btfmslim = dai->dev->platform_data;
struct btfmslim_ch *ch;
uint8_t rxport, grp = false, nchan = 1;
+ bt_soc_enable_status = 0;
BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
dai->id, dai->rate);
@@ -171,6 +198,10 @@
}
ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, grp, nchan);
+
+ /* save the enable channel status */
+ if (ret == 0)
+ bt_soc_enable_status = 1;
return ret;
}
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index d1e01bd..2ede69e 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -2186,9 +2186,11 @@
kref_init(&me->channel[cid].kref);
pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
- err = glink_queue_rx_intent(me->channel[cid].chan, NULL, 64);
+ err = glink_queue_rx_intent(me->channel[cid].chan, NULL, 16);
+ err |= glink_queue_rx_intent(me->channel[cid].chan, NULL, 64);
if (err)
- pr_info("adsprpc: initial intent failed for %d\n", cid);
+ pr_warn("adsprpc: initial intent fail for %d err %d\n",
+ cid, err);
if (me->channel[cid].ssrcount !=
me->channel[cid].prevssrcount) {
me->channel[cid].prevssrcount =
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index a0a9ab6..177bbdb 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -69,6 +69,7 @@
"Uses Device Tree: %d\n"
"Apps Supports Separate CMDRSP: %d\n"
"Apps Supports HDLC Encoding: %d\n"
+ "Apps Supports Header Untagging: %d\n"
"Apps Supports Sockets: %d\n"
"Logging Mode: %d\n"
"RSP Buffer is Busy: %d\n"
@@ -83,6 +84,7 @@
driver->use_device_tree,
driver->supports_separate_cmdrsp,
driver->supports_apps_hdlc_encoding,
+ driver->supports_apps_header_untagging,
driver->supports_sockets,
driver->logging_mode,
driver->rsp_buf_busy,
@@ -94,7 +96,7 @@
for (i = 0; i < NUM_PERIPHERALS; i++) {
ret += scnprintf(buf+ret, buf_size-ret,
- "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c|\n",
+ "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c|\n",
PERIPHERAL_STRING(i),
driver->feature[i].feature_mask[0],
driver->feature[i].feature_mask[1],
@@ -105,7 +107,8 @@
driver->feature[i].mask_centralization ? 'M':'m',
driver->feature[i].stm_support ? 'Q':'q',
driver->feature[i].sockets_enabled ? 'S':'s',
- driver->feature[i].sent_feature_mask ? 'T':'t');
+ driver->feature[i].sent_feature_mask ? 'T':'t',
+ driver->feature[i].untag_header ? 'U':'u');
}
#ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 8aefb5a1..d734e29 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -28,7 +28,8 @@
#define DIAG_SET_FEATURE_MASK(x) (feature_bytes[(x)/8] |= (1 << (x & 0x7)))
#define diag_check_update(x) \
- (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x)))) \
+ (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x))) \
+ || (info && (info->peripheral_mask & MD_PERIPHERAL_PD_MASK(x)))) \
struct diag_mask_info msg_mask;
struct diag_mask_info msg_bt_mask;
@@ -90,8 +91,8 @@
int err = 0;
int send_once = 0;
int header_len = sizeof(struct diag_ctrl_log_mask);
- uint8_t *buf = NULL;
- uint8_t *temp = NULL;
+ uint8_t *buf = NULL, *temp = NULL;
+ uint8_t upd = 0;
uint32_t mask_size = 0;
struct diag_ctrl_log_mask ctrl_pkt;
struct diag_mask_info *mask_info = NULL;
@@ -107,11 +108,25 @@
return;
}
- if (driver->md_session_mask != 0 &&
- driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))
- mask_info = driver->md_session_map[peripheral]->log_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->log_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->log_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &log_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -196,8 +211,8 @@
static void diag_send_event_mask_update(uint8_t peripheral)
{
- uint8_t *buf = NULL;
- uint8_t *temp = NULL;
+ uint8_t *buf = NULL, *temp = NULL;
+ uint8_t upd = 0;
struct diag_ctrl_event_mask header;
struct diag_mask_info *mask_info = NULL;
int num_bytes = EVENT_COUNT_TO_BYTES(driver->last_event_id);
@@ -221,11 +236,25 @@
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->event_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->event_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->event_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &event_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -285,8 +314,8 @@
int err = 0;
int header_len = sizeof(struct diag_ctrl_msg_mask);
int temp_len = 0;
- uint8_t *buf = NULL;
- uint8_t *temp = NULL;
+ uint8_t *buf = NULL, *temp = NULL;
+ uint8_t upd = 0;
uint32_t mask_size = 0;
struct diag_mask_info *mask_info = NULL;
struct diag_msg_mask_t *mask = NULL;
@@ -303,11 +332,25 @@
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->msg_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->msg_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->msg_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &msg_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -466,6 +509,13 @@
DIAG_SET_FEATURE_MASK(F_DIAG_REQ_RSP_SUPPORT);
if (driver->supports_apps_hdlc_encoding)
DIAG_SET_FEATURE_MASK(F_DIAG_APPS_HDLC_ENCODE);
+ if (driver->supports_apps_header_untagging) {
+ if (peripheral == PERIPHERAL_MODEM) {
+ DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG);
+ driver->peripheral_untag[peripheral] =
+ ENABLE_PKT_HEADER_UNTAGGING;
+ }
+ }
DIAG_SET_FEATURE_MASK(F_DIAG_MASK_CENTRALIZATION);
if (driver->supports_sockets)
DIAG_SET_FEATURE_MASK(F_DIAG_SOCKETS_ENABLED);
@@ -1933,17 +1983,27 @@
void diag_send_updates_peripheral(uint8_t peripheral)
{
diag_send_feature_mask_update(peripheral);
- if (driver->time_sync_enabled)
- diag_send_time_sync_update(peripheral);
- mutex_lock(&driver->md_session_lock);
- diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
- diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
- diag_send_event_mask_update(peripheral);
- mutex_unlock(&driver->md_session_lock);
- diag_send_real_time_update(peripheral,
+ /*
+ * Masks (F3, logs and events) will be sent to
+ * peripheral immediately following feature mask update only
+ * if diag_id support is not present or
+ * diag_id support is present and diag_id has been sent to
+ * peripheral.
+ */
+ if (!driver->feature[peripheral].diag_id_support ||
+ driver->diag_id_sent[peripheral]) {
+ if (driver->time_sync_enabled)
+ diag_send_time_sync_update(peripheral);
+ mutex_lock(&driver->md_session_lock);
+ diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
+ diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
+ diag_send_event_mask_update(peripheral);
+ mutex_unlock(&driver->md_session_lock);
+ diag_send_real_time_update(peripheral,
driver->real_time_mode[DIAG_LOCAL_PROC]);
- diag_send_peripheral_buffering_mode(
- &driver->buffering_mode[peripheral]);
+ diag_send_peripheral_buffering_mode(
+ &driver->buffering_mode[peripheral]);
+ }
}
int diag_process_apps_masks(unsigned char *buf, int len,
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index 13ad402..7e3fe90 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -29,6 +29,7 @@
#include "diagmem.h"
#include "diagfwd.h"
#include "diagfwd_peripheral.h"
+#include "diag_ipc_logging.h"
struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = {
{
@@ -132,7 +133,7 @@
uint8_t found = 0;
unsigned long flags;
struct diag_md_info *ch = NULL;
- uint8_t peripheral;
+ int peripheral;
struct diag_md_session_t *session_info = NULL;
if (id < 0 || id >= NUM_DIAG_MD_DEV || id >= DIAG_NUM_PROC)
@@ -141,11 +142,12 @@
if (!buf || len < 0)
return -EINVAL;
- peripheral = GET_BUF_PERIPHERAL(ctx);
- if (peripheral > NUM_PERIPHERALS)
+ peripheral = diag_md_get_peripheral(ctx);
+ if (peripheral < 0)
return -EINVAL;
- session_info = diag_md_session_get_peripheral(peripheral);
+ session_info =
+ diag_md_session_get_peripheral(peripheral);
if (!session_info)
return -EIO;
@@ -214,7 +216,7 @@
struct diag_md_info *ch = NULL;
struct diag_buf_tbl_t *entry = NULL;
uint8_t drain_again = 0;
- uint8_t peripheral = 0;
+ int peripheral = 0;
struct diag_md_session_t *session_info = NULL;
for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
@@ -223,12 +225,15 @@
entry = &ch->tbl[j];
if (entry->len <= 0)
continue;
- peripheral = GET_BUF_PERIPHERAL(entry->ctx);
- /* Account for Apps data as well */
- if (peripheral > NUM_PERIPHERALS)
+
+ peripheral = diag_md_get_peripheral(entry->ctx);
+ if (peripheral < 0)
goto drop_data;
session_info =
diag_md_session_get_peripheral(peripheral);
+ if (!session_info)
+ goto drop_data;
+
if (session_info && info &&
(session_info->pid != info->pid))
continue;
@@ -320,8 +325,15 @@
spin_lock_irqsave(&ch->lock, flags);
for (i = 0; i < ch->num_tbl_entries && !found; i++) {
entry = &ch->tbl[i];
- if (GET_BUF_PERIPHERAL(entry->ctx) != peripheral)
- continue;
+
+ if (peripheral > NUM_PERIPHERALS) {
+ if (GET_PD_CTXT(entry->ctx) != peripheral)
+ continue;
+ } else {
+ if (GET_BUF_PERIPHERAL(entry->ctx) !=
+ peripheral)
+ continue;
+ }
found = 1;
if (ch->ops && ch->ops->write_done) {
ch->ops->write_done(entry->buf, entry->len,
diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c
index 8f5a002..e65b493 100644
--- a/drivers/char/diag/diag_mux.c
+++ b/drivers/char/diag/diag_mux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -27,7 +27,8 @@
#include "diag_mux.h"
#include "diag_usb.h"
#include "diag_memorydevice.h"
-
+#include "diagfwd_peripheral.h"
+#include "diag_ipc_logging.h"
struct diag_mux_state_t *diag_mux;
static struct diag_logger_t usb_logger;
@@ -141,9 +142,13 @@
if (!diag_mux)
return -EIO;
- peripheral = GET_BUF_PERIPHERAL(ctx);
- if (peripheral > NUM_PERIPHERALS)
+ peripheral = diag_md_get_peripheral(ctx);
+ if (peripheral < 0) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag:%s:%d invalid peripheral = %d\n",
+ __func__, __LINE__, peripheral);
return -EINVAL;
+ }
if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
logger = diag_mux->md_ptr;
@@ -162,8 +167,13 @@
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
/* Peripheral should account for Apps data as well */
- if (peripheral > NUM_PERIPHERALS)
- return -EINVAL;
+ if (peripheral > NUM_PERIPHERALS) {
+ if (!driver->num_pd_session)
+ return -EINVAL;
+ if (peripheral > NUM_MD_SESSIONS)
+ return -EINVAL;
+ }
+
if (!diag_mux)
return -EIO;
@@ -184,7 +194,8 @@
if (!req_mode)
return -EINVAL;
- if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) {
+ if (*peripheral_mask <= 0 ||
+ (*peripheral_mask > (DIAG_CON_ALL | DIAG_CON_UPD_ALL))) {
pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__);
return -EINVAL;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 8051d5d..ac3c1fd 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -58,19 +58,23 @@
#define DIAG_CTRL_MSG_F3_MASK 11
#define CONTROL_CHAR 0x7E
+#define DIAG_ID_ROOT_STRING "root"
+
#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */
-#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */
-#define DIAG_CON_CDSP (0x0040)
+#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */
+#define DIAG_CON_CDSP (0x0040) /* Bit mask for CDSP */
+#define DIAG_CON_UPD_WLAN (0x1000) /*Bit mask for WLAN PD*/
#define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/
#define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \
| DIAG_CON_LPASS | DIAG_CON_WCNSS \
| DIAG_CON_SENSORS | DIAG_CON_WDSP \
| DIAG_CON_CDSP)
+#define DIAG_CON_UPD_ALL (DIAG_CON_UPD_WLAN)
#define DIAG_STM_MODEM 0x01
#define DIAG_STM_LPASS 0x02
@@ -165,7 +169,7 @@
#define PKT_ALLOC 1
#define PKT_RESET 2
-#define FEATURE_MASK_LEN 2
+#define FEATURE_MASK_LEN 4
#define DIAG_MD_NONE 0
#define DIAG_MD_PERIPHERAL 1
@@ -209,11 +213,18 @@
#define NUM_PERIPHERALS 6
#define APPS_DATA (NUM_PERIPHERALS)
+#define UPD_WLAN 7
+#define NUM_UPD 1
+#define MAX_PERIPHERAL_UPD 1
/* Number of sessions possible in Memory Device Mode. +1 for Apps data */
-#define NUM_MD_SESSIONS (NUM_PERIPHERALS + 1)
+#define NUM_MD_SESSIONS (NUM_PERIPHERALS \
+ + NUM_UPD + 1)
#define MD_PERIPHERAL_MASK(x) (1 << x)
+#define MD_PERIPHERAL_PD_MASK(x) \
+ ((x == PERIPHERAL_MODEM) ? (1 << UPD_WLAN) : 0)\
+
/*
* Number of stm processors includes all the peripherals and
* apps.Added 1 below to indicate apps
@@ -439,6 +450,7 @@
struct diag_logging_mode_param_t {
uint32_t req_mode;
uint32_t peripheral_mask;
+ uint32_t pd_mask;
uint8_t mode_param;
} __packed;
@@ -485,11 +497,13 @@
uint8_t log_on_demand;
uint8_t separate_cmd_rsp;
uint8_t encode_hdlc;
+ uint8_t untag_header;
uint8_t peripheral_buffering;
uint8_t mask_centralization;
uint8_t stm_support;
uint8_t sockets_enabled;
uint8_t sent_feature_mask;
+ uint8_t diag_id_support;
};
struct diagchar_dev {
@@ -516,6 +530,8 @@
int use_device_tree;
int supports_separate_cmdrsp;
int supports_apps_hdlc_encoding;
+ int supports_apps_header_untagging;
+ int peripheral_untag[NUM_PERIPHERALS];
int supports_sockets;
/* The state requested in the STM command */
int stm_state_requested[NUM_STM_PROCESSORS];
@@ -612,6 +628,10 @@
int in_busy_dcipktdata;
int logging_mode;
int logging_mask;
+ int pd_logging_mode[NUM_UPD];
+ int pd_session_clear[NUM_UPD];
+ int num_pd_session;
+ int diag_id_sent[NUM_PERIPHERALS];
int mask_check;
uint32_t md_session_mask;
uint8_t md_session_mode;
@@ -672,6 +692,7 @@
int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
int diag_mask_param(void);
void diag_clear_masks(struct diag_md_session_t *info);
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask);
void diag_record_stats(int type, int flag);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index aaf67b7..f0e69ef 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -393,9 +393,28 @@
ret |= DIAG_CON_WDSP;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_CDSP))
ret |= DIAG_CON_CDSP;
-
+ if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_WLAN))
+ ret |= DIAG_CON_UPD_WLAN;
return ret;
}
+
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask)
+{
+ uint8_t upd = 0;
+ uint32_t pd_mask = 0;
+
+ pd_mask = diag_translate_kernel_to_user_mask(peripheral_mask);
+ switch (pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ upd = UPD_WLAN;
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with no pd mask set\n");
+ }
+ return upd;
+}
+
int diag_mask_param(void)
{
return diag_mask_clear_param;
@@ -423,8 +442,9 @@
static void diag_close_logging_process(const int pid)
{
- int i;
- int session_peripheral_mask;
+ int i, j;
+ int session_mask;
+ uint32_t p_mask;
struct diag_md_session_t *session_info = NULL;
struct diag_logging_mode_param_t params;
@@ -440,18 +460,33 @@
mutex_unlock(&driver->diag_maskclear_mutex);
mutex_lock(&driver->diagchar_mutex);
- session_peripheral_mask = session_info->peripheral_mask;
+ session_mask = session_info->peripheral_mask;
diag_md_session_close(session_info);
- mutex_unlock(&driver->diagchar_mutex);
+
+ p_mask =
+ diag_translate_kernel_to_user_mask(session_mask);
+
for (i = 0; i < NUM_MD_SESSIONS; i++)
- if (MD_PERIPHERAL_MASK(i) & session_peripheral_mask)
+ if (MD_PERIPHERAL_MASK(i) & session_mask)
diag_mux_close_peripheral(DIAG_LOCAL_PROC, i);
params.req_mode = USB_MODE;
params.mode_param = 0;
- params.peripheral_mask =
- diag_translate_kernel_to_user_mask(session_peripheral_mask);
- mutex_lock(&driver->diagchar_mutex);
+ params.pd_mask = 0;
+ params.peripheral_mask = p_mask;
+
+ if (driver->num_pd_session > 0) {
+ for (i = UPD_WLAN; (i < NUM_MD_SESSIONS); i++) {
+ if (session_mask & MD_PERIPHERAL_MASK(i)) {
+ j = i - UPD_WLAN;
+ driver->pd_session_clear[j] = 1;
+ driver->pd_logging_mode[j] = 0;
+ driver->num_pd_session -= 1;
+ params.pd_mask = p_mask;
+ }
+ }
+ }
+
diag_switch_logging(¶ms);
mutex_unlock(&driver->diagchar_mutex);
}
@@ -1580,17 +1615,20 @@
ret |= (1 << PERIPHERAL_WDSP);
if (peripheral_mask & DIAG_CON_CDSP)
ret |= (1 << PERIPHERAL_CDSP);
+ if (peripheral_mask & DIAG_CON_UPD_WLAN)
+ ret |= (1 << UPD_WLAN);
return ret;
}
static int diag_switch_logging(struct diag_logging_mode_param_t *param)
{
- int new_mode;
+ int new_mode, i = 0;
int curr_mode;
int err = 0;
uint8_t do_switch = 1;
uint32_t peripheral_mask = 0;
+ uint8_t peripheral, upd;
if (!param)
return -EINVAL;
@@ -1601,8 +1639,41 @@
return -EINVAL;
}
- peripheral_mask = diag_translate_mask(param->peripheral_mask);
- param->peripheral_mask = peripheral_mask;
+ if (param->pd_mask) {
+ switch (param->pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ peripheral = PERIPHERAL_MODEM;
+ upd = UPD_WLAN;
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "asking for mode switch with no pd mask set\n");
+ return -EINVAL;
+ }
+
+ if (driver->md_session_map[peripheral] &&
+ (MD_PERIPHERAL_MASK(peripheral) &
+ diag_mux->mux_mask)) {
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag_fr: User PD is already logging onto active peripheral logging\n");
+ i = upd - UPD_WLAN;
+ driver->pd_session_clear[i] = 0;
+ return -EINVAL;
+ }
+ peripheral_mask =
+ diag_translate_mask(param->pd_mask);
+ param->peripheral_mask = peripheral_mask;
+ i = upd - UPD_WLAN;
+ if (!driver->pd_session_clear[i]) {
+ driver->pd_logging_mode[i] = 1;
+ driver->num_pd_session += 1;
+ }
+ driver->pd_session_clear[i] = 0;
+ } else {
+ peripheral_mask =
+ diag_translate_mask(param->peripheral_mask);
+ param->peripheral_mask = peripheral_mask;
+ }
switch (param->req_mode) {
case CALLBACK_MODE:
@@ -1622,7 +1693,7 @@
curr_mode = driver->logging_mode;
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "request to switch logging from %d mask:%0x to %d mask:%0x\n",
+ "request to switch logging from %d mask:%0x to new_mode %d mask:%0x\n",
curr_mode, driver->md_session_mask, new_mode, peripheral_mask);
err = diag_md_session_check(curr_mode, new_mode, param, &do_switch);
@@ -1946,6 +2017,52 @@
return 0;
}
+static int diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param)
+{
+ int ret = -EINVAL;
+ int peripheral;
+ char *p_str = NULL;
+
+ if (!param)
+ return -EINVAL;
+
+ if (!param->pd_mask) {
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "query with no pd mask set, returning error\n");
+ return -EINVAL;
+ }
+
+ switch (param->pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ peripheral = PERIPHERAL_MODEM;
+ p_str = "MODEM";
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "Invalid pd mask, returning EINVAL\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag: %s: Untagging support on APPS is %s\n", __func__,
+ ((driver->supports_apps_header_untagging) ?
+ "present" : "absent"));
+
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag: %s: Tagging support on %s is %s\n",
+ __func__, p_str,
+ (driver->feature[peripheral].untag_header ?
+ "present" : "absent"));
+
+ if (driver->supports_apps_header_untagging &&
+ driver->feature[peripheral].untag_header)
+ ret = 0;
+
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return ret;
+}
+
static int diag_ioctl_register_callback(unsigned long ioarg)
{
int err = 0;
@@ -2183,6 +2300,12 @@
case DIAG_IOCTL_HDLC_TOGGLE:
result = diag_ioctl_hdlc_toggle(ioarg);
break;
+ case DIAG_IOCTL_QUERY_PD_LOGGING:
+ if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
+ sizeof(mode_param)))
+ return -EFAULT;
+ result = diag_ioctl_query_pd_logging(&mode_param);
+ break;
}
return result;
}
@@ -2306,6 +2429,12 @@
case DIAG_IOCTL_HDLC_TOGGLE:
result = diag_ioctl_hdlc_toggle(ioarg);
break;
+ case DIAG_IOCTL_QUERY_PD_LOGGING:
+ if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
+ sizeof(mode_param)))
+ return -EFAULT;
+ result = diag_ioctl_query_pd_logging(&mode_param);
+ break;
}
return result;
}
@@ -3359,7 +3488,7 @@
* to be logged to IPC
*/
diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI |
- DIAG_DEBUG_BRIDGE;
+ DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE;
}
#else
static void diag_debug_init(void)
@@ -3489,6 +3618,11 @@
poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
driver->num_clients = max_clients;
driver->logging_mode = DIAG_USB_MODE;
+ for (i = 0; i < NUM_UPD; i++) {
+ driver->pd_logging_mode[i] = 0;
+ driver->pd_session_clear[i] = 0;
+ }
+ driver->num_pd_session = 0;
driver->mask_check = 0;
driver->in_busy_pktdata = 0;
driver->in_busy_dcipktdata = 0;
@@ -3506,8 +3640,10 @@
mutex_init(&apps_data_mutex);
mutex_init(&driver->msg_mask_lock);
mutex_init(&driver->hdlc_recovery_mutex);
- for (i = 0; i < NUM_PERIPHERALS; i++)
+ for (i = 0; i < NUM_PERIPHERALS; i++) {
mutex_init(&driver->diagfwd_channel_mutex[i]);
+ driver->diag_id_sent[i] = 0;
+ }
init_waitqueue_head(&driver->wait_q);
INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
INIT_WORK(&(driver->update_user_clients),
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 3f00a7e..b59f245 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -38,6 +38,7 @@
#include "diag_masks.h"
#include "diag_usb.h"
#include "diag_mux.h"
+#include "diag_ipc_logging.h"
#define STM_CMD_VERSION_OFFSET 4
#define STM_CMD_MASK_OFFSET 5
@@ -1663,6 +1664,9 @@
driver->real_time_mode[i] = 1;
driver->supports_separate_cmdrsp = 1;
driver->supports_apps_hdlc_encoding = 1;
+ driver->supports_apps_header_untagging = 1;
+ for (i = 0; i < NUM_PERIPHERALS; i++)
+ driver->peripheral_untag[i] = 0;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
mutex_init(&driver->mode_lock);
@@ -1692,9 +1696,12 @@
driver->feature[i].rcvd_feature_mask = 0;
driver->feature[i].peripheral_buffering = 0;
driver->feature[i].encode_hdlc = 0;
+ driver->feature[i].untag_header =
+ DISABLE_PKT_HEADER_UNTAGGING;
driver->feature[i].mask_centralization = 0;
driver->feature[i].log_on_demand = 0;
driver->feature[i].sent_feature_mask = 0;
+ driver->feature[i].diag_id_support = 0;
driver->buffering_mode[i].peripheral = i;
driver->buffering_mode[i].mode = DIAG_BUFFERING_MODE_STREAMING;
driver->buffering_mode[i].high_wm_val = DEFAULT_HIGH_WM_VAL;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 47c8555..677099f 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2017, 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
@@ -19,9 +19,11 @@
*/
#define SET_BUF_CTXT(p, d, n) \
(((p & 0xFF) << 16) | ((d & 0xFF) << 8) | (n & 0xFF))
+#define SET_PD_CTXT(u) ((u & 0xFF) << 24)
#define GET_BUF_PERIPHERAL(p) ((p & 0xFF0000) >> 16)
#define GET_BUF_TYPE(d) ((d & 0x00FF00) >> 8)
#define GET_BUF_NUM(n) ((n & 0x0000FF))
+#define GET_PD_CTXT(u) ((u & 0xFF000000) >> 24)
#define CHK_OVERFLOW(bufStart, start, end, length) \
((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 5282e02..d7e24fc 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -70,6 +70,7 @@
driver->feature[peripheral].rcvd_feature_mask = 0;
reg_dirty |= PERIPHERAL_MASK(peripheral);
diag_cmd_remove_reg_by_proc(peripheral);
+ driver->diag_id_sent[peripheral] = 0;
driver->feature[peripheral].stm_support = DISABLE_STM;
driver->feature[peripheral].log_on_demand = 0;
driver->stm_state[peripheral] = DISABLE_STM;
@@ -198,6 +199,20 @@
}
}
+static void process_upd_header_untagging_feature(uint8_t peripheral)
+{
+ if (peripheral >= NUM_PERIPHERALS)
+ return;
+
+ if (driver->supports_apps_header_untagging) {
+ driver->feature[peripheral].untag_header =
+ ENABLE_PKT_HEADER_UNTAGGING;
+ } else {
+ driver->feature[peripheral].untag_header =
+ DISABLE_PKT_HEADER_UNTAGGING;
+ }
+}
+
static void process_command_deregistration(uint8_t *buf, uint32_t len,
uint8_t peripheral)
{
@@ -374,6 +389,8 @@
driver->feature[peripheral].separate_cmd_rsp = 1;
if (FEATURE_SUPPORTED(F_DIAG_APPS_HDLC_ENCODE))
process_hdlc_encoding_feature(peripheral);
+ if (FEATURE_SUPPORTED(F_DIAG_PKT_HEADER_UNTAG))
+ process_upd_header_untagging_feature(peripheral);
if (FEATURE_SUPPORTED(F_DIAG_STM))
enable_stm_feature(peripheral);
if (FEATURE_SUPPORTED(F_DIAG_MASK_CENTRALIZATION))
@@ -382,6 +399,8 @@
driver->feature[peripheral].peripheral_buffering = 1;
if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED))
enable_socket_feature(peripheral);
+ if (FEATURE_SUPPORTED(F_DIAG_DIAGID_SUPPORT))
+ driver->feature[peripheral].diag_id_support = 1;
}
process_socket_feature(peripheral);
@@ -706,12 +725,24 @@
{
struct diag_ctrl_diagid *header = NULL;
struct diag_ctrl_diagid ctrl_pkt;
+ struct diagfwd_info *fwd_info_data = NULL;
+ struct diagfwd_info *fwd_info_cmd = NULL;
char *process_name = NULL;
int err = 0;
uint8_t local_diag_id = 0;
+ uint8_t new_request = 0;
if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
return;
+
+ fwd_info_data = &peripheral_info[TYPE_DATA][peripheral];
+ if (!fwd_info_data)
+ return;
+
+ fwd_info_cmd = &peripheral_info[TYPE_CMD][peripheral];
+ if (!fwd_info_cmd)
+ return;
+
header = (struct diag_ctrl_diagid *)buf;
process_name = (char *)&header->process_name;
if (diag_query_diag_id(process_name, &local_diag_id))
@@ -720,7 +751,27 @@
diag_id++;
diag_add_diag_id_to_list(diag_id, process_name);
ctrl_pkt.diag_id = diag_id;
+ new_request = 1;
}
+
+ if (new_request) {
+ fwd_info_data->num_pd++;
+ fwd_info_cmd->num_pd++;
+ }
+
+ if (strnstr(process_name, DIAG_ID_ROOT_STRING, strlen(process_name))) {
+ fwd_info_cmd->diagid_root = diag_id;
+ fwd_info_data->diagid_root = diag_id;
+ driver->diag_id_sent[peripheral] = 0;
+ } else {
+ fwd_info_cmd->diagid_user[fwd_info_cmd->num_pd - 2] = diag_id;
+ fwd_info_data->diagid_user[fwd_info_data->num_pd - 2] = diag_id;
+ }
+
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
+ peripheral, process_name, ctrl_pkt.diag_id);
+
ctrl_pkt.pkt_id = DIAG_CTRL_MSG_DIAGID;
ctrl_pkt.version = 1;
strlcpy((char *)&ctrl_pkt.process_name, process_name,
@@ -730,8 +781,21 @@
err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, ctrl_pkt.len +
sizeof(ctrl_pkt.pkt_id) + sizeof(ctrl_pkt.len));
if (err && err != -ENODEV) {
- pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
+ pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
peripheral, err);
+ } else {
+ /*
+ * Masks (F3, logs and events) will be sent to
+ * peripheral immediately following feature mask update only
+ * if diag_id support is not present or
+ * diag_id support is present and diag_id has been sent to
+ * peripheral.
+ * With diag_id being sent now, mask will be updated
+ * to peripherals.
+ */
+ driver->diag_id_sent[peripheral] = 1;
+ diag_send_updates_peripheral(peripheral);
+ diagfwd_buffers_init(fwd_info_data);
}
}
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 7823040..8b22d7e 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -68,6 +68,7 @@
#define F_DIAG_SOCKETS_ENABLED 13
#define F_DIAG_DCI_EXTENDED_HEADER_SUPPORT 14
#define F_DIAG_DIAGID_SUPPORT 15
+#define F_DIAG_PKT_HEADER_UNTAG 16
#define ENABLE_SEPARATE_CMDRSP 1
#define DISABLE_SEPARATE_CMDRSP 0
@@ -82,6 +83,9 @@
#define ENABLE_APPS_HDLC_ENCODING 1
#define DISABLE_APPS_HDLC_ENCODING 0
+#define ENABLE_PKT_HEADER_UNTAGGING 1
+#define DISABLE_PKT_HEADER_UNTAGGING 0
+
#define DIAG_MODE_PKT_LEN 36
struct diag_ctrl_pkt_header_t {
@@ -279,6 +283,7 @@
void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf,
int len);
int diag_send_real_time_update(uint8_t peripheral, int real_time);
+void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral);
int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params);
void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index);
void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index);
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index dd5a552..955d81f 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -45,6 +45,8 @@
static void diagfwd_cntl_close(struct diagfwd_info *fwd_info);
static void diagfwd_dci_open(struct diagfwd_info *fwd_info);
static void diagfwd_dci_close(struct diagfwd_info *fwd_info);
+static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
+ unsigned char *buf, int len);
static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
unsigned char *buf, int len);
static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
@@ -58,7 +60,7 @@
static struct diag_channel_ops data_ch_ops = {
.open = NULL,
.close = NULL,
- .read_done = diagfwd_data_read_done
+ .read_done = diagfwd_data_read_untag_done
};
static struct diag_channel_ops cntl_ch_ops = {
@@ -213,6 +215,317 @@
return buf->len;
}
+int diag_md_get_peripheral(int ctxt)
+{
+ int pd = 0, i = 0;
+ int type = 0, peripheral = -EINVAL;
+ struct diagfwd_info *fwd_info = NULL;
+
+ peripheral = GET_BUF_PERIPHERAL(ctxt);
+ if (peripheral < 0 || peripheral > NUM_PERIPHERALS)
+ return -EINVAL;
+
+ if (peripheral == APPS_DATA)
+ return peripheral;
+
+ type = GET_BUF_TYPE(ctxt);
+ if (type < 0 || type >= NUM_TYPES)
+ return -EINVAL;
+
+ fwd_info = &peripheral_info[type][peripheral];
+ if (!fwd_info)
+ return -EINVAL;
+
+ pd = GET_PD_CTXT(ctxt);
+
+ if (driver->num_pd_session) {
+ if (pd == fwd_info->diagid_root) {
+ if (peripheral > NUM_PERIPHERALS)
+ peripheral = -EINVAL;
+ } else {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (pd == fwd_info->diagid_user[i]) {
+ switch (peripheral) {
+ case PERIPHERAL_MODEM:
+ if (driver->pd_logging_mode[0])
+ peripheral = UPD_WLAN;
+ break;
+ default:
+ peripheral = -EINVAL;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return peripheral;
+}
+
+static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
+ struct diagfwd_buf_t *buf, int len)
+{
+ int err = 0;
+ int write_len = 0, peripheral = 0;
+ unsigned char *write_buf = NULL;
+ struct diag_md_session_t *session_info = NULL;
+ uint8_t hdlc_disabled = 0;
+
+ if (!fwd_info || !buf || len <= 0) {
+ diag_ws_release();
+ return;
+ }
+
+ switch (fwd_info->type) {
+ case TYPE_DATA:
+ case TYPE_CMD:
+ break;
+ default:
+ pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
+ diag_ws_release();
+ return;
+ }
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ mutex_lock(&fwd_info->data_mutex);
+
+ peripheral =
+ diag_md_get_peripheral(buf->ctxt);
+ if (peripheral < 0) {
+ pr_err("diag:%s:%d invalid peripheral = %d\n",
+ __func__, __LINE__, peripheral);
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ diag_ws_release();
+ return;
+ }
+
+ session_info =
+ diag_md_session_get_peripheral(peripheral);
+ if (session_info)
+ hdlc_disabled = session_info->hdlc_disabled;
+ else
+ hdlc_disabled = driver->hdlc_disabled;
+
+ if (hdlc_disabled) {
+ /* The data is raw and and on APPS side HDLC is disabled */
+ if (!buf) {
+ pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+ if (len > PERIPHERAL_BUF_SZ) {
+ pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
+ __func__, len, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+ write_len = len;
+ if (write_len <= 0)
+ goto end;
+ write_buf = buf->data_raw;
+ } else {
+ if (!buf) {
+ pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+
+ write_len = check_bufsize_for_encoding(buf, len);
+ if (write_len <= 0) {
+ pr_err("diag: error in checking buf for encoding\n");
+ goto end;
+ }
+ write_buf = buf->data;
+ err = diag_add_hdlc_encoding(write_buf, &write_len,
+ buf->data_raw, len);
+ if (err) {
+ pr_err("diag: error in adding hdlc encoding\n");
+ goto end;
+ }
+ }
+
+ if (write_len > 0) {
+ err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
+ buf->ctxt);
+ if (err) {
+ pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
+ __func__, err);
+ goto end;
+ }
+ }
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ diagfwd_queue_read(fwd_info);
+ return;
+
+end:
+ diag_ws_release();
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ if (buf) {
+ diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
+ GET_BUF_NUM(buf->ctxt));
+ }
+ diagfwd_queue_read(fwd_info);
+}
+
+static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
+ unsigned char *buf, int len)
+{
+ int i = 0;
+ int len_cpd = 0;
+ int ctxt_cpd = 0;
+ int len_upd[MAX_PERIPHERAL_UPD] = {0};
+ int ctxt_upd[MAX_PERIPHERAL_UPD] = {0};
+ int packet_len = 0, processed = 0;
+ unsigned char *temp_buf_main = NULL;
+ unsigned char *temp_buf_cpd = NULL;
+ unsigned char *temp_buf_upd[MAX_PERIPHERAL_UPD] = {NULL};
+ struct diagfwd_buf_t *temp_fwdinfo_cpd = NULL;
+ struct diagfwd_buf_t *temp_fwdinfo_upd = NULL;
+ int flag_buf_1 = 0, flag_buf_2 = 0;
+ uint8_t peripheral;
+
+ if (!fwd_info || !buf || len <= 0) {
+ diag_ws_release();
+ return;
+ }
+
+ switch (fwd_info->type) {
+ case TYPE_DATA:
+ case TYPE_CMD:
+ break;
+ default:
+ pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
+ diag_ws_release();
+ return;
+ }
+ peripheral = fwd_info->peripheral;
+ if (peripheral >= NUM_PERIPHERALS)
+ return;
+
+ if (driver->feature[peripheral].encode_hdlc &&
+ driver->feature[peripheral].untag_header &&
+ driver->peripheral_untag[peripheral]) {
+ temp_buf_cpd = buf;
+ temp_buf_main = buf;
+ if (fwd_info->buf_1 &&
+ fwd_info->buf_1->data_raw == buf) {
+ flag_buf_1 = 1;
+ temp_fwdinfo_cpd = fwd_info->buf_1;
+ if (fwd_info->type == TYPE_DATA) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ temp_buf_upd[i] =
+ fwd_info->buf_upd[i][0]->data_raw;
+ }
+ } else if (fwd_info->buf_2 &&
+ fwd_info->buf_2->data_raw == buf) {
+ flag_buf_2 = 1;
+ temp_fwdinfo_cpd = fwd_info->buf_2;
+ if (fwd_info->type == TYPE_DATA) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ temp_buf_upd[i] =
+ fwd_info->buf_upd[i][1]->data_raw;
+ }
+ } else {
+ pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, peripheral,
+ fwd_info->type);
+ goto end;
+ }
+
+ while (processed < len) {
+ pr_debug("diag_fr:untagged packet buf contents: %02x %02x %02x %02x\n",
+ *temp_buf_main, *(temp_buf_main+1),
+ *(temp_buf_main+2), *(temp_buf_main+3));
+ packet_len =
+ *(uint16_t *) (temp_buf_main + 2);
+ if (packet_len > PERIPHERAL_BUF_SZ)
+ goto end;
+ if ((*temp_buf_main) == fwd_info->diagid_root) {
+ ctxt_cpd = fwd_info->diagid_root;
+ len_cpd += packet_len;
+ if (temp_buf_cpd) {
+ memcpy(temp_buf_cpd,
+ (temp_buf_main + 4), packet_len);
+ temp_buf_cpd += packet_len;
+ }
+ } else {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ if ((*temp_buf_main) ==
+ fwd_info->diagid_user[i])
+ break;
+ ctxt_upd[i] = fwd_info->diagid_user[i];
+ if (temp_buf_upd[i]) {
+ memcpy(temp_buf_upd[i],
+ (temp_buf_main + 4), packet_len);
+ temp_buf_upd[i] += packet_len;
+ }
+ len_upd[i] += packet_len;
+ }
+ len = len - 4;
+ temp_buf_main += (packet_len + 4);
+ processed += packet_len;
+ }
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->type == TYPE_DATA && len_upd[i]) {
+ if (flag_buf_1) {
+ fwd_info->upd_len[i][0] = len_upd[i];
+ temp_fwdinfo_upd =
+ fwd_info->buf_upd[i][0];
+ } else {
+ fwd_info->upd_len[i][1] = len_upd[i];
+ temp_fwdinfo_upd =
+ fwd_info->buf_upd[i][1];
+ }
+ temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
+ temp_fwdinfo_upd->ctxt |=
+ (SET_PD_CTXT(ctxt_upd[i]));
+ atomic_set(&temp_fwdinfo_upd->in_busy, 1);
+ diagfwd_data_process_done(fwd_info,
+ temp_fwdinfo_upd, len_upd[i]);
+ } else {
+ if (flag_buf_1)
+ fwd_info->upd_len[i][0] = 0;
+ if (flag_buf_2)
+ fwd_info->upd_len[i][1] = 0;
+ }
+ }
+ if (len_cpd) {
+ if (flag_buf_1)
+ fwd_info->cpd_len_1 = len_cpd;
+ else
+ fwd_info->cpd_len_2 = len_cpd;
+ temp_fwdinfo_cpd->ctxt &= 0x00FFFFFF;
+ temp_fwdinfo_cpd->ctxt |=
+ (SET_PD_CTXT(ctxt_cpd));
+ diagfwd_data_process_done(fwd_info,
+ temp_fwdinfo_cpd, len_cpd);
+ } else {
+ if (flag_buf_1)
+ fwd_info->cpd_len_1 = 0;
+ if (flag_buf_2)
+ fwd_info->cpd_len_2 = 0;
+ }
+ } else {
+ diagfwd_data_read_done(fwd_info, buf, len);
+ }
+ return;
+end:
+ diag_ws_release();
+ if (temp_fwdinfo_cpd) {
+ diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
+ GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
+ }
+ diagfwd_queue_read(fwd_info);
+}
+
static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
unsigned char *buf, int len)
{
@@ -413,6 +726,7 @@
uint8_t peripheral;
uint8_t transport;
uint8_t type;
+ int i = 0;
struct diagfwd_info *fwd_info = NULL;
for (transport = 0; transport < NUM_TRANSPORT; transport++) {
@@ -436,9 +750,20 @@
fwd_info->inited = 1;
fwd_info->read_bytes = 0;
fwd_info->write_bytes = 0;
+ fwd_info->cpd_len_1 = 0;
+ fwd_info->cpd_len_2 = 0;
+ fwd_info->num_pd = 0;
mutex_init(&fwd_info->buf_mutex);
mutex_init(&fwd_info->data_mutex);
spin_lock_init(&fwd_info->write_buf_lock);
+
+ for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
+ fwd_info->diagid_user[i] = 0;
+ fwd_info->upd_len[i][0] = 0;
+ fwd_info->upd_len[i][1] = 0;
+ fwd_info->buf_upd[i][0] = NULL;
+ fwd_info->buf_upd[i][1] = NULL;
+ }
}
}
@@ -452,9 +777,20 @@
fwd_info->ch_open = 0;
fwd_info->read_bytes = 0;
fwd_info->write_bytes = 0;
+ fwd_info->num_pd = 0;
+ fwd_info->cpd_len_1 = 0;
+ fwd_info->cpd_len_2 = 0;
spin_lock_init(&fwd_info->write_buf_lock);
mutex_init(&fwd_info->buf_mutex);
mutex_init(&fwd_info->data_mutex);
+
+ for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
+ fwd_info->diagid_user[i] = 0;
+ fwd_info->upd_len[i][0] = 0;
+ fwd_info->upd_len[i][1] = 0;
+ fwd_info->buf_upd[i][0] = NULL;
+ fwd_info->buf_upd[i][1] = NULL;
+ }
/*
* This state shouldn't be set for Control channels
* during initialization. This is set when the feature
@@ -730,6 +1066,16 @@
if (!fwd_info->inited || !atomic_read(&fwd_info->opened))
return -ENODEV;
+ if (type == TYPE_CMD) {
+ if (driver->feature[peripheral].untag_header)
+ if (!fwd_info->diagid_root ||
+ (!driver->diag_id_sent[peripheral])) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: diag_id is not assigned yet\n");
+ return 0;
+ }
+ }
+
if (!(fwd_info->p_ops && fwd_info->p_ops->write && fwd_info->ctxt))
return -EIO;
@@ -948,17 +1294,45 @@
void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
{
+ int i = 0;
struct diagfwd_info *fwd_info = NULL;
if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
return;
fwd_info = &peripheral_info[type][peripheral];
- if (ctxt == 1 && fwd_info->buf_1)
+ if (!fwd_info)
+ return;
+
+ if (ctxt == 1 && fwd_info->buf_1) {
+ /* Buffer 1 for core PD is freed */
atomic_set(&fwd_info->buf_1->in_busy, 0);
- else if (ctxt == 2 && fwd_info->buf_2)
+ fwd_info->cpd_len_1 = 0;
+ } else if (ctxt == 2 && fwd_info->buf_2) {
+ /* Buffer 2 for core PD is freed */
atomic_set(&fwd_info->buf_2->in_busy, 0);
- else
+ fwd_info->cpd_len_2 = 0;
+ } else if (ctxt >= 3 && (ctxt % 2)) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->buf_upd[i][0]) {
+ /* Buffer 1 for ith user PD is freed */
+ atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
+ fwd_info->upd_len[i][0] = 0;
+ }
+ if (!fwd_info->cpd_len_1)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ }
+ } else if (ctxt >= 4 && !(ctxt % 2)) {
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->buf_upd[i][1]) {
+ /* Buffer 2 for ith user PD is freed */
+ atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
+ fwd_info->upd_len[i][1] = 0;
+ }
+ if (!fwd_info->cpd_len_2)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ }
+ } else
pr_err("diag: In %s, invalid ctxt %d\n", __func__, ctxt);
diagfwd_queue_read(fwd_info);
@@ -1087,8 +1461,65 @@
fwd_info->p_ops->queue_read(fwd_info->ctxt);
}
+static int diagfwd_buffers_allocate(struct diagfwd_info *fwd_info)
+{
+ int i, j;
+
+ for (i = 0; ((fwd_info->num_pd > 1) &&
+ (i <= (fwd_info->num_pd - 2))); i++) {
+ for (j = 0; j < NUM_WRITE_BUFFERS; j++) {
+ if (!fwd_info->buf_upd[i][j]) {
+ fwd_info->buf_upd[i][j] =
+ kzalloc(sizeof(struct diagfwd_buf_t),
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_upd[i][j]))
+ return -ENOMEM;
+ kmemleak_not_leak(fwd_info->buf_upd[i][j]);
+ }
+
+ if (fwd_info->buf_upd[i][j] &&
+ !fwd_info->buf_upd[i][j]->data) {
+ fwd_info->buf_upd[i][j]->data =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(
+ fwd_info->buf_upd[i][j]->data))
+ return -ENOMEM;
+ fwd_info->buf_upd[i][j]->len =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(
+ fwd_info->buf_upd[i][j]->data);
+ fwd_info->buf_upd[i][j]->ctxt =
+ SET_BUF_CTXT(fwd_info->peripheral,
+ fwd_info->type, ((2 * i) + (j + 3)));
+ }
+
+ if (driver->supports_apps_hdlc_encoding) {
+ if (fwd_info->buf_upd[i][j] &&
+ !fwd_info->buf_upd[i][j]->data_raw) {
+ fwd_info->buf_upd[i][j]->data_raw =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(
+ fwd_info->buf_upd[i][j]->data_raw))
+ return -ENOMEM;
+ fwd_info->buf_upd[i][j]->len_raw =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(
+ fwd_info->buf_upd[i][j]->data_raw);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
{
+ int ret = 0;
+ unsigned char *temp_char_buf;
if (!fwd_info)
return;
@@ -1100,18 +1531,20 @@
}
mutex_lock(&fwd_info->buf_mutex);
+
if (!fwd_info->buf_1) {
fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_1)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_1))
goto err;
kmemleak_not_leak(fwd_info->buf_1);
}
+
if (!fwd_info->buf_1->data) {
fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_1->data))
goto err;
fwd_info->buf_1->len = PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_1->data);
@@ -1123,7 +1556,7 @@
if (!fwd_info->buf_2) {
fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_2)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_2))
goto err;
kmemleak_not_leak(fwd_info->buf_2);
}
@@ -1132,7 +1565,7 @@
fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_2->data)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_2->data))
goto err;
fwd_info->buf_2->len = PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_2->data);
@@ -1141,6 +1574,11 @@
fwd_info->type, 2);
}
+ if (driver->feature[fwd_info->peripheral].untag_header)
+ ret = diagfwd_buffers_allocate(fwd_info);
+ if (ret)
+ goto err;
+
if (driver->supports_apps_hdlc_encoding) {
/* In support of hdlc encoding */
if (!fwd_info->buf_1->data_raw) {
@@ -1148,34 +1586,44 @@
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data_raw)
+ temp_char_buf =
+ fwd_info->buf_1->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_char_buf))
goto err;
- fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_1->data_raw);
+ fwd_info->buf_1->len_raw =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(temp_char_buf);
}
+
if (!fwd_info->buf_2->data_raw) {
fwd_info->buf_2->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_2->data_raw)
+ temp_char_buf =
+ fwd_info->buf_2->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_char_buf))
goto err;
- fwd_info->buf_2->len_raw = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_2->data_raw);
+ fwd_info->buf_2->len_raw =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(temp_char_buf);
}
}
}
- if (fwd_info->type == TYPE_CMD && driver->supports_apps_hdlc_encoding) {
+ if (fwd_info->type == TYPE_CMD &&
+ driver->supports_apps_hdlc_encoding) {
/* In support of hdlc encoding */
if (!fwd_info->buf_1->data_raw) {
fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data_raw)
+ temp_char_buf =
+ fwd_info->buf_1->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_char_buf))
goto err;
fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_1->data_raw);
+ kmemleak_not_leak(temp_char_buf);
}
}
@@ -1185,10 +1633,12 @@
err:
mutex_unlock(&fwd_info->buf_mutex);
diagfwd_buffers_exit(fwd_info);
+ return;
}
static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info)
{
+ int i = 0;
if (!fwd_info)
return;
@@ -1210,6 +1660,24 @@
kfree(fwd_info->buf_2);
fwd_info->buf_2 = NULL;
}
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->buf_upd[i][0]) {
+ kfree(fwd_info->buf_upd[i][0]->data);
+ fwd_info->buf_upd[i][0]->data = NULL;
+ kfree(fwd_info->buf_upd[i][0]->data_raw);
+ fwd_info->buf_upd[i][0]->data_raw = NULL;
+ kfree(fwd_info->buf_upd[i][0]);
+ fwd_info->buf_upd[i][0] = NULL;
+ }
+ if (fwd_info->buf_upd[i][1]) {
+ kfree(fwd_info->buf_upd[i][1]->data);
+ fwd_info->buf_upd[i][1]->data = NULL;
+ kfree(fwd_info->buf_upd[i][1]->data_raw);
+ fwd_info->buf_upd[i][1]->data_raw = NULL;
+ kfree(fwd_info->buf_upd[i][1]);
+ fwd_info->buf_upd[i][1] = NULL;
+ }
+ }
mutex_unlock(&fwd_info->buf_mutex);
}
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index 5884a12..b16670e 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -68,6 +68,12 @@
uint8_t transport;
uint8_t inited;
uint8_t ch_open;
+ uint8_t num_pd;
+ uint8_t diagid_root;
+ uint8_t diagid_user[MAX_PERIPHERAL_UPD];
+ int cpd_len_1;
+ int cpd_len_2;
+ int upd_len[MAX_PERIPHERAL_UPD][2];
atomic_t opened;
unsigned long read_bytes;
unsigned long write_bytes;
@@ -77,6 +83,7 @@
void *ctxt;
struct diagfwd_buf_t *buf_1;
struct diagfwd_buf_t *buf_2;
+ struct diagfwd_buf_t *buf_upd[MAX_PERIPHERAL_UPD][2];
struct diagfwd_buf_t *buf_ptr[NUM_WRITE_BUFFERS];
struct diag_peripheral_ops *p_ops;
struct diag_channel_ops *c_ops;
@@ -94,6 +101,9 @@
void diagfwd_late_open(struct diagfwd_info *fwd_info);
void diagfwd_close(uint8_t peripheral, uint8_t type);
+
+int diag_md_get_peripheral(int ctxt);
+
int diagfwd_register(uint8_t transport, uint8_t peripheral, uint8_t type,
void *ctxt, struct diag_peripheral_ops *ops,
struct diagfwd_info **fwd_ctxt);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 7cdf45b..5638333 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2631,7 +2631,46 @@
pr_info(fmt, ##__VA_ARGS__); \
} while (0)
-int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
+/*
+ * clock_debug_print_enabled_debug_suspend() - Print names of enabled clocks
+ * during suspend.
+ */
+static void clock_debug_print_enabled_debug_suspend(struct seq_file *s)
+{
+ struct clk_core *core;
+ int cnt = 0;
+
+ if (!mutex_trylock(&clk_debug_lock))
+ return;
+
+ clock_debug_output(s, 0, "Enabled clocks:\n");
+
+ hlist_for_each_entry(core, &clk_debug_list, debug_node) {
+ if (!core || !core->prepare_count)
+ continue;
+
+ if (core->vdd_class)
+ clock_debug_output(s, 0, " %s:%u:%u [%ld, %d]",
+ core->name, core->prepare_count,
+ core->enable_count, core->rate,
+ clk_find_vdd_level(core, core->rate));
+
+ else
+ clock_debug_output(s, 0, " %s:%u:%u [%ld]",
+ core->name, core->prepare_count,
+ core->enable_count, core->rate);
+ cnt++;
+ }
+
+ mutex_unlock(&clk_debug_lock);
+
+ if (cnt)
+ clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt);
+ else
+ clock_debug_output(s, 0, "No clocks enabled.\n");
+}
+
+static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
{
char *start = "";
struct clk *clk;
@@ -3005,7 +3044,7 @@
if (likely(!debug_suspend))
return;
- clock_debug_print_enabled_clocks(NULL);
+ clock_debug_print_enabled_debug_suspend(NULL);
}
EXPORT_SYMBOL_GPL(clock_debug_print_enabled);
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index f0db049..b52aa25 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -10,6 +10,7 @@
*/
struct clk_hw;
+struct clk_core;
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 67c6b2d..9106027 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -28,11 +28,13 @@
struct device *dev;
struct dp_aux dp_aux;
struct dp_catalog_aux *catalog;
+ struct dp_aux_cfg *cfg;
struct mutex mutex;
struct completion comp;
u32 aux_error_num;
+ u32 retry_cnt;
bool cmd_busy;
bool native;
bool read;
@@ -127,7 +129,7 @@
timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
if (!timeout) {
- pr_err("aux write timeout\n");
+ pr_err("aux %s timeout\n", (aux->read ? "read" : "write"));
return -ETIMEDOUT;
}
@@ -232,6 +234,22 @@
dp_aux_i2c_handler(aux);
}
+static void dp_aux_reconfig(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->catalog->update_aux_cfg(aux->catalog,
+ aux->cfg, PHY_AUX_CFG1);
+ aux->catalog->reset(aux->catalog);
+}
+
/*
* This function does the real job to process an AUX transaction.
* It will call aux_reset() function to reset the AUX channel,
@@ -243,6 +261,7 @@
ssize_t ret;
int const aux_cmd_native_max = 16;
int const aux_cmd_i2c_max = 128;
+ int const retry_count = 5;
struct dp_aux_private *aux = container_of(drm_aux,
struct dp_aux_private, drm_aux);
@@ -270,8 +289,14 @@
}
ret = dp_aux_cmd_fifo_tx(aux, msg);
- if (ret < 0) {
- aux->catalog->reset(aux->catalog); /* reset aux */
+ if ((ret < 0) && aux->native) {
+ aux->retry_cnt++;
+ if (!(aux->retry_cnt % retry_count))
+ aux->catalog->update_aux_cfg(aux->catalog,
+ aux->cfg, PHY_AUX_CFG1);
+ aux->catalog->reset(aux->catalog);
+ goto unlock_exit;
+ } else if (ret < 0) {
goto unlock_exit;
}
@@ -289,6 +314,7 @@
/* Return requested size for success or retry */
ret = msg->size;
+ aux->retry_cnt = 0;
unlock_exit:
aux->cmd_busy = false;
@@ -296,11 +322,19 @@
return ret;
}
-static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
+static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg)
+{
+ int i = 0;
+
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+ aux_cfg[i].current_index = 0;
+}
+
+static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
{
struct dp_aux_private *aux;
- if (!dp_aux) {
+ if (!dp_aux || !aux_cfg) {
pr_err("invalid input\n");
return;
}
@@ -309,6 +343,8 @@
aux->catalog->reset(aux->catalog);
aux->catalog->enable(aux->catalog, true);
+ aux->retry_cnt = 0;
+ dp_aux_reset_phy_config_indices(aux_cfg);
aux->catalog->setup(aux->catalog, aux_cfg);
}
@@ -365,13 +401,14 @@
drm_dp_aux_unregister(&aux->drm_aux);
}
-struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
+ struct dp_aux_cfg *aux_cfg)
{
int rc = 0;
struct dp_aux_private *aux;
struct dp_aux *dp_aux;
- if (!catalog) {
+ if (!catalog || !aux_cfg) {
pr_err("invalid input\n");
rc = -ENODEV;
goto error;
@@ -389,13 +426,16 @@
aux->dev = dev;
aux->catalog = catalog;
+ aux->cfg = aux_cfg;
dp_aux = &aux->dp_aux;
+ aux->retry_cnt = 0;
dp_aux->isr = dp_aux_isr;
dp_aux->init = dp_aux_init;
dp_aux->deinit = dp_aux_deinit;
dp_aux->drm_aux_register = dp_aux_register;
dp_aux->drm_aux_deregister = dp_aux_deregister;
+ dp_aux->reconfig = dp_aux_reconfig;
return dp_aux;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index f08c12b..5d96fd9 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -32,11 +32,13 @@
int (*drm_aux_register)(struct dp_aux *aux);
void (*drm_aux_deregister)(struct dp_aux *aux);
void (*isr)(struct dp_aux *aux);
- void (*init)(struct dp_aux *aux, u32 *aux_cfg);
+ void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
void (*deinit)(struct dp_aux *aux);
+ void (*reconfig)(struct dp_aux *aux);
};
-struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog);
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
+ struct dp_aux_cfg *aux_cfg);
void dp_aux_put(struct dp_aux *aux);
#endif /*__DP_AUX_H_*/
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 914c408..95a7dc4 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -175,11 +175,37 @@
dp_write(base + DP_AUX_CTRL, aux_ctrl);
}
-static void dp_catalog_aux_setup(struct dp_catalog_aux *aux, u32 *aux_cfg)
+static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type)
{
struct dp_catalog_private *catalog;
+ u32 new_index = 0, current_index = 0;
- if (!aux || !aux_cfg) {
+ if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(aux);
+
+ current_index = cfg[type].current_index;
+ new_index = (current_index + 1) % cfg[type].cfg_cnt;
+ pr_debug("Updating %s from 0x%08x to 0x%08x\n",
+ dp_phy_aux_config_type_to_string(type),
+ cfg[type].lut[current_index], cfg[type].lut[new_index]);
+
+ dp_write(catalog->io->phy_io.base + cfg[type].offset,
+ cfg[type].lut[new_index]);
+ cfg[type].current_index = new_index;
+}
+
+static void dp_catalog_aux_setup(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *cfg)
+{
+ struct dp_catalog_private *catalog;
+ int i = 0;
+
+ if (!aux || !cfg) {
pr_err("invalid input\n");
return;
}
@@ -195,16 +221,13 @@
QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
/* DP AUX CFG register programming */
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG0, aux_cfg[0]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG1, aux_cfg[1]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG2, aux_cfg[2]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG3, aux_cfg[3]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG4, aux_cfg[4]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG5, aux_cfg[5]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG6, aux_cfg[6]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG7, aux_cfg[7]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG8, aux_cfg[8]);
- dp_write(catalog->io->phy_io.base + DP_PHY_AUX_CFG9, aux_cfg[9]);
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
+ pr_debug("%s: offset=0x%08x, value=0x%08x\n",
+ dp_phy_aux_config_type_to_string(i),
+ cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
+ dp_write(catalog->io->phy_io.base + cfg[i].offset,
+ cfg[i].lut[cfg[i].current_index]);
+ }
dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
}
@@ -723,6 +746,7 @@
.write_data = dp_catalog_aux_write_data,
.write_trans = dp_catalog_aux_write_trans,
.reset = dp_catalog_aux_reset,
+ .update_aux_cfg = dp_catalog_aux_update_cfg,
.enable = dp_catalog_aux_enable,
.setup = dp_catalog_aux_setup,
.get_irq = dp_catalog_aux_get_irq,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 2bd6bfd..7fde025 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -43,7 +43,10 @@
int (*write_trans)(struct dp_catalog_aux *aux);
void (*reset)(struct dp_catalog_aux *aux);
void (*enable)(struct dp_catalog_aux *aux, bool enable);
- void (*setup)(struct dp_catalog_aux *aux, u32 *aux_cfg);
+ void (*update_aux_cfg)(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type);
+ void (*setup)(struct dp_catalog_aux *aux,
+ struct dp_aux_cfg *aux_cfg);
void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy);
};
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index e191c1a..b4dafe4 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -502,13 +502,10 @@
int rc = 0;
u32 max_pclk_from_edid = 0;
- rc = dp->panel->read_dpcd(dp->panel);
+ rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
return rc;
- sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
- (void **)&dp->panel->edid_ctrl);
-
max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
@@ -729,7 +726,7 @@
goto err;
}
- dp->aux = dp_aux_get(dev, &dp->catalog->aux);
+ dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
pr_err("failed to initialize aux, rc = %d\n", rc);
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index d4e33e9..2e21033 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -28,6 +28,7 @@
struct dp_aux *aux;
struct dp_catalog_panel *catalog;
bool lane_switch_supported;
+ bool aux_cfg_update_done;
};
static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
@@ -80,6 +81,71 @@
return rc;
}
+
+static int dp_panel_read_edid(struct dp_panel *dp_panel,
+ struct drm_connector *connector)
+{
+ int retry_cnt = 0;
+ const int max_retry = 10;
+ struct dp_panel_private *panel;
+
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+ do {
+ sde_get_edid(connector, &panel->aux->drm_aux->ddc,
+ (void **)&dp_panel->edid_ctrl);
+ if (!dp_panel->edid_ctrl->edid) {
+ pr_err("EDID read failed\n");
+ retry_cnt++;
+ panel->aux->reconfig(panel->aux);
+ panel->aux_cfg_update_done = true;
+ } else {
+ return 0;
+ }
+ } while (retry_cnt < max_retry);
+
+ return -EINVAL;
+}
+
+static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
+ struct drm_connector *connector)
+{
+ int rc = 0;
+ struct dp_panel_private *panel;
+
+ if (!dp_panel || !connector) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+ rc = dp_panel_read_dpcd(dp_panel);
+ if (rc) {
+ pr_err("panel dpcd read failed\n");
+ return rc;
+ }
+
+ rc = dp_panel_read_edid(dp_panel, connector);
+ if (rc) {
+ pr_err("panel edid read failed\n");
+ return rc;
+ }
+
+ if (panel->aux_cfg_update_done) {
+ pr_debug("read DPCD with updated AUX config\n");
+ dp_panel_read_dpcd(dp_panel);
+ panel->aux_cfg_update_done = false;
+ }
+
+ return 0;
+}
+
static u32 dp_panel_get_max_pclk(struct dp_panel *dp_panel)
{
struct drm_dp_link *link_info;
@@ -290,12 +356,13 @@
panel->catalog = catalog;
dp_panel = &panel->dp_panel;
+ panel->aux_cfg_update_done = false;
dp_panel->sde_edid_register = dp_panel_edid_register;
dp_panel->sde_edid_deregister = dp_panel_edid_deregister;
dp_panel->init_info = dp_panel_init_panel_info;
dp_panel->timing_cfg = dp_panel_timing_cfg;
- dp_panel->read_dpcd = dp_panel_read_dpcd;
+ dp_panel->read_sink_caps = dp_panel_read_sink_caps;
dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate;
dp_panel->get_max_pclk = dp_panel_get_max_pclk;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 6cca0f1..ab9a451 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -43,6 +43,7 @@
struct drm_dp_link link_info;
struct sde_edid_ctrl *edid_ctrl;
+ struct drm_connector *connector;
struct dp_panel_info pinfo;
u32 vic;
@@ -52,7 +53,8 @@
void (*sde_edid_deregister)(struct dp_panel *dp_panel);
int (*init_info)(struct dp_panel *dp_panel);
int (*timing_cfg)(struct dp_panel *dp_panel);
- int (*read_dpcd)(struct dp_panel *dp_panel);
+ int (*read_sink_caps)(struct dp_panel *dp_panel,
+ struct drm_connector *connector);
u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel);
u32 (*get_max_pclk)(struct dp_panel *dp_panel);
};
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index e81bbb3..c85c2a2 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -101,23 +101,85 @@
return rc;
}
+static const char *dp_get_phy_aux_config_property(u32 cfg_type)
+{
+ switch (cfg_type) {
+ case PHY_AUX_CFG0:
+ return "qcom,aux-cfg0-settings";
+ case PHY_AUX_CFG1:
+ return "qcom,aux-cfg1-settings";
+ case PHY_AUX_CFG2:
+ return "qcom,aux-cfg2-settings";
+ case PHY_AUX_CFG3:
+ return "qcom,aux-cfg3-settings";
+ case PHY_AUX_CFG4:
+ return "qcom,aux-cfg4-settings";
+ case PHY_AUX_CFG5:
+ return "qcom,aux-cfg5-settings";
+ case PHY_AUX_CFG6:
+ return "qcom,aux-cfg6-settings";
+ case PHY_AUX_CFG7:
+ return "qcom,aux-cfg7-settings";
+ case PHY_AUX_CFG8:
+ return "qcom,aux-cfg8-settings";
+ case PHY_AUX_CFG9:
+ return "qcom,aux-cfg9-settings";
+ default:
+ return "unknown";
+ }
+}
+
+static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser)
+{
+ int i = 0;
+
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+ parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 };
+}
+
static int dp_parser_aux(struct dp_parser *parser)
{
- int len = 0, i = 0, rc = 0;
struct device_node *of_node = parser->pdev->dev.of_node;
+ int len = 0, i = 0, j = 0, config_count = 0;
const char *data;
+ int const minimum_config_count = 1;
- data = of_get_property(of_node, "qcom,aux-cfg-settings", &len);
- if (!data || (len != AUX_CFG_LEN)) {
- pr_err("Unable to read DP AUX CFG settings\n");
- rc = -EINVAL;
- goto end;
+ for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
+ const char *property = dp_get_phy_aux_config_property(i);
+
+ data = of_get_property(of_node, property, &len);
+ if (!data) {
+ pr_err("Unable to read %s\n", property);
+ goto error;
+ }
+
+ config_count = len - 1;
+ if ((config_count < minimum_config_count) ||
+ (config_count > DP_AUX_CFG_MAX_VALUE_CNT)) {
+ pr_err("Invalid config count (%d) configs for %s\n",
+ config_count, property);
+ goto error;
+ }
+
+ parser->aux_cfg[i].offset = data[0];
+ parser->aux_cfg[i].cfg_cnt = config_count;
+ pr_debug("%s offset=0x%x, cfg_cnt=%d\n",
+ property,
+ parser->aux_cfg[i].offset,
+ parser->aux_cfg[i].cfg_cnt);
+ for (j = 1; j < len; j++) {
+ parser->aux_cfg[i].lut[j - 1] = data[j];
+ pr_debug("%s lut[%d]=0x%x\n",
+ property,
+ i,
+ parser->aux_cfg[i].lut[j - 1]);
+ }
}
+ return 0;
- for (i = 0; i < len; i++)
- parser->aux_cfg[i] = data[i];
-end:
- return rc;
+error:
+ dp_parser_phy_aux_cfg_reset(parser);
+ return -EINVAL;
}
static int dp_parser_misc(struct dp_parser *parser)
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index fdcdd3a..7794da5 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -93,6 +93,66 @@
struct pinctrl_state *state_suspend;
};
+#define DP_ENUM_STR(x) #x
+#define DP_AUX_CFG_MAX_VALUE_CNT 3
+/**
+ * struct dp_aux_cfg - DP's AUX configuration settings
+ *
+ * @cfg_cnt: count of the configurable settings for the AUX register
+ * @current_index: current index of the AUX config lut
+ * @offset: register offset of the AUX config register
+ * @lut: look up table for the AUX config values for this register
+ */
+struct dp_aux_cfg {
+ u32 cfg_cnt;
+ u32 current_index;
+ u32 offset;
+ u32 lut[DP_AUX_CFG_MAX_VALUE_CNT];
+};
+
+/* PHY AUX config registers */
+enum dp_phy_aux_config_type {
+ PHY_AUX_CFG0,
+ PHY_AUX_CFG1,
+ PHY_AUX_CFG2,
+ PHY_AUX_CFG3,
+ PHY_AUX_CFG4,
+ PHY_AUX_CFG5,
+ PHY_AUX_CFG6,
+ PHY_AUX_CFG7,
+ PHY_AUX_CFG8,
+ PHY_AUX_CFG9,
+ PHY_AUX_CFG_MAX,
+};
+
+static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
+{
+ switch (cfg_type) {
+ case PHY_AUX_CFG0:
+ return DP_ENUM_STR(PHY_AUX_CFG0);
+ case PHY_AUX_CFG1:
+ return DP_ENUM_STR(PHY_AUX_CFG1);
+ case PHY_AUX_CFG2:
+ return DP_ENUM_STR(PHY_AUX_CFG2);
+ case PHY_AUX_CFG3:
+ return DP_ENUM_STR(PHY_AUX_CFG3);
+ case PHY_AUX_CFG4:
+ return DP_ENUM_STR(PHY_AUX_CFG4);
+ case PHY_AUX_CFG5:
+ return DP_ENUM_STR(PHY_AUX_CFG5);
+ case PHY_AUX_CFG6:
+ return DP_ENUM_STR(PHY_AUX_CFG6);
+ case PHY_AUX_CFG7:
+ return DP_ENUM_STR(PHY_AUX_CFG7);
+ case PHY_AUX_CFG8:
+ return DP_ENUM_STR(PHY_AUX_CFG8);
+ case PHY_AUX_CFG9:
+ return DP_ENUM_STR(PHY_AUX_CFG9);
+ default:
+ return "unknown";
+ }
+}
+
/**
* struct dp_parser - DP parser's data exposed to clients
*
@@ -111,7 +171,7 @@
struct dp_display_data disp_data;
u8 l_map[4];
- u32 aux_cfg[AUX_CFG_LEN];
+ struct dp_aux_cfg aux_cfg[AUX_CFG_LEN];
u32 max_pclk_khz;
int (*parse)(struct dp_parser *parser);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 20dd14e..96136ba 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -2032,8 +2032,6 @@
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0);
- /* Perform a soft reset before enabling dsi controller */
- dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
pr_debug("[DSI_%d]Host initialization complete\n",
dsi_ctrl->cell_index);
dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 797d969..547a3e5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -3716,6 +3716,13 @@
goto error_ctrl_clk_off;
}
+ rc = dsi_display_set_clk_src(display);
+ if (rc) {
+ pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
+ display->name, rc);
+ goto error_phy_disable;
+ }
+
rc = dsi_display_ctrl_init(display);
if (rc) {
pr_err("[%s] failed to setup DSI controller, rc=%d\n",
@@ -3723,10 +3730,10 @@
goto error_phy_disable;
}
- rc = dsi_display_set_clk_src(display);
+ rc = dsi_display_ctrl_host_enable(display);
if (rc) {
- pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
- display->name, rc);
+ pr_err("[%s] failed to enable DSI host, rc=%d\n",
+ display->name, rc);
goto error_ctrl_deinit;
}
@@ -3735,29 +3742,28 @@
if (rc) {
pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
display->name, rc);
- goto error_ctrl_deinit;
+ goto error_host_engine_off;
}
- rc = dsi_display_ctrl_host_enable(display);
+ rc = dsi_display_soft_reset(display);
if (rc) {
- pr_err("[%s] failed to enable DSI host, rc=%d\n",
- display->name, rc);
+ pr_err("[%s] failed soft reset, rc=%d\n", display->name, rc);
goto error_ctrl_link_off;
}
rc = dsi_panel_prepare(display->panel);
if (rc) {
pr_err("[%s] panel prepare failed, rc=%d\n", display->name, rc);
- goto error_host_engine_off;
+ goto error_ctrl_link_off;
}
goto error;
-error_host_engine_off:
- (void)dsi_display_ctrl_host_disable(display);
error_ctrl_link_off:
(void)dsi_display_clk_ctrl(display->dsi_clk_handle,
DSI_LINK_CLK, DSI_CLK_OFF);
+error_host_engine_off:
+ (void)dsi_display_ctrl_host_disable(display);
error_ctrl_deinit:
(void)dsi_display_ctrl_deinit(display);
error_phy_disable:
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 113664a..431a67e 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -941,6 +941,7 @@
/* GPUCC registers */
#define A6XX_GPU_CC_GX_GDSCR 0x24403
+#define A6XX_GPU_CC_GX_DOMAIN_MISC 0x24542
/* GPU RSC sequencer registers */
#define A6XX_RSCC_PDC_SEQ_START_ADDR 0x23408
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4900b3a..01b877f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -642,6 +642,8 @@
ADRENO_REG_GMU_HOST2GMU_INTR_SET,
ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
+ ADRENO_REG_GMU_NMI_CONTROL_STATUS,
+ ADRENO_REG_GMU_CM3_CFG,
ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
ADRENO_REG_REGISTER_MAX,
};
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index a25652a..5551cea 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1289,6 +1289,10 @@
{
struct gmu_device *gmu = &device->gmu;
struct device *dev = &gmu->pdev->dev;
+ int val;
+
+ kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val);
+ WARN_ON(!(val & 0x1));
/* RSC wake sequence */
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1));
@@ -2770,6 +2774,10 @@
A6XX_GMU_HOST2GMU_INTR_CLR),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
A6XX_GMU_HOST2GMU_INTR_RAW_INFO),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_NMI_CONTROL_STATUS,
+ A6XX_GMU_NMI_CONTROL_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_CM3_CFG,
+ A6XX_GMU_CM3_CFG),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
A6XX_RBBM_SECVID_TRUST_CNTL),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 70afc91..e1f1595 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -231,9 +231,9 @@
0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA03,
/* GPU RSCC */
- 0x23740, 0x23742, 0x23744, 0x23747, 0x2374C, 0x23787, 0x237EC, 0x237EF,
- 0x237F4, 0x2382F, 0x23894, 0x23897, 0x2389C, 0x238D7, 0x2393C, 0x2393F,
- 0x23944, 0x2397F,
+ 0x2348C, 0x2348C, 0x23501, 0x23502, 0x23740, 0x23742, 0x23744, 0x23747,
+ 0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897,
+ 0x2389C, 0x238D7, 0x2393C, 0x2393F, 0x23944, 0x2397F,
/* GMU AO */
0x23B00, 0x23B16, 0x23C00, 0x23C00,
/* GPU CC */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 4aaea80..6bad70b 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -669,9 +669,14 @@
static inline int kgsl_state_is_awake(struct kgsl_device *device)
{
+ struct gmu_device *gmu = &device->gmu;
+
if (device->state == KGSL_STATE_ACTIVE ||
device->state == KGSL_STATE_AWARE)
return true;
+ else if (kgsl_gmu_isenabled(device) &&
+ test_bit(GMU_CLK_ON, &gmu->flags))
+ return true;
else
return false;
}
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 2848424..c511040 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1344,6 +1344,36 @@
return 0;
}
+static void gmu_snapshot(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct gmu_device *gmu = &device->gmu;
+
+ if (!test_and_set_bit(GMU_FAULT, &gmu->flags)) {
+ /* Mask so there's no interrupt caused by NMI */
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
+
+ /* Make sure the interrupt is masked before causing it */
+ wmb();
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0);
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_CM3_CFG, (1 << 9));
+
+ /* Wait for the NMI to be handled */
+ wmb();
+ udelay(100);
+ kgsl_device_snapshot(device, NULL);
+
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
+ (unsigned int) ~HFI_IRQ_MASK);
+ }
+}
+
/* To be called to power on both GPU and GMU */
int gmu_start(struct kgsl_device *device)
{
@@ -1449,11 +1479,6 @@
break;
}
- /*
- * OOB to enable power management of GMU.
- * In v2, this function call shall move ahead
- * of hfi_start() to save power.
- */
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
gpudev->oob_clear(adreno_dev,
OOB_BOOT_SLUMBER_CLEAR_MASK);
@@ -1461,15 +1486,17 @@
return ret;
error_gpu:
+ gmu_snapshot(device);
hfi_stop(gmu);
gmu_irq_disable(device);
- if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
- gpudev->oob_clear(adreno_dev,
- OOB_BOOT_SLUMBER_CLEAR_MASK);
+ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
+ gpudev->oob_clear(adreno_dev,
+ OOB_BOOT_SLUMBER_CLEAR_MASK);
gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
error_bus:
- msm_bus_scale_client_update_request(gmu->pcl, 0);
+ msm_bus_scale_client_update_request(gmu->pcl, 0);
error_clks:
+ gmu_snapshot(device);
gmu_disable_clks(gmu);
gmu_disable_gdsc(gmu);
return ret;
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index a741beb..63ca028 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -82,6 +82,7 @@
GMU_BOOT_INIT_DONE = 0,
GMU_CLK_ON = 1,
GMU_HFI_ON = 2,
+ GMU_FAULT = 3
};
/**
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index cb19cef..f18022b 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -160,18 +160,19 @@
#define QPNP_WLED_MOD_EN_SHFT 7
#define QPNP_WLED_MOD_EN 1
#define QPNP_WLED_GATE_DRV_MASK 0xFE
-#define QPNP_WLED_SYNC_DLY_MASK 0xF8
+#define QPNP_WLED_SYNC_DLY_MASK GENMASK(2, 0)
#define QPNP_WLED_SYNC_DLY_MIN_US 0
#define QPNP_WLED_SYNC_DLY_MAX_US 1400
#define QPNP_WLED_SYNC_DLY_STEP_US 200
#define QPNP_WLED_DEF_SYNC_DLY_US 400
-#define QPNP_WLED_FS_CURR_MASK 0xF0
+#define QPNP_WLED_FS_CURR_MASK GENMASK(3, 0)
#define QPNP_WLED_FS_CURR_MIN_UA 0
#define QPNP_WLED_FS_CURR_MAX_UA 30000
#define QPNP_WLED_FS_CURR_STEP_UA 2500
-#define QPNP_WLED_CABC_MASK 0x7F
+#define QPNP_WLED_CABC_MASK 0x80
#define QPNP_WLED_CABC_SHIFT 7
#define QPNP_WLED_CURR_SINK_SHIFT 4
+#define QPNP_WLED_CURR_SINK_MASK GENMASK(7, 4)
#define QPNP_WLED_BRIGHT_LSB_MASK 0xFF
#define QPNP_WLED_BRIGHT_MSB_SHIFT 8
#define QPNP_WLED_BRIGHT_MSB_MASK 0x0F
@@ -208,12 +209,14 @@
#define QPNP_WLED_SEC_UNLOCK 0xA5
#define QPNP_WLED_MAX_STRINGS 4
+#define QPNP_PM660_WLED_MAX_STRINGS 3
#define WLED_MAX_LEVEL_4095 4095
#define QPNP_WLED_RAMP_DLY_MS 20
#define QPNP_WLED_TRIGGER_NONE "none"
#define QPNP_WLED_STR_SIZE 20
#define QPNP_WLED_MIN_MSLEEP 20
#define QPNP_WLED_SC_DLY_MS 20
+#define QPNP_WLED_SOFT_START_DLY_US 10000
#define NUM_SUPPORTED_AVDD_VOLTAGES 6
#define QPNP_WLED_DFLT_AVDD_MV 7600
@@ -381,6 +384,8 @@
u16 ramp_ms;
u16 ramp_step;
u16 cons_sync_write_delay_us;
+ u16 auto_calibration_ovp_count;
+ u16 max_strings;
u8 strings[QPNP_WLED_MAX_STRINGS];
u8 num_strings;
u8 loop_auto_gm_thresh;
@@ -396,6 +401,9 @@
bool en_ext_pfet_sc_pro;
bool prev_state;
bool ovp_irq_disabled;
+ bool auto_calib_enabled;
+ bool auto_calib_done;
+ ktime_t start_ovp_fault_time;
};
/* helper to read a pmic register */
@@ -531,7 +539,7 @@
u8 reg;
/* set brightness registers */
- for (i = 0; i < wled->num_strings; i++) {
+ for (i = 0; i < wled->max_strings; i++) {
reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
rc = qpnp_wled_write_reg(wled,
QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base,
@@ -600,7 +608,8 @@
* OVP interrupt disabled when the module is disabled.
*/
if (state) {
- usleep_range(10000, 11000);
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
rc = qpnp_wled_psm_config(wled, false);
if (rc < 0)
return rc;
@@ -873,32 +882,25 @@
struct device_attribute *attr, const char *buf, size_t count)
{
struct qpnp_wled *wled = dev_get_drvdata(dev);
- int data, i, rc, temp;
+ int data, i, rc;
u8 reg;
rc = kstrtoint(buf, 10, &data);
if (rc)
return rc;
- for (i = 0; i < wled->num_strings; i++) {
+ for (i = 0; i < wled->max_strings; i++) {
if (data < QPNP_WLED_FS_CURR_MIN_UA)
data = QPNP_WLED_FS_CURR_MIN_UA;
else if (data > QPNP_WLED_FS_CURR_MAX_UA)
data = QPNP_WLED_FS_CURR_MAX_UA;
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), ®);
+ reg = data / QPNP_WLED_FS_CURR_STEP_UA;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
+ QPNP_WLED_FS_CURR_MASK, reg);
if (rc < 0)
return rc;
- reg &= QPNP_WLED_FS_CURR_MASK;
- temp = data / QPNP_WLED_FS_CURR_STEP_UA;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
}
wled->fs_curr_ua = data;
@@ -1090,6 +1092,229 @@
return 0;
}
+#define AUTO_CALIB_BRIGHTNESS 16
+static int wled_auto_calibrate(struct qpnp_wled *wled)
+{
+ int rc = 0, i;
+ u8 reg = 0, sink_config = 0, sink_test = 0, sink_valid = 0, int_sts;
+
+ mutex_lock(&wled->lock);
+
+ /* disable OVP IRQ */
+ if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
+ disable_irq_nosync(wled->ovp_irq);
+ wled->ovp_irq_disabled = true;
+ }
+
+ /* read configured sink configuration */
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), &sink_config);
+ if (rc < 0) {
+ pr_err("Failed to read SINK configuration rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* disable the module before starting calibration */
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK, 0);
+ if (rc < 0) {
+ pr_err("Failed to disable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* set low brightness across all sinks */
+ rc = qpnp_wled_set_level(wled, AUTO_CALIB_BRIGHTNESS);
+ if (rc < 0) {
+ pr_err("Failed to set brightness for calibration rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* disable all sinks */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), 0);
+ if (rc < 0) {
+ pr_err("Failed to disable all sinks rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK,
+ QPNP_WLED_MODULE_EN_MASK);
+ if (rc < 0) {
+ pr_err("Failed to enable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+ /*
+ * Delay for the WLED soft-start, check the OVP status
+ * only after soft-start is complete
+ */
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
+
+ /* iterate through the strings one by one */
+ for (i = 0; i < wled->max_strings; i++) {
+ sink_test = 1 << (QPNP_WLED_CURR_SINK_SHIFT + i);
+
+ /* Enable feedback control */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
+ i + 1);
+ if (rc < 0) {
+ pr_err("Failed to enable feedback for SINK %d rc = %d\n",
+ i + 1, rc);
+ goto failed_calib;
+ }
+
+ /* enable the sink */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_test);
+ if (rc < 0) {
+ pr_err("Failed to configure SINK %d rc=%d\n",
+ i + 1, rc);
+ goto failed_calib;
+ }
+
+ /* delay for WLED soft-start */
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
+
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts);
+ if (rc < 0) {
+ pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ if (int_sts & QPNP_WLED_OVP_FAULT_BIT)
+ pr_debug("WLED OVP fault detected with SINK %d\n",
+ i + 1);
+ else
+ sink_valid |= sink_test;
+ }
+
+ if (sink_valid == sink_config) {
+ pr_debug("WLED auto-calibration complete, default sink-config=%x OK!\n",
+ sink_config);
+ } else {
+ pr_warn("Invalid WLED default sink config=%x changing it to=%x\n",
+ sink_config, sink_valid);
+ sink_config = sink_valid;
+ }
+
+ if (!sink_config) {
+ pr_warn("No valid WLED sinks found\n");
+ goto failed_calib;
+ }
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK, 0);
+ if (rc < 0) {
+ pr_err("Failed to disable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* write the new sink configuration */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_config);
+ if (rc < 0) {
+ pr_err("Failed to reconfigure the default sink rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* MODULATOR_EN setting for valid sinks */
+ for (i = 0; i < wled->max_strings; i++) {
+ if (sink_config & (1 << (QPNP_WLED_CURR_SINK_SHIFT + i)))
+ reg = (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT);
+ else
+ reg = 0x0; /* disable modulator_en for unused sink */
+
+ if (wled->dim_mode == QPNP_WLED_DIM_HYBRID)
+ reg &= QPNP_WLED_GATE_DRV_MASK;
+ else
+ reg |= ~QPNP_WLED_GATE_DRV_MASK;
+
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg);
+ if (rc < 0) {
+ pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc);
+ goto failed_calib;
+ }
+ }
+
+ /* restore the feedback setting */
+ rc = qpnp_wled_write_reg(wled,
+ QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
+ wled->fdbk_op);
+ if (rc < 0) {
+ pr_err("Failed to restore feedback setting rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* restore brightness */
+ rc = qpnp_wled_set_level(wled, wled->cdev.brightness);
+ if (rc < 0) {
+ pr_err("Failed to set brightness after calibration rc=%d\n",
+ rc);
+ goto failed_calib;
+ }
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
+ QPNP_WLED_MODULE_EN_MASK,
+ QPNP_WLED_MODULE_EN_MASK);
+ if (rc < 0) {
+ pr_err("Failed to enable WLED module rc=%d\n", rc);
+ goto failed_calib;
+ }
+
+ /* delay for WLED soft-start */
+ usleep_range(QPNP_WLED_SOFT_START_DLY_US,
+ QPNP_WLED_SOFT_START_DLY_US + 1000);
+
+failed_calib:
+ if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
+ enable_irq(wled->ovp_irq);
+ wled->ovp_irq_disabled = false;
+ }
+ mutex_unlock(&wled->lock);
+ return rc;
+}
+
+#define WLED_AUTO_CAL_OVP_COUNT 5
+#define WLED_AUTO_CAL_CNT_DLY_US 1000000 /* 1 second */
+static bool qpnp_wled_auto_cal_required(struct qpnp_wled *wled)
+{
+ s64 elapsed_time_us;
+
+ /*
+ * Check if the OVP fault was an occasional one
+ * or if its firing continuously, the latter qualifies
+ * for an auto-calibration check.
+ */
+ if (!wled->auto_calibration_ovp_count) {
+ wled->start_ovp_fault_time = ktime_get();
+ wled->auto_calibration_ovp_count++;
+ } else {
+ elapsed_time_us = ktime_us_delta(ktime_get(),
+ wled->start_ovp_fault_time);
+ if (elapsed_time_us > WLED_AUTO_CAL_CNT_DLY_US)
+ wled->auto_calibration_ovp_count = 0;
+ else
+ wled->auto_calibration_ovp_count++;
+
+ if (wled->auto_calibration_ovp_count >=
+ WLED_AUTO_CAL_OVP_COUNT) {
+ wled->auto_calibration_ovp_count = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* ovp irq handler */
static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled)
{
@@ -1114,6 +1339,21 @@
if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT))
pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
int_sts, fault_sts);
+
+ if (fault_sts & QPNP_WLED_OVP_FAULT_BIT) {
+ if (wled->auto_calib_enabled && !wled->auto_calib_done) {
+ if (qpnp_wled_auto_cal_required(wled)) {
+ rc = wled_auto_calibrate(wled);
+ if (rc < 0) {
+ pr_err("Failed auto-calibration rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
+ wled->auto_calib_done = true;
+ }
+ }
+ }
+
return IRQ_HANDLED;
}
@@ -1423,7 +1663,7 @@
static int qpnp_wled_config(struct qpnp_wled *wled)
{
int rc, i, temp;
- u8 reg = 0;
+ u8 reg = 0, sink_en = 0, mask;
/* Configure display type */
rc = qpnp_wled_set_disp(wled, wled->ctrl_base);
@@ -1622,16 +1862,50 @@
rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base),
reg);
+ for (i = 0; i < wled->max_strings; i++) {
+ /* SYNC DELAY */
+ if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
+ wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
+
+ reg = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
+ mask = QPNP_WLED_SYNC_DLY_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_SYNC_DLY_REG(wled->sink_base, i),
+ mask, reg);
+ if (rc < 0)
+ return rc;
+
+ /* FULL SCALE CURRENT */
+ if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
+ wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
+
+ reg = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
+ mask = QPNP_WLED_FS_CURR_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
+ mask, reg);
+ if (rc < 0)
+ return rc;
+
+ /* CABC */
+ reg = wled->en_cabc ? (1 << QPNP_WLED_CABC_SHIFT) : 0;
+ mask = QPNP_WLED_CABC_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_CABC_REG(wled->sink_base, i),
+ mask, reg);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* Settings specific to valid sinks */
for (i = 0; i < wled->num_strings; i++) {
- if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) {
+ if (wled->strings[i] >= wled->max_strings) {
dev_err(&wled->pdev->dev, "Invalid string number\n");
return -EINVAL;
}
-
/* MODULATOR */
rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_MOD_EN_REG(wled->sink_base,
- wled->strings[i]), ®);
+ QPNP_WLED_MOD_EN_REG(wled->sink_base, i), ®);
if (rc < 0)
return rc;
reg &= QPNP_WLED_MOD_EN_MASK;
@@ -1643,72 +1917,22 @@
reg |= ~QPNP_WLED_GATE_DRV_MASK;
rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_MOD_EN_REG(wled->sink_base,
- wled->strings[i]), reg);
+ QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg);
if (rc)
return rc;
- /* SYNC DELAY */
- if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
- wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
-
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
- wled->strings[i]), ®);
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_SYNC_DLY_MASK;
- temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
-
- /* FULL SCALE CURRENT */
- if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
- wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
-
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), ®);
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_FS_CURR_MASK;
- temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_FS_CURR_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
-
- /* CABC */
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_CABC_REG(wled->sink_base,
- wled->strings[i]), ®);
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_CABC_MASK;
- reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT);
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_CABC_REG(wled->sink_base,
- wled->strings[i]), reg);
- if (rc)
- return rc;
-
- /* Enable CURRENT SINK */
- rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_CURR_SINK_REG(wled->sink_base), ®);
- if (rc < 0)
- return rc;
+ /* SINK EN */
temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT;
- reg |= (1 << temp);
- rc = qpnp_wled_write_reg(wled,
- QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg);
- if (rc)
- return rc;
+ sink_en |= (1 << temp);
+ }
+ mask = QPNP_WLED_CURR_SINK_MASK;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_CURR_SINK_REG(wled->sink_base),
+ mask, sink_en);
+ if (rc < 0) {
+ dev_err(&wled->pdev->dev,
+ "Failed to enable WLED sink config rc = %d\n", rc);
+ return rc;
}
rc = qpnp_wled_sync_reg_toggle(wled);
@@ -1728,8 +1952,13 @@
wled->ovp_irq, rc);
return rc;
}
- disable_irq(wled->ovp_irq);
- wled->ovp_irq_disabled = true;
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), ®);
+ /* disable the OVP irq only if the module is not enabled */
+ if (!rc && !(reg & QPNP_WLED_MODULE_EN_MASK)) {
+ disable_irq(wled->ovp_irq);
+ wled->ovp_irq_disabled = true;
+ }
}
if (wled->sc_irq >= 0) {
@@ -2091,11 +2320,16 @@
wled->en_cabc = of_property_read_bool(pdev->dev.of_node,
"qcom,en-cabc");
+ if (wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
+ wled->max_strings = QPNP_PM660_WLED_MAX_STRINGS;
+ else
+ wled->max_strings = QPNP_WLED_MAX_STRINGS;
+
prop = of_find_property(pdev->dev.of_node,
"qcom,led-strings-list", &temp_val);
if (!prop || !temp_val || temp_val > QPNP_WLED_MAX_STRINGS) {
dev_err(&pdev->dev, "Invalid strings info, use default");
- wled->num_strings = QPNP_WLED_MAX_STRINGS;
+ wled->num_strings = wled->max_strings;
for (i = 0; i < wled->num_strings; i++)
wled->strings[i] = i;
} else {
@@ -2118,6 +2352,9 @@
wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node,
"qcom,lcd-psm-ctrl");
+
+ wled->auto_calib_enabled = of_property_read_bool(pdev->dev.of_node,
+ "qcom,auto-calibration-enable");
return 0;
}
@@ -2186,13 +2423,13 @@
}
mutex_init(&wled->bus_lock);
+ mutex_init(&wled->lock);
rc = qpnp_wled_config(wled);
if (rc) {
dev_err(&pdev->dev, "wled config failed\n");
return rc;
}
- mutex_init(&wled->lock);
INIT_WORK(&wled->work, qpnp_wled_work);
wled->ramp_ms = QPNP_WLED_RAMP_DLY_MS;
wled->ramp_step = 1;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6e3bcca..971e57a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -464,6 +464,12 @@
if (vb2->type != type || vb2->index != index)
continue;
+ if (mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING) {
+ print_vidc_buffer(VIDC_DBG,
+ "skip rel buf (rbr pending)", inst, mbuf);
+ continue;
+ }
+
print_vidc_buffer(VIDC_DBG, "release buf", inst, mbuf);
msm_comm_unmap_vidc_buffer(inst, mbuf);
list_del(&mbuf->list);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 8074c05..51023f0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -190,7 +190,7 @@
&inst->registeredbufs.list, list) {
if (temp->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- temp->deferred) {
+ temp->flags & MSM_VIDC_FLAG_DEFERRED) {
filled_len = max(filled_len,
temp->vvb.vb2_buf.planes[0].bytesused);
device_addr = temp->smem[0].device_addr;
@@ -676,7 +676,7 @@
list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
if (temp->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- temp->deferred) {
+ temp->flags & MSM_VIDC_FLAG_DEFERRED) {
filled_len = max(filled_len,
temp->vvb.vb2_buf.planes[0].bytesused);
device_addr = temp->smem[0].device_addr;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 0321cf5..e72c099 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3839,7 +3839,7 @@
continue;
/* count only deferred buffers */
- if (!mbuf->deferred)
+ if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED))
continue;
++count;
@@ -3867,7 +3867,7 @@
continue;
/* count only deferred buffers */
- if (!mbuf->deferred)
+ if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED))
continue;
++count;
@@ -3915,6 +3915,41 @@
}
}
+static int msm_comm_qbuf_rbr(struct msm_vidc_inst *inst,
+ struct msm_vidc_buffer *mbuf)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct vidc_frame_data frame_data = {0};
+
+ if (!inst || !inst->core || !inst->core->device || !mbuf) {
+ dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR, "%s: inst is in bad state\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_comm_scale_clocks_and_bus(inst);
+ populate_frame_data(&frame_data, mbuf, inst);
+
+ rc = call_hfi_op(hdev, session_ftb, inst->session, &frame_data);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to issue ftb: %d\n", rc);
+ goto err_bad_input;
+ }
+
+ log_frame(inst, &frame_data, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+err_bad_input:
+ return rc;
+}
+
+
/*
* Attempts to queue `vb` to hardware. If, for various reasons, the buffer
* cannot be queued to hardware, the buffer will be staged for commit in the
@@ -3946,10 +3981,6 @@
return -EINVAL;
}
- /* initially assume every buffer is going to be deferred */
- if (mbuf)
- mbuf->deferred = true;
-
batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE)
== V4L2_VIDC_QBUF_BATCHED;
capture_count = (batch_mode ? &count_single_batch : &count_buffers)
@@ -3977,7 +4008,7 @@
if (defer) {
if (mbuf) {
- mbuf->deferred = true;
+ mbuf->flags |= MSM_VIDC_FLAG_DEFERRED;
print_vidc_buffer(VIDC_DBG, "deferred qbuf",
inst, mbuf);
}
@@ -4018,7 +4049,7 @@
list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
struct vidc_frame_data *frame_data = NULL;
- if (!temp->deferred)
+ if (!(temp->flags & MSM_VIDC_FLAG_DEFERRED))
continue;
switch (temp->vvb.vb2_buf.type) {
@@ -4040,7 +4071,7 @@
populate_frame_data(frame_data, temp, inst);
/* this buffer going to be queued (not deferred) */
- temp->deferred = false;
+ temp->flags &= ~MSM_VIDC_FLAG_DEFERRED;
print_vidc_buffer(VIDC_DBG, "qbuf", inst, temp);
}
@@ -4816,10 +4847,16 @@
&inst->bufq[port].vb2_bufq.queued_list) {
struct vb2_buffer *vb = container_of(ptr,
struct vb2_buffer, queued_entry);
- vb->planes[0].bytesused = 0;
- print_vb2_buffer(VIDC_ERR, "flush in invalid",
- inst, vb);
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ if (vb->state == VB2_BUF_STATE_ACTIVE) {
+ vb->planes[0].bytesused = 0;
+ print_vb2_buffer(VIDC_ERR, "flush in invalid",
+ inst, vb);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ } else {
+ dprintk(VIDC_WARN,
+ "%s VB is in state %d not in ACTIVE state\n"
+ , __func__, vb->state);
+ }
}
mutex_unlock(&inst->bufq[port].lock);
}
@@ -4829,7 +4866,7 @@
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
{
- int rc = 0;
+ int i, rc = 0;
bool ip_flush = false;
bool op_flush = false;
struct msm_vidc_buffer *mbuf, *next;
@@ -4854,8 +4891,6 @@
return 0;
}
- /* Finish FLUSH As Soon As Possible. */
-
msm_clock_data_reset(inst);
if (inst->state == MSM_VIDC_CORE_INVALID) {
@@ -4868,22 +4903,41 @@
mutex_lock(&inst->registeredbufs.lock);
list_for_each_entry_safe(mbuf, next, &inst->registeredbufs.list, list) {
- /* flush only deferred buffers (which are not queued yet) */
- if (!mbuf->deferred)
- continue;
-
- /* don't flush input buffers if flush not requested on it */
+ /* don't flush input buffers if input flush is not requested */
if (!ip_flush && mbuf->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
continue;
+ /* flush only deferred or rbr pending buffers */
+ if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED ||
+ mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING))
+ continue;
+
+ /*
+ * flush buffers which are queued by client already,
+ * the refcount will be two or more for those buffers.
+ */
+ if (!(mbuf->smem[0].refcount >= 2))
+ continue;
+
print_vidc_buffer(VIDC_DBG, "flush buf", inst, mbuf);
msm_comm_flush_vidc_buffer(inst, mbuf);
- msm_comm_unmap_vidc_buffer(inst, mbuf);
- /* remove from list */
- list_del(&mbuf->list);
- kref_put_mbuf(mbuf);
+ for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+ if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+ print_vidc_buffer(VIDC_ERR,
+ "dqbuf: unmap failed.", inst, mbuf);
+ if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+ print_vidc_buffer(VIDC_ERR,
+ "dqbuf: unmap failed..", inst, mbuf);
+ }
+ if (!mbuf->smem[0].refcount) {
+ list_del(&mbuf->list);
+ kref_put_mbuf(mbuf);
+ } else {
+ /* buffer is no more a deferred buffer */
+ mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+ }
}
mutex_unlock(&inst->registeredbufs.lock);
@@ -5759,27 +5813,27 @@
if (vb2->num_planes == 1)
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x\n",
str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
vb2->index, vb2->planes[0].m.fd,
vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
vb2->planes[0].length, vb2->planes[0].bytesused,
mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
- mbuf->smem[0].refcount);
+ mbuf->smem[0].refcount, mbuf->flags);
else
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
vb2->index, vb2->planes[0].m.fd,
vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
vb2->planes[0].length, vb2->planes[0].bytesused,
mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
- mbuf->smem[0].refcount, vb2->planes[1].m.fd,
- vb2->planes[1].data_offset, mbuf->smem[1].device_addr,
- vb2->planes[1].length, vb2->planes[1].bytesused,
- mbuf->smem[1].refcount);
+ mbuf->smem[0].refcount, mbuf->flags,
+ vb2->planes[1].m.fd, vb2->planes[1].data_offset,
+ mbuf->smem[1].device_addr, vb2->planes[1].length,
+ vb2->planes[1].bytesused, mbuf->smem[1].refcount);
}
void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
@@ -5798,13 +5852,14 @@
vb2->planes[0].bytesused);
else
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n",
str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
vb2->index, vb2->planes[0].m.fd,
vb2->planes[0].data_offset, vb2->planes[0].length,
vb2->planes[0].bytesused, vb2->planes[1].m.fd,
- vb2->planes[1].data_offset, vb2->planes[1].length);
+ vb2->planes[1].data_offset, vb2->planes[1].length,
+ vb2->planes[1].bytesused);
}
void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
@@ -5824,7 +5879,7 @@
v4l2->m.planes[0].bytesused);
else
dprintk(tag,
- "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+ "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n",
str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
v4l2->index, v4l2->m.planes[0].m.fd,
@@ -5833,7 +5888,8 @@
v4l2->m.planes[0].bytesused,
v4l2->m.planes[1].m.fd,
v4l2->m.planes[1].data_offset,
- v4l2->m.planes[1].length);
+ v4l2->m.planes[1].length,
+ v4l2->m.planes[1].bytesused);
}
bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst,
@@ -6051,6 +6107,9 @@
kref_init(&mbuf->kref);
}
+ /* Initially assume all the buffer are going to be deferred */
+ mbuf->flags |= MSM_VIDC_FLAG_DEFERRED;
+
vbuf = to_vb2_v4l2_buffer(vb2);
memcpy(&mbuf->vvb, vbuf, sizeof(struct vb2_v4l2_buffer));
vb = &mbuf->vvb.vb2_buf;
@@ -6097,6 +6156,16 @@
if (found_plane0)
rc = -EEXIST;
}
+ /*
+ * If RBR pending on this buffer then enable RBR_PENDING flag
+ * and clear the DEFERRED flag to avoid this buffer getting
+ * queued to video hardware in msm_comm_qbuf() which tries to
+ * queue all the DEFERRED buffers.
+ */
+ if (rc == -EEXIST) {
+ mbuf->flags |= MSM_VIDC_FLAG_RBR_PENDING;
+ mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+ }
}
/* add the new buffer to list */
@@ -6193,10 +6262,14 @@
}
}
if (found) {
+ /* send RBR event to client */
msm_vidc_queue_rbr_event(inst,
mbuf->vvb.vb2_buf.planes[0].m.fd,
mbuf->vvb.vb2_buf.planes[0].data_offset);
+ /* clear RBR_PENDING flag */
+ mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING;
+
for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
print_vidc_buffer(VIDC_ERR,
@@ -6232,7 +6305,7 @@
if (!found)
goto unlock;
- /* found means client queued the buffer already */
+ /* buffer found means client queued the buffer already */
if (inst->in_reconfig || inst->in_flush) {
print_vidc_buffer(VIDC_DBG, "rbr flush buf", inst, mbuf);
msm_comm_flush_vidc_buffer(inst, mbuf);
@@ -6244,12 +6317,16 @@
/* don't queue the buffer */
found = false;
}
+ /* clear DEFERRED flag, if any, as the buffer is going to be queued */
+ if (found)
+ mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+
unlock:
mutex_unlock(&inst->registeredbufs.lock);
if (found) {
print_vidc_buffer(VIDC_DBG, "rbr qbuf", inst, mbuf);
- rc = msm_comm_qbuf(inst, mbuf);
+ rc = msm_comm_qbuf_rbr(inst, mbuf);
if (rc)
print_vidc_buffer(VIDC_ERR,
"rbr qbuf failed", inst, mbuf);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 57dfd52..195410d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -399,12 +399,17 @@
int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+enum msm_vidc_flags {
+ MSM_VIDC_FLAG_DEFERRED = BIT(0),
+ MSM_VIDC_FLAG_RBR_PENDING = BIT(1),
+};
+
struct msm_vidc_buffer {
struct list_head list;
struct kref kref;
struct msm_smem smem[VIDEO_MAX_PLANES];
struct vb2_v4l2_buffer vvb;
- bool deferred;
+ enum msm_vidc_flags flags;
};
void msm_comm_handle_thermal_event(void);
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index 204142b..a23f069 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -30,6 +30,7 @@
#define YEAR_BASE 1900
#define EL2_SCM_ID 0x02001902
+#define KP_EL2_REPORT_REVISION 0x01000101
static struct seemp_logk_dev *slogk_dev;
@@ -610,6 +611,9 @@
/ sizeof(struct el2_report_data_t);
header = (struct el2_report_header_t *) el2_shared_mem;
+ if (header->report_version < KP_EL2_REPORT_REVISION)
+ return -EINVAL;
+
while (!kthread_should_stop()) {
for (i = 1; i < num_entries + 1; i++) {
struct el2_report_data_t *report;
@@ -628,7 +632,8 @@
|| report->sequence_number >
last_sequence_number)) {
seemp_logk_rtic(report->report_type,
- report->actor,
+ ((struct task_struct *) report->actor)
+ ->pid,
/* leave this empty until
* asset id is provided
*/
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index c77b808..dd5f78f 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -278,6 +278,7 @@
int slope_limit_temp;
int esr_pulse_thresh_ma;
int esr_meas_curr_ma;
+ int bmd_en_delay_ms;
int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c
index d616dd8..e0a5150 100644
--- a/drivers/power/supply/qcom/pmic-voter.c
+++ b/drivers/power/supply/qcom/pmic-voter.c
@@ -521,11 +521,10 @@
lock_votable(votable);
- seq_printf(m, "Votable %s:\n", votable->name);
- seq_puts(m, "clients:\n");
for (i = 0; i < votable->num_clients; i++) {
if (votable->client_strs[i]) {
- seq_printf(m, "%-15s:\t\ten=%d\t\tv=%d\n",
+ seq_printf(m, "%s: %s:\t\t\ten=%d v=%d\n",
+ votable->name,
votable->client_strs[i],
votable->votes[i].enabled,
votable->votes[i].value);
@@ -544,11 +543,11 @@
break;
}
- seq_printf(m, "type: %s\n", type_str);
- seq_puts(m, "Effective:\n");
effective_client_str = get_effective_client_locked(votable);
- seq_printf(m, "%-15s:\t\tv=%d\n",
+ seq_printf(m, "%s: effective=%s type=%s v=%d\n",
+ votable->name,
effective_client_str ? effective_client_str : "none",
+ type_str,
get_effective_result_locked(votable));
unlock_votable(votable);
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index d522926..56f3b1e 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -892,8 +892,8 @@
goto out;
}
- /* Wait for 200ms before enabling BMD again */
- msleep(200);
+ /* Wait for BATT_ID to settle down before enabling BMD again */
+ msleep(chip->dt.bmd_en_delay_ms);
fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
chip->batt_id_ohms = batt_id;
@@ -4036,6 +4036,7 @@
#define DEFAULT_ESR_CLAMP_MOHMS 20
#define DEFAULT_ESR_PULSE_THRESH_MA 110
#define DEFAULT_ESR_MEAS_CURR_MA 120
+#define DEFAULT_BMD_EN_DELAY_MS 200
static int fg_parse_dt(struct fg_chip *chip)
{
struct device_node *child, *revid_node, *node = chip->dev->of_node;
@@ -4382,6 +4383,13 @@
chip->dt.esr_meas_curr_ma = temp;
}
+ chip->dt.bmd_en_delay_ms = DEFAULT_BMD_EN_DELAY_MS;
+ rc = of_property_read_u32(node, "qcom,fg-bmd-en-delay-ms", &temp);
+ if (!rc) {
+ if (temp > DEFAULT_BMD_EN_DELAY_MS)
+ chip->dt.bmd_en_delay_ms = temp;
+ }
+
return 0;
}
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 4284b6c..d590d24 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -26,6 +26,7 @@
#include <linux/pm_opp.h>
#include <linux/cpu_cooling.h>
#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
@@ -102,10 +103,12 @@
unsigned long max_freq;
unsigned long min_freq;
unsigned long hw_freq_limit;
+ struct device_attribute lmh_freq_attr;
struct list_head list;
atomic_t is_irq_enabled;
struct mutex access_lock;
struct __limits_cdev_data *cdev_data;
+ struct regulator *isens_reg;
};
LIST_HEAD(lmh_dcvs_hw_list);
@@ -430,6 +433,60 @@
return 0;
}
+static void limits_isens_vref_ldo_init(struct platform_device *pdev,
+ struct limits_dcvs_hw *hw)
+{
+ int ret = 0;
+ uint32_t settings[3];
+
+ hw->isens_reg = devm_regulator_get(&pdev->dev, "isens_vref");
+ if (IS_ERR_OR_NULL(hw->isens_reg)) {
+ if (PTR_ERR(hw->isens_reg) == -ENODEV)
+ return;
+
+ pr_err("Regulator:isens_vref init error:%ld\n",
+ PTR_ERR(hw->isens_reg));
+ return;
+ }
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "isens-vref-settings",
+ settings, 3);
+ if (ret) {
+ pr_err("Regulator:isens_vref settings read error:%d\n",
+ ret);
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+ ret = regulator_set_voltage(hw->isens_reg, settings[0], settings[1]);
+ if (ret) {
+ pr_err("Regulator:isens_vref set voltage error:%d\n", ret);
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+ ret = regulator_set_load(hw->isens_reg, settings[2]);
+ if (ret) {
+ pr_err("Regulator:isens_vref set load error:%d\n", ret);
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+ if (regulator_enable(hw->isens_reg)) {
+ pr_err("Failed to enable regulator:isens_vref\n");
+ devm_regulator_put(hw->isens_reg);
+ return;
+ }
+}
+
+static ssize_t
+lmh_freq_limit_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct limits_dcvs_hw *hw = container_of(devattr,
+ struct limits_dcvs_hw,
+ lmh_freq_attr);
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", hw->hw_freq_limit);
+}
+
static int limits_dcvs_probe(struct platform_device *pdev)
{
int ret;
@@ -585,6 +642,11 @@
ret = 0;
goto probe_exit;
}
+ limits_isens_vref_ldo_init(pdev, hw);
+ hw->lmh_freq_attr.attr.name = "lmh_freq_limit";
+ hw->lmh_freq_attr.show = lmh_freq_limit_show;
+ hw->lmh_freq_attr.attr.mode = 0444;
+ device_create_file(&pdev->dev, &hw->lmh_freq_attr);
probe_exit:
mutex_lock(&lmh_dcvs_list_access);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 95ef027..2bfe1b5 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -477,6 +477,7 @@
* So, start monitoring again.
*/
monitor_thermal_zone(tz);
+ trace_thermal_handle_trip(tz, trip);
}
/**
@@ -567,6 +568,7 @@
ret = tz->ops->set_trips(tz, low, high);
if (ret)
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+ trace_thermal_set_trip(tz);
exit:
mutex_unlock(&tz->lock);
@@ -621,6 +623,7 @@
if (!tz->ops->get_temp)
return;
+ trace_thermal_device_update(tz, event);
update_temperature(tz);
thermal_zone_set_trips(tz);
@@ -1934,6 +1937,7 @@
current_target = instance->target;
}
}
+ trace_cdev_update_start(cdev);
cdev->ops->set_cur_state(cdev, current_target);
if (cdev->ops->set_min_state)
cdev->ops->set_min_state(cdev, min_target);
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index ae063c4..dca4811 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -377,6 +377,8 @@
struct list_head svid_handlers;
struct list_head instance;
+
+ u16 ss_lane_svid;
};
static LIST_HEAD(_usbpd); /* useful for debugging */
@@ -445,6 +447,47 @@
extcon_set_state_sync(pd->extcon, EXTCON_USB, 1);
}
+/**
+ * This API allows client driver to request for releasing SS lanes. It should
+ * not be called from atomic context.
+ *
+ * @pd - USBPD handler
+ * @hdlr - client's handler
+ *
+ * @returns int - Success - 0, else negative error code
+ */
+static int usbpd_release_ss_lane(struct usbpd *pd,
+ struct usbpd_svid_handler *hdlr)
+{
+ int ret = 0;
+
+ if (!hdlr || !pd)
+ return -EINVAL;
+
+ usbpd_dbg(&pd->dev, "hdlr:%pK svid:%d", hdlr, hdlr->svid);
+ /*
+ * If USB SS lanes are already used by one client, and other client is
+ * requesting for same or same client requesting again, return -EBUSY.
+ */
+ if (pd->ss_lane_svid) {
+ usbpd_dbg(&pd->dev, "-EBUSY: ss_lanes are already used by(%d)",
+ pd->ss_lane_svid);
+ ret = -EBUSY;
+ goto err_exit;
+ }
+
+ ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0);
+ if (ret) {
+ usbpd_err(&pd->dev, "err(%d) for releasing ss lane", ret);
+ goto err_exit;
+ }
+
+ pd->ss_lane_svid = hdlr->svid;
+
+err_exit:
+ return ret;
+}
+
static int set_power_role(struct usbpd *pd, enum power_role pr)
{
union power_supply_propval val = {0};
@@ -764,6 +807,7 @@
if (pd->current_dr == DR_NONE) {
pd->current_dr = DR_DFP;
start_usb_host(pd, true);
+ pd->ss_lane_svid = 0x0;
}
dual_role_instance_changed(pd->dual_role);
@@ -1084,6 +1128,7 @@
usbpd_dbg(&pd->dev, "registered handler for SVID 0x%04x\n", hdlr->svid);
list_add_tail(&hdlr->entry, &pd->svid_handlers);
+ hdlr->request_usb_ss_lane = usbpd_release_ss_lane;
/* already connected with this SVID discovered? */
if (pd->vdm_state >= DISCOVERED_SVIDS) {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 1731c3a..95fe239 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -65,6 +65,7 @@
#define DIAG_IOCTL_PERIPHERAL_BUF_DRAIN 36
#define DIAG_IOCTL_REGISTER_CALLBACK 37
#define DIAG_IOCTL_HDLC_TOGGLE 38
+#define DIAG_IOCTL_QUERY_PD_LOGGING 39
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
diff --git a/include/linux/ipc_router.h b/include/linux/ipc_router.h
index 767551e..c18290f 100644
--- a/include/linux/ipc_router.h
+++ b/include/linux/ipc_router.h
@@ -144,6 +144,7 @@
uint32_t num_rx;
unsigned long num_tx_bytes;
unsigned long num_rx_bytes;
+ uint32_t last_served_svc_id;
void *priv;
};
diff --git a/include/linux/seemp_instrumentation.h b/include/linux/seemp_instrumentation.h
index ff09bd2..1db7a44 100644
--- a/include/linux/seemp_instrumentation.h
+++ b/include/linux/seemp_instrumentation.h
@@ -69,7 +69,7 @@
seemp_logk_kernel_end(blck);
}
-static inline void seemp_logk_rtic(__u8 type, __u64 actor, __u8 asset_id[0x20],
+static inline void seemp_logk_rtic(__u8 type, pid_t pid, __u8 asset_id[0x20],
__u8 asset_category, __u8 response)
{
char *buf = NULL;
@@ -80,8 +80,8 @@
return;
SEEMP_LOGK_RECORD(SEEMP_API_kernel__rtic,
- "app_pid=%llu,rtic_type=%u,asset_id=%s,asset_category=%u,response=%u",
- actor, type, asset_id, asset_category, response);
+ "app_pid=%d,rtic_type=%u,asset_id=%s,asset_category=%u,response=%u",
+ pid, type, asset_id, asset_category, response);
seemp_logk_kernel_end(blck);
}
diff --git a/include/linux/usb/usbpd.h b/include/linux/usb/usbpd.h
index 3566a7a..4dbd91f 100644
--- a/include/linux/usb/usbpd.h
+++ b/include/linux/usb/usbpd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -46,6 +46,10 @@
void (*connect)(struct usbpd_svid_handler *hdlr);
void (*disconnect)(struct usbpd_svid_handler *hdlr);
+ /* DP driver -> PE driver for requesting USB SS lanes */
+ int (*request_usb_ss_lane)(struct usbpd *pd,
+ struct usbpd_svid_handler *hdlr);
+
/* Unstructured VDM */
void (*vdm_received)(struct usbpd_svid_handler *hdlr, u32 vdm_hdr,
const u32 *vdos, int num_vdos);
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h
index 031ae49..c0475a2 100644
--- a/include/trace/events/thermal.h
+++ b/include/trace/events/thermal.h
@@ -45,6 +45,23 @@
__entry->temp)
);
+TRACE_EVENT(cdev_update_start,
+
+ TP_PROTO(struct thermal_cooling_device *cdev),
+
+ TP_ARGS(cdev),
+
+ TP_STRUCT__entry(
+ __string(type, cdev->type)
+ ),
+
+ TP_fast_assign(
+ __assign_str(type, cdev->type);
+ ),
+
+ TP_printk("type=%s update start", __get_str(type))
+);
+
TRACE_EVENT(cdev_update,
TP_PROTO(struct thermal_cooling_device *cdev, unsigned long target,
@@ -98,6 +115,75 @@
show_tzt_type(__entry->trip_type))
);
+TRACE_EVENT(thermal_handle_trip,
+
+ TP_PROTO(struct thermal_zone_device *tz, int trip),
+
+ TP_ARGS(tz, trip),
+
+ TP_STRUCT__entry(
+ __string(thermal_zone, tz->type)
+ __field(int, id)
+ __field(int, trip)
+ ),
+
+ TP_fast_assign(
+ __assign_str(thermal_zone, tz->type);
+ __entry->id = tz->id;
+ __entry->trip = trip;
+ ),
+
+ TP_printk("thermal_zone=%s id=%d handle trip=%d",
+ __get_str(thermal_zone), __entry->id, __entry->trip)
+);
+
+TRACE_EVENT(thermal_device_update,
+
+ TP_PROTO(struct thermal_zone_device *tz, int event),
+
+ TP_ARGS(tz, event),
+
+ TP_STRUCT__entry(
+ __string(thermal_zone, tz->type)
+ __field(int, id)
+ __field(int, event)
+ ),
+
+ TP_fast_assign(
+ __assign_str(thermal_zone, tz->type);
+ __entry->id = tz->id;
+ __entry->event = event;
+ ),
+
+ TP_printk("thermal_zone=%s id=%d received event:%d",
+ __get_str(thermal_zone), __entry->id, __entry->event)
+);
+
+TRACE_EVENT(thermal_set_trip,
+
+ TP_PROTO(struct thermal_zone_device *tz),
+
+ TP_ARGS(tz),
+
+ TP_STRUCT__entry(
+ __string(thermal_zone, tz->type)
+ __field(int, id)
+ __field(int, low)
+ __field(int, high)
+ ),
+
+ TP_fast_assign(
+ __assign_str(thermal_zone, tz->type);
+ __entry->id = tz->id;
+ __entry->low = tz->prev_low_trip;
+ __entry->high = tz->prev_high_trip;
+ ),
+
+ TP_printk("thermal_zone=%s id=%d low trip=%d high trip=%d",
+ __get_str(thermal_zone), __entry->id, __entry->low,
+ __entry->high)
+);
+
TRACE_EVENT(thermal_power_cpu_get_power,
TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,
size_t load_len, u32 dynamic_power, u32 static_power),
diff --git a/mm/cma.c b/mm/cma.c
index b3eaf39..4938216 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -36,6 +36,7 @@
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/show_mem_notifier.h>
#include <trace/events/cma.h>
#include "cma.h"
@@ -95,6 +96,29 @@
mutex_unlock(&cma->lock);
}
+static int cma_showmem_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int i;
+ unsigned long used;
+ struct cma *cma;
+
+ for (i = 0; i < cma_area_count; i++) {
+ cma = &cma_areas[i];
+ used = bitmap_weight(cma->bitmap,
+ (int)cma_bitmap_maxno(cma));
+ used <<= cma->order_per_bit;
+ pr_info("cma-%d pages: => %lu used of %lu total pages\n",
+ i, used, cma->count);
+ }
+
+ return 0;
+}
+
+static struct notifier_block cma_nb = {
+ .notifier_call = cma_showmem_notifier,
+};
+
static int __init cma_activate_area(struct cma *cma)
{
int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);
@@ -158,6 +182,8 @@
return ret;
}
+ show_mem_notifier_register(&cma_nb);
+
return 0;
}
core_initcall(cma_init_reserved_areas);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 2efa9c9..3a22b14 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -37,6 +37,7 @@
#include <linux/ratelimit.h>
#include <linux/kthread.h>
#include <linux/init.h>
+#include <linux/show_mem_notifier.h>
#include <asm/tlb.h>
#include "internal.h"
@@ -416,8 +417,11 @@
dump_stack();
if (oc->memcg)
mem_cgroup_print_oom_info(oc->memcg, p);
- else
+ else {
show_mem(SHOW_MEM_FILTER_NODES);
+ show_mem_call_notifiers();
+ }
+
if (sysctl_oom_dump_tasks)
dump_tasks(oc->memcg, oc->nodemask);
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bdd2bea..44085b2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -64,6 +64,7 @@
#include <linux/page_owner.h>
#include <linux/kthread.h>
#include <linux/memcontrol.h>
+#include <linux/show_mem_notifier.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
@@ -3130,8 +3131,10 @@
pr_cont(", mode:%#x(%pGg)\n", gfp_mask, &gfp_mask);
dump_stack();
- if (!should_suppress_show_mem())
+ if (!should_suppress_show_mem()) {
show_mem(filter);
+ show_mem_call_notifiers();
+ }
}
static inline struct page *
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index 7c8af29f..a28b1af 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -363,6 +363,8 @@
svc_id = rport_ptr->server->name.service;
svc_ins = rport_ptr->server->name.instance;
port_type = CLIENT_PORT;
+ port_ptr->last_served_svc_id =
+ rport_ptr->server->name.service;
} else if (port_ptr && (port_ptr->type == SERVER_PORT)) {
svc_id = port_ptr->port_name.service;
svc_ins = port_ptr->port_name.instance;
@@ -1330,8 +1332,9 @@
mutex_init(&port_ptr->port_rx_q_lock_lhc3);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_ws_name, MAX_WS_NAME_SZ,
- "ipc%08x_%s",
+ "ipc%08x_%d_%s",
port_ptr->this_port.port_id,
+ task_pid_nr(current),
current->comm);
port_ptr->port_rx_ws = wakeup_source_register(port_ptr->rx_ws_name);
if (!port_ptr->port_rx_ws) {
@@ -3847,15 +3850,18 @@
int j;
struct msm_ipc_port *port_ptr;
- seq_printf(s, "%-11s|%-11s|\n", "Node_id", "Port_id");
+ seq_printf(s, "%-11s|%-11s|%-32s|%-11s|\n",
+ "Node_id", "Port_id", "Wakelock", "Last SVCID");
seq_puts(s, "------------------------------------------------------------\n");
down_read(&local_ports_lock_lhc2);
for (j = 0; j < LP_HASH_SIZE; j++) {
list_for_each_entry(port_ptr, &local_ports[j], list) {
mutex_lock(&port_ptr->port_lock_lhc3);
- seq_printf(s, "0x%08x |0x%08x |\n",
+ seq_printf(s, "0x%08x |0x%08x |%-32s|0x%08x |\n",
port_ptr->this_port.node_id,
- port_ptr->this_port.port_id);
+ port_ptr->this_port.port_id,
+ port_ptr->rx_ws_name,
+ port_ptr->last_served_svc_id);
mutex_unlock(&port_ptr->port_lock_lhc3);
}
}