summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-msm.txt3
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt20
-rw-r--r--arch/arm/boot/compressed/head.S2
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-falcon.dtsi204
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-falcon.dtsi409
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts29
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi64
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-rumi.dts26
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-sim.dts26
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi60
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi74
-rw-r--r--arch/arm/configs/msmfalcon_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig1
-rw-r--r--arch/arm64/configs/msmcortex_defconfig1
-rw-r--r--arch/arm64/configs/msmfalcon-perf_defconfig1
-rw-r--r--arch/arm64/configs/msmfalcon_defconfig1
-rw-r--r--arch/arm64/include/asm/mmu_context.h7
-rw-r--r--drivers/clk/msm/clock-mmss-cobalt.c9
-rw-r--r--drivers/clk/msm/clock-osm.c6
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c122
-rw-r--r--drivers/clk/qcom/clk-rcg2.c2
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c55
-rw-r--r--drivers/clk/qcom/common.c31
-rw-r--r--drivers/clk/qcom/common.h2
-rw-r--r--drivers/clk/qcom/gcc-msmfalcon.c9
-rw-r--r--drivers/clk/qcom/gpucc-msmfalcon.c8
-rw-r--r--drivers/devfreq/governor_memlat.c24
-rw-r--r--drivers/gpu/msm/adreno.c2
-rw-r--r--drivers/gpu/msm/adreno_a5xx_snapshot.c2
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c45
-rw-r--r--drivers/gpu/msm/kgsl_pwrscale.c6
-rw-r--r--drivers/gpu/msm/kgsl_pwrscale.h4
-rw-r--r--drivers/media/dvb-core/demux.h6
-rw-r--r--drivers/media/dvb-core/dmxdev.c51
-rw-r--r--drivers/media/dvb-core/dvb_demux.c16
-rw-r--r--drivers/media/dvb-core/dvb_net.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp44.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp46.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c26
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c12
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h8
-rw-r--r--drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c4
-rw-r--r--drivers/mmc/host/sdhci-msm.c727
-rw-r--r--drivers/mmc/host/sdhci-msm.h4
-rw-r--r--drivers/platform/msm/gsi/gsi.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_rm.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_i.h4
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_resource.c15
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_resource.h3
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_intf.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c37
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c26
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h1
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_intf.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_rt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c6
-rw-r--r--drivers/power/power_supply_sysfs.c3
-rw-r--r--drivers/power/qcom-charger/bcl_peripheral.c2
-rw-r--r--drivers/power/qcom-charger/fg-util.c11
-rw-r--r--drivers/power/qcom-charger/qpnp-fg-gen3.c33
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c212
-rw-r--r--drivers/power/qcom-charger/smb-lib.c981
-rw-r--r--drivers/power/qcom-charger/smb-lib.h36
-rw-r--r--drivers/power/qcom-charger/smb-reg.h25
-rw-r--r--drivers/power/qcom-charger/smb138x-charger.c12
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c7
-rw-r--r--drivers/scsi/ufs/ufshcd.c16
-rw-r--r--drivers/scsi/ufs/ufshcd.h7
-rw-r--r--drivers/soc/qcom/Kconfig8
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/early_random.c63
-rw-r--r--drivers/soc/qcom/icnss.c55
-rw-r--r--drivers/soc/qcom/service-notifier.c4
-rw-r--r--drivers/thermal/lmh_lite.c13
-rw-r--r--drivers/thermal/msm_lmh_dcvs.c2
-rw-r--r--drivers/thermal/msm_thermal.c2
-rw-r--r--drivers/tty/serial/msm_serial_hs.c1
-rw-r--r--drivers/usb/gadget/function/f_midi.c1
-rw-r--r--drivers/usb/gadget/function/f_qc_rndis.c6
-rw-r--r--drivers/usb/pd/policy_engine.c183
-rw-r--r--drivers/video/fbdev/msm/mdss.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c177
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h35
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c51
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c95
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h73
-rw-r--r--include/dt-bindings/clock/msm-clocks-cobalt.h8
-rw-r--r--include/linux/power_supply.h3
-rw-r--r--include/linux/sched.h15
-rw-r--r--include/linux/sched/core_ctl.h (renamed from kernel/sched/core_ctl.h)7
-rw-r--r--include/linux/sched/sysctl.h1
-rw-r--r--include/linux/types.h3
-rw-r--r--include/trace/events/sched.h63
-rw-r--r--init/main.c9
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/sched/core.c42
-rw-r--r--kernel/sched/core_ctl.c33
-rw-r--r--kernel/sched/debug.c1
-rw-r--r--kernel/sched/fair.c5
-rw-r--r--kernel/sched/hmp.c715
-rw-r--r--kernel/sched/sched.h31
-rw-r--r--kernel/smpboot.c2
-rw-r--r--kernel/sysctl.c8
-rw-r--r--sound/soc/codecs/wcd-spi.c89
-rw-r--r--sound/soc/codecs/wcd9335.c12
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c171
-rw-r--r--sound/soc/msm/msmcobalt.c6
-rw-r--r--sound/usb/usb_audio_qmi_svc.c2
120 files changed, 4442 insertions, 1230 deletions
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 3fc5d6cda7c9..0b46fd3d8ebf 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,6 +4,9 @@ Secure Digital Host Controller provides standard host interface to SD/MMC/SDIO c
Required properties:
- compatible : should be "qcom,sdhci-msm"
+ For SDCC version 5.0.0, MCI registers are removed from SDCC interface
+ and some registers are moved to HC. New compatible string is added to
+ support this change - "qcom,sdhci-msm-v5".
- reg : should contain SDHC, SD Core register map.
- reg-names : indicates various resources passed to driver (via reg proptery) by name.
Required "reg-names" are "hc_mem" and "core_mem"
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
index 12ac75a8608c..82386ba9b082 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
@@ -110,6 +110,25 @@ Charger specific properties:
will use io-channel-names to match IIO input names
with IIO specifiers.
+- qcom,float-option
+ Usage: optional
+ Value type: <u32>
+ Definition: Configures how the charger behaves when a float charger is
+ detected by APSD
+ 1 - Treat as a DCP
+ 2 - Treat as a SDP
+ 3 - Disable charging
+ 4 - Suspend USB input
+
+- qcom,hvdcp-disable
+ Usage: optional
+ Value type: <empty>
+ Definition: Specifies if hvdcp charging is to be enabled or not.
+ If this property is not specified hvdcp will be enabled.
+ If this property is specified, hvdcp 2.0 detection will still
+ happen but the adapter won't be asked to switch to a higher
+ voltage point.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
@@ -143,7 +162,6 @@ pmicobalt_charger: qcom,qpnp-smb2 {
io-channels = <&pmic_rradc 0>;
io-channel-names = "rradc_batt_id";
- qcom,suspend-input;
dpdm-supply = <&qusb_phy0>;
qcom,step-soc-thresholds = <60 70 80 90>;
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index ae85dcdcb7df..d2e43b053d9b 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -776,7 +776,7 @@ __armv7_mmu_cache_on:
orrne r0, r0, #1 @ MMU enabled
movne r1, #0xfffffffd @ domain 0 = client
bic r6, r6, #1 << 31 @ 32-bit translation system
- bic r6, r6, #3 << 0 @ use only ttbr0
+ bic r6, r6, #(7 << 0) | (1 << 4) @ use only ttbr0
mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
mcr p15, 0, r0, c7, c5, 4 @ ISB
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-falcon.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-falcon.dtsi
new file mode 100644
index 000000000000..e4824418409b
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-falcon.dtsi
@@ -0,0 +1,204 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/clock/qcom,gcc-msmfalcon.h>
+#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&soc {
+ anoc2_smmu: arm,smmu-anoc2@16c0000 {
+ compatible = "qcom,smmu-v2";
+ reg = <0x16c0000 0x40000>;
+ #iommu-cells = <1>;
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <2>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 374 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 375 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 376 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 377 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 378 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 463 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 442 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 443 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clock_rpmcc RPM_AGGR2_NOC_CLK>;
+ clock-names = "smmu_aggr2_noc_clk";
+ #clock-cells = <1>;
+ };
+
+ lpass_q6_smmu: arm,smmu-lpass_q6@5100000 {
+ status = "disabled";
+ compatible = "qcom,smmu-v2";
+ reg = <0x5100000 0x40000>;
+ #iommu-cells = <1>;
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <2>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_hlos1_vote_lpass_adsp>;
+ clocks = <&clock_gcc HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>;
+ clock-names = "lpass_q6_smmu_clk";
+ #clock-cells = <1>;
+ };
+
+ mmss_bimc_smmu: arm,smmu-mmss@cd00000 {
+ status = "disabled";
+ compatible = "qcom,smmu-v2";
+ reg = <0xcd00000 0x40000>;
+ #iommu-cells = <1>;
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <2>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_bimc_smmu>;
+ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_gcc MMSSNOC_AXI_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>;
+ clock-names = "mmss_mnoc_ahb_clk",
+ "mmssnoc_axi_clk",
+ "mmss_bimc_smmu_ahb_clk",
+ "mmss_bimc_smmu_axi_clk";
+ #clock-cells = <1>;
+ qcom,bus-master-id = <MSM_BUS_MNOC_BIMC_MAS>;
+ };
+
+ kgsl_smmu: arm,smmu-kgsl@5040000 {
+ status = "disabled";
+ compatible = "qcom,smmu-v2";
+ reg = <0x5040000 0x10000>;
+ #iommu-cells = <1>;
+ qcom,dynamic;
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <2>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_gpu_cx>;
+ clocks = <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gcc GCC_BIMC_GFX_CLK>,
+ <&clock_gcc GCC_GPU_BIMC_GFX_CLK>;
+ clock-names = "gcc_gpu_cfg_ahb_clk",
+ "gcc_bimc_gfx_clk",
+ "gcc_gpu_bimc_gfx_clk";
+ #clock-cells = <1>;
+ };
+
+ turing_q6_smmu: arm,smmu-turing_q6@5180000 {
+ status = "disabled";
+ compatible = "qcom,smmu-v2";
+ reg = <0x5180000 0x40000>;
+ #iommu-cells = <1>;
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <2>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 533 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 534 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 535 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 536 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 537 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 538 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 539 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 540 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 541 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 542 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 543 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 544 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 545 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 546 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 547 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 548 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 549 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_hlos1_vote_turing_adsp>;
+ clocks = <&clock_gcc HLOS1_VOTE_TURING_ADSP_SMMU_CLK>;
+ clock-names = "turing_q6_smmu_clk";
+ #clock-cells = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-falcon.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-falcon.dtsi
new file mode 100644
index 000000000000..f060f2d7008c
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-falcon.dtsi
@@ -0,0 +1,409 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&kgsl_smmu {
+ attach-impl-defs = <0x6000 0x2378>,
+ <0x6060 0x1055>,
+ <0x678c 0x8>,
+ <0x6794 0x28>,
+ <0x6800 0x6>,
+ <0x6900 0x3ff>,
+ <0x6924 0x204>,
+ <0x6928 0x11000>,
+ <0x6930 0x800>,
+ <0x6960 0xffffffff>,
+ <0x6b64 0x1a5551>,
+ <0x6b68 0x9a82a382>;
+};
+
+&lpass_q6_smmu {
+ attach-impl-defs = <0x6000 0x2378>,
+ <0x6060 0x1055>,
+ <0x6070 0xe0>,
+ <0x6074 0xe0>,
+ <0x6078 0xe0>,
+ <0x607c 0xe0>,
+ <0x60f0 0xc0>,
+ <0x60f4 0xc8>,
+ <0x60f8 0xd0>,
+ <0x60fc 0xd8>,
+ <0x6170 0x0>,
+ <0x6174 0x30>,
+ <0x6178 0x60>,
+ <0x617c 0x90>,
+ <0x6270 0x0>,
+ <0x6274 0x2>,
+ <0x6278 0x4>,
+ <0x627c 0x6>,
+ <0x62f0 0x8>,
+ <0x62f4 0xe>,
+ <0x62f8 0x14>,
+ <0x62fc 0x1a>,
+ <0x6370 0x20>,
+ <0x6374 0x40>,
+ <0x6378 0x60>,
+ <0x637c 0x80>,
+ <0x6784 0x0>,
+ <0x678c 0x10>,
+ <0x67a0 0x0>,
+ <0x67a4 0x0>,
+ <0x67a8 0x20>,
+ <0x67b0 0x0>,
+ <0x67b4 0x8>,
+ <0x67b8 0xc8>,
+ <0x67d0 0x4>,
+ <0x67dc 0x8>,
+ <0x67e0 0x8>,
+ <0x6800 0x6>,
+ <0x6900 0x3ff>,
+ <0x6924 0x202>,
+ <0x6928 0x10a00>,
+ <0x6930 0x500>,
+ <0x6960 0xffffffff>,
+ <0x6b64 0x121151>,
+ <0x6b68 0xea800080>,
+ <0x6c00 0x0>,
+ <0x6c04 0x0>,
+ <0x6c08 0x0>,
+ <0x6c0c 0x0>,
+ <0x6c10 0x1>,
+ <0x6c14 0x1>,
+ <0x6c18 0x1>,
+ <0x6c1c 0x1>,
+ <0x6c20 0x2>,
+ <0x6c24 0x2>,
+ <0x6c28 0x2>,
+ <0x6c2c 0x2>,
+ <0x6c30 0x3>,
+ <0x6c34 0x3>,
+ <0x6c38 0x3>,
+ <0x6c3c 0x3>;
+};
+
+&turing_q6_smmu {
+ attach-impl-defs = <0x6000 0x2378>,
+ <0x6060 0x1055>,
+ <0x6070 0xe0>,
+ <0x6074 0xe0>,
+ <0x6078 0xe0>,
+ <0x607c 0xe0>,
+ <0x60f0 0xc0>,
+ <0x60f4 0xc8>,
+ <0x60f8 0xd0>,
+ <0x60fc 0xd8>,
+ <0x6170 0x0>,
+ <0x6174 0x30>,
+ <0x6178 0x60>,
+ <0x617c 0x90>,
+ <0x6270 0x0>,
+ <0x6274 0x2>,
+ <0x6278 0x4>,
+ <0x627c 0x6>,
+ <0x62f0 0x8>,
+ <0x62f4 0xe>,
+ <0x62f8 0x14>,
+ <0x62fc 0x1a>,
+ <0x6370 0x20>,
+ <0x6374 0x40>,
+ <0x6378 0x60>,
+ <0x637c 0x80>,
+ <0x6784 0x0>,
+ <0x678c 0x10>,
+ <0x67a0 0x0>,
+ <0x67a4 0x0>,
+ <0x67a8 0x20>,
+ <0x67b0 0x0>,
+ <0x67b4 0x8>,
+ <0x67b8 0xc8>,
+ <0x67d0 0x4>,
+ <0x67dc 0x8>,
+ <0x67e0 0x8>,
+ <0x6800 0x6>,
+ <0x6900 0x3ff>,
+ <0x6924 0x202>,
+ <0x6928 0x10a00>,
+ <0x6930 0x500>,
+ <0x6960 0xffffffff>,
+ <0x6b64 0x121151>,
+ <0x6b68 0xea800080>,
+ <0x6c00 0x0>,
+ <0x6c04 0x0>,
+ <0x6c08 0x0>,
+ <0x6c0c 0x0>,
+ <0x6c10 0x1>,
+ <0x6c14 0x1>,
+ <0x6c18 0x1>,
+ <0x6c1c 0x1>,
+ <0x6c20 0x2>,
+ <0x6c24 0x2>,
+ <0x6c28 0x2>,
+ <0x6c2c 0x2>,
+ <0x6c30 0x3>,
+ <0x6c34 0x3>,
+ <0x6c38 0x3>,
+ <0x6c3c 0x3>;
+};
+
+&mmss_bimc_smmu {
+ attach-impl-defs = <0x6000 0x2378>,
+ <0x6060 0x1055>,
+ <0x678c 0x28>,
+ <0x6794 0xe0>,
+ <0x6800 0x6>,
+ <0x6900 0x3ff>,
+ <0x6924 0x204>,
+ <0x6928 0x11002>,
+ <0x6930 0x800>,
+ <0x6960 0xffffffff>,
+ <0x6964 0xffffffff>,
+ <0x6968 0xffffffff>,
+ <0x696c 0xffffffff>,
+ <0x6b48 0x330330>,
+ <0x6b4c 0x81>,
+ <0x6b50 0x3333>,
+ <0x6b54 0x3333>,
+ <0x6b64 0x1a5555>,
+ <0x6b68 0xbaaa892a>,
+ <0x6b70 0x10100202>,
+ <0x6b74 0x10100202>,
+ <0x6b78 0x10100000>,
+ <0x6b80 0x20042004>,
+ <0x6b84 0x20042004>;
+};
+
+&anoc2_smmu {
+ attach-impl-defs = <0x6000 0x2378>,
+ <0x6060 0x1055>,
+ <0x6070 0xf>,
+ <0x6074 0x23>,
+ <0x6078 0x37>,
+ <0x607c 0x39>,
+ <0x6080 0x3f>,
+ <0x6084 0x6f>,
+ <0x6088 0x74>,
+ <0x608c 0x92>,
+ <0x6090 0xb0>,
+ <0x6094 0xf0>,
+ <0x6098 0xf0>,
+ <0x609c 0xf0>,
+ <0x60f0 0x0>,
+ <0x60f4 0x1>,
+ <0x60f8 0x3>,
+ <0x60fc 0x4>,
+ <0x6100 0x6>,
+ <0x6104 0x8>,
+ <0x6108 0x9>,
+ <0x610c 0xb>,
+ <0x6110 0xd>,
+ <0x6114 0xf>,
+ <0x6118 0xf>,
+ <0x611c 0xf>,
+ <0x6170 0x0>,
+ <0x6174 0x0>,
+ <0x6178 0x0>,
+ <0x617c 0x0>,
+ <0x6180 0x0>,
+ <0x6184 0x0>,
+ <0x6188 0x0>,
+ <0x618c 0x0>,
+ <0x6190 0x0>,
+ <0x6194 0x0>,
+ <0x6198 0x0>,
+ <0x619c 0x0>,
+ <0x6270 0x0>,
+ <0x6274 0x1>,
+ <0x6278 0x2>,
+ <0x627c 0x4>,
+ <0x6280 0x4>,
+ <0x6284 0x6>,
+ <0x6288 0x6>,
+ <0x628c 0xa>,
+ <0x6290 0xc>,
+ <0x6294 0xc>,
+ <0x6298 0xc>,
+ <0x629c 0xc>,
+ <0x62f0 0xc>,
+ <0x62f4 0x12>,
+ <0x62f8 0x18>,
+ <0x62fc 0x1a>,
+ <0x6300 0x1d>,
+ <0x6304 0x23>,
+ <0x6308 0x24>,
+ <0x630c 0x28>,
+ <0x6310 0x2c>,
+ <0x6314 0x30>,
+ <0x6318 0x30>,
+ <0x631c 0x30>,
+ <0x6370 0x30>,
+ <0x6374 0x35>,
+ <0x6378 0x3a>,
+ <0x637c 0x3e>,
+ <0x6380 0x46>,
+ <0x6384 0x50>,
+ <0x6388 0x55>,
+ <0x638c 0x5d>,
+ <0x6390 0x67>,
+ <0x6394 0x80>,
+ <0x6398 0x80>,
+ <0x639c 0x80>,
+ <0x678c 0x12>,
+ <0x6794 0x32>,
+ <0x67a0 0x0>,
+ <0x67a4 0xe1>,
+ <0x67a8 0xf0>,
+ <0x67b0 0x0>,
+ <0x67b4 0xc>,
+ <0x67b8 0x9c>,
+ <0x67d0 0x0>,
+ <0x67dc 0x4>,
+ <0x67e0 0x8>,
+ <0x6800 0x6>,
+ <0x6900 0x3ff>,
+ <0x6b48 0x330330>,
+ <0x6b4c 0x81>,
+ <0x6b50 0x1313>,
+ <0x6b64 0x121155>,
+ <0x6b68 0xcaa84920>,
+ <0x6b70 0xc0c0000>,
+ <0x6b74 0x8080000>,
+ <0x6b78 0x8080000>,
+ <0x6b80 0x20002000>,
+ <0x6b84 0x20002000>,
+ <0x6c00 0x5>,
+ <0x6c04 0x0>,
+ <0x6c08 0x5>,
+ <0x6c0c 0x0>,
+ <0x6c10 0x5>,
+ <0x6c14 0x0>,
+ <0x6c18 0x5>,
+ <0x6c1c 0x0>,
+ <0x6c20 0x5>,
+ <0x6c24 0x0>,
+ <0x6c28 0x0>,
+ <0x6c2c 0x0>,
+ <0x6c30 0x0>,
+ <0x6c34 0x0>,
+ <0x6c38 0x0>,
+ <0x6c3c 0x0>,
+ <0x6c40 0x0>,
+ <0x6c44 0x0>,
+ <0x6c48 0x0>,
+ <0x6c4c 0x0>,
+ <0x6c50 0x0>,
+ <0x6c54 0x0>,
+ <0x6c58 0x0>,
+ <0x6c5c 0x0>,
+ <0x6c60 0x0>,
+ <0x6c64 0x0>,
+ <0x6c68 0x0>,
+ <0x6c6c 0x0>,
+ <0x6c70 0x0>,
+ <0x6c74 0x0>,
+ <0x6c78 0x0>,
+ <0x6c7c 0x0>,
+ <0x6c80 0x0>,
+ <0x6c84 0x0>,
+ <0x6c88 0x0>,
+ <0x6c8c 0x0>,
+ <0x6c90 0x0>,
+ <0x6c94 0x0>,
+ <0x6c98 0x0>,
+ <0x6c9c 0x0>,
+ <0x6ca0 0x0>,
+ <0x6ca4 0x0>,
+ <0x6ca8 0x0>,
+ <0x6cac 0x0>,
+ <0x6cb0 0x0>,
+ <0x6cb4 0x0>,
+ <0x6cb8 0x0>,
+ <0x6cbc 0x0>,
+ <0x6cc0 0x0>,
+ <0x6cc4 0x0>,
+ <0x6cc8 0x0>,
+ <0x6ccc 0x0>,
+ <0x6cd0 0x0>,
+ <0x6cd4 0x0>,
+ <0x6cd8 0x0>,
+ <0x6cdc 0x0>,
+ <0x6ce0 0x0>,
+ <0x6ce4 0x0>,
+ <0x6ce8 0x0>,
+ <0x6cec 0x0>,
+ <0x6cf0 0x0>,
+ <0x6cf4 0x0>,
+ <0x6cf8 0x0>,
+ <0x6cfc 0x0>,
+ <0x6d00 0x3>,
+ <0x6d04 0x4>,
+ <0x6d08 0x4>,
+ <0x6d0c 0x0>,
+ <0x6d10 0x8>,
+ <0x6d14 0x8>,
+ <0x6d18 0x3>,
+ <0x6d1c 0x2>,
+ <0x6d20 0x4>,
+ <0x6d24 0x0>,
+ <0x6d28 0x4>,
+ <0x6d2c 0x0>,
+ <0x6d30 0x7>,
+ <0x6d34 0x0>,
+ <0x6d38 0x6>,
+ <0x6d3c 0x0>,
+ <0x6d40 0x0>,
+ <0x6d44 0x1>,
+ <0x6d48 0x4>,
+ <0x6d4c 0x0>,
+ <0x6d50 0x4>,
+ <0x6d54 0x0>,
+ <0x6d58 0x4>,
+ <0x6d5c 0x0>,
+ <0x6d60 0x0>,
+ <0x6d64 0x0>,
+ <0x6d68 0x0>,
+ <0x6d6c 0x0>,
+ <0x6d70 0x0>,
+ <0x6d74 0x0>,
+ <0x6d78 0x0>,
+ <0x6d7c 0x0>,
+ <0x6d80 0x0>,
+ <0x6d84 0x0>,
+ <0x6d88 0x0>,
+ <0x6d8c 0x0>,
+ <0x6d90 0x0>,
+ <0x6d94 0x0>,
+ <0x6d98 0x0>,
+ <0x6d9c 0x0>,
+ <0x6da0 0x0>,
+ <0x6da4 0x0>,
+ <0x6da8 0x0>,
+ <0x6dac 0x0>,
+ <0x6db0 0x0>,
+ <0x6db4 0x0>,
+ <0x6db8 0x0>,
+ <0x6dbc 0x0>,
+ <0x6dc0 0x0>,
+ <0x6dc4 0x0>,
+ <0x6dc8 0x0>,
+ <0x6dcc 0x0>,
+ <0x6dd0 0x0>,
+ <0x6dd4 0x0>,
+ <0x6dd8 0x0>,
+ <0x6ddc 0x0>,
+ <0x6de0 0x0>,
+ <0x6de4 0x0>,
+ <0x6de8 0x0>,
+ <0x6dec 0x0>,
+ <0x6df0 0x0>,
+ <0x6df4 0x0>,
+ <0x6df8 0x0>,
+ <0x6dfc 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi
index a37fa26b1055..27e537c9c702 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi
@@ -391,6 +391,7 @@
<&clock_mmss clk_mmss_mnoc_ahb_clk>,
<&clock_mmss clk_mmss_camss_ahb_clk>,
<&clock_mmss clk_mmss_camss_top_ahb_clk>,
+ <&clock_mmss clk_cpp_clk_src>,
<&clock_mmss clk_mmss_camss_cpp_clk>,
<&clock_mmss clk_mmss_camss_cpp_ahb_clk>,
<&clock_mmss clk_mmss_camss_cpp_axi_clk>,
@@ -400,10 +401,11 @@
clock-names = "mmssnoc_axi_clk",
"mnoc_ahb_clk",
"camss_ahb_clk", "camss_top_ahb_clk",
+ "cpp_src_clk",
"cpp_core_clk", "camss_cpp_ahb_clk",
"camss_cpp_axi_clk", "micro_iface_clk",
"mmss_smmu_axi_clk", "cpp_vbif_ahb_clk";
- qcom,clock-rates = <0 0 0 0 200000000 0 0 0 0 0>;
+ qcom,clock-rates = <0 0 0 0 200000000 200000000 0 0 0 0 0>;
qcom,min-clock-rate = <200000000>;
qcom,bus-master = <1>;
qcom,vbif-qos-setting = <0x20 0x10000000>,
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi
index f9bb6e512d33..7948dc3489cb 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi
@@ -289,9 +289,11 @@
reg = <0x1000 0x700>;
io-channels = <&smb138x_tadc 2>,
- <&smb138x_tadc 12>;
+ <&smb138x_tadc 12>,
+ <&smb138x_tadc 3>;
io-channel-names = "charger_temp",
- "charger_temp_max";
+ "charger_temp_max",
+ "batt_i";
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts
index e53912071502..ee6a58a41b4f 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts
@@ -21,3 +21,32 @@
compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd";
qcom,board-id = <0x02000b 0x80>;
};
+
+&soc {
+ sound-tavil {
+ qcom,model = "msmcobalt-qvr-tavil-snd-card";
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "SpkrLeft IN", "SPK1 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <1>;
+ /delete-property/ qcom,us-euro-gpios;
+ /delete-property/ qcom,hph-en0-gpio;
+ /delete-property/ qcom,hph-en0-gpio;
+
+ qcom,wsa-max-devs = <1>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi
index c028ea0eeab3..f8069856f3d8 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi
@@ -61,7 +61,7 @@
50000000 100000000 200000000>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- cd-gpios = <&tlmm 95 0x1>;
+ cd-gpios = <&tlmm 95 0x0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi
index 8016a3822a7f..81e2203a5e61 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi
@@ -672,8 +672,8 @@
<1036800 444000000 0x55555555>, /* 720p@240, 1080p@120,1440p@60,
* UHD@30 */ /*NOMINAL*/
< 829440 355200000 0x55555555>, /* UHD/4096x2160@30 SVSL1 */
- < 489600 269330000 0x55555555>, /* 1080p@60 SVS */
- < 432000 200000000 0x55555555>, /* 720p@120, 1080p@30 */
+ < 489600 269330000 0x55555555>, /* 1080p@60, 720p@120 SVS */
+ < 345600 200000000 0x55555555>, /* 2560x1440@24, 1080p@30 */
/* SVS2 */
/* Decoders */
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
index d28d09c2a527..e8c66871425d 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
@@ -48,5 +48,69 @@
output-low;
};
};
+
+ /* SDC pin type */
+ sdc1_clk_on: sdc1_clk_on {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc1_clk_off: sdc1_clk_off {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_cmd_on: sdc1_cmd_on {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_cmd_off: sdc1_cmd_off {
+ config {
+ pins = "sdc1_cmd";
+ num-grp-pins = <1>;
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_data_on: sdc1_data_on {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_data_off: sdc1_data_off {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_rclk_on: sdc1_rclk_on {
+ config {
+ pins = "sdc1_rclk";
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ sdc1_rclk_off: sdc1_rclk_off {
+ config {
+ pins = "sdc1_rclk";
+ bias-pull-down; /* pull down */
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
index 0d694a6cd9fa..f0ba8b115120 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
@@ -27,3 +27,29 @@
pinctrl-names = "default";
pinctrl-0 = <&uart_console_active>;
};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pmfalcon_l4b>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pmfalcon_l8a>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 192000000
+ 384000000>;
+
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
index eaaa1b407425..085419b7e108 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
@@ -27,3 +27,29 @@
pinctrl-names = "default";
pinctrl-0 = <&uart_console_active>;
};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pmfalcon_l4b>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pmfalcon_l8a>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 192000000
+ 384000000>;
+
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi
index e5db2766c553..e93067e3697c 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi
@@ -195,4 +195,27 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ /* ssr - inbound entry from turing */
+ smp2pgpio_ssr_smp2p_5_in: qcom,smp2pgpio-ssr-smp2p-5-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <5>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to turing */
+ smp2pgpio_ssr_smp2p_5_out: qcom,smp2pgpio-ssr-smp2p-5-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 2b2a201db8bc..8e8c407734eb 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -26,6 +26,7 @@
aliases {
serial0 = &uartblsp1dm1;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
};
chosen {
@@ -377,9 +378,8 @@
};
};
- clock_rpmcc: qcom,dummycc {
- compatible = "qcom,dummycc";
- clock-output-names = "rpmcc_clocks";
+ clock_rpmcc: qcom,rpmcc {
+ compatible = "qcom,rpmcc-msmfalcon", "qcom,rpmcc";
#clock-cells = <1>;
};
@@ -404,6 +404,26 @@
#reset-cells = <1>;
};
+ sdhc_1: sdhci@c0c4000 {
+ compatible = "qcom,sdhci-msm-v5";
+ reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>;
+ reg-names = "hc_mem", "cmdq_mem";
+
+ interrupts = <0 129 0>, <0 227 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <8>;
+ qcom,large-address-bus;
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>,
+ <&clock_gcc GCC_SDCC1_APPS_CLK>;
+ clock-names = "iface_clk", "core_clk";
+
+ status = "disabled";
+ };
+
qcom,ipc-spinlock@1f40000 {
compatible = "qcom,ipc-spinlock-sfpb";
reg = <0x1f40000 0x8000>;
@@ -702,6 +722,38 @@
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
status = "ok";
};
+
+ qcom,turing@1a300000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x1a300000 0x00100>;
+ interrupts = <0 518 1>;
+
+ vdd_cx-supply = <&pmfalcon_s3b_level>;
+ qcom,proxy-reg-names = "vdd_cx";
+ qcom,vdd_cx-uV-uA = <RPM_SMD_REGULATOR_LEVEL_TURBO 100000>;
+
+ clocks = <&clock_rpmcc CXO_PIL_CDSP_CLK>;
+ clock-names = "xo";
+ qcom,proxy-clock-names = "xo";
+
+ qcom,pas-id = <18>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <423>;
+ qcom,sysmon-id = <7>;
+ qcom,ssctl-instance-id = <0x17>;
+ qcom,firmware-name = "cdsp";
+ memory-region = <&cdsp_fw_mem>;
+
+ /* GPIO inputs from turing */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_5_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_5_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_5_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_5_in 3 0>;
+
+ /* GPIO output to turing*/
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>;
+ status = "ok";
+ };
};
#include "msmfalcon-ion.dtsi"
@@ -792,3 +844,5 @@
#include "msm-pmfalcon.dtsi"
#include "msm-pm2falcon.dtsi"
+#include "msm-arm-smmu-falcon.dtsi"
+#include "msm-arm-smmu-impl-defs-falcon.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi b/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi
index 695a4f3b63c7..1a72414de094 100644
--- a/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi
@@ -133,4 +133,27 @@
compatible = "qcom,smp2pgpio-sleepstate-out";
gpios = <&smp2pgpio_sleepstate_2_out 0 0>;
};
+
+ /* ssr - inbound entry from lpass */
+ smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to lpass */
+ smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index 09bb5f081602..083c14af7839 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -177,6 +177,14 @@
reg = <0x0 0x92a00000 0x0 0x1e00000>;
};
+ venus_fw_mem: venus_fw_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0x0 0x80000000 0x0 0x20000000>;
+ reusable;
+ alignment = <0x0 0x400000>;
+ size = <0x0 0x800000>;
+ };
+
adsp_mem: adsp_region {
compatible = "shared-dma-pool";
alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
@@ -326,9 +334,8 @@
};
};
- clock_rpmcc: qcom,dummycc {
- compatible = "qcom,dummycc";
- clock-output-names = "rpmcc_clocks";
+ clock_rpmcc: qcom,rpmcc {
+ compatible = "qcom,rpmcc-msmfalcon", "qcom,rpmcc";
#clock-cells = <1>;
};
@@ -541,6 +548,67 @@
<0 425 0>; /* CE11 */
qcom,wlan-msa-memory = <0x100000>;
};
+
+ qcom,lpass@15700000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x15700000 0x00100>;
+ interrupts = <0 162 1>;
+
+ vdd_cx-supply = <&pmfalcon_s3b_level>;
+ qcom,proxy-reg-names = "vdd_cx";
+ qcom,vdd_cx-uV-uA = <RPM_SMD_REGULATOR_LEVEL_TURBO 100000>;
+
+ clocks = <&clock_rpmcc CXO_PIL_LPASS_CLK>;
+ clock-names = "xo";
+ qcom,proxy-clock-names = "xo";
+
+ qcom,pas-id = <1>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <423>;
+ qcom,sysmon-id = <1>;
+ qcom,ssctl-instance-id = <0x14>;
+ qcom,firmware-name = "adsp";
+ memory-region = <&adsp_fw_mem>;
+
+ /* GPIO inputs from lpass */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>;
+
+ /* GPIO output to lpass */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+ status = "ok";
+ };
+
+ qcom,venus@cce0000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0xcce0000 0x4000>;
+
+ vdd-supply = <&gdsc_venus>;
+ qcom,proxy-reg-names = "vdd";
+
+ clocks = <&clock_mmss MMSS_VIDEO_CORE_CLK>,
+ <&clock_mmss MMSS_VIDEO_AHB_CLK>,
+ <&clock_mmss MMSS_VIDEO_AXI_CLK>;
+ clock-names = "core_clk","iface_clk",
+ "bus_clk";
+ qcom,proxy-clock-names = "core_clk",
+ "iface_clk","bus_clk";
+
+ qcom,msm-bus,name = "pil-venus";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <63 512 0 0>,
+ <63 512 0 304000>;
+
+ qcom,pas-id = <9>;
+ qcom,proxy-timeout-ms = <100>;
+ qcom,firmware-name = "venus";
+ memory-region = <&venus_fw_mem>;
+ status = "ok";
+ };
};
#include "msmtriton-ion.dtsi"
diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig
index 64da50bb55b2..069603eefe48 100644
--- a/arch/arm/configs/msmfalcon_defconfig
+++ b/arch/arm/configs/msmfalcon_defconfig
@@ -336,7 +336,6 @@ CONFIG_FB_MSM=y
CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
-CONFIG_FB_MSM_MDSS_DP_PANEL=y
CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
@@ -420,7 +419,7 @@ CONFIG_IPA3=y
CONFIG_RMNET_IPA3=y
CONFIG_GPIO_USB_DETECT=y
CONFIG_USB_BAM=y
-CONFIG_MSM_MDSS_PLL=y
+CONFIG_QCOM_CLK_SMD_RPM=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 799e43f09a11..5d2f29b053c4 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -535,6 +535,7 @@ CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_SMCINVOKE=y
+CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index dfd658d815fe..741f2e5bc8f6 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -554,6 +554,7 @@ CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_SMCINVOKE=y
+CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig
index 1bc352704893..5d271cad0aad 100644
--- a/arch/arm64/configs/msmfalcon-perf_defconfig
+++ b/arch/arm64/configs/msmfalcon-perf_defconfig
@@ -473,6 +473,7 @@ CONFIG_RMNET_IPA3=y
CONFIG_GPIO_USB_DETECT=y
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
+CONFIG_QCOM_CLK_SMD_RPM=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig
index 348c34a94119..707bc68c825f 100644
--- a/arch/arm64/configs/msmfalcon_defconfig
+++ b/arch/arm64/configs/msmfalcon_defconfig
@@ -483,6 +483,7 @@ CONFIG_RMNET_IPA3=y
CONFIG_GPIO_USB_DETECT=y
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
+CONFIG_QCOM_CLK_SMD_RPM=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 24165784b803..32441df2270e 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -27,19 +27,24 @@
#include <asm-generic/mm_hooks.h>
#include <asm/cputype.h>
#include <asm/pgtable.h>
+#include <linux/msm_rtb.h>
#ifdef CONFIG_PID_IN_CONTEXTIDR
static inline void contextidr_thread_switch(struct task_struct *next)
{
+ pid_t pid = task_pid_nr(next);
asm(
" msr contextidr_el1, %0\n"
" isb"
:
- : "r" (task_pid_nr(next)));
+ : "r" (pid));
+ uncached_logk(LOGK_CTXID, (void *)(u64)pid);
+
}
#else
static inline void contextidr_thread_switch(struct task_struct *next)
{
+ uncached_logk(LOGK_CTXID, (void *)(u64)task_pid_nr(next));
}
#endif
diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c
index 873dd40d3a44..9c1cdf967fb1 100644
--- a/drivers/clk/msm/clock-mmss-cobalt.c
+++ b/drivers/clk/msm/clock-mmss-cobalt.c
@@ -399,6 +399,8 @@ static struct clk_freq_tbl ftbl_cpp_clk_src[] = {
static struct clk_freq_tbl ftbl_cpp_clk_src_vq[] = {
F_MM( 100000000, mmsscc_gpll0, 6, 0, 0),
F_MM( 200000000, mmsscc_gpll0, 3, 0, 0),
+ F_MM( 384000000, mmpll4_pll_out, 2, 0, 0),
+ F_MM( 404000000, mmpll0_pll_out, 2, 0, 0),
F_MM( 480000000, mmpll7_pll_out, 2, 0, 0),
F_MM( 576000000, mmpll10_pll_out, 1, 0, 0),
F_MM( 600000000, mmsscc_gpll0, 1, 0, 0),
@@ -1112,8 +1114,8 @@ static struct rcg_clk dp_pixel_clk_src = {
.parent = &ext_dp_phy_pll_vco.c,
.ops = &clk_ops_rcg_dp,
.flags = CLKFLAG_NO_RATE_CACHE,
- VDD_DIG_FMAX_MAP3(LOWER, 148380, LOW, 296740,
- NOMINAL, 593470),
+ VDD_DIG_FMAX_MAP3(LOWER, 154000000, LOW, 337500000,
+ NOMINAL, 675000000),
CLK_INIT(dp_pixel_clk_src.c),
},
};
@@ -2703,7 +2705,6 @@ static void msm_mmsscc_hamster_fixup(void)
csi2phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333;
mdp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 330000000;
- dp_pixel_clk_src.c.fmax[VDD_DIG_LOWER] = 154000000;
extpclk_clk_src.c.fmax[VDD_DIG_LOW] = 312500000;
extpclk_clk_src.c.fmax[VDD_DIG_LOW_L1] = 375000000;
rot_clk_src.c.fmax[VDD_DIG_LOW_L1] = 330000000;
@@ -2736,8 +2737,6 @@ static void msm_mmsscc_v2_fixup(void)
csi1_clk_src.c.fmax[VDD_DIG_NOMINAL] = 480000000;
csi2_clk_src.c.fmax[VDD_DIG_NOMINAL] = 480000000;
csi3_clk_src.c.fmax[VDD_DIG_NOMINAL] = 480000000;
-
- dp_pixel_clk_src.c.fmax[VDD_DIG_LOWER] = 148380000;
}
int msm_mmsscc_cobalt_probe(struct platform_device *pdev)
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index d29fd60719c9..a119c0b27321 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -1776,7 +1776,7 @@ static void clk_osm_setup_fsms(struct clk_osm *c)
val = clk_osm_read_reg(c,
DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
- val |= BVAL(31, 16, clk_osm_count_ns(c, 500));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, 250));
clk_osm_write_reg(c, val,
DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
}
@@ -1793,7 +1793,7 @@ static void clk_osm_setup_fsms(struct clk_osm *c)
val = clk_osm_read_reg(c,
DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
- val |= BVAL(15, 0, clk_osm_count_ns(c, 15000));
+ val |= BVAL(15, 0, clk_osm_count_ns(c, 250));
clk_osm_write_reg(c, val,
DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
}
@@ -1807,7 +1807,7 @@ static void clk_osm_setup_fsms(struct clk_osm *c)
if (c->wfx_fsm_en || c->ps_fsm_en || c->droop_fsm_en) {
clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG);
- clk_osm_write_reg(c, clk_osm_count_ns(c, 500),
+ clk_osm_write_reg(c, clk_osm_count_ns(c, 5),
DROOP_RELEASE_TIMER_CTRL);
clk_osm_write_reg(c, clk_osm_count_ns(c, 500),
DCVS_DROOP_TIMER_CTRL);
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
index 1228d925761b..4b2d8bba0940 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
@@ -1016,19 +1016,19 @@ static struct clk_mux_ops mdss_mux_ops = {
* | vco_clk |
* +-------+-------+
* |
- * +--------------------------------------+
- * | |
- * +-------v-------+ |
- * | bitclk_src | |
- * | DIV(1..15) | |
- * +-------+-------+ |
- * | |
- * +--------------------+ |
- * Shadow Path | | |
- * + +-------v-------+ +------v------+ +------v-------+
- * | | byteclk_src | |post_bit_div | |post_vco_div |
- * | | DIV(8) | |DIV(1,2) | |DIV(1,4) |
- * | +-------+-------+ +------+------+ +------+-------+
+ * +----------------------+------------------+
+ * | | |
+ * +-------v-------+ +-------v-------+ +-------v-------+
+ * | bitclk_src | | post_vco_div1 | | post_vco_div4 |
+ * | DIV(1..15) | +-------+-------+ +-------+-------+
+ * +-------+-------+ | |
+ * | +------------+ |
+ * +--------------------+ | |
+ * Shadow Path | | | |
+ * + +-------v-------+ +------v------+ +---v-----v------+
+ * | | byteclk_src | |post_bit_div | \ post_vco_mux /
+ * | | DIV(8) | |DIV(1,2) | \ /
+ * | +-------+-------+ +------+------+ +---+------+
* | | | |
* | | +------+ +----+
* | +--------+ | |
@@ -1085,19 +1085,51 @@ static struct div_clk dsi0pll_bitclk_src = {
}
};
-static struct div_clk dsi0pll_post_vco_div = {
+static struct div_clk dsi0pll_post_vco_div1 = {
.data = {
.div = 1,
.min_div = 1,
+ .max_div = 1,
+ },
+ .ops = &clk_post_vco_div_ops,
+ .c = {
+ .parent = &dsi0pll_vco_clk.c,
+ .dbg_name = "dsi0pll_post_vco_div1",
+ .ops = &clk_ops_post_vco_div_c,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(dsi0pll_post_vco_div1.c),
+ }
+};
+
+static struct div_clk dsi0pll_post_vco_div4 = {
+ .data = {
+ .div = 4,
+ .min_div = 4,
.max_div = 4,
},
.ops = &clk_post_vco_div_ops,
.c = {
.parent = &dsi0pll_vco_clk.c,
- .dbg_name = "dsi0pll_post_vco_div",
+ .dbg_name = "dsi0pll_post_vco_div4",
.ops = &clk_ops_post_vco_div_c,
.flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_post_vco_div.c),
+ CLK_INIT(dsi0pll_post_vco_div4.c),
+ }
+};
+
+static struct mux_clk dsi0pll_post_vco_mux = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]) {
+ {&dsi0pll_post_vco_div1.c, 0},
+ {&dsi0pll_post_vco_div4.c, 1},
+ },
+ .ops = &mdss_mux_ops,
+ .c = {
+ .parent = &dsi0pll_post_vco_div1.c,
+ .dbg_name = "dsi0pll_post_vco_mux",
+ .ops = &clk_ops_gen_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(dsi0pll_post_vco_mux.c),
}
};
@@ -1121,7 +1153,7 @@ static struct mux_clk dsi0pll_pclk_src_mux = {
.num_parents = 2,
.parents = (struct clk_src[]) {
{&dsi0pll_post_bit_div.c, 0},
- {&dsi0pll_post_vco_div.c, 1},
+ {&dsi0pll_post_vco_mux.c, 1},
},
.ops = &mdss_mux_ops,
.c = {
@@ -1222,19 +1254,51 @@ static struct div_clk dsi1pll_bitclk_src = {
}
};
-static struct div_clk dsi1pll_post_vco_div = {
+static struct div_clk dsi1pll_post_vco_div1 = {
.data = {
.div = 1,
.min_div = 1,
+ .max_div = 1,
+ },
+ .ops = &clk_post_vco_div_ops,
+ .c = {
+ .parent = &dsi1pll_vco_clk.c,
+ .dbg_name = "dsi1pll_post_vco_div1",
+ .ops = &clk_ops_post_vco_div_c,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(dsi1pll_post_vco_div1.c),
+ }
+};
+
+static struct div_clk dsi1pll_post_vco_div4 = {
+ .data = {
+ .div = 4,
+ .min_div = 4,
.max_div = 4,
},
.ops = &clk_post_vco_div_ops,
.c = {
.parent = &dsi1pll_vco_clk.c,
- .dbg_name = "dsi1pll_post_vco_div",
+ .dbg_name = "dsi1pll_post_vco_div4",
.ops = &clk_ops_post_vco_div_c,
.flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_post_vco_div.c),
+ CLK_INIT(dsi1pll_post_vco_div4.c),
+ }
+};
+
+static struct mux_clk dsi1pll_post_vco_mux = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]) {
+ {&dsi1pll_post_vco_div1.c, 0},
+ {&dsi1pll_post_vco_div4.c, 1},
+ },
+ .ops = &mdss_mux_ops,
+ .c = {
+ .parent = &dsi1pll_post_vco_div1.c,
+ .dbg_name = "dsi1pll_post_vco_mux",
+ .ops = &clk_ops_gen_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(dsi1pll_post_vco_mux.c),
}
};
@@ -1258,7 +1322,7 @@ static struct mux_clk dsi1pll_pclk_src_mux = {
.num_parents = 2,
.parents = (struct clk_src[]) {
{&dsi1pll_post_bit_div.c, 0},
- {&dsi1pll_post_vco_div.c, 1},
+ {&dsi1pll_post_vco_mux.c, 1},
},
.ops = &mdss_mux_ops,
.c = {
@@ -1338,7 +1402,9 @@ static struct clk_lookup mdss_dsi_pll0cc_cobalt[] = {
CLK_LIST(dsi0pll_pclk_src),
CLK_LIST(dsi0pll_pclk_src_mux),
CLK_LIST(dsi0pll_post_bit_div),
- CLK_LIST(dsi0pll_post_vco_div),
+ CLK_LIST(dsi0pll_post_vco_mux),
+ CLK_LIST(dsi0pll_post_vco_div1),
+ CLK_LIST(dsi0pll_post_vco_div4),
CLK_LIST(dsi0pll_bitclk_src),
CLK_LIST(dsi0pll_vco_clk),
};
@@ -1349,7 +1415,9 @@ static struct clk_lookup mdss_dsi_pll1cc_cobalt[] = {
CLK_LIST(dsi1pll_pclk_src),
CLK_LIST(dsi1pll_pclk_src_mux),
CLK_LIST(dsi1pll_post_bit_div),
- CLK_LIST(dsi1pll_post_vco_div),
+ CLK_LIST(dsi1pll_post_vco_mux),
+ CLK_LIST(dsi1pll_post_vco_div1),
+ CLK_LIST(dsi1pll_post_vco_div4),
CLK_LIST(dsi1pll_bitclk_src),
CLK_LIST(dsi1pll_vco_clk),
};
@@ -1407,7 +1475,9 @@ int dsi_pll_clock_register_cobalt(struct platform_device *pdev,
dsi0pll_pclk_src.priv = pll_res;
dsi0pll_pclk_src_mux.priv = pll_res;
dsi0pll_post_bit_div.priv = pll_res;
- dsi0pll_post_vco_div.priv = pll_res;
+ dsi0pll_post_vco_mux.priv = pll_res;
+ dsi0pll_post_vco_div1.priv = pll_res;
+ dsi0pll_post_vco_div4.priv = pll_res;
dsi0pll_bitclk_src.priv = pll_res;
dsi0pll_vco_clk.priv = pll_res;
@@ -1421,7 +1491,9 @@ int dsi_pll_clock_register_cobalt(struct platform_device *pdev,
dsi1pll_pclk_src.priv = pll_res;
dsi1pll_pclk_src_mux.priv = pll_res;
dsi1pll_post_bit_div.priv = pll_res;
- dsi1pll_post_vco_div.priv = pll_res;
+ dsi1pll_post_vco_mux.priv = pll_res;
+ dsi1pll_post_vco_div1.priv = pll_res;
+ dsi1pll_post_vco_div4.priv = pll_res;
dsi1pll_bitclk_src.priv = pll_res;
dsi1pll_vco_clk.priv = pll_res;
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 933a208392bd..6d12ddb3e245 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -935,6 +935,8 @@ static int clk_gfx3d_src_set_rate_and_parent(struct clk_hw *hw,
}
const struct clk_ops clk_gfx3d_src_ops = {
+ .enable = clk_rcg2_enable,
+ .disable = clk_rcg2_disable,
.is_enabled = clk_rcg2_is_enabled,
.get_parent = clk_rcg2_get_parent,
.set_parent = clk_rcg2_set_parent,
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index ac007ec667bb..612e7b37a8d0 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -29,6 +29,8 @@
#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/mfd/qcom-rpm.h>
+#include "clk-voter.h"
+
#define QCOM_RPM_KEY_SOFTWARE_ENABLE 0x6e657773
#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370
#define QCOM_RPM_SMD_KEY_RATE 0x007a484b
@@ -603,7 +605,7 @@ DEFINE_CLK_SMD_RPM(msmfalcon, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(msmfalcon, cnoc_periph_clk, cnoc_periph_a_clk,
QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msmfalcon, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(msmfalcon, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk,
+DEFINE_CLK_SMD_RPM(msmfalcon, mmssnoc_axi_clk, mmssnoc_axi_a_clk,
QCOM_SMD_RPM_MMAXI_CLK, 0);
DEFINE_CLK_SMD_RPM(msmfalcon, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM(msmfalcon, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
@@ -624,6 +626,27 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk2_pin,
ln_bb_clk2_pin_ao, 0x2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk3_pin,
ln_bb_clk3_pin_ao, 0x3);
+/* Voter clocks */
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, bimc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, bimc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, cnoc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, cnoc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, snoc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, snoc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_periph_keepalive_a_clk, cnoc_periph_a_clk,
+ LONG_MAX);
+static DEFINE_CLK_VOTER(mcd_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(qcedev_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(qcrypto_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(qseecom_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(scm_ce1_clk, ce1_clk, 85710000);
+
+static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_cdsp_clk, cxo);
+
static struct clk_hw *msmfalcon_clks[] = {
[RPM_XO_CLK_SRC] = &msmfalcon_cxo.hw,
[RPM_XO_A_CLK_SRC] = &msmfalcon_cxo_a.hw,
@@ -639,8 +662,8 @@ static struct clk_hw *msmfalcon_clks[] = {
[RPM_AGGR2_NOC_A_CLK] = &msmfalcon_aggre2_noc_a_clk.hw,
[RPM_CNOC_CLK] = &msmfalcon_cnoc_clk.hw,
[RPM_CNOC_A_CLK] = &msmfalcon_cnoc_a_clk.hw,
- [RPM_MMAXI_CLK] = &msmfalcon_mmssnoc_axi_rpm_clk.hw,
- [RPM_MMAXI_A_CLK] = &msmfalcon_mmssnoc_axi_rpm_a_clk.hw,
+ [RPM_MMAXI_CLK] = &msmfalcon_mmssnoc_axi_clk.hw,
+ [RPM_MMAXI_A_CLK] = &msmfalcon_mmssnoc_axi_a_clk.hw,
[RPM_IPA_CLK] = &msmfalcon_ipa_clk.hw,
[RPM_IPA_A_CLK] = &msmfalcon_ipa_a_clk.hw,
[RPM_CE1_CLK] = &msmfalcon_ce1_clk.hw,
@@ -661,6 +684,25 @@ static struct clk_hw *msmfalcon_clks[] = {
[RPM_LN_BB_CLK3_PIN_AO] = &msmfalcon_ln_bb_clk3_pin_ao.hw,
[RPM_CNOC_PERIPH_CLK] = &msmfalcon_cnoc_periph_clk.hw,
[RPM_CNOC_PERIPH_A_CLK] = &msmfalcon_cnoc_periph_a_clk.hw,
+
+ /* Voter Clocks */
+ [BIMC_MSMBUS_CLK] = &bimc_msmbus_clk.hw,
+ [BIMC_MSMBUS_A_CLK] = &bimc_msmbus_a_clk.hw,
+ [CNOC_MSMBUS_CLK] = &cnoc_msmbus_clk.hw,
+ [CNOC_MSMBUS_A_CLK] = &cnoc_msmbus_a_clk.hw,
+ [MCD_CE1_CLK] = &mcd_ce1_clk.hw,
+ [QCEDEV_CE1_CLK] = &qcedev_ce1_clk.hw,
+ [QCRYPTO_CE1_CLK] = &qcrypto_ce1_clk.hw,
+ [QSEECOM_CE1_CLK] = &qseecom_ce1_clk.hw,
+ [SCM_CE1_CLK] = &scm_ce1_clk.hw,
+ [SNOC_MSMBUS_CLK] = &snoc_msmbus_clk.hw,
+ [SNOC_MSMBUS_A_CLK] = &snoc_msmbus_a_clk.hw,
+ [CXO_DWC3_CLK] = &cxo_dwc3_clk.hw,
+ [CXO_LPM_CLK] = &cxo_lpm_clk.hw,
+ [CXO_OTG_CLK] = &cxo_otg_clk.hw,
+ [CXO_PIL_LPASS_CLK] = &cxo_pil_lpass_clk.hw,
+ [CXO_PIL_CDSP_CLK] = &cxo_pil_cdsp_clk.hw,
+ [CNOC_PERIPH_KEEPALIVE_A_CLK] = &cnoc_periph_keepalive_a_clk.hw,
};
static const struct rpm_smd_clk_desc rpm_clk_msmfalcon = {
@@ -757,9 +799,14 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
/* Keep an active vote on CXO in case no other driver votes for it */
if (is_8996)
clk_prepare_enable(msm8996_cxo_a.hw.clk);
- else if (is_falcon)
+ else if (is_falcon) {
clk_prepare_enable(msmfalcon_cxo_a.hw.clk);
+ /* Hold an active set vote for the cnoc_periph resource */
+ clk_set_rate(cnoc_periph_keepalive_a_clk.hw.clk, 19200000);
+ clk_prepare_enable(cnoc_periph_keepalive_a_clk.hw.clk);
+ }
+
dev_info(&pdev->dev, "Registered RPM clocks\n");
return 0;
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index f7c226ab4307..423e975dffee 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -177,7 +177,7 @@ EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
int qcom_cc_really_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc, struct regmap *regmap)
{
- int i, ret;
+ int i = 0, ret, j = 0;
struct device *dev = &pdev->dev;
struct clk *clk;
struct clk_onecell_data *data;
@@ -187,8 +187,10 @@ int qcom_cc_really_probe(struct platform_device *pdev,
struct gdsc_desc *scd;
size_t num_clks = desc->num_clks;
struct clk_regmap **rclks = desc->clks;
+ struct clk_hw **hw_clks = desc->hwclks;
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
+ cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) *
+ (num_clks + desc->num_hwclks),
GFP_KERNEL);
if (!cc)
return -ENOMEM;
@@ -196,17 +198,32 @@ int qcom_cc_really_probe(struct platform_device *pdev,
clks = cc->clks;
data = &cc->data;
data->clks = clks;
- data->clk_num = num_clks;
+ data->clk_num = num_clks + desc->num_hwclks;
- for (i = 0; i < num_clks; i++) {
- if (!rclks[i]) {
+ for (i = 0; i < desc->num_hwclks; i++) {
+ if (!hw_clks[i]) {
clks[i] = ERR_PTR(-ENOENT);
continue;
}
- clk = devm_clk_register_regmap(dev, rclks[i]);
+ clk = devm_clk_register(dev, hw_clks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
+ pr_debug("Index for hw_clocks %d added %s\n", i,
+ __clk_get_name(clk));
+ }
+
+ for (j = i; j < num_clks; j++) {
+ if (!rclks[j]) {
+ clks[j] = ERR_PTR(-ENOENT);
+ continue;
+ }
+ clk = devm_clk_register_regmap(dev, rclks[j]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clks[j] = clk;
+ pr_debug("Index for Regmap clocks %d added %s\n", j,
+ __clk_get_name(clk));
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 10cabca921be..e3f450533470 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -25,7 +25,9 @@ struct parent_map;
struct qcom_cc_desc {
const struct regmap_config *config;
struct clk_regmap **clks;
+ struct clk_hw **hwclks;
size_t num_clks;
+ size_t num_hwclks;
const struct qcom_reset_map *resets;
size_t num_resets;
struct gdsc **gdscs;
diff --git a/drivers/clk/qcom/gcc-msmfalcon.c b/drivers/clk/qcom/gcc-msmfalcon.c
index 78858a3c6f1c..2cbc9dff047b 100644
--- a/drivers/clk/qcom/gcc-msmfalcon.c
+++ b/drivers/clk/qcom/gcc-msmfalcon.c
@@ -2739,6 +2739,8 @@ static const struct qcom_cc_desc gcc_falcon_desc = {
.config = &gcc_falcon_regmap_config,
.clks = gcc_falcon_clocks,
.num_clks = ARRAY_SIZE(gcc_falcon_clocks),
+ .hwclks = gcc_msmfalcon_hws,
+ .num_hwclks = ARRAY_SIZE(gcc_msmfalcon_hws),
.resets = gcc_falcon_resets,
.num_resets = ARRAY_SIZE(gcc_falcon_resets),
};
@@ -2765,13 +2767,6 @@ static int gcc_falcon_probe(struct platform_device *pdev)
*/
regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
- /* register hardware clocks */
- for (i = 0; i < ARRAY_SIZE(gcc_msmfalcon_hws); i++) {
- clk = devm_clk_register(&pdev->dev, gcc_msmfalcon_hws[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- }
-
vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
if (IS_ERR(vdd_dig.regulator[0])) {
if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
diff --git a/drivers/clk/qcom/gpucc-msmfalcon.c b/drivers/clk/qcom/gpucc-msmfalcon.c
index a2127e2629c7..f194abb471cd 100644
--- a/drivers/clk/qcom/gpucc-msmfalcon.c
+++ b/drivers/clk/qcom/gpucc-msmfalcon.c
@@ -84,12 +84,12 @@ static struct pll_vco gpu_vco[] = {
{ 250000000, 500000000, 3 },
};
-/* 640MHz configuration */
+/* 800MHz configuration */
static const struct pll_config gpu_pll0_config = {
- .l = 0x21,
+ .l = 0x29,
.config_ctl_val = 0x4001055b,
- .alpha = 0x55555600,
- .alpha_u = 0x55,
+ .alpha = 0xaaaaab00,
+ .alpha_u = 0xaa,
.alpha_en_mask = BIT(24),
.vco_val = 0x2 << 20,
.vco_mask = 0x3 << 20,
diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c
index 010f9defe33e..a3c826e152e1 100644
--- a/drivers/devfreq/governor_memlat.c
+++ b/drivers/devfreq/governor_memlat.c
@@ -81,6 +81,29 @@ show_attr(__attr) \
store_attr(__attr, min, max) \
static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
+static ssize_t show_map(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq *df = to_devfreq(dev);
+ struct memlat_node *n = df->data;
+ struct core_dev_map *map = n->hw->freq_map;
+ unsigned int cnt = 0;
+
+ cnt += snprintf(buf, PAGE_SIZE, "Core freq (MHz)\tDevice BW\n");
+
+ while (map->core_mhz && cnt < PAGE_SIZE) {
+ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%15u\t%9u\n",
+ map->core_mhz, map->target_freq);
+ map++;
+ }
+ if (cnt < PAGE_SIZE)
+ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n");
+
+ return cnt;
+}
+
+static DEVICE_ATTR(freq_map, 0444, show_map, NULL);
+
static unsigned long core_to_dev_freq(struct memlat_node *node,
unsigned long coref)
{
@@ -247,6 +270,7 @@ gov_attr(ratio_ceil, 1U, 10000U);
static struct attribute *dev_attr[] = {
&dev_attr_ratio_ceil.attr,
+ &dev_attr_freq_map.attr,
NULL,
};
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 94d828027f20..9940f7a7c2b7 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1961,7 +1961,7 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
KGSL_STATE_ACTIVE);
device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
adreno_fault_detect_stop(adreno_dev);
- kgsl_pwrscale_disable(device);
+ kgsl_pwrscale_disable(device, true);
}
mutex_unlock(&device->mutex);
diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c
index aeffeab2f6dc..c09d2f8c1947 100644
--- a/drivers/gpu/msm/adreno_a5xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c
@@ -410,8 +410,6 @@ static const unsigned int a5xx_registers[] = {
0xEA80, 0xEA80, 0xEA82, 0xEAA3, 0xEAA5, 0xEAC2,
/* GPMU */
0xA800, 0xA8FF, 0xAC60, 0xAC60,
- /* DPM */
- 0xB000, 0xB97F, 0xB9A0, 0xB9BF,
};
struct a5xx_hlsq_sp_tp_regs {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index d71c6a63f2d3..172de7406c26 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1387,6 +1387,47 @@ done:
return 0;
}
+static ssize_t kgsl_pwrctrl_pwrscale_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int ret;
+ unsigned int enable = 0;
+
+ if (device == NULL)
+ return 0;
+
+ ret = kgsl_sysfs_store(buf, &enable);
+ if (ret)
+ return ret;
+
+ mutex_lock(&device->mutex);
+
+ if (enable)
+ kgsl_pwrscale_enable(device);
+ else
+ kgsl_pwrscale_disable(device, false);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static ssize_t kgsl_pwrctrl_pwrscale_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrscale *psc;
+
+ if (device == NULL)
+ return 0;
+ psc = &device->pwrscale;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", psc->enabled);
+}
+
static DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show,
kgsl_pwrctrl_gpuclk_store);
static DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
@@ -1449,6 +1490,9 @@ static DEVICE_ATTR(clock_mhz, 0444, kgsl_pwrctrl_clock_mhz_show, NULL);
static DEVICE_ATTR(freq_table_mhz, 0444,
kgsl_pwrctrl_freq_table_mhz_show, NULL);
static DEVICE_ATTR(temp, 0444, kgsl_pwrctrl_temp_show, NULL);
+static DEVICE_ATTR(pwrscale, 0644,
+ kgsl_pwrctrl_pwrscale_show,
+ kgsl_pwrctrl_pwrscale_store);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -1477,6 +1521,7 @@ static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_clock_mhz,
&dev_attr_freq_table_mhz,
&dev_attr_temp,
+ &dev_attr_pwrscale,
NULL
};
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 01d3b74c16fd..85cd29b5364e 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -189,19 +189,21 @@ EXPORT_SYMBOL(kgsl_pwrscale_update);
/*
* kgsl_pwrscale_disable - temporarily disable the governor
* @device: The device
+ * @turbo: Indicates if pwrlevel should be forced to turbo
*
* Temporarily disable the governor, to prevent interference
* with profiling tools that expect a fixed clock frequency.
* This function must be called with the device mutex locked.
*/
-void kgsl_pwrscale_disable(struct kgsl_device *device)
+void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo)
{
BUG_ON(!mutex_is_locked(&device->mutex));
if (device->pwrscale.devfreqptr)
queue_work(device->pwrscale.devfreq_wq,
&device->pwrscale.devfreq_suspend_ws);
device->pwrscale.enabled = false;
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
+ if (turbo)
+ kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
}
EXPORT_SYMBOL(kgsl_pwrscale_disable);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index c85317869f1d..0756a4490f22 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -123,7 +123,7 @@ void kgsl_pwrscale_sleep(struct kgsl_device *device);
void kgsl_pwrscale_wake(struct kgsl_device *device);
void kgsl_pwrscale_enable(struct kgsl_device *device);
-void kgsl_pwrscale_disable(struct kgsl_device *device);
+void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo);
int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags);
int kgsl_devfreq_get_dev_status(struct device *, struct devfreq_dev_status *);
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
index cd02396abbe7..227dbfa97d64 100644
--- a/drivers/media/dvb-core/demux.h
+++ b/drivers/media/dvb-core/demux.h
@@ -407,8 +407,7 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1,
size_t buffer1_length,
const u8 *buffer2,
size_t buffer2_length,
- struct dmx_ts_feed *source,
- enum dmx_success success);
+ struct dmx_ts_feed *source);
/**
* typedef dmx_section_cb - DVB demux TS filter callback function prototype
@@ -449,8 +448,7 @@ typedef int (*dmx_section_cb)(const u8 *buffer1,
size_t buffer1_len,
const u8 *buffer2,
size_t buffer2_len,
- struct dmx_section_filter *source,
- enum dmx_success success);
+ struct dmx_section_filter *source);
typedef int (*dmx_ts_fullness) (
struct dmx_ts_feed *source,
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 63becfd57eaa..a9c4237d631a 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -2603,15 +2603,15 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
- struct dmx_section_filter *filter,
- enum dmx_success success)
+ struct dmx_section_filter *filter)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
struct dmx_filter_event event;
ssize_t free;
+
if (!dmxdevfilter) {
- pr_err("%s: null filter. status=%d\n", __func__, success);
+ pr_err("%s: null filter.\n", __func__);
return -EINVAL;
}
@@ -2633,7 +2633,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
}
if ((buffer1_len + buffer2_len) == 0) {
- if (success == DMX_CRC_ERROR) {
+ if (buffer1 == NULL && buffer2 == NULL) {
/* Section was dropped due to CRC error */
event.type = DMX_EVENT_SECTION_CRC_ERROR;
dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
@@ -2671,11 +2671,6 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
event.params.section.actual_length =
event.params.section.total_length;
- if (success == DMX_MISSED_ERROR)
- event.params.section.flags = DMX_FILTER_CC_ERROR;
- else
- event.params.section.flags = 0;
-
dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
@@ -2687,8 +2682,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
- struct dmx_ts_feed *feed,
- enum dmx_success success)
+ struct dmx_ts_feed *feed)
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer;
@@ -2697,11 +2691,10 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
ssize_t free;
if (!dmxdevfilter) {
- pr_err("%s: null filter (feed->is_filtering=%d) status=%d\n",
- __func__, feed->is_filtering, success);
+ pr_err("%s: null filter (feed->is_filtering=%d)\n",
+ __func__, feed->is_filtering);
return -EINVAL;
}
-
spin_lock(&dmxdevfilter->dev->lock);
if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER ||
@@ -2725,36 +2718,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
return buffer->error;
}
- if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) {
- if (success == DMX_OK && !events->current_event_data_size) {
- events->current_event_start_offset = buffer->pwrite;
- } else if (success == DMX_OK_PES_END) {
- event.type = DMX_EVENT_NEW_PES;
-
- event.params.pes.actual_length =
- events->current_event_data_size;
- event.params.pes.total_length =
- events->current_event_data_size;
-
- event.params.pes.base_offset =
- events->current_event_start_offset;
- event.params.pes.start_offset =
- events->current_event_start_offset;
-
- event.params.pes.flags = 0;
- event.params.pes.stc = 0;
- event.params.pes.transport_error_indicator_counter = 0;
- event.params.pes.continuity_error_counter = 0;
- event.params.pes.ts_packets_num = 0;
-
- /* Do not report zero length PES */
- if (event.params.pes.total_length)
- dvb_dmxdev_add_event(events, &event);
- events->current_event_data_size = 0;
- }
- } else if (!events->current_event_data_size) {
+ if (!events->current_event_data_size)
events->current_event_start_offset = buffer->pwrite;
- }
/* Verify output buffer has sufficient space, or report overflow */
free = dvb_ringbuffer_free(buffer);
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index d45bcc55b76a..7809770bd1ae 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -550,7 +550,7 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
if (feed->pusi_seen == 0)
return 0;
- ret = feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
+ ret = feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
/* Verify TS packet was copied successfully */
if (!ret) {
@@ -582,7 +582,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
return 0;
return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
- NULL, 0, &f->filter, DMX_OK);
+ NULL, 0, &f->filter);
}
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@@ -613,7 +613,7 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
/* Notify on CRC error */
feed->cb.sec(NULL, 0, NULL, 0,
- &f->filter, DMX_CRC_ERROR);
+ &f->filter);
return -1;
}
@@ -1256,9 +1256,9 @@ static inline void dvb_dmx_swfilter_output_packet(
*/
if (feed->tsp_out_format == DMX_TSP_FORMAT_192_HEAD)
feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL,
- 0, &feed->feed.ts, DMX_OK);
+ 0, &feed->feed.ts);
- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
/*
* if we output 192 packet with timestamp at tail of packet,
@@ -1266,7 +1266,7 @@ static inline void dvb_dmx_swfilter_output_packet(
*/
if (feed->tsp_out_format == DMX_TSP_FORMAT_192_TAIL)
feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL,
- 0, &feed->feed.ts, DMX_OK);
+ 0, &feed->feed.ts);
if (feed->idx_params.enable)
dvb_dmx_index(feed, buf, timestamp);
@@ -1749,7 +1749,7 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
{
spin_lock(&demux->lock);
- demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
+ demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
spin_unlock(&demux->lock);
}
@@ -2520,7 +2520,7 @@ static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
return 0;
}
- feed->cb.ts(data, size, NULL, 0, ts_feed, DMX_OK);
+ feed->cb.ts(data, size, NULL, 0, ts_feed);
spin_unlock(&demux->lock);
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 454584a8bf17..ce4332e80a91 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -761,8 +761,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
- struct dmx_ts_feed *feed,
- enum dmx_success success)
+ struct dmx_ts_feed *feed)
{
struct net_device *dev = feed->priv;
@@ -871,8 +870,7 @@ static void dvb_net_sec(struct net_device *dev,
static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
- struct dmx_section_filter *filter,
- enum dmx_success success)
+ struct dmx_section_filter *filter)
{
struct net_device *dev = filter->priv;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index a2aa2983b056..98b29cc3a9e3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1943,7 +1943,7 @@ static void msm_vfe40_stats_cfg_wm_reg(
stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
stats_base = VFE40_STATS_BASE(stats_idx);
/*WR_ADDR_CFG*/
- msm_camera_io_w(stream_info->framedrop_period << 2,
+ msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
vfe_dev->vfe_base + stats_base + 0x8);
/*WR_IRQ_FRAMEDROP_PATTERN*/
msm_camera_io_w(stream_info->framedrop_pattern,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
index c77eff66ccca..0e14e0957a2a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
@@ -1590,7 +1590,7 @@ static void msm_vfe44_stats_cfg_wm_reg(
if (stats_idx == STATS_IDX_BF_SCALE)
return;
/*WR_ADDR_CFG*/
- msm_camera_io_w(stream_info->framedrop_period << 2,
+ msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
vfe_dev->vfe_base + stats_base + 0x8);
/*WR_IRQ_FRAMEDROP_PATTERN*/
msm_camera_io_w(stream_info->framedrop_pattern,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
index 6336892b1b4e..5237b84e9477 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
@@ -1680,7 +1680,7 @@ static void msm_vfe46_stats_cfg_wm_reg(
return;
/* WR_ADDR_CFG */
- msm_camera_io_w(stream_info->framedrop_period << 2,
+ msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
vfe_dev->vfe_base + stats_base + 0x8);
/* WR_IRQ_FRAMEDROP_PATTERN */
msm_camera_io_w(stream_info->framedrop_pattern,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index 9a469abc56ca..df7e2a88e7ca 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -30,10 +30,13 @@
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#define VFE47_8996V1_VERSION 0x70000000
+#define VFE48_SDM660_VERSION 0x80000003
#define VFE47_BURST_LEN 3
+#define VFE48_SDM660_BURST_LEN 4
#define VFE47_FETCH_BURST_LEN 3
#define VFE47_STATS_BURST_LEN 3
+#define VFE48_SDM660_STATS_BURST_LEN 4
#define VFE47_UB_SIZE_VFE0 2048
#define VFE47_UB_SIZE_VFE1 1536
#define VFE47_UB_STATS_SIZE 144
@@ -359,13 +362,13 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev)
else
id = CAM_AHB_CLIENT_VFE1;
+ vfe_dev->hw_info->vfe_ops.platform_ops.set_clk_rate(vfe_dev, &rate);
+
if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0)
pr_err("%s: failed to vote for AHB\n", __func__);
vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE;
- vfe_dev->hw_info->vfe_ops.platform_ops.set_clk_rate(vfe_dev, &rate);
-
vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(
vfe_dev, 0);
vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
@@ -1504,7 +1507,7 @@ void msm_vfe47_axi_cfg_wm_reg(
{
uint32_t val;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
- uint32_t wm_base;
+ uint32_t wm_base, burst_len;
wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0x14);
@@ -1522,7 +1525,11 @@ void msm_vfe47_axi_cfg_wm_reg(
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x1C);
/* WR_BUFFER_CFG */
- val = VFE47_BURST_LEN |
+ if (vfe_dev->vfe_hw_version == VFE48_SDM660_VERSION)
+ burst_len = VFE48_SDM660_BURST_LEN;
+ else
+ burst_len = VFE47_BURST_LEN;
+ val = burst_len |
(stream_info->plane_cfg[vfe_idx][plane_idx].
output_height - 1) <<
2 |
@@ -2055,7 +2062,7 @@ void msm_vfe47_stats_cfg_wm_reg(
stats_base = VFE47_STATS_BASE(stats_idx);
/* WR_ADDR_CFG */
- msm_camera_io_w(stream_info->framedrop_period << 2,
+ msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
vfe_dev->vfe_base + stats_base + 0x10);
/* WR_IRQ_FRAMEDROP_PATTERN */
msm_camera_io_w(stream_info->framedrop_pattern,
@@ -2089,7 +2096,7 @@ void msm_vfe47_stats_clear_wm_reg(
void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev)
{
int i;
- uint32_t ub_offset = 0;
+ uint32_t ub_offset = 0, stats_burst_len;
uint32_t ub_size[VFE47_NUM_STATS_TYPE] = {
16, /* MSM_ISP_STATS_HDR_BE */
16, /* MSM_ISP_STATS_BG */
@@ -2108,9 +2115,14 @@ void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev)
else
pr_err("%s: incorrect VFE device\n", __func__);
+ if (vfe_dev->vfe_hw_version == VFE48_SDM660_VERSION)
+ stats_burst_len = VFE48_SDM660_STATS_BURST_LEN;
+ else
+ stats_burst_len = VFE47_STATS_BURST_LEN;
+
for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
ub_offset -= ub_size[i];
- msm_camera_io_w(VFE47_STATS_BURST_LEN << 30 |
+ msm_camera_io_w(stats_burst_len << 30 |
ub_offset << 16 | (ub_size[i] - 1),
vfe_dev->vfe_base + VFE47_STATS_BASE(i) + 0x14);
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index e226f7e40a07..afa498f80928 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -1263,7 +1263,7 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg)
stream_info->framedrop_pattern = 0x0;
else
stream_info->framedrop_pattern = 0x1;
- stream_info->framedrop_period = framedrop_period - 1;
+ stream_info->framedrop_period = framedrop_period;
if (stream_info->init_stats_frame_drop == 0)
for (k = 0; k < stream_info->num_isp; k++)
stream_info->vfe_dev[k]->hw_info->
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 258e08c1b34f..e0d6977b24a6 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -2748,14 +2748,14 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
break;
default: {
if (ioctl_ptr == NULL) {
- pr_err("Wrong ioctl_ptr %pK\n", ioctl_ptr);
+ pr_err("Wrong ioctl_ptr for cmd %u\n", cmd);
return -EINVAL;
}
*ioctl_ptr = arg;
if ((*ioctl_ptr == NULL) ||
- ((*ioctl_ptr)->ioctl_ptr == NULL)) {
- pr_err("Wrong arg %pK\n", arg);
+ (*ioctl_ptr)->ioctl_ptr == NULL) {
+ pr_err("Error invalid ioctl argument cmd %u", cmd);
return -EINVAL;
}
break;
@@ -2780,6 +2780,12 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
pr_err("cpp_dev is null\n");
return -EINVAL;
}
+
+ if (_IOC_DIR(cmd) == _IOC_NONE) {
+ pr_err("Invalid ioctl/subdev cmd %u", cmd);
+ return -EINVAL;
+ }
+
rc = msm_cpp_validate_input(cmd, arg, &ioctl_ptr);
if (rc != 0) {
pr_err("input validation failed\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
index 79d7d94582c5..bba0b2bc9cdb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
@@ -50,11 +50,11 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_1_3ph = {
{0x148, 0xFE},
{0x14C, 0x1},
{0x154, 0x0},
- {0x15C, 0x23},
+ {0x15C, 0x63},
{0x160, ULPM_WAKE_UP_TIMER_MODE},
{0x164, 0x00},
- {0x168, 0xA0},
- {0x16C, 0x25},
+ {0x168, 0xAC},
+ {0x16C, 0xA5},
{0x170, 0x41},
{0x174, 0x41},
{0x178, 0x3E},
@@ -98,7 +98,7 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_1_3ph = {
{0x0, 0x91},
{0x70C, 0xA5},
{0x38, 0xFE},
- {0x81c, 0x6},
+ {0x81c, 0x2},
};
struct csiphy_settings_t csiphy_combo_mode_v5_0_1 = {
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index d1e3c090c972..fb8f0c4bae37 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4186,7 +4186,7 @@ static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed,
mpq_feed->sdmx_buf.size) {
feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread],
header->payload_length,
- NULL, 0, &f->filter, DMX_OK);
+ NULL, 0, &f->filter);
} else {
int split = mpq_feed->sdmx_buf.size - mpq_feed->sdmx_buf.pread;
@@ -4194,7 +4194,7 @@ static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed,
split,
&mpq_feed->sdmx_buf.data[0],
header->payload_length - split,
- &f->filter, DMX_OK);
+ &f->filter);
}
return 0;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index be3ccf2536d9..203daf3bd5eb 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -21,6 +21,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/gfp.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
@@ -48,11 +49,7 @@
#define CORE_SW_RST (1 << 7)
#define SDHCI_VER_100 0x2B
-#define CORE_MCI_DATA_CNT 0x30
-#define CORE_MCI_STATUS 0x34
-#define CORE_MCI_FIFO_CNT 0x44
-#define CORE_MCI_VERSION 0x050
#define CORE_VERSION_STEP_MASK 0x0000FFFF
#define CORE_VERSION_MINOR_MASK 0x0FFF0000
#define CORE_VERSION_MINOR_SHIFT 16
@@ -61,23 +58,12 @@
#define CORE_VERSION_TARGET_MASK 0x000000FF
#define SDHCI_MSM_VER_420 0x49
-#define CORE_GENERICS 0x70
#define SWITCHABLE_SIGNALLING_VOL (1 << 29)
#define CORE_HC_MODE 0x78
#define HC_MODE_EN 0x1
#define FF_CLK_SW_RST_DIS (1 << 13)
-#define CORE_TESTBUS_CONFIG 0x0CC
-#define CORE_TESTBUS_SEL2_BIT 4
-#define CORE_TESTBUS_ENA (1 << 3)
-#define CORE_TESTBUS_SEL2 (1 << CORE_TESTBUS_SEL2_BIT)
-
-#define CORE_PWRCTL_STATUS 0xDC
-#define CORE_PWRCTL_MASK 0xE0
-#define CORE_PWRCTL_CLEAR 0xE4
-#define CORE_PWRCTL_CTL 0xE8
-
#define CORE_PWRCTL_BUS_OFF 0x01
#define CORE_PWRCTL_BUS_ON (1 << 1)
#define CORE_PWRCTL_IO_LOW (1 << 2)
@@ -91,7 +77,6 @@
#define INT_MASK 0xF
#define MAX_PHASES 16
-#define CORE_DLL_CONFIG 0x100
#define CORE_CMD_DAT_TRACK_SEL (1 << 0)
#define CORE_DLL_EN (1 << 16)
#define CORE_CDR_EN (1 << 17)
@@ -100,11 +85,9 @@
#define CORE_DLL_PDN (1 << 29)
#define CORE_DLL_RST (1 << 30)
-#define CORE_DLL_STATUS 0x108
#define CORE_DLL_LOCK (1 << 7)
#define CORE_DDR_DLL_LOCK (1 << 11)
-#define CORE_VENDOR_SPEC 0x10C
#define CORE_CLK_PWRSAVE (1 << 1)
#define CORE_HC_MCLK_SEL_DFLT (2 << 8)
#define CORE_HC_MCLK_SEL_HS400 (3 << 8)
@@ -117,23 +100,16 @@
#define CORE_HC_SELECT_IN_MASK (7 << 19)
#define CORE_VENDOR_SPEC_POR_VAL 0xA1C
-#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR0 0x114
-#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR1 0x118
-
-#define CORE_VENDOR_SPEC_FUNC2 0x110
#define HC_SW_RST_WAIT_IDLE_DIS (1 << 20)
#define HC_SW_RST_REQ (1 << 21)
#define CORE_ONE_MID_EN (1 << 25)
-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11C
#define CORE_8_BIT_SUPPORT (1 << 18)
#define CORE_3_3V_SUPPORT (1 << 24)
#define CORE_3_0V_SUPPORT (1 << 25)
#define CORE_1_8V_SUPPORT (1 << 26)
#define CORE_SYS_BUS_SUPPORT_64_BIT BIT(28)
-#define CORE_SDCC_DEBUG_REG 0x124
-
#define CORE_CSR_CDC_CTLR_CFG0 0x130
#define CORE_SW_TRIG_FULL_CALIB (1 << 16)
#define CORE_HW_AUTOCAL_ENA (1 << 17)
@@ -161,25 +137,20 @@
#define CORE_CDC_SWITCH_BYPASS_OFF (1 << 0)
#define CORE_CDC_SWITCH_RC_EN (1 << 1)
-#define CORE_DDR_200_CFG 0x184
#define CORE_CDC_T4_DLY_SEL (1 << 0)
#define CORE_CMDIN_RCLK_EN (1 << 1)
#define CORE_START_CDC_TRAFFIC (1 << 6)
-#define CORE_VENDOR_SPEC3 0x1B0
#define CORE_PWRSAVE_DLL (1 << 3)
#define CORE_CMDEN_HS400_INPUT_MASK_CNT (1 << 13)
-#define CORE_DLL_CONFIG_2 0x1B4
#define CORE_DDR_CAL_EN (1 << 0)
#define CORE_FLL_CYCLE_CNT (1 << 18)
#define CORE_DLL_CLOCK_DISABLE (1 << 21)
-#define CORE_DDR_CONFIG 0x1B8
#define DDR_CONFIG_POR_VAL 0x80040853
#define DDR_CONFIG_PRG_RCLK_DLY_MASK 0x1FF
#define DDR_CONFIG_PRG_RCLK_DLY 115
-#define CORE_DDR_CONFIG_2 0x1BC
#define DDR_CONFIG_2_POR_VAL 0x80040873
/* 512 descriptors */
@@ -196,6 +167,149 @@
#define MAX_DRV_TYPES_SUPPORTED_HS200 4
#define MSM_AUTOSUSPEND_DELAY_MS 100
+struct sdhci_msm_offset {
+ u32 CORE_MCI_DATA_CNT;
+ u32 CORE_MCI_STATUS;
+ u32 CORE_MCI_FIFO_CNT;
+ u32 CORE_MCI_VERSION;
+ u32 CORE_GENERICS;
+ u32 CORE_TESTBUS_CONFIG;
+ u32 CORE_TESTBUS_SEL2_BIT;
+ u32 CORE_TESTBUS_ENA;
+ u32 CORE_TESTBUS_SEL2;
+ u32 CORE_PWRCTL_STATUS;
+ u32 CORE_PWRCTL_MASK;
+ u32 CORE_PWRCTL_CLEAR;
+ u32 CORE_PWRCTL_CTL;
+ u32 CORE_SDCC_DEBUG_REG;
+ u32 CORE_DLL_CONFIG;
+ u32 CORE_DLL_STATUS;
+ u32 CORE_VENDOR_SPEC;
+ u32 CORE_VENDOR_SPEC_ADMA_ERR_ADDR0;
+ u32 CORE_VENDOR_SPEC_ADMA_ERR_ADDR1;
+ u32 CORE_VENDOR_SPEC_FUNC2;
+ u32 CORE_VENDOR_SPEC_CAPABILITIES0;
+ u32 CORE_DDR_200_CFG;
+ u32 CORE_VENDOR_SPEC3;
+ u32 CORE_DLL_CONFIG_2;
+ u32 CORE_DDR_CONFIG;
+ u32 CORE_DDR_CONFIG_2;
+};
+
+struct sdhci_msm_offset sdhci_msm_offset_mci_removed = {
+ .CORE_MCI_DATA_CNT = 0x35C,
+ .CORE_MCI_STATUS = 0x324,
+ .CORE_MCI_FIFO_CNT = 0x308,
+ .CORE_MCI_VERSION = 0x318,
+ .CORE_GENERICS = 0x320,
+ .CORE_TESTBUS_CONFIG = 0x32C,
+ .CORE_TESTBUS_SEL2_BIT = 3,
+ .CORE_TESTBUS_ENA = (1 << 31),
+ .CORE_TESTBUS_SEL2 = (1 << 3),
+ .CORE_PWRCTL_STATUS = 0x240,
+ .CORE_PWRCTL_MASK = 0x244,
+ .CORE_PWRCTL_CLEAR = 0x248,
+ .CORE_PWRCTL_CTL = 0x24C,
+ .CORE_SDCC_DEBUG_REG = 0x358,
+ .CORE_DLL_CONFIG = 0x200,
+ .CORE_DLL_STATUS = 0x208,
+ .CORE_VENDOR_SPEC = 0x20C,
+ .CORE_VENDOR_SPEC_ADMA_ERR_ADDR0 = 0x214,
+ .CORE_VENDOR_SPEC_ADMA_ERR_ADDR1 = 0x218,
+ .CORE_VENDOR_SPEC_FUNC2 = 0x210,
+ .CORE_VENDOR_SPEC_CAPABILITIES0 = 0x21C,
+ .CORE_DDR_200_CFG = 0x224,
+ .CORE_VENDOR_SPEC3 = 0x250,
+ .CORE_DLL_CONFIG_2 = 0x254,
+ .CORE_DDR_CONFIG = 0x258,
+ .CORE_DDR_CONFIG_2 = 0x25C,
+};
+
+struct sdhci_msm_offset sdhci_msm_offset_mci_present = {
+ .CORE_MCI_DATA_CNT = 0x30,
+ .CORE_MCI_STATUS = 0x34,
+ .CORE_MCI_FIFO_CNT = 0x44,
+ .CORE_MCI_VERSION = 0x050,
+ .CORE_GENERICS = 0x70,
+ .CORE_TESTBUS_CONFIG = 0x0CC,
+ .CORE_TESTBUS_SEL2_BIT = 4,
+ .CORE_TESTBUS_ENA = (1 << 3),
+ .CORE_TESTBUS_SEL2 = (1 << 4),
+ .CORE_PWRCTL_STATUS = 0xDC,
+ .CORE_PWRCTL_MASK = 0xE0,
+ .CORE_PWRCTL_CLEAR = 0xE4,
+ .CORE_PWRCTL_CTL = 0xE8,
+ .CORE_SDCC_DEBUG_REG = 0x124,
+ .CORE_DLL_CONFIG = 0x100,
+ .CORE_DLL_STATUS = 0x108,
+ .CORE_VENDOR_SPEC = 0x10C,
+ .CORE_VENDOR_SPEC_ADMA_ERR_ADDR0 = 0x114,
+ .CORE_VENDOR_SPEC_ADMA_ERR_ADDR1 = 0x118,
+ .CORE_VENDOR_SPEC_FUNC2 = 0x110,
+ .CORE_VENDOR_SPEC_CAPABILITIES0 = 0x11C,
+ .CORE_DDR_200_CFG = 0x184,
+ .CORE_VENDOR_SPEC3 = 0x1B0,
+ .CORE_DLL_CONFIG_2 = 0x1B4,
+ .CORE_DDR_CONFIG = 0x1B8,
+ .CORE_DDR_CONFIG_2 = 0x1BC,
+};
+
+u8 sdhci_msm_readb_relaxed(struct sdhci_host *host, u32 offset)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ void __iomem *base_addr;
+
+ if (msm_host->mci_removed)
+ base_addr = host->ioaddr;
+ else
+ base_addr = msm_host->core_mem;
+
+ return readb_relaxed(base_addr + offset);
+}
+
+u32 sdhci_msm_readl_relaxed(struct sdhci_host *host, u32 offset)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ void __iomem *base_addr;
+
+ if (msm_host->mci_removed)
+ base_addr = host->ioaddr;
+ else
+ base_addr = msm_host->core_mem;
+
+ return readl_relaxed(base_addr + offset);
+}
+
+void sdhci_msm_writeb_relaxed(u8 val, struct sdhci_host *host, u32 offset)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ void __iomem *base_addr;
+
+ if (msm_host->mci_removed)
+ base_addr = host->ioaddr;
+ else
+ base_addr = msm_host->core_mem;
+
+ writeb_relaxed(val, base_addr + offset);
+}
+
+void sdhci_msm_writel_relaxed(u32 val, struct sdhci_host *host, u32 offset)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ void __iomem *base_addr;
+
+ if (msm_host->mci_removed)
+ base_addr = host->ioaddr;
+ else
+ base_addr = msm_host->core_mem;
+
+ writel_relaxed(val, base_addr + offset);
+}
+
static const u32 tuning_block_64[] = {
0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -241,10 +355,14 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
u32 wait_cnt = 50;
u8 ck_out_en = 0;
struct mmc_host *mmc = host->mmc;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
/* poll for CK_OUT_EN bit. max. poll time = 50us */
- ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
- CORE_CK_OUT_EN);
+ ck_out_en = !!(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
while (ck_out_en != poll) {
if (--wait_cnt == 0) {
@@ -256,7 +374,7 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
udelay(1);
ck_out_en = !!(readl_relaxed(host->ioaddr +
- CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
+ msm_host_offset->CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
}
out:
return rc;
@@ -270,18 +388,25 @@ static int msm_enable_cdr_cm_sdc4_dll(struct sdhci_host *host)
{
int rc = 0;
u32 config;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
- config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+ config = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
config |= CORE_CDR_EN;
config &= ~(CORE_CDR_EXT_EN | CORE_CK_OUT_EN);
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(config, host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
rc = msm_dll_poll_ck_out_en(host, 0);
if (rc)
goto err;
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) |
- CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) | CORE_CK_OUT_EN),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
rc = msm_dll_poll_ck_out_en(host, 1);
if (rc)
@@ -328,6 +453,8 @@ static int sdhci_msm_config_auto_tuning_cmd(struct sdhci_host *host,
int rc = 0;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
u32 val = 0;
if (!msm_host->en_auto_cmd21)
@@ -340,11 +467,13 @@ static int sdhci_msm_config_auto_tuning_cmd(struct sdhci_host *host,
if (enable) {
rc = msm_enable_cdr_cm_sdc4_dll(host);
- writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
- val, host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) | val,
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
} else {
- writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
- ~val, host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) & ~val,
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
}
return rc;
}
@@ -352,6 +481,10 @@ static int sdhci_msm_config_auto_tuning_cmd(struct sdhci_host *host,
static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
{
int rc = 0;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
0x8};
@@ -362,10 +495,12 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
spin_lock_irqsave(&host->lock, flags);
- config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+ config = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(config, host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
rc = msm_dll_poll_ck_out_en(host, 0);
@@ -376,24 +511,28 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
* Write the selected DLL clock output phase (0 ... 15)
* to CDR_SELEXT bit field of DLL_CONFIG register.
*/
- writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
& ~(0xF << 20))
| (grey_coded_phase_table[phase] << 20)),
- host->ioaddr + CORE_DLL_CONFIG);
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) | CORE_CK_OUT_EN),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
rc = msm_dll_poll_ck_out_en(host, 1);
if (rc)
goto err_out;
- config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+ config = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
config |= CORE_CDR_EN;
config &= ~CORE_CDR_EXT_EN;
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(config, host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
goto out;
err_out:
@@ -522,6 +661,10 @@ static int msm_find_most_appropriate_phase(struct sdhci_host *host,
static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
{
u32 mclk_freq = 0;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
/* Program the MCLK value to MCLK_FREQ bit field */
if (host->clock <= 112000000)
@@ -541,9 +684,10 @@ static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
else if (host->clock <= 200000000)
mclk_freq = 7;
- writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
& ~(7 << 24)) | (mclk_freq << 24)),
- host->ioaddr + CORE_DLL_CONFIG);
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
}
/* Initialize the DLL (Programmable Delay Line ) */
@@ -551,6 +695,8 @@ static int msm_init_cm_dll(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
struct mmc_host *mmc = host->mmc;
int rc = 0;
unsigned long flags;
@@ -559,8 +705,8 @@ static int msm_init_cm_dll(struct sdhci_host *host)
pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
spin_lock_irqsave(&host->lock, flags);
- prev_pwrsave = !!(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
- CORE_CLK_PWRSAVE);
+ prev_pwrsave = !!(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) & CORE_CLK_PWRSAVE);
curr_pwrsave = prev_pwrsave;
/*
* Make sure that clock is always enabled when DLL
@@ -569,76 +715,89 @@ static int msm_init_cm_dll(struct sdhci_host *host)
* here and re-enable it once tuning is completed.
*/
if (prev_pwrsave) {
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
- & ~CORE_CLK_PWRSAVE),
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC)
+ & ~CORE_CLK_PWRSAVE), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
curr_pwrsave = false;
}
if (msm_host->use_updated_dll_reset) {
/* Disable the DLL clock */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- & ~CORE_CK_OUT_EN),
- host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
+ & ~CORE_CK_OUT_EN), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
- | CORE_DLL_CLOCK_DISABLE),
- host->ioaddr + CORE_DLL_CONFIG_2);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2)
+ | CORE_DLL_CLOCK_DISABLE), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2);
}
/* Write 1 to DLL_RST bit of DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) | CORE_DLL_RST),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
/* Write 1 to DLL_PDN bit of DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) | CORE_DLL_PDN),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
msm_cm_dll_set_freq(host);
if (msm_host->use_updated_dll_reset) {
u32 mclk_freq = 0;
- if ((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+ if ((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2)
& CORE_FLL_CYCLE_CNT))
mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 8);
else
mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 4);
- writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
- & ~(0xFF << 10)) | (mclk_freq << 10)),
- host->ioaddr + CORE_DLL_CONFIG_2);
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2)
+ & ~(0xFF << 10)) | (mclk_freq << 10)),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG_2);
/* wait for 5us before enabling DLL clock */
udelay(5);
}
/* Write 0 to DLL_RST bit of DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) & ~CORE_DLL_RST),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
/* Write 0 to DLL_PDN bit of DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) & ~CORE_DLL_PDN),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
if (msm_host->use_updated_dll_reset) {
msm_cm_dll_set_freq(host);
/* Enable the DLL clock */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
- & ~CORE_DLL_CLOCK_DISABLE),
- host->ioaddr + CORE_DLL_CONFIG_2);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2)
+ & ~CORE_DLL_CLOCK_DISABLE), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2);
}
/* Set DLL_EN bit to 1. */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG) | CORE_DLL_EN),
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
/* Set CK_OUT_EN bit to 1. */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
+ | CORE_CK_OUT_EN), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
wait_cnt = 50;
/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
- while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
- CORE_DLL_LOCK)) {
+ while (!(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_STATUS) & CORE_DLL_LOCK)) {
/* max. wait for 50us sec for LOCK bit to be set */
if (--wait_cnt == 0) {
pr_err("%s: %s: DLL failed to LOCK\n",
@@ -653,14 +812,16 @@ static int msm_init_cm_dll(struct sdhci_host *host)
out:
/* Restore the correct PWRSAVE state */
if (prev_pwrsave ^ curr_pwrsave) {
- u32 reg = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+ u32 reg = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
if (prev_pwrsave)
reg |= CORE_CLK_PWRSAVE;
else
reg &= ~CORE_CLK_PWRSAVE;
- writel_relaxed(reg, host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(reg, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -673,13 +834,18 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
u32 calib_done;
int ret = 0;
int cdc_err = 0;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DDR_200_CFG)
& ~CORE_CDC_T4_DLY_SEL),
- host->ioaddr + CORE_DDR_200_CFG);
+ host->ioaddr + msm_host_offset->CORE_DDR_200_CFG);
/* Write 0 to CDC_SWITCH_BYPASS_OFF field in CORE_CSR_CDC_GEN_CFG */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG)
@@ -692,9 +858,10 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
host->ioaddr + CORE_CSR_CDC_GEN_CFG);
/* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DDR_200_CFG)
& ~CORE_START_CDC_TRAFFIC),
- host->ioaddr + CORE_DDR_200_CFG);
+ host->ioaddr + msm_host_offset->CORE_DDR_200_CFG);
/*
* Perform CDC Register Initialization Sequence
@@ -765,9 +932,10 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
}
/* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DDR_200_CFG)
| CORE_START_CDC_TRAFFIC),
- host->ioaddr + CORE_DDR_200_CFG);
+ host->ioaddr + msm_host_offset->CORE_DDR_200_CFG);
out:
pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
__func__, ret);
@@ -778,6 +946,8 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
u32 dll_status, ddr_config;
int ret = 0;
@@ -788,27 +958,31 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
* bootloaders.
*/
if (msm_host->rclk_delay_fix) {
- writel_relaxed(DDR_CONFIG_2_POR_VAL,
- host->ioaddr + CORE_DDR_CONFIG_2);
+ writel_relaxed(DDR_CONFIG_2_POR_VAL, host->ioaddr +
+ msm_host_offset->CORE_DDR_CONFIG_2);
} else {
ddr_config = DDR_CONFIG_POR_VAL &
~DDR_CONFIG_PRG_RCLK_DLY_MASK;
ddr_config |= DDR_CONFIG_PRG_RCLK_DLY;
- writel_relaxed(ddr_config, host->ioaddr + CORE_DDR_CONFIG);
+ writel_relaxed(ddr_config, host->ioaddr +
+ msm_host_offset->CORE_DDR_CONFIG);
}
if (msm_host->enhanced_strobe && mmc_card_strobe(msm_host->mmc->card))
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
- | CORE_CMDIN_RCLK_EN),
- host->ioaddr + CORE_DDR_200_CFG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DDR_200_CFG)
+ | CORE_CMDIN_RCLK_EN), host->ioaddr +
+ msm_host_offset->CORE_DDR_200_CFG);
/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG_2)
| CORE_DDR_CAL_EN),
- host->ioaddr + CORE_DLL_CONFIG_2);
+ host->ioaddr + msm_host_offset->CORE_DLL_CONFIG_2);
/* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */
- ret = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS,
+ ret = readl_poll_timeout(host->ioaddr +
+ msm_host_offset->CORE_DLL_STATUS,
dll_status, (dll_status & CORE_DDR_DLL_LOCK), 10, 1000);
if (ret == -ETIMEDOUT) {
@@ -826,9 +1000,10 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
* turned on for host controllers using this DLL.
*/
if (!msm_host->use_14lpp_dll)
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3)
- | CORE_PWRSAVE_DLL),
- host->ioaddr + CORE_VENDOR_SPEC3);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3)
+ | CORE_PWRSAVE_DLL), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3);
mb();
out:
pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
@@ -877,6 +1052,8 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
int ret = 0;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
@@ -894,9 +1071,10 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
goto out;
/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_CMD_DAT_TRACK_SEL),
- host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
+ | CORE_CMD_DAT_TRACK_SEL), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
if (msm_host->use_cdclp533)
/* Calibrate CDCLP533 DLL HW */
@@ -2321,12 +2499,17 @@ void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
mmc_hostname(host->mmc),
- readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
- readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
- readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS),
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_MASK),
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_CTL));
}
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
@@ -2334,6 +2517,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
struct sdhci_host *host = (struct sdhci_host *)data;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
u8 irq_status = 0;
u8 irq_ack = 0;
int ret = 0;
@@ -2341,12 +2526,16 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
unsigned long flags;
int retry = 10;
- irq_status = readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+ irq_status = sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS);
+
pr_debug("%s: Received IRQ(%d), status=0x%x\n",
mmc_hostname(msm_host->mmc), irq, irq_status);
/* Clear the interrupt */
- writeb_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+ sdhci_msm_writeb_relaxed(irq_status, host,
+ msm_host_offset->CORE_PWRCTL_CLEAR);
+
/*
* SDHC has core_mem and hc_mem device memory and these memory
* addresses do not fall within 1KB region. Hence, any update to
@@ -2361,16 +2550,16 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
* sure status register is cleared. Otherwise, this will result in
* a spurious power IRQ resulting in system instability.
*/
- while (irq_status &
- readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS)) {
+ while (irq_status & sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS)) {
if (retry == 0) {
pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
mmc_hostname(host->mmc), irq_status);
sdhci_msm_dump_pwr_ctrl_regs(host);
BUG_ON(1);
}
- writeb_relaxed(irq_status,
- (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+ sdhci_msm_writeb_relaxed(irq_status, host,
+ msm_host_offset->CORE_PWRCTL_CLEAR);
retry--;
udelay(10);
}
@@ -2432,7 +2621,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
}
/* ACK status to the core */
- writeb_relaxed(irq_ack, (msm_host->core_mem + CORE_PWRCTL_CTL));
+ sdhci_msm_writeb_relaxed(irq_ack, host,
+ msm_host_offset->CORE_PWRCTL_CTL);
/*
* SDHC has core_mem and hc_mem device memory and these memory
* addresses do not fall within 1KB region. Hence, any update to
@@ -2442,14 +2632,16 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
mb();
if ((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & CORE_3_0V_SUPPORT))
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
- ~CORE_IO_PAD_PWR_SWITCH),
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) &
+ ~CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
else if ((io_level & REQ_IO_LOW) ||
(msm_host->caps_0 & CORE_1_8V_SUPPORT))
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
- CORE_IO_PAD_PWR_SWITCH),
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) |
+ CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
mb();
pr_debug("%s: Handled IRQ(%d), ret=%d, ack=0x%x\n",
@@ -2534,6 +2726,8 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
unsigned long flags;
bool done = false;
u32 io_sig_sts;
@@ -2542,7 +2736,9 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
mmc_hostname(host->mmc), __func__, req_type,
msm_host->curr_pwr_state, msm_host->curr_io_level);
- io_sig_sts = readl_relaxed(msm_host->core_mem + CORE_GENERICS);
+ io_sig_sts = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_GENERICS);
+
/*
* The IRQ for request type IO High/Low will be generated when -
* 1. SWITCHABLE_SIGNALLING_VOL is enabled in HW.
@@ -2589,16 +2785,23 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
{
- u32 config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
+ u32 config = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
if (enable) {
config |= CORE_CDR_EN;
config &= ~CORE_CDR_EXT_EN;
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(config, host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
} else {
config &= ~CORE_CDR_EN;
config |= CORE_CDR_EXT_EN;
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(config, host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
}
}
@@ -2809,6 +3012,8 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
int rc;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
struct mmc_card *card = host->mmc->card;
struct mmc_ios curr_ios = host->mmc->ios;
u32 sup_clock, ddr_clock, dll_lock;
@@ -2819,8 +3024,10 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
* disable pwrsave to ensure clock is not auto-gated until
* the rate is >400KHz (initialization complete).
*/
- writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
- ~CORE_CLK_PWRSAVE, host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) &
+ ~CORE_CLK_PWRSAVE, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
sdhci_msm_prepare_clocks(host, false);
host->clock = clock;
goto out;
@@ -2830,21 +3037,23 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
if (rc)
goto out;
- curr_pwrsave = !!(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
- CORE_CLK_PWRSAVE);
+ curr_pwrsave = !!(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) & CORE_CLK_PWRSAVE);
if ((clock > 400000) &&
!curr_pwrsave && card && mmc_host_may_gate_card(card))
- writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
- | CORE_CLK_PWRSAVE,
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC)
+ | CORE_CLK_PWRSAVE, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
/*
* Disable pwrsave for a newly added card if doesn't allow clock
* gating.
*/
else if (curr_pwrsave && card && !mmc_host_may_gate_card(card))
- writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
- & ~CORE_CLK_PWRSAVE,
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC)
+ & ~CORE_CLK_PWRSAVE, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
sup_clock = sdhci_msm_get_sup_clk_rate(host, clock);
if ((curr_ios.timing == MMC_TIMING_UHS_DDR50) ||
@@ -2880,10 +3089,11 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
*/
if (curr_ios.timing == MMC_TIMING_MMC_HS400) {
/* Select the divided clock (free running MCLK/2) */
- writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
- & ~CORE_HC_MCLK_SEL_MASK)
- | CORE_HC_MCLK_SEL_HS400),
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC)
+ & ~CORE_HC_MCLK_SEL_MASK)
+ | CORE_HC_MCLK_SEL_HS400), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
/*
* Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
* register
@@ -2897,10 +3107,10 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
* field in VENDOR_SPEC_FUNC
*/
writel_relaxed((readl_relaxed(host->ioaddr + \
- CORE_VENDOR_SPEC)
+ msm_host_offset->CORE_VENDOR_SPEC)
| CORE_HC_SELECT_IN_HS400
- | CORE_HC_SELECT_IN_EN),
- host->ioaddr + CORE_VENDOR_SPEC);
+ | CORE_HC_SELECT_IN_EN), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
}
if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) {
/*
@@ -2908,7 +3118,8 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
* CORE_DLL_STATUS to be set. This should get set
* with in 15 us at 200 MHz.
*/
- rc = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS,
+ rc = readl_poll_timeout(host->ioaddr +
+ msm_host_offset->CORE_DLL_STATUS,
dll_lock, (dll_lock & (CORE_DLL_LOCK |
CORE_DDR_DLL_LOCK)), 10, 1000);
if (rc == -ETIMEDOUT)
@@ -2920,14 +3131,16 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
if (!msm_host->use_cdclp533)
/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */
writel_relaxed((readl_relaxed(host->ioaddr +
- CORE_VENDOR_SPEC3) & ~CORE_PWRSAVE_DLL),
- host->ioaddr + CORE_VENDOR_SPEC3);
+ msm_host_offset->CORE_VENDOR_SPEC3)
+ & ~CORE_PWRSAVE_DLL), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3);
/* Select the default clock (free running MCLK) */
- writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC)
& ~CORE_HC_MCLK_SEL_MASK)
- | CORE_HC_MCLK_SEL_DFLT),
- host->ioaddr + CORE_VENDOR_SPEC);
+ | CORE_HC_MCLK_SEL_DFLT), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
/*
* Disable HC_SELECT_IN to be able to use the UHS mode select
@@ -2937,10 +3150,11 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
* Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
* in VENDOR_SPEC_FUNC
*/
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC)
& ~CORE_HC_SELECT_IN_EN
- & ~CORE_HC_SELECT_IN_MASK),
- host->ioaddr + CORE_VENDOR_SPEC);
+ & ~CORE_HC_SELECT_IN_MASK), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
}
mb();
@@ -2971,6 +3185,8 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
u16 ctrl_2;
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -3006,14 +3222,16 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
*
* Write 1 to DLL_RST bit of DLL_CONFIG register
*/
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_DLL_RST),
- host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
+ | CORE_DLL_RST), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
/* Write 1 to DLL_PDN bit of DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
- | CORE_DLL_PDN),
- host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG)
+ | CORE_DLL_PDN), host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG);
mb();
/*
@@ -3033,12 +3251,15 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
#define DRV_NAME "cmdq-host"
static void sdhci_msm_cmdq_dump_debug_ram(struct sdhci_host *host)
{
+ int i = 0;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
- int i = 0;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
struct cmdq_host *cq_host = host->cq_host;
- u32 version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION);
+ u32 version = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_MCI_VERSION);
u16 minor = version & CORE_VERSION_TARGET_MASK;
/* registers offset changed starting from 4.2.0 */
int offset = minor >= SDHCI_MSM_VER_420 ? 0 : 0x48;
@@ -3060,6 +3281,8 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
int tbsel, tbsel2;
int i, index = 0;
u32 test_bus_val = 0;
@@ -3071,19 +3294,29 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
sdhci_msm_cmdq_dump_debug_ram(host);
pr_info("Data cnt: 0x%08x | Fifo cnt: 0x%08x | Int sts: 0x%08x\n",
- readl_relaxed(msm_host->core_mem + CORE_MCI_DATA_CNT),
- readl_relaxed(msm_host->core_mem + CORE_MCI_FIFO_CNT),
- readl_relaxed(msm_host->core_mem + CORE_MCI_STATUS));
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_MCI_DATA_CNT),
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_MCI_FIFO_CNT),
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_MCI_STATUS));
pr_info("DLL cfg: 0x%08x | DLL sts: 0x%08x | SDCC ver: 0x%08x\n",
- readl_relaxed(host->ioaddr + CORE_DLL_CONFIG),
- readl_relaxed(host->ioaddr + CORE_DLL_STATUS),
- readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION));
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_CONFIG),
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_DLL_STATUS),
+ sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_MCI_VERSION));
pr_info("Vndr func: 0x%08x | Vndr adma err : addr0: 0x%08x addr1: 0x%08x\n",
- readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC),
- readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_ADMA_ERR_ADDR0),
- readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_ADMA_ERR_ADDR1));
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC),
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_ADMA_ERR_ADDR0),
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_ADMA_ERR_ADDR1));
pr_info("Vndr func2: 0x%08x\n",
- readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2));
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2));
/*
* tbsel indicates [2:0] bits and tbsel2 indicates [7:4] bits
@@ -3098,12 +3331,13 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
for (tbsel = 0; tbsel < 8; tbsel++) {
if (index >= MAX_TEST_BUS)
break;
- test_bus_val = (tbsel2 << CORE_TESTBUS_SEL2_BIT) |
- tbsel | CORE_TESTBUS_ENA;
- writel_relaxed(test_bus_val,
- msm_host->core_mem + CORE_TESTBUS_CONFIG);
- debug_reg[index++] = readl_relaxed(msm_host->core_mem +
- CORE_SDCC_DEBUG_REG);
+ test_bus_val =
+ (tbsel2 << msm_host_offset->CORE_TESTBUS_SEL2_BIT) |
+ tbsel | msm_host_offset->CORE_TESTBUS_ENA;
+ sdhci_msm_writel_relaxed(test_bus_val, host,
+ msm_host_offset->CORE_TESTBUS_CONFIG);
+ debug_reg[index++] = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_SDCC_DEBUG_REG);
}
}
for (i = 0; i < MAX_TEST_BUS; i = i + 4)
@@ -3140,6 +3374,8 @@ static void sdhci_msm_enhanced_strobe_mask(struct sdhci_host *host, bool set)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
if (!msm_host->enhanced_strobe ||
!mmc_card_strobe(msm_host->mmc->card)) {
@@ -3149,13 +3385,15 @@ static void sdhci_msm_enhanced_strobe_mask(struct sdhci_host *host, bool set)
}
if (set) {
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3)
- | CORE_CMDEN_HS400_INPUT_MASK_CNT),
- host->ioaddr + CORE_VENDOR_SPEC3);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3)
+ | CORE_CMDEN_HS400_INPUT_MASK_CNT),
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC3);
} else {
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3)
- & ~CORE_CMDEN_HS400_INPUT_MASK_CNT),
- host->ioaddr + CORE_VENDOR_SPEC3);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3)
+ & ~CORE_CMDEN_HS400_INPUT_MASK_CNT),
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC3);
}
}
@@ -3163,15 +3401,19 @@ static void sdhci_msm_clear_set_dumpregs(struct sdhci_host *host, bool set)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
if (set) {
- writel_relaxed(CORE_TESTBUS_ENA,
- msm_host->core_mem + CORE_TESTBUS_CONFIG);
+ sdhci_msm_writel_relaxed(msm_host_offset->CORE_TESTBUS_ENA,
+ host, msm_host_offset->CORE_TESTBUS_CONFIG);
} else {
u32 value;
- value = readl_relaxed(msm_host->core_mem + CORE_TESTBUS_CONFIG);
- value &= ~CORE_TESTBUS_ENA;
- writel_relaxed(value, msm_host->core_mem + CORE_TESTBUS_CONFIG);
+ value = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_TESTBUS_CONFIG);
+ value &= ~(msm_host_offset->CORE_TESTBUS_ENA);
+ sdhci_msm_writel_relaxed(value, host,
+ msm_host_offset->CORE_TESTBUS_CONFIG);
}
}
@@ -3205,15 +3447,20 @@ void sdhci_msm_reset_workaround(struct sdhci_host *host, u32 enable)
{
u32 vendor_func2;
unsigned long timeout;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
- vendor_func2 = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
+ vendor_func2 = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
if (enable) {
writel_relaxed(vendor_func2 | HC_SW_RST_REQ, host->ioaddr +
- CORE_VENDOR_SPEC_FUNC2);
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
timeout = 10000;
- while (readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2) &
- HC_SW_RST_REQ) {
+ while (readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2) & HC_SW_RST_REQ) {
if (timeout == 0) {
pr_info("%s: Applying wait idle disable workaround\n",
mmc_hostname(host->mmc));
@@ -3225,10 +3472,10 @@ void sdhci_msm_reset_workaround(struct sdhci_host *host, u32 enable)
* AXI bus.
*/
vendor_func2 = readl_relaxed(host->ioaddr +
- CORE_VENDOR_SPEC_FUNC2);
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
writel_relaxed(vendor_func2 |
- HC_SW_RST_WAIT_IDLE_DIS,
- host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
+ HC_SW_RST_WAIT_IDLE_DIS, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
host->reset_wa_t = ktime_get();
return;
}
@@ -3239,7 +3486,7 @@ void sdhci_msm_reset_workaround(struct sdhci_host *host, u32 enable)
mmc_hostname(host->mmc));
} else {
writel_relaxed(vendor_func2 & ~HC_SW_RST_WAIT_IDLE_DIS,
- host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
}
}
@@ -3755,8 +4002,11 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
u16 minor;
u8 major;
u32 val;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
- version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION);
+ version = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_MCI_VERSION);
major = (version & CORE_VERSION_MAJOR_MASK) >>
CORE_VERSION_MAJOR_SHIFT;
minor = version & CORE_VERSION_TARGET_MASK;
@@ -3789,9 +4039,10 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
*/
if (major == 1 && (minor == 0x2e || minor == 0x3e)) {
host->quirks2 |= SDHCI_QUIRK2_USE_RESET_WORKAROUND;
- val = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
+ val = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
writel_relaxed((val | CORE_ONE_MID_EN),
- host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
}
/*
* SDCC 5 controller with major version 1, minor version 0x34 and later
@@ -3825,9 +4076,9 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
/* Fake 3.0V support for SDIO devices which requires such voltage */
if (msm_host->pdata->core_3_0v_support) {
caps |= CORE_3_0V_SUPPORT;
- writel_relaxed(
- (readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES) |
- caps), host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ SDHCI_CAPABILITIES) | caps), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_CAPABILITIES0);
}
if ((major == 1) && (minor >= 0x49))
@@ -3839,7 +4090,8 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
if (!msm_host->pdata->largeaddressbus)
caps &= ~CORE_SYS_BUS_SUPPORT_64_BIT;
- writel_relaxed(caps, host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0);
+ writel_relaxed(caps, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_CAPABILITIES0);
/* keep track of the value in SDHCI_CAPABILITIES */
msm_host->caps_0 = caps;
}
@@ -3892,6 +4144,7 @@ static bool sdhci_msm_is_bootdevice(struct device *dev)
static int sdhci_msm_probe(struct platform_device *pdev)
{
+ const struct sdhci_msm_offset *msm_host_offset;
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_msm_host *msm_host;
@@ -3911,6 +4164,14 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto out;
}
+ if (of_find_compatible_node(NULL, NULL, "qcom,sdhci-msm-v5")) {
+ msm_host->mci_removed = true;
+ msm_host->offset = &sdhci_msm_offset_mci_removed;
+ } else {
+ msm_host->mci_removed = false;
+ msm_host->offset = &sdhci_msm_offset_mci_present;
+ }
+ msm_host_offset = msm_host->offset;
msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
if (IS_ERR(host)) {
@@ -4086,17 +4347,19 @@ static int sdhci_msm_probe(struct platform_device *pdev)
/* Reset the core and Enable SDHC mode */
core_memres = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "core_mem");
- if (!core_memres) {
- dev_err(&pdev->dev, "Failed to get iomem resource\n");
- goto vreg_deinit;
- }
- msm_host->core_mem = devm_ioremap(&pdev->dev, core_memres->start,
- resource_size(core_memres));
+ if (!msm_host->mci_removed) {
+ if (!core_memres) {
+ dev_err(&pdev->dev, "Failed to get iomem resource\n");
+ goto vreg_deinit;
+ }
+ msm_host->core_mem = devm_ioremap(&pdev->dev,
+ core_memres->start, resource_size(core_memres));
- if (!msm_host->core_mem) {
- dev_err(&pdev->dev, "Failed to remap registers\n");
- ret = -ENOMEM;
- goto vreg_deinit;
+ if (!msm_host->core_mem) {
+ dev_err(&pdev->dev, "Failed to remap registers\n");
+ ret = -ENOMEM;
+ goto vreg_deinit;
+ }
}
tlmm_memres = platform_get_resource_byname(pdev,
@@ -4119,24 +4382,27 @@ static int sdhci_msm_probe(struct platform_device *pdev)
* Reset the vendor spec register to power on reset state.
*/
writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
- host->ioaddr + CORE_VENDOR_SPEC);
-
- /* Set HC_MODE_EN bit in HC_MODE register */
- writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
+ host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
- /* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */
- writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_HC_MODE) |
- FF_CLK_SW_RST_DIS, msm_host->core_mem + CORE_HC_MODE);
+ if (!msm_host->mci_removed) {
+ /* Set HC_MODE_EN bit in HC_MODE register */
+ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
+ /* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */
+ writel_relaxed(readl_relaxed(msm_host->core_mem +
+ CORE_HC_MODE) | FF_CLK_SW_RST_DIS,
+ msm_host->core_mem + CORE_HC_MODE);
+ }
sdhci_set_default_hw_caps(msm_host, host);
/*
* Set the PAD_PWR_SWTICH_EN bit so that the PAD_PWR_SWITCH bit can
* be used as required later on.
*/
- writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
- CORE_IO_PAD_PWR_SWITCH_EN),
- host->ioaddr + CORE_VENDOR_SPEC);
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC) |
+ CORE_IO_PAD_PWR_SWITCH_EN), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
/*
* CORE_SW_RST above may trigger power irq if previous status of PWRCTL
* was either BUS_ON or IO_HIGH_V. So before we enable the power irq
@@ -4144,14 +4410,19 @@ static int sdhci_msm_probe(struct platform_device *pdev)
* ensure that any pending power irq interrupt status is acknowledged
* otherwise power irq interrupt handler would be fired prematurely.
*/
- irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
- writel_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
- irq_ctl = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL);
+ irq_status = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS);
+ sdhci_msm_writel_relaxed(irq_status, host,
+ msm_host_offset->CORE_PWRCTL_CLEAR);
+ irq_ctl = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_CTL);
+
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
irq_ctl |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_HIGH | CORE_PWRCTL_IO_LOW))
irq_ctl |= CORE_PWRCTL_IO_SUCCESS;
- writel_relaxed(irq_ctl, (msm_host->core_mem + CORE_PWRCTL_CTL));
+ sdhci_msm_writel_relaxed(irq_ctl, host,
+ msm_host_offset->CORE_PWRCTL_CTL);
/*
* Ensure that above writes are propogated before interrupt enablement
@@ -4215,7 +4486,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)
}
/* Enable pwr irq interrupts */
- writel_relaxed(INT_MASK, (msm_host->core_mem + CORE_PWRCTL_MASK));
+ sdhci_msm_writel_relaxed(INT_MASK, host,
+ msm_host_offset->CORE_PWRCTL_MASK);
#ifdef CONFIG_MMC_CLKGATE
/* Set clock gating delay to be used when CONFIG_MMC_CLKGATE is set */
@@ -4653,6 +4925,7 @@ static const struct dev_pm_ops sdhci_msm_pmops = {
#endif
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm"},
+ {.compatible = "qcom,sdhci-msm-v5"},
{},
};
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index e47a5083e8a6..6f96ea97bddc 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -214,6 +214,8 @@ struct sdhci_msm_host {
bool pm_qos_group_enable;
struct sdhci_msm_pm_qos_irq pm_qos_irq;
bool tuning_in_progress;
+ bool mci_removed;
+ const struct sdhci_msm_offset *offset;
};
extern char *saved_command_line;
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 352defe6204b..bd2132d77360 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/msm_gsi.h>
#include <linux/platform_device.h>
+#include <linux/delay.h>
#include "gsi.h"
#include "gsi_reg.h"
@@ -26,6 +27,8 @@
#define GSI_MHI_ER_START 10
#define GSI_MHI_ER_END 16
+#define GSI_RESET_WA_MIN_SLEEP 1000
+#define GSI_RESET_WA_MAX_SLEEP 2000
static const struct of_device_id msm_gsi_match[] = {
{ .compatible = "qcom,msm_gsi", },
{ },
@@ -1982,6 +1985,7 @@ reset:
/* workaround: reset GSI producers again */
if (ctx->props.dir == GSI_CHAN_DIR_FROM_GSI && !reset_done) {
+ usleep_range(GSI_RESET_WA_MIN_SLEEP, GSI_RESET_WA_MAX_SLEEP);
reset_done = true;
goto reset;
}
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 209264d69b26..bcdd99deae1f 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -820,7 +820,8 @@ static void ipa_rm_wq_resume_handler(struct work_struct *work)
}
ipa_rm_resource_consumer_request_work(
(struct ipa_rm_resource_cons *)resource,
- ipa_rm_work->prev_state, ipa_rm_work->needed_bw, true);
+ ipa_rm_work->prev_state, ipa_rm_work->needed_bw, true,
+ ipa_rm_work->inc_usage_count);
spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags);
bail:
kfree(ipa_rm_work);
@@ -916,7 +917,8 @@ int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name,
int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_state prev_state,
- u32 needed_bw)
+ u32 needed_bw,
+ bool inc_usage_count)
{
int result = -ENOMEM;
struct ipa_rm_wq_suspend_resume_work_type *work = kzalloc(sizeof(*work),
@@ -926,6 +928,7 @@ int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name,
work->resource_name = resource_name;
work->prev_state = prev_state;
work->needed_bw = needed_bw;
+ work->inc_usage_count = inc_usage_count;
result = queue_work(ipa_rm_ctx->ipa_rm_wq,
(struct work_struct *)work);
} else {
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
index eb86c54d7382..1610bb1e1ead 100644
--- a/drivers/platform/msm/ipa/ipa_rm_i.h
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -118,6 +118,7 @@ struct ipa_rm_wq_suspend_resume_work_type {
enum ipa_rm_resource_name resource_name;
enum ipa_rm_resource_state prev_state;
u32 needed_bw;
+ bool inc_usage_count;
};
@@ -128,7 +129,8 @@ int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_state prev_state,
- u32 needed_bw);
+ u32 needed_bw,
+ bool inc_usage_count);
int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_state prev_state,
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 0a3f66307eee..da4490ce0aa0 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -116,7 +116,8 @@ bail:
int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer,
enum ipa_rm_resource_state prev_state,
u32 prod_needed_bw,
- bool notify_completion)
+ bool notify_completion,
+ bool dec_client_on_err)
{
int driver_result;
@@ -135,7 +136,8 @@ int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer,
} else if (driver_result != -EINPROGRESS) {
consumer->resource.state = prev_state;
consumer->resource.needed_bw -= prod_needed_bw;
- consumer->usage_count--;
+ if (dec_client_on_err)
+ consumer->usage_count--;
}
return driver_result;
@@ -170,19 +172,22 @@ int ipa_rm_resource_consumer_request(
ipa_rm_resource_str(consumer->resource.name));
ipa_rm_wq_send_resume_cmd(consumer->resource.name,
prev_state,
- prod_needed_bw);
+ prod_needed_bw,
+ inc_usage_count);
result = -EINPROGRESS;
break;
}
result = ipa_rm_resource_consumer_request_work(consumer,
prev_state,
prod_needed_bw,
- false);
+ false,
+ inc_usage_count);
break;
case IPA_RM_GRANTED:
if (wake_client) {
result = ipa_rm_resource_consumer_request_work(
- consumer, prev_state, prod_needed_bw, false);
+ consumer, prev_state, prod_needed_bw, false,
+ inc_usage_count);
break;
}
ipa_rm_perf_profile_change(consumer->resource.name);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index 5c3a0190753f..da149c51c96c 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -155,7 +155,8 @@ int ipa_rm_resource_producer_print_stat(
int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer,
enum ipa_rm_resource_state prev_state,
u32 needed_bw,
- bool notify_completion);
+ bool notify_completion,
+ bool dec_client_on_err);
int ipa_rm_resource_consumer_release_work(
struct ipa_rm_resource_cons *consumer,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
index 249de808ec5c..f5afb4b0141c 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
@@ -523,10 +523,9 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
start = buf;
while (1) {
- prepare_to_wait(&ipa_ctx->msg_waitq, &wait, TASK_INTERRUPTIBLE);
-
mutex_lock(&ipa_ctx->msg_lock);
locked = 1;
+ prepare_to_wait(&ipa_ctx->msg_waitq, &wait, TASK_INTERRUPTIBLE);
if (!list_empty(&ipa_ctx->msg_list)) {
msg = list_first_entry(&ipa_ctx->msg_list,
struct ipa_push_msg, link);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 94e8bba1fe01..09c7c1b0fd05 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -778,10 +778,28 @@ static void ipa3_transport_irq_cmd_ack(void *user1, int user2)
*/
int ipa3_send_cmd(u16 num_desc, struct ipa3_desc *descr)
{
+ return ipa3_send_cmd_timeout(num_desc, descr, 0);
+}
+
+/**
+ * ipa3_send_cmd_timeout - send immediate commands with limited time
+ * waiting for ACK from IPA HW
+ * @num_desc: number of descriptors within the desc struct
+ * @descr: descriptor structure
+ * @timeout: millisecond to wait till get ACK from IPA HW
+ *
+ * Function will block till command gets ACK from IPA HW or timeout.
+ * Caller needs to free any resources it allocated after function returns
+ * The callback in ipa3_desc should not be set by the caller
+ * for this function.
+ */
+int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout)
+{
struct ipa3_desc *desc;
int i, result = 0;
struct ipa3_sys_context *sys;
int ep_idx;
+ int completed;
for (i = 0; i < num_desc; i++)
IPADBG("sending imm cmd %d\n", descr[i].opcode);
@@ -808,7 +826,14 @@ int ipa3_send_cmd(u16 num_desc, struct ipa3_desc *descr)
result = -EFAULT;
goto bail;
}
- wait_for_completion(&descr->xfer_done);
+ if (timeout) {
+ completed = wait_for_completion_timeout(
+ &descr->xfer_done, msecs_to_jiffies(timeout));
+ if (!completed)
+ IPADBG("timeout waiting for imm-cmd ACK\n");
+ } else {
+ wait_for_completion(&descr->xfer_done);
+ }
} else {
desc = &descr[num_desc - 1];
init_completion(&desc->xfer_done);
@@ -823,7 +848,15 @@ int ipa3_send_cmd(u16 num_desc, struct ipa3_desc *descr)
result = -EFAULT;
goto bail;
}
- wait_for_completion(&desc->xfer_done);
+ if (timeout) {
+ completed = wait_for_completion_timeout(
+ &desc->xfer_done, msecs_to_jiffies(timeout));
+ if (!completed)
+ IPADBG("timeout waiting for imm-cmd ACK\n");
+ } else {
+ wait_for_completion(&desc->xfer_done);
+ }
+
}
bail:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 11da023c9d6a..93fa1492cfd5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -326,7 +326,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
int needed_len;
int mem_size;
- IPADBG_LOW("processing type %d hdr_hdl %d\n",
+ IPADBG_LOW("Add processing type %d hdr_hdl %d\n",
proc_ctx->type, proc_ctx->hdr_hdl);
if (!HDR_PROC_TYPE_IS_VALID(proc_ctx->type)) {
@@ -335,10 +335,17 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
}
hdr_entry = ipa3_id_find(proc_ctx->hdr_hdl);
- if (!hdr_entry || (hdr_entry->cookie != IPA_COOKIE)) {
+ if (!hdr_entry) {
IPAERR("hdr_hdl is invalid\n");
return -EINVAL;
}
+ if (hdr_entry->cookie != IPA_COOKIE) {
+ IPAERR("Invalid header cookie %u\n", hdr_entry->cookie);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ IPADBG("Associated header is name=%s is_hdr_proc_ctx=%d\n",
+ hdr_entry->name, hdr_entry->is_hdr_proc_ctx);
entry = kmem_cache_zalloc(ipa3_ctx->hdr_proc_ctx_cache, GFP_KERNEL);
if (!entry) {
@@ -403,7 +410,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
entry->offset_entry = offset;
list_add(&entry->link, &htbl->head_proc_ctx_entry_list);
htbl->proc_ctx_cnt++;
- IPADBG_LOW("add proc ctx of sz=%d cnt=%d ofst=%d\n", needed_len,
+ IPADBG("add proc ctx of sz=%d cnt=%d ofst=%d\n", needed_len,
htbl->proc_ctx_cnt, offset->offset);
id = ipa3_id_alloc(entry);
@@ -520,12 +527,12 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
list_add(&entry->link, &htbl->head_hdr_entry_list);
htbl->hdr_cnt++;
if (entry->is_hdr_proc_ctx)
- IPADBG_LOW("add hdr of sz=%d hdr_cnt=%d phys_base=%pa\n",
+ IPADBG("add hdr of sz=%d hdr_cnt=%d phys_base=%pa\n",
hdr->hdr_len,
htbl->hdr_cnt,
&entry->phys_base);
else
- IPADBG_LOW("add hdr of sz=%d hdr_cnt=%d ofst=%d\n",
+ IPADBG("add hdr of sz=%d hdr_cnt=%d ofst=%d\n",
hdr->hdr_len,
htbl->hdr_cnt,
entry->offset_entry->offset);
@@ -580,7 +587,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
return -EINVAL;
}
- IPADBG("del ctx proc cnt=%d ofst=%d\n",
+ IPADBG("del proc ctx cnt=%d ofst=%d\n",
htbl->proc_ctx_cnt, entry->offset_entry->offset);
if (--entry->ref_cnt) {
@@ -624,11 +631,12 @@ int __ipa3_del_hdr(u32 hdr_hdl)
}
if (entry->is_hdr_proc_ctx)
- IPADBG("del hdr of sz=%d hdr_cnt=%d phys_base=%pa\n",
+ IPADBG("del hdr of len=%d hdr_cnt=%d phys_base=%pa\n",
entry->hdr_len, htbl->hdr_cnt, &entry->phys_base);
else
- IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len,
- htbl->hdr_cnt, entry->offset_entry->offset);
+ IPADBG("del hdr of len=%d hdr_cnt=%d ofst=%d\n",
+ entry->hdr_len, htbl->hdr_cnt,
+ entry->offset_entry->offset);
if (--entry->ref_cnt) {
IPADBG("hdr_hdl %x ref_cnt %d\n", hdr_hdl, entry->ref_cnt);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 8e85822d9719..33be22f98b9d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1835,6 +1835,7 @@ int ipa3_init_mem_partition(struct device_node *dev_node);
int ipa3_controller_static_bind(struct ipa3_controller *controller,
enum ipa_hw_type ipa_hw_type);
int ipa3_cfg_route(struct ipahal_reg_route *route);
+int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout);
int ipa3_send_cmd(u16 num_desc, struct ipa3_desc *descr);
int ipa3_cfg_filter(u32 disable);
int ipa3_pipe_mem_init(u32 start_ofst, u32 size);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
index 22756c1fb168..b9f57552533e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
@@ -528,12 +528,12 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count,
start = buf;
while (1) {
+ mutex_lock(&ipa3_ctx->msg_lock);
+ locked = 1;
prepare_to_wait(&ipa3_ctx->msg_waitq,
&wait,
TASK_INTERRUPTIBLE);
- mutex_lock(&ipa3_ctx->msg_lock);
- locked = 1;
if (!list_empty(&ipa3_ctx->msg_list)) {
msg = list_first_entry(&ipa3_ctx->msg_list,
struct ipa3_push_msg, link);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 6c7bf500e760..ac7e57f10062 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -1210,8 +1210,9 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
__ipa3_release_hdr_proc_ctx(entry->proc_ctx->id);
list_del(&entry->link);
entry->tbl->rule_cnt--;
- IPADBG("del rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n",
- entry->tbl->idx, entry->tbl->rule_cnt, entry->rule_id);
+ IPADBG("del rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n ref_cnt=%u",
+ entry->tbl->idx, entry->tbl->rule_cnt,
+ entry->rule_id, entry->tbl->ref_cnt);
idr_remove(&entry->tbl->rule_ids, entry->rule_id);
if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) {
if (__ipa_del_rt_tbl(entry->tbl))
@@ -1488,6 +1489,8 @@ int ipa3_put_rt_tbl(u32 rt_tbl_hdl)
entry->ref_cnt--;
if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
+ IPADBG("zero ref_cnt, delete rt tbl (idx=%u)\n",
+ entry->idx);
if (__ipa_del_rt_tbl(entry))
IPAERR("fail to del RT tbl\n");
/* commit for put */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index a21eb9c1530b..c0a6e8b00d71 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -47,6 +47,8 @@
#define IPA_EOT_COAL_GRAN_MIN (1)
#define IPA_EOT_COAL_GRAN_MAX (16)
+#define IPA_DMA_TASK_FOR_GSI_TIMEOUT_MSEC (15)
+
#define IPA_AGGR_BYTE_LIMIT (\
IPA_ENDP_INIT_AGGR_N_AGGR_BYTE_LIMIT_BMSK >> \
IPA_ENDP_INIT_AGGR_N_AGGR_BYTE_LIMIT_SHFT)
@@ -101,7 +103,7 @@
#define IPA_GROUP_DPL IPA_GROUP_DL
#define IPA_GROUP_DIAG (2)
#define IPA_GROUP_DMA (3)
-#define IPA_GROUP_IMM_CMD IPA_GROUP_DMA
+#define IPA_GROUP_IMM_CMD IPA_GROUP_UL
#define IPA_GROUP_Q6ZIP (4)
#define IPA_GROUP_Q6ZIP_GENERAL IPA_GROUP_Q6ZIP
#define IPA_GROUP_UC_RX_Q (5)
@@ -3470,7 +3472,8 @@ int ipa3_inject_dma_task_for_gsi(void)
desc.type = IPA_IMM_CMD_DESC;
IPADBG("sending 1B packet to IPA\n");
- if (ipa3_send_cmd(1, &desc)) {
+ if (ipa3_send_cmd_timeout(1, &desc,
+ IPA_DMA_TASK_FOR_GSI_TIMEOUT_MSEC)) {
IPAERR("ipa3_send_cmd failed\n");
return -EFAULT;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index bcd2cb3bfd7a..2bc179d5a33c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -1222,9 +1222,9 @@ int ipahal_cp_proc_ctx_to_hw_buff(enum ipa_hdr_proc_type type,
if (!base ||
!hdr_len ||
- (!phys_base && !hdr_base_addr) ||
- !hdr_base_addr ||
- ((is_hdr_proc_ctx == false) && !offset_entry)) {
+ (is_hdr_proc_ctx && !phys_base) ||
+ (!is_hdr_proc_ctx && !offset_entry) ||
+ (!is_hdr_proc_ctx && !hdr_base_addr)) {
IPAHAL_ERR(
"invalid input: hdr_len:%u phys_base:%pad hdr_base_addr:%u is_hdr_proc_ctx:%d offset_entry:%pK\n"
, hdr_len, &phys_base, hdr_base_addr
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 0619b314b7de..2718ea93bd45 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -249,6 +249,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(flash_current_max),
POWER_SUPPLY_ATTR(update_now),
POWER_SUPPLY_ATTR(esr_count),
+ POWER_SUPPLY_ATTR(buck_freq),
POWER_SUPPLY_ATTR(safety_timer_enabled),
POWER_SUPPLY_ATTR(charge_done),
POWER_SUPPLY_ATTR(flash_active),
@@ -273,6 +274,8 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(charger_temp),
POWER_SUPPLY_ATTR(charger_temp_max),
POWER_SUPPLY_ATTR(parallel_disable),
+ POWER_SUPPLY_ATTR(parallel_percent),
+ POWER_SUPPLY_ATTR(pe_start),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/qcom-charger/bcl_peripheral.c b/drivers/power/qcom-charger/bcl_peripheral.c
index fc958b160f86..8a7012ac2bef 100644
--- a/drivers/power/qcom-charger/bcl_peripheral.c
+++ b/drivers/power/qcom-charger/bcl_peripheral.c
@@ -459,7 +459,7 @@ static void bcl_lmh_dcvs_enable(void)
desc_arg.arginfo = SCM_ARGS(5, SCM_RO, SCM_VAL, SCM_VAL,
SCM_VAL, SCM_VAL);
- dmac_flush_range(payload, payload + 5 * (sizeof(uint32_t)));
+ dmac_flush_range(payload, (void *)payload + 5 * (sizeof(uint32_t)));
if (scm_call2(SCM_SIP_FNID(SCM_SVC_LMH, LMH_DCVSH),
&desc_arg))
pr_err("Error enabling LMH BCL monitoringfor cluster0\n");
diff --git a/drivers/power/qcom-charger/fg-util.c b/drivers/power/qcom-charger/fg-util.c
index bbdbe48896d7..0e3c7dbb5731 100644
--- a/drivers/power/qcom-charger/fg-util.c
+++ b/drivers/power/qcom-charger/fg-util.c
@@ -621,6 +621,17 @@ static ssize_t fg_sram_dfs_reg_write(struct file *file, const char __user *buf,
/* Parse the data in the buffer. It should be a string of numbers */
while ((pos < count) &&
sscanf(kbuf + pos, "%i%n", &data, &bytes_read) == 1) {
+ /*
+ * We shouldn't be receiving a string of characters that
+ * exceeds a size of 5 to keep this functionally correct.
+ * Also, we should make sure that pos never gets overflowed
+ * beyond the limit.
+ */
+ if (bytes_read > 5 || bytes_read > INT_MAX - pos) {
+ cnt = 0;
+ ret = -EINVAL;
+ break;
+ }
pos += bytes_read;
values[cnt++] = data & 0xff;
}
diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c
index 30408218b7e7..c0a19ae115d0 100644
--- a/drivers/power/qcom-charger/qpnp-fg-gen3.c
+++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c
@@ -1644,6 +1644,37 @@ out:
return rc;
}
+static void fg_notify_charger(struct fg_chip *chip)
+{
+ union power_supply_propval prop = {0, };
+ int rc;
+
+ if (!is_charger_available(chip)) {
+ pr_warn("Charger not available yet?\n");
+ return;
+ }
+
+ prop.intval = chip->bp.float_volt_uv;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
+ if (rc < 0) {
+ pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
+ rc);
+ return;
+ }
+
+ prop.intval = chip->bp.fastchg_curr_ma;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
+ if (rc < 0) {
+ pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
+ rc);
+ return;
+ }
+
+ fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
+}
+
static void profile_load_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work,
@@ -1709,6 +1740,7 @@ done:
rc);
}
+ fg_notify_charger(chip);
chip->profile_loaded = true;
fg_dbg(chip, FG_STATUS, "profile loaded successfully");
out:
@@ -1798,6 +1830,7 @@ static int fg_psy_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
pval->intval = chip->bp.float_volt_uv;
+ break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
pval->intval = fg_get_cycle_count(chip);
break;
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 8aaeb095db3c..93965dbe99ae 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -216,12 +217,15 @@ struct smb_dt_props {
u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1];
s32 step_cc_delta[STEP_CHARGING_MAX_STEPS];
struct device_node *revid_dev_node;
+ int float_option;
+ bool hvdcp_disable;
};
struct smb2 {
- struct smb_charger chg;
- struct smb_dt_props dt;
- bool bad_part;
+ struct smb_charger chg;
+ struct dentry *dfs_root;
+ struct smb_dt_props dt;
+ bool bad_part;
};
static int __debug_mask;
@@ -229,11 +233,6 @@ module_param_named(
debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR
);
-static int __pl_master_percent = 50;
-module_param_named(
- pl_master_percent, __pl_master_percent, int, S_IRUSR | S_IWUSR
-);
-
#define MICRO_1P5A 1500000
static int smb2_parse_dt(struct smb2 *chip)
{
@@ -320,6 +319,15 @@ static int smb2_parse_dt(struct smb2 *chip)
}
}
+ of_property_read_u32(node, "qcom,float-option", &chip->dt.float_option);
+ if (chip->dt.float_option < 0 || chip->dt.float_option > 4) {
+ pr_err("qcom,float-option is out of range [0, 4]\n");
+ return -EINVAL;
+ }
+
+ chip->dt.hvdcp_disable = of_property_read_bool(node,
+ "qcom,hvdcp-disable");
+
return 0;
}
@@ -333,6 +341,7 @@ static enum power_supply_property smb2_usb_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_PD_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_TYPEC_MODE,
@@ -342,7 +351,7 @@ static enum power_supply_property smb2_usb_props[] = {
POWER_SUPPLY_PROP_PD_ACTIVE,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
- POWER_SUPPLY_PROP_PARALLEL_DISABLE,
+ POWER_SUPPLY_PROP_PE_START,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -372,6 +381,9 @@ static int smb2_usb_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
rc = smblib_get_prop_usb_voltage_now(chg, val);
break;
+ case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
+ rc = smblib_get_prop_pd_current_max(chg, val);
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_get_prop_usb_current_max(chg, val);
break;
@@ -405,9 +417,14 @@ static int smb2_usb_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW:
rc = smblib_get_prop_usb_current_now(chg, val);
break;
- case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
- val->intval = get_client_vote(chg->pl_disable_votable,
- USER_VOTER);
+ case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
+ rc = smblib_get_prop_pd_in_hard_reset(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
+ val->intval = chg->system_suspend_supported;
+ break;
+ case POWER_SUPPLY_PROP_PE_START:
+ rc = smblib_get_pe_start(chg, val);
break;
default:
pr_err("get prop %d is not supported\n", psp);
@@ -436,25 +453,23 @@ static int smb2_usb_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_set_prop_usb_voltage_max(chg, val);
break;
+ case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
+ rc = smblib_set_prop_pd_current_max(chg, val);
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_set_prop_usb_current_max(chg, val);
break;
- case POWER_SUPPLY_PROP_TYPE:
- if (chg->pd_active && val->intval == POWER_SUPPLY_TYPE_USB_PD) {
- chg->usb_psy_desc.type = val->intval;
- } else {
- pr_err("set type %d not allowed\n", val->intval);
- rc = -EINVAL;
- }
- break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
rc = smblib_set_prop_typec_power_role(chg, val);
break;
case POWER_SUPPLY_PROP_PD_ACTIVE:
rc = smblib_set_prop_pd_active(chg, val);
break;
- case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
- vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
+ case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
+ rc = smblib_set_prop_pd_in_hard_reset(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
+ chg->system_suspend_supported = val->intval;
break;
default:
pr_err("set prop %d is not supported\n", psp);
@@ -470,7 +485,6 @@ static int smb2_usb_prop_is_writeable(struct power_supply *psy,
{
switch (psp) {
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
- case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
return 1;
default:
break;
@@ -623,12 +637,16 @@ static enum power_supply_property smb2_batt_props[] = {
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_STEP_CHARGING_STEP,
POWER_SUPPLY_PROP_CHARGE_DONE,
+ POWER_SUPPLY_PROP_PARALLEL_DISABLE,
+ POWER_SUPPLY_PROP_PARALLEL_PERCENT,
};
static int smb2_batt_get_prop(struct power_supply *psy,
@@ -668,6 +686,7 @@ static int smb2_batt_get_prop(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
rc = smblib_get_prop_input_current_limited(chg, val);
+ break;
case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
val->intval = chg->step_chg_enabled;
break;
@@ -677,9 +696,16 @@ static int smb2_batt_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
rc = smblib_get_prop_batt_voltage_now(chg, val);
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = get_client_vote(chg->fv_votable, DEFAULT_VOTER);
+ break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
rc = smblib_get_prop_batt_current_now(chg, val);
break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ val->intval = get_client_vote(chg->fcc_max_votable,
+ DEFAULT_VOTER);
+ break;
case POWER_SUPPLY_PROP_TEMP:
rc = smblib_get_prop_batt_temp(chg, val);
break;
@@ -689,6 +715,13 @@ static int smb2_batt_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_DONE:
rc = smblib_get_prop_batt_charge_done(chg, val);
break;
+ case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+ val->intval = get_client_vote(chg->pl_disable_votable,
+ USER_VOTER);
+ break;
+ case POWER_SUPPLY_PROP_PARALLEL_PERCENT:
+ val->intval = chg->pl.slave_pct;
+ break;
default:
pr_err("batt power supply prop %d not supported\n", psp);
return -EINVAL;
@@ -719,6 +752,21 @@ static int smb2_batt_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY:
rc = smblib_set_prop_batt_capacity(chg, val);
break;
+ case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+ vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
+ break;
+ case POWER_SUPPLY_PROP_PARALLEL_PERCENT:
+ if (val->intval < 0 || val->intval > 100)
+ return -EINVAL;
+ chg->pl.slave_pct = val->intval;
+ rerun_election(chg->fcc_votable);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ vote(chg->fcc_max_votable, DEFAULT_VOTER, true, val->intval);
+ break;
default:
rc = -EINVAL;
}
@@ -733,6 +781,8 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
case POWER_SUPPLY_PROP_CAPACITY:
+ case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+ case POWER_SUPPLY_PROP_PARALLEL_PERCENT:
return 1;
default:
break;
@@ -1022,6 +1072,14 @@ static int smb2_init_hw(struct smb2 *chip)
DEFAULT_VOTER, true, chip->dt.usb_icl_ua);
vote(chg->dc_icl_votable,
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
+ vote(chg->hvdcp_disable_votable, DEFAULT_VOTER,
+ chip->dt.hvdcp_disable, 0);
+ vote(chg->hvdcp_disable_votable, PD_INACTIVE_VOTER,
+ true, 0);
+ vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
+ true, 0);
+ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
+ true, 0);
/* Configure charge enable for software control; active high */
rc = smblib_masked_write(chg, CHGR_CFG2_REG,
@@ -1119,6 +1177,35 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
+ /* configure float charger options */
+ switch (chip->dt.float_option) {
+ case 1:
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+ FLOAT_OPTIONS_MASK, 0);
+ break;
+ case 2:
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+ FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
+ break;
+ case 3:
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+ FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
+ break;
+ case 4:
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+ FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
+ break;
+ default:
+ rc = 0;
+ break;
+ }
+
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
+ rc);
+ return rc;
+ }
+
return rc;
}
@@ -1314,7 +1401,8 @@ static struct smb2_irq_info smb2_irqs[] = {
},
{
.name = "dcin-plugin",
- .handler = smblib_handle_debug,
+ .handler = smblib_handle_dc_plugin,
+ .wake = true,
},
{
.name = "div2-en-dg",
@@ -1438,9 +1526,74 @@ static int smb2_request_interrupts(struct smb2 *chip)
return rc;
}
-/*********
- * PROBE *
- *********/
+#if defined(CONFIG_DEBUG_FS)
+
+static int force_batt_psy_update_write(void *data, u64 val)
+{
+ struct smb_charger *chg = data;
+
+ power_supply_changed(chg->batt_psy);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
+ force_batt_psy_update_write, "0x%02llx\n");
+
+static int force_usb_psy_update_write(void *data, u64 val)
+{
+ struct smb_charger *chg = data;
+
+ power_supply_changed(chg->usb_psy);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
+ force_usb_psy_update_write, "0x%02llx\n");
+
+static int force_dc_psy_update_write(void *data, u64 val)
+{
+ struct smb_charger *chg = data;
+
+ power_supply_changed(chg->dc_psy);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
+ force_dc_psy_update_write, "0x%02llx\n");
+
+static void smb2_create_debugfs(struct smb2 *chip)
+{
+ struct dentry *file;
+
+ chip->dfs_root = debugfs_create_dir("charger", NULL);
+ if (IS_ERR_OR_NULL(chip->dfs_root)) {
+ pr_err("Couldn't create charger debugfs rc=%ld\n",
+ (long)chip->dfs_root);
+ return;
+ }
+
+ file = debugfs_create_file("force_batt_psy_update", S_IRUSR | S_IWUSR,
+ chip->dfs_root, chip, &force_batt_psy_update_ops);
+ if (IS_ERR_OR_NULL(file))
+ pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
+ (long)file);
+
+ file = debugfs_create_file("force_usb_psy_update", S_IRUSR | S_IWUSR,
+ chip->dfs_root, chip, &force_usb_psy_update_ops);
+ if (IS_ERR_OR_NULL(file))
+ pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
+ (long)file);
+
+ file = debugfs_create_file("force_dc_psy_update", S_IRUSR | S_IWUSR,
+ chip->dfs_root, chip, &force_dc_psy_update_ops);
+ if (IS_ERR_OR_NULL(file))
+ pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
+ (long)file);
+}
+
+#else
+
+static void smb2_create_debugfs(struct smb2 *chip)
+{}
+
+#endif
static int smb2_probe(struct platform_device *pdev)
{
@@ -1458,7 +1611,7 @@ static int smb2_probe(struct platform_device *pdev)
chg->param = v1_params;
chg->debug_mask = &__debug_mask;
chg->mode = PARALLEL_MASTER;
- chg->pl.master_percent = &__pl_master_percent;
+ chg->name = "PMI";
chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
if (!chg->regmap) {
@@ -1527,6 +1680,7 @@ static int smb2_probe(struct platform_device *pdev)
return 0;
}
+ chg->pl.slave_pct = 50;
rc = smb2_init_batt_psy(chip);
if (rc < 0) {
pr_err("Couldn't initialize batt psy rc=%d\n", rc);
@@ -1552,6 +1706,8 @@ static int smb2_probe(struct platform_device *pdev)
goto cleanup;
}
+ smb2_create_debugfs(chip);
+
pr_info("QPNP SMB2 probed successfully\n");
return rc;
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index ce76260be6f6..5785e42e0140 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -22,18 +22,24 @@
#include "storm-watch.h"
#include "pmic-voter.h"
+#define smblib_err(chg, fmt, ...) \
+ pr_err("%s: %s: " fmt, chg->name, \
+ __func__, ##__VA_ARGS__) \
+
#define smblib_dbg(chg, reason, fmt, ...) \
do { \
if (*chg->debug_mask & (reason)) \
- dev_info(chg->dev, fmt, ##__VA_ARGS__); \
+ pr_info("%s: %s: " fmt, chg->name, \
+ __func__, ##__VA_ARGS__); \
else \
- dev_dbg(chg->dev, fmt, ##__VA_ARGS__); \
+ pr_debug("%s: %s: " fmt, chg->name, \
+ __func__, ##__VA_ARGS__); \
} while (0)
static bool is_secure(struct smb_charger *chg, int addr)
{
- /* assume everything above 0xC0 is secure */
- return (bool)((addr & 0xFF) >= 0xC0);
+ /* assume everything above 0xA0 is secure */
+ return (bool)((addr & 0xFF) >= 0xA0);
}
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
@@ -85,21 +91,19 @@ unlock:
return rc;
}
-static int smblib_get_step_charging_adjustment(struct smb_charger *chg,
- int *cc_offset)
+static int smblib_get_step_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
{
- int step_state;
- int rc;
+ int rc, step_state;
u8 stat;
if (!chg->step_chg_enabled) {
- *cc_offset = 0;
+ *cc_delta_ua = 0;
return 0;
}
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
rc);
return rc;
}
@@ -107,57 +111,71 @@ static int smblib_get_step_charging_adjustment(struct smb_charger *chg,
step_state = (stat & STEP_CHARGING_STATUS_MASK) >>
STEP_CHARGING_STATUS_SHIFT;
rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state],
- cc_offset);
+ cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
+ return rc;
+ }
- return rc;
+ return 0;
}
-static void smblib_fcc_split_ua(struct smb_charger *chg, int total_fcc,
- int *master_ua, int *slave_ua)
+static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
{
- int rc, cc_reduction_ua = 0;
- int step_cc_delta;
- int master_percent = min(max(*chg->pl.master_percent, 0), 100);
- union power_supply_propval pval = {0, };
- int effective_fcc;
+ int rc, cc_minus_ua;
+ u8 stat;
- /*
- * if master_percent is 0, s/w will configure master's fcc to zero and
- * slave's fcc to the max. However since master's fcc is zero it
- * disables its own charging and as a result the slave's charging is
- * disabled via the fault line.
- */
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+ rc);
+ return rc;
+ }
- rc = smblib_get_prop_batt_health(chg, &pval);
- if (rc == 0) {
- if (pval.intval == POWER_SUPPLY_HEALTH_WARM
- || pval.intval == POWER_SUPPLY_HEALTH_COOL) {
- rc = smblib_get_charge_param(chg,
- &chg->param.jeita_cc_comp,
- &cc_reduction_ua);
- if (rc < 0) {
- dev_err(chg->dev, "Could not get jeita comp, rc=%d\n",
- rc);
- cc_reduction_ua = 0;
- }
- }
+ if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
+ *cc_delta_ua = 0;
+ return 0;
}
- rc = smblib_get_step_charging_adjustment(chg, &step_cc_delta);
- if (rc < 0)
- step_cc_delta = 0;
+ rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
+ &cc_minus_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
+ return rc;
+ }
- /*
- * During JEITA condition and with step_charging enabled, PMI will
- * pick the lower of the two value: (FCC - JEITA current compensation)
- * or (FCC + step_charging current delta)
- */
+ *cc_delta_ua = -cc_minus_ua;
+ return 0;
+}
+
+static void smblib_split_fcc(struct smb_charger *chg, int total_ua,
+ int *master_ua, int *slave_ua)
+{
+ int rc, jeita_cc_delta_ua, step_cc_delta_ua, effective_total_ua,
+ slave_limited_ua, hw_cc_delta_ua = 0;
- effective_fcc = min(max(0, total_fcc - cc_reduction_ua),
- max(0, total_fcc + step_cc_delta));
- *master_ua = (effective_fcc * master_percent) / 100;
- *slave_ua = (effective_fcc - *master_ua) * chg->pl.taper_percent / 100;
- *master_ua = max(0, *master_ua + total_fcc - effective_fcc);
+ rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
+ step_cc_delta_ua = 0;
+ } else {
+ hw_cc_delta_ua = step_cc_delta_ua;
+ }
+
+ rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
+ jeita_cc_delta_ua = 0;
+ } else if (jeita_cc_delta_ua < 0) {
+ /* HW will take the min between JEITA and step charge */
+ hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
+ }
+
+ effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
+ slave_limited_ua = min(effective_total_ua, chg->input_limited_fcc_ua);
+ *slave_ua = (slave_limited_ua * chg->pl.slave_pct) / 100;
+ *slave_ua = (*slave_ua * chg->pl.taper_pct) / 100;
+ *master_ua = max(0, total_ua - *slave_ua);
}
/********************
@@ -172,7 +190,7 @@ int smblib_get_charge_param(struct smb_charger *chg,
rc = smblib_read(chg, param->reg, &val_raw);
if (rc < 0) {
- dev_err(chg->dev, "%s: Couldn't read from 0x%04x rc=%d\n",
+ smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
param->name, param->reg, rc);
return rc;
}
@@ -194,7 +212,7 @@ int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
return rc;
}
*suspend = temp & USBIN_SUSPEND_BIT;
@@ -208,47 +226,97 @@ struct apsd_result {
const enum power_supply_type pst;
};
+enum {
+ UNKNOWN,
+ SDP,
+ CDP,
+ DCP,
+ OCP,
+ FLOAT,
+ HVDCP2,
+ HVDCP3,
+ MAX_TYPES
+};
+
static const struct apsd_result const smblib_apsd_results[] = {
- {"UNKNOWN", 0, POWER_SUPPLY_TYPE_UNKNOWN},
- {"SDP", SDP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB},
- {"CDP", CDP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_CDP},
- {"DCP", DCP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
- {"OCP", OCP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
- {"FLOAT", FLOAT_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
- {"HVDCP2", DCP_CHARGER_BIT | QC_2P0_BIT, POWER_SUPPLY_TYPE_USB_HVDCP},
- {"HVDCP3", DCP_CHARGER_BIT | QC_3P0_BIT, POWER_SUPPLY_TYPE_USB_HVDCP_3},
+ [UNKNOWN] = {
+ .name = "UNKNOWN",
+ .bit = 0,
+ .pst = POWER_SUPPLY_TYPE_UNKNOWN
+ },
+ [SDP] = {
+ .name = "SDP",
+ .bit = SDP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB
+ },
+ [CDP] = {
+ .name = "CDP",
+ .bit = CDP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_CDP
+ },
+ [DCP] = {
+ .name = "DCP",
+ .bit = DCP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_DCP
+ },
+ [OCP] = {
+ .name = "OCP",
+ .bit = OCP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_DCP
+ },
+ [FLOAT] = {
+ .name = "FLOAT",
+ .bit = FLOAT_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_DCP
+ },
+ [HVDCP2] = {
+ .name = "HVDCP2",
+ .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_HVDCP
+ },
+ [HVDCP3] = {
+ .name = "HVDCP3",
+ .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
+ },
};
static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
{
int rc, i;
- u8 stat;
+ u8 apsd_stat, stat;
+ const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
- rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
- return &smblib_apsd_results[0];
+ smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+ return result;
}
- smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+ smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
- if (!(stat & APSD_DTC_STATUS_DONE_BIT))
- return &smblib_apsd_results[0];
+ if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
+ return result;
rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
+ smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
rc);
- return &smblib_apsd_results[0];
+ return result;
}
stat &= APSD_RESULT_STATUS_MASK;
for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
if (smblib_apsd_results[i].bit == stat)
- return &smblib_apsd_results[i];
+ result = &smblib_apsd_results[i];
}
- dev_err(chg->dev, "Couldn't find an APSD result for 0x%02x\n", stat);
- return &smblib_apsd_results[0];
+ if (apsd_stat & QC_CHARGER_BIT) {
+ /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
+ if (result != &smblib_apsd_results[HVDCP3])
+ result = &smblib_apsd_results[HVDCP2];
+ }
+
+ return result;
}
@@ -268,7 +336,7 @@ int smblib_set_charge_param(struct smb_charger *chg,
return -EINVAL;
} else {
if (val_u > param->max_u || val_u < param->min_u) {
- dev_err(chg->dev, "%s: %d is out of range [%d, %d]\n",
+ smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
param->name, val_u, param->min_u, param->max_u);
return -EINVAL;
}
@@ -278,7 +346,7 @@ int smblib_set_charge_param(struct smb_charger *chg,
rc = smblib_write(chg, param->reg, val_raw);
if (rc < 0) {
- dev_err(chg->dev, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
+ smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
param->name, val_raw, param->reg, rc);
return rc;
}
@@ -295,14 +363,14 @@ static int step_charge_soc_update(struct smb_charger *chg, int capacity)
rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity);
if (rc < 0) {
- dev_err(chg->dev, "Error in updating soc, rc=%d\n", rc);
+ smblib_err(chg, "Error in updating soc, rc=%d\n", rc);
return rc;
}
rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG,
STEP_CHG_SOC_VBATT_V_UPDATE_BIT);
if (rc < 0) {
- dev_err(chg->dev,
+ smblib_err(chg,
"Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n",
rc);
return rc;
@@ -318,7 +386,7 @@ int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
suspend ? USBIN_SUSPEND_BIT : 0);
if (rc < 0)
- dev_err(chg->dev, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
+ smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
suspend ? "suspend" : "resume", rc);
return rc;
@@ -331,7 +399,7 @@ int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
suspend ? DCIN_SUSPEND_BIT : 0);
if (rc < 0)
- dev_err(chg->dev, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
+ smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
suspend ? "suspend" : "resume", rc);
return rc;
@@ -359,14 +427,14 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
} else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
} else {
- dev_err(chg->dev, "invalid allowed voltage [%d, %d]\n",
+ smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
min_allowed_uv, max_allowed_uv);
return -EINVAL;
}
rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
+ smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
allowed_voltage, rc);
return rc;
}
@@ -378,50 +446,44 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
* HELPER FUNCTIONS *
********************/
-static int smblib_update_usb_type(struct smb_charger *chg)
+static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
{
- int rc = 0;
const struct apsd_result *apsd_result;
- /* if PD is active, APSD is disabled so won't have a valid result */
- if (chg->pd_active)
- return rc;
-
- apsd_result = smblib_get_apsd_result(chg);
- chg->usb_psy_desc.type = apsd_result->pst;
- return rc;
+ /*
+ * PD_INACTIVE_VOTER on hvdcp_disable_votable indicates whether
+ * apsd rerun was tried earlier
+ */
+ if (get_client_vote(chg->hvdcp_disable_votable, PD_INACTIVE_VOTER)) {
+ vote(chg->hvdcp_disable_votable, PD_INACTIVE_VOTER, false, 0);
+ /* ensure hvdcp is enabled */
+ if (!get_effective_result(chg->hvdcp_disable_votable)) {
+ apsd_result = smblib_get_apsd_result(chg);
+ if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
+ /* rerun APSD */
+ smblib_dbg(chg, PR_MISC, "rerun APSD\n");
+ smblib_masked_write(chg, CMD_APSD_REG,
+ APSD_RERUN_BIT,
+ APSD_RERUN_BIT);
+ }
+ }
+ }
+ return 0;
}
-static int smblib_detach_usb(struct smb_charger *chg)
+static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
{
- int rc;
-
- cancel_delayed_work_sync(&chg->hvdcp_detect_work);
- chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
-
- /* reconfigure allowed voltage for HVDCP */
- rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
- USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
- rc);
- return rc;
- }
-
- chg->voltage_min_uv = MICRO_5V;
- chg->voltage_max_uv = MICRO_5V;
+ const struct apsd_result *apsd_result;
- /* clear USB ICL vote for PD_VOTER */
- rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't vote for USB ICL rc=%d\n",
- rc);
- return rc;
+ /* if PD is active, APSD is disabled so won't have a valid result */
+ if (chg->pd_active) {
+ chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
+ return 0;
}
- vote(chg->pd_allowed_votable, DEFAULT_VOTER, false, 0);
-
- return rc;
+ apsd_result = smblib_get_apsd_result(chg);
+ chg->usb_psy_desc.type = apsd_result->pst;
+ return apsd_result;
}
static int smblib_notifier_call(struct notifier_block *nb,
@@ -452,7 +514,7 @@ static int smblib_register_notifier(struct smb_charger *chg)
chg->nb.notifier_call = smblib_notifier_call;
rc = power_supply_reg_notifier(&chg->nb);
if (rc < 0) {
- pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
return rc;
}
@@ -526,44 +588,47 @@ static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
}
static int smblib_fcc_vote_callback(struct votable *votable, void *data,
- int fcc_ua, const char *client)
+ int total_fcc_ua, const char *client)
{
struct smb_charger *chg = data;
- int rc = 0;
union power_supply_propval pval = {0, };
- int master_ua = fcc_ua, slave_ua;
+ int rc, master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
- if (fcc_ua < 0) {
- smblib_dbg(chg, PR_MISC, "No Voter\n");
+ if (total_fcc_ua < 0)
return 0;
- }
if (chg->mode == PARALLEL_MASTER
&& !get_effective_result_locked(chg->pl_disable_votable)) {
- smblib_fcc_split_ua(chg, fcc_ua, &master_ua, &slave_ua);
+ smblib_split_fcc(chg, total_fcc_ua, &master_fcc_ua,
+ &slave_fcc_ua);
/*
* parallel charger is not disabled, implying that
* chg->pl.psy exists
*/
- pval.intval = slave_ua;
+ pval.intval = slave_fcc_ua;
rc = power_supply_set_property(chg->pl.psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
if (rc < 0) {
- dev_err(chg->dev, "Could not set parallel fcc, rc=%d\n",
+ smblib_err(chg, "Could not set parallel fcc, rc=%d\n",
rc);
return rc;
}
- chg->pl.slave_fcc = slave_ua;
+ chg->pl.slave_fcc_ua = slave_fcc_ua;
}
- rc = smblib_set_charge_param(chg, &chg->param.fcc, master_ua);
+ rc = smblib_set_charge_param(chg, &chg->param.fcc, master_fcc_ua);
if (rc < 0) {
- dev_err(chg->dev, "Error in setting fcc, rc=%d\n", rc);
+ smblib_err(chg, "Couldn't set master fcc rc=%d\n", rc);
return rc;
}
+ smblib_dbg(chg, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
+ master_fcc_ua, slave_fcc_ua,
+ (master_fcc_ua * 100) / total_fcc_ua,
+ (slave_fcc_ua * 100) / total_fcc_ua);
+
return 0;
}
@@ -582,8 +647,7 @@ static int smblib_fv_vote_callback(struct votable *votable, void *data,
rc = smblib_set_charge_param(chg, &chg->param.fv, fv_uv);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't set floating voltage rc=%d\n", rc);
+ smblib_err(chg, "Couldn't set floating voltage rc=%d\n", rc);
return rc;
}
@@ -592,7 +656,7 @@ static int smblib_fv_vote_callback(struct votable *votable, void *data,
rc = power_supply_set_property(chg->pl.psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
if (rc < 0) {
- dev_err(chg->dev,
+ smblib_err(chg,
"Couldn't set float on parallel rc=%d\n", rc);
return rc;
}
@@ -601,41 +665,67 @@ static int smblib_fv_vote_callback(struct votable *votable, void *data,
return 0;
}
-#define USBIN_25MA 25000
-#define USBIN_100MA 100000
+#define USBIN_25MA 25000
+#define USBIN_100MA 100000
+#define USBIN_150MA 150000
+#define USBIN_500MA 500000
+#define USBIN_900MA 900000
static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
struct smb_charger *chg = data;
int rc = 0;
- bool suspend;
+ bool suspend = (icl_ua < USBIN_25MA);
+ u8 icl_options = 0;
- if (icl_ua < 0) {
- smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
- icl_ua = 0;
- }
-
- suspend = (icl_ua < USBIN_25MA);
if (suspend)
- goto suspend;
+ goto out;
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
- rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- USB51_MODE_BIT,
- (icl_ua > USBIN_100MA) ? USB51_MODE_BIT : 0);
- else
+ if (chg->usb_psy_desc.type != POWER_SUPPLY_TYPE_USB) {
rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
+ return rc;
+ }
+
+ goto out;
+ }
+
+ /* power source is SDP */
+ switch (icl_ua) {
+ case USBIN_100MA:
+ /* USB 2.0 100mA */
+ icl_options = 0;
+ break;
+ case USBIN_150MA:
+ /* USB 3.0 150mA */
+ icl_options = CFG_USB3P0_SEL_BIT;
+ break;
+ case USBIN_500MA:
+ /* USB 2.0 500mA */
+ icl_options = USB51_MODE_BIT;
+ break;
+ case USBIN_900MA:
+ /* USB 3.0 900mA */
+ icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
+ break;
+ default:
+ smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
+ icl_options = 0;
+ break;
+ }
+out:
+ rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+ CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't set USB input current limit rc=%d\n", rc);
+ smblib_err(chg, "Couldn't set ICL opetions rc=%d\n", rc);
return rc;
}
-suspend:
rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't %s input rc=%d\n",
+ smblib_err(chg, "Couldn't %s input rc=%d\n",
suspend ? "suspend" : "resume", rc);
return rc;
}
@@ -650,8 +740,7 @@ static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua)
rc = smblib_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set otg current limit rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't set otg current limit rc=%d\n", rc);
return rc;
}
@@ -660,7 +749,7 @@ static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua)
ENG_SSUPPLY_CFG_SKIP_TH_V0P2_BIT,
otg_cl_ua > MICRO_250MA ? 1 : 0);
if (rc < 0) {
- dev_err(chg->dev,
+ smblib_err(chg,
"Couldn't write DC_ENG_SSUPPLY_CFG3_REG rc=%d\n", rc);
return rc;
}
@@ -686,7 +775,7 @@ static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set DC input current limit rc=%d\n",
+ smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
rc);
return rc;
}
@@ -694,13 +783,25 @@ static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
suspend:
rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
+ smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
suspend ? "suspend" : "resume", rc);
return rc;
}
return rc;
}
+static int smblib_pd_disallowed_votable_indirect_callback(
+ struct votable *votable, void *data, int disallowed, const char *client)
+{
+ struct smb_charger *chg = data;
+ int rc;
+
+ rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
+ !disallowed, 0);
+
+ return rc;
+}
+
static int smblib_awake_vote_callback(struct votable *votable, void *data,
int awake, const char *client)
{
@@ -724,7 +825,7 @@ static int smblib_pl_disable_vote_callback(struct votable *votable, void *data,
if (chg->mode != PARALLEL_MASTER || !chg->pl.psy)
return 0;
- chg->pl.taper_percent = 100;
+ chg->pl.taper_pct = 100;
rerun_election(chg->fv_votable);
rerun_election(chg->fcc_votable);
@@ -732,11 +833,14 @@ static int smblib_pl_disable_vote_callback(struct votable *votable, void *data,
rc = power_supply_set_property(chg->pl.psy,
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
if (rc < 0) {
- dev_err(chg->dev,
+ smblib_err(chg,
"Couldn't change slave suspend state rc=%d\n", rc);
return rc;
}
+ smblib_dbg(chg, PR_PARALLEL, "parallel charging %s\n",
+ pl_disable ? "disabled" : "enabled");
+
return 0;
}
@@ -750,7 +854,7 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
CHARGING_ENABLE_CMD_BIT,
chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't %s charging rc=%d\n",
+ smblib_err(chg, "Couldn't %s charging rc=%d\n",
chg_disable ? "disable" : "enable", rc);
return rc;
}
@@ -768,6 +872,55 @@ static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
return 0;
}
+static int smblib_hvdcp_disable_vote_callback(struct votable *votable,
+ void *data,
+ int hvdcp_disable, const char *client)
+{
+ struct smb_charger *chg = data;
+ int rc;
+ u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT
+ | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT | HVDCP_EN_BIT;
+
+ /*
+ * Disable the autonomous bit and auth bit for disabling hvdcp.
+ * This ensures only qc 2.0 detection runs but no vbus
+ * negotiation happens.
+ */
+ if (hvdcp_disable)
+ val = HVDCP_EN_BIT;
+
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_EN_BIT
+ | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT
+ | HVDCP_AUTH_ALG_EN_CFG_BIT,
+ val);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
+ hvdcp_disable ? "disable" : "enable", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int smblib_apsd_disable_vote_callback(struct votable *votable,
+ void *data,
+ int apsd_disable, const char *client)
+{
+ struct smb_charger *chg = data;
+ int rc;
+
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ AUTO_SRC_DETECT_BIT,
+ apsd_disable ? 0 : AUTO_SRC_DETECT_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't %s APSD rc=%d\n",
+ apsd_disable ? "disable" : "enable", rc);
+ return rc;
+ }
+
+ return 0;
+}
/*****************
* OTG REGULATOR *
*****************/
@@ -783,21 +936,21 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
ENG_BUCKBOOST_HALT1_8_MODE_BIT,
ENG_BUCKBOOST_HALT1_8_MODE_BIT);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
+ smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
rc);
return rc;
}
rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable OTG regulator rc=%d\n", rc);
+ smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
return rc;
}
msleep(OTG_SOFT_START_DELAY_MS);
rc = smblib_read(chg, OTG_STATUS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read OTG_STATUS_REG rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read OTG_STATUS_REG rc=%d\n", rc);
return rc;
}
if (stat & BOOST_SOFTSTART_DONE_BIT)
@@ -813,7 +966,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
rc = smblib_write(chg, CMD_OTG_REG, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't disable OTG regulator rc=%d\n", rc);
+ smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
return rc;
}
@@ -822,7 +975,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
+ smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
rc);
return rc;
}
@@ -839,7 +992,7 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
rc = smblib_read(chg, CMD_OTG_REG, &cmd);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read CMD_OTG rc=%d", rc);
+ smblib_err(chg, "Couldn't read CMD_OTG rc=%d", rc);
return rc;
}
@@ -862,7 +1015,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
*/
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
stat = stat & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
@@ -870,7 +1023,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
VCONN_EN_VALUE_BIT | stat);
if (rc < 0)
- dev_err(chg->dev, "Couldn't enable vconn setting rc=%d\n", rc);
+ smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
return rc;
}
@@ -883,7 +1036,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_VALUE_BIT, 0);
if (rc < 0)
- dev_err(chg->dev, "Couldn't disable vconn regulator rc=%d\n",
+ smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n",
rc);
return rc;
@@ -897,7 +1050,7 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &cmd);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+ smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
rc);
return rc;
}
@@ -925,8 +1078,7 @@ int smblib_get_prop_batt_present(struct smb_charger *chg,
rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATIF_INT_RT_STS rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
return rc;
}
@@ -962,7 +1114,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
rc = smblib_get_prop_usb_online(chg, &pval);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get usb online property rc=%d\n",
+ smblib_err(chg, "Couldn't get usb online property rc=%d\n",
rc);
return rc;
}
@@ -970,7 +1122,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
rc = smblib_get_prop_dc_online(chg, &pval);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get dc online property rc=%d\n",
+ smblib_err(chg, "Couldn't get dc online property rc=%d\n",
rc);
return rc;
}
@@ -983,7 +1135,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
rc);
return rc;
}
@@ -1020,7 +1172,7 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
rc);
return rc;
}
@@ -1052,7 +1204,7 @@ int smblib_get_prop_batt_health(struct smb_charger *chg,
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
rc);
return rc;
}
@@ -1060,7 +1212,7 @@ int smblib_get_prop_batt_health(struct smb_charger *chg,
stat);
if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
- dev_err(chg->dev, "battery over-voltage\n");
+ smblib_err(chg, "battery over-voltage\n");
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
goto done;
}
@@ -1095,7 +1247,7 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg,
rc = smblib_read(chg, AICL_STATUS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read AICL_STATUS rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
return rc;
}
val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
@@ -1154,7 +1306,7 @@ int smblib_get_prop_step_chg_step(struct smb_charger *chg,
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
rc);
return rc;
}
@@ -1173,7 +1325,7 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
rc);
return rc;
}
@@ -1194,14 +1346,14 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg,
rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't vote to %s USB rc=%d\n",
+ smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
(bool)val->intval ? "suspend" : "resume", rc);
return rc;
}
rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
+ smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
(bool)val->intval ? "suspend" : "resume", rc);
return rc;
}
@@ -1258,7 +1410,7 @@ int smblib_get_prop_dc_present(struct smb_charger *chg,
rc = smblib_read(chg, DC_INT_RT_STS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read DC_INT_RT_STS_REG rc=%d\n",
+ smblib_err(chg, "Couldn't read DC_INT_RT_STS_REG rc=%d\n",
rc);
return rc;
}
@@ -1283,7 +1435,7 @@ int smblib_get_prop_dc_online(struct smb_charger *chg,
rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+ smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
rc);
return rc;
}
@@ -1328,8 +1480,7 @@ int smblib_get_prop_usb_present(struct smb_charger *chg,
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
@@ -1353,7 +1504,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg,
rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+ smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
rc);
return rc;
}
@@ -1384,10 +1535,18 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
}
+int smblib_get_prop_pd_current_max(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ val->intval = get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
+ return 0;
+}
+
int smblib_get_prop_usb_current_max(struct smb_charger *chg,
union power_supply_propval *val)
{
- val->intval = get_effective_result_locked(chg->usb_icl_votable);
+ val->intval = get_client_vote_locked(chg->usb_icl_votable,
+ USB_PSY_VOTER);
return 0;
}
@@ -1452,8 +1611,7 @@ int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
@@ -1487,7 +1645,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
return POWER_SUPPLY_TYPEC_NONE;
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
@@ -1515,7 +1673,7 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
return POWER_SUPPLY_TYPEC_NONE;
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
@@ -1546,7 +1704,7 @@ int smblib_get_prop_typec_mode(struct smb_charger *chg,
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
val->intval = POWER_SUPPLY_TYPEC_NONE;
return rc;
}
@@ -1573,7 +1731,7 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg,
rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+ smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
rc);
return rc;
}
@@ -1597,7 +1755,7 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg,
break;
default:
val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
- dev_err(chg->dev, "unsupported power role 0x%02lx\n",
+ smblib_err(chg, "unsupported power role 0x%02lx\n",
ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
return -EINVAL;
}
@@ -1608,7 +1766,7 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg,
int smblib_get_prop_pd_allowed(struct smb_charger *chg,
union power_supply_propval *val)
{
- val->intval = get_effective_result_locked(chg->pd_allowed_votable);
+ val->intval = get_effective_result(chg->pd_allowed_votable);
return 0;
}
@@ -1618,16 +1776,68 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg,
return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
}
+int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ int rc;
+ u8 ctrl;
+
+ rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
+ return 0;
+}
+
+int smblib_get_pe_start(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ /*
+ * hvdcp timeout voter is the last one to allow pd. Use its vote
+ * to indicate start of pe engine
+ */
+ val->intval
+ = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
+ HVDCP_TIMEOUT_VOTER);
+ return 0;
+}
+
/*******************
* USB PSY SETTERS *
* *****************/
+int smblib_set_prop_pd_current_max(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ int rc;
+
+ if (chg->pd_active)
+ rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
+ else
+ rc = -EPERM;
+
+ return rc;
+}
+
int smblib_set_prop_usb_current_max(struct smb_charger *chg,
const union power_supply_propval *val)
{
int rc;
- rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
+ if (!chg->pd_active) {
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+ true, val->intval);
+ } else if (chg->system_suspend_supported) {
+ if (val->intval <= USBIN_25MA)
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+ true, val->intval);
+ else
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+ false, 0);
+ }
return rc;
}
@@ -1651,14 +1861,14 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg,
power_role = DFP_EN_CMD_BIT;
break;
default:
- dev_err(chg->dev, "power role %d not supported\n", val->intval);
+ smblib_err(chg, "power role %d not supported\n", val->intval);
return -EINVAL;
}
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
TYPEC_POWER_ROLE_CMD_MASK, power_role);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+ smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
power_role, rc);
return rc;
}
@@ -1675,7 +1885,7 @@ int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
chg->voltage_max_uv);
if (rc < 0) {
- dev_err(chg->dev, "invalid max voltage %duV rc=%d\n",
+ smblib_err(chg, "invalid max voltage %duV rc=%d\n",
val->intval, rc);
return rc;
}
@@ -1697,7 +1907,7 @@ int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
max_uv);
if (rc < 0) {
- dev_err(chg->dev, "invalid min voltage %duV rc=%d\n",
+ smblib_err(chg, "invalid min voltage %duV rc=%d\n",
val->intval, rc);
return rc;
}
@@ -1710,60 +1920,82 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val)
{
int rc;
- u8 stat;
+ u8 stat = 0;
+ bool cc_debounced;
+ bool orientation;
+ bool pd_active = val->intval;
if (!get_effective_result(chg->pd_allowed_votable)) {
- dev_err(chg->dev, "PD is not allowed\n");
+ smblib_err(chg, "PD is not allowed\n");
return -EINVAL;
}
- rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
- AUTO_SRC_DETECT_BIT,
- val->intval ? 0 : AUTO_SRC_DETECT_BIT);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't %s APSD rc=%d\n",
- val->intval ? "disable" : "enable", rc);
- return rc;
- }
-
- vote(chg->pd_allowed_votable, PD_VOTER, val->intval, 0);
+ vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
+ vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
/*
* VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
* when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
* or when VCONN_EN_VALUE_BIT is set.
*/
- if (val->intval) {
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
- return rc;
- }
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ return rc;
+ }
- stat &= CC_ORIENTATION_BIT;
+ if (pd_active) {
+ orientation = stat & CC_ORIENTATION_BIT;
rc = smblib_masked_write(chg,
- TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- VCONN_EN_ORIENTATION_BIT,
- stat ? 0 : VCONN_EN_ORIENTATION_BIT);
- if (rc < 0)
- dev_err(chg->dev,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ VCONN_EN_ORIENTATION_BIT,
+ orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
+ if (rc < 0) {
+ smblib_err(chg,
"Couldn't enable vconn on CC line rc=%d\n", rc);
+ return rc;
+ }
}
/* CC pin selection s/w override in PD session; h/w otherwise. */
rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
TYPEC_SPARE_CFG_BIT,
- val->intval ? TYPEC_SPARE_CFG_BIT : 0);
+ pd_active ? TYPEC_SPARE_CFG_BIT : 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't change cc_out ctrl to %s rc=%d\n",
- val->intval ? "SW" : "HW", rc);
+ smblib_err(chg, "Couldn't change cc_out ctrl to %s rc=%d\n",
+ pd_active ? "SW" : "HW", rc);
return rc;
}
- chg->pd_active = (bool)val->intval;
+ cc_debounced = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+ if (!pd_active && cc_debounced)
+ try_rerun_apsd_for_hvdcp(chg);
+
+ chg->pd_active = pd_active;
smblib_update_usb_type(chg);
+ power_supply_changed(chg->usb_psy);
+
+ rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT,
+ chg->pd_active ? 0 : EN_TRYSINK_MODE_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ int rc;
+
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT,
+ (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
+
return rc;
}
@@ -1836,7 +2068,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
rc);
return IRQ_HANDLED;
}
@@ -1891,7 +2123,7 @@ irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
rc = smblib_get_prop_batt_capacity(chg, &pval);
if (rc < 0)
- dev_err(chg->dev, "Couldn't get batt capacity rc=%d\n", rc);
+ smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
else
step_charge_soc_update(chg, pval.intval);
@@ -1940,7 +2172,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
"dpdm-supply", NULL)) {
chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
if (IS_ERR(chg->dpdm_reg)) {
- dev_err(chg->dev, "Couldn't get dpdm regulator rc=%ld\n",
+ smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
PTR_ERR(chg->dpdm_reg));
chg->dpdm_reg = NULL;
}
@@ -1951,7 +2183,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
return IRQ_HANDLED;
}
@@ -1962,7 +2194,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
rc = regulator_enable(chg->dpdm_reg);
if (rc < 0)
- dev_err(chg->dev, "Couldn't enable dpdm regulator rc=%d\n",
+ smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
rc);
}
} else {
@@ -1970,7 +2202,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
rc = regulator_disable(chg->dpdm_reg);
if (rc < 0)
- dev_err(chg->dev, "Couldn't disable dpdm regulator rc=%d\n",
+ smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
rc);
}
}
@@ -1982,25 +2214,34 @@ skip_dpdm_float:
return IRQ_HANDLED;
}
-#define USB_WEAK_INPUT_MA 1400000
+#define USB_WEAK_INPUT_UA 1400000
+#define EFFICIENCY_PCT 80
irqreturn_t smblib_handle_icl_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- int icl_ma;
- int rc;
+ int rc, icl_ua;
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
- rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ma);
+ rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ua);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", rc);
+ smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
return IRQ_HANDLED;
}
- if (chg->mode == PARALLEL_MASTER)
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
- icl_ma >= USB_WEAK_INPUT_MA, 0);
+ if (chg->mode != PARALLEL_MASTER)
+ return IRQ_HANDLED;
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+ chg->input_limited_fcc_ua = div64_s64(
+ (s64)icl_ua * MICRO_5V * EFFICIENCY_PCT,
+ (s64)get_effective_result(chg->fv_votable) * 100);
+
+ if (!get_effective_result(chg->pl_disable_votable))
+ rerun_election(chg->fcc_votable);
+
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
+ icl_ua >= USB_WEAK_INPUT_UA, 0);
return IRQ_HANDLED;
}
@@ -2047,9 +2288,13 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
bool rising, bool qc_charger)
{
- if (rising && !qc_charger) {
- vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
- power_supply_changed(chg->usb_psy);
+ /* Hold off PD only until hvdcp 2.0 detection timeout */
+ if (rising) {
+ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
+ false, 0);
+ if (get_effective_result(chg->pd_disallowed_votable_indirect))
+ /* could be a legacy cable, try doing hvdcp */
+ try_rerun_apsd_for_hvdcp(chg);
}
smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
@@ -2072,19 +2317,20 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
#define HVDCP_DET_MS 2500
static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
{
- int rc;
const struct apsd_result *apsd_result;
if (!rising)
return;
- apsd_result = smblib_get_apsd_result(chg);
+ apsd_result = smblib_update_usb_type(chg);
switch (apsd_result->bit) {
case SDP_CHARGER_BIT:
case CDP_CHARGER_BIT:
case OCP_CHARGER_BIT:
case FLOAT_CHARGER_BIT:
- vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
+ /* if not DCP then no hvdcp timeout happens. Enable pd here */
+ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
+ false, 0);
break;
case DCP_CHARGER_BIT:
if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
@@ -2095,10 +2341,6 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
break;
}
- rc = smblib_update_usb_type(chg);
- if (rc < 0)
- dev_err(chg->dev, "Couldn't update usb type rc=%d\n", rc);
-
smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
apsd_result->name);
}
@@ -2112,7 +2354,7 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
return IRQ_HANDLED;
}
smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
@@ -2144,48 +2386,124 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
return IRQ_HANDLED;
}
-static void smblib_handle_typec_cc(struct smb_charger *chg, bool attached)
+static void typec_source_removal(struct smb_charger *chg)
{
int rc;
- if (!attached) {
- rc = smblib_detach_usb(chg);
- if (rc < 0)
- dev_err(chg->dev, "Couldn't detach USB rc=%d\n", rc);
+ vote(chg->pl_disable_votable, TYPEC_SRC_VOTER, true, 0);
+ /* reset both usbin current and voltage votes */
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+ /* reset taper_end voter here */
+ vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
+
+ cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+
+ /* reconfigure allowed voltage for HVDCP */
+ rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
+ USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+ rc);
+
+ chg->voltage_min_uv = MICRO_5V;
+ chg->voltage_max_uv = MICRO_5V;
+
+ /* clear USB ICL vote for PD_VOTER */
+ rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
+
+ /* clear USB ICL vote for USB_PSY_VOTER */
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
+}
+
+static void typec_source_insertion(struct smb_charger *chg)
+{
+ vote(chg->pl_disable_votable, TYPEC_SRC_VOTER, false, 0);
+}
+
+static void typec_sink_insertion(struct smb_charger *chg)
+{
+ /* when a sink is inserted we should not wait on hvdcp timeout to
+ * enable pd
+ */
+ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
+ false, 0);
+}
+
+static void smblib_handle_typec_removal(struct smb_charger *chg)
+{
+ vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
+ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
+ vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER, true, 0);
+ vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
+
+ /* reset votes from vbus_cc_short */
+ vote(chg->hvdcp_disable_votable, VBUS_CC_SHORT_VOTER, true, 0);
+
+ vote(chg->hvdcp_disable_votable, PD_INACTIVE_VOTER, true, 0);
+
+ /*
+ * cable could be removed during hard reset, remove its vote to
+ * disable apsd
+ */
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+
+ typec_source_removal(chg);
+
+ smblib_update_usb_type(chg);
+}
+
+static void smblib_handle_typec_insertion(struct smb_charger *chg,
+ bool sink_attached, bool legacy_cable)
+{
+ int rp;
+ bool vbus_cc_short = false;
+
+ vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
+
+ if (sink_attached) {
+ typec_source_removal(chg);
+ typec_sink_insertion(chg);
+ } else {
+ typec_source_insertion(chg);
}
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: CC %s\n",
- attached ? "attached" : "detached");
+ vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER,
+ legacy_cable, 0);
+
+ if (legacy_cable) {
+ rp = smblib_get_prop_ufp_mode(chg);
+ if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
+ || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
+ vbus_cc_short = true;
+ smblib_err(chg, "Disabling PD and HVDCP, VBUS-CC shorted, rp = %d found\n",
+ rp);
+ }
+ }
+
+ vote(chg->hvdcp_disable_votable, VBUS_CC_SHORT_VOTER, vbus_cc_short, 0);
+ vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER,
+ vbus_cc_short, 0);
}
static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
- bool rising, bool sink_attached)
+ bool rising, bool sink_attached, bool legacy_cable)
{
int rc;
union power_supply_propval pval = {0, };
- /* allow PD for attached sinks */
- if (rising && sink_attached)
- vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
+ if (rising)
+ smblib_handle_typec_insertion(chg, sink_attached, legacy_cable);
+ else
+ smblib_handle_typec_removal(chg);
rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0)
- dev_err(chg->dev, "Couldn't get prop typec mode rc=%d\n", rc);
-
- /*
- * vote to enable parallel charging if a source is attached, and disable
- * otherwise
- */
- vote(chg->pl_disable_votable, TYPEC_SRC_VOTER,
- !rising || sink_attached, 0);
-
- if (!rising || sink_attached) {
- /* reset both usbin current and voltage votes */
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
- vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
- /* reset taper_end voter here */
- vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
- }
+ smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
rising ? "rising" : "falling",
@@ -2198,20 +2516,27 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
struct smb_charger *chg = irq_data->parent_data;
int rc;
u8 stat;
+ bool debounce_done, sink_attached, legacy_cable;
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return IRQ_HANDLED;
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
+ debounce_done = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+ sink_attached = (bool)(stat & UFP_DFP_MODE_STATUS_BIT);
+
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
+ return IRQ_HANDLED;
+ }
+ smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat);
+ legacy_cable = (bool)(stat & TYPEC_LEGACY_CABLE_STATUS_BIT);
- smblib_handle_typec_cc(chg,
- (bool)(stat & CC_ATTACHED_BIT));
smblib_handle_typec_debounce_done(chg,
- (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
- (bool)(stat & UFP_DFP_MODE_STATUS_BIT));
+ debounce_done, sink_attached, legacy_cable);
power_supply_changed(chg->usb_psy);
@@ -2222,6 +2547,15 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
return IRQ_HANDLED;
}
+irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ power_supply_changed(chg->dc_psy);
+ return IRQ_HANDLED;
+}
+
irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
@@ -2241,14 +2575,15 @@ static void smblib_hvdcp_detect_work(struct work_struct *work)
{
struct smb_charger *chg = container_of(work, struct smb_charger,
hvdcp_detect_work.work);
- const struct apsd_result *apsd_result;
- apsd_result = smblib_get_apsd_result(chg);
- if (apsd_result->bit &&
- !(apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT))) {
- vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
+ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
+ false, 0);
+ if (get_effective_result(chg->pd_disallowed_votable_indirect))
+ /* pd is still disabled, try hvdcp */
+ try_rerun_apsd_for_hvdcp(chg);
+ else
+ /* notify pd now that pd is allowed */
power_supply_changed(chg->usb_psy);
- }
}
static void bms_update_work(struct work_struct *work)
@@ -2267,7 +2602,7 @@ static void step_soc_req_work(struct work_struct *work)
rc = smblib_get_prop_batt_capacity(chg, &pval);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get batt capacity rc=%d\n", rc);
+ smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
return;
}
@@ -2284,7 +2619,7 @@ static void smblib_pl_detect_work(struct work_struct *work)
#define MINIMUM_PARALLEL_FCC_UA 500000
#define PL_TAPER_WORK_DELAY_MS 100
-#define TAPER_RESIDUAL_PERCENT 75
+#define TAPER_RESIDUAL_PCT 75
static void smblib_pl_taper_work(struct work_struct *work)
{
struct smb_charger *chg = container_of(work, struct smb_charger,
@@ -2292,22 +2627,22 @@ static void smblib_pl_taper_work(struct work_struct *work)
union power_supply_propval pval = {0, };
int rc;
- if (chg->pl.slave_fcc < MINIMUM_PARALLEL_FCC_UA) {
+ if (chg->pl.slave_fcc_ua < MINIMUM_PARALLEL_FCC_UA) {
vote(chg->pl_disable_votable, TAPER_END_VOTER, true, 0);
goto done;
}
rc = smblib_get_prop_batt_charge_type(chg, &pval);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
+ smblib_err(chg, "Couldn't get batt charge type rc=%d\n", rc);
goto done;
}
if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, true, 0);
/* Reduce the taper percent by 25 percent */
- chg->pl.taper_percent = chg->pl.taper_percent
- * TAPER_RESIDUAL_PERCENT / 100;
+ chg->pl.taper_pct = chg->pl.taper_pct
+ * TAPER_RESIDUAL_PCT / 100;
rerun_election(chg->fcc_votable);
schedule_delayed_work(&chg->pl_taper_work,
msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
@@ -2389,8 +2724,16 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
- chg->pd_allowed_votable = create_votable("PD_ALLOWED", VOTE_SET_ANY,
- NULL, NULL);
+ chg->pd_disallowed_votable_indirect
+ = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
+ smblib_pd_disallowed_votable_indirect_callback, chg);
+ if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
+ rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
+ return rc;
+ }
+
+ chg->pd_allowed_votable = create_votable("PD_ALLOWED",
+ VOTE_SET_ANY, NULL, NULL);
if (IS_ERR(chg->pd_allowed_votable)) {
rc = PTR_ERR(chg->pd_allowed_votable);
return rc;
@@ -2429,6 +2772,24 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->hvdcp_disable_votable = create_votable("HVDCP_DISABLE",
+ VOTE_SET_ANY,
+ smblib_hvdcp_disable_vote_callback,
+ chg);
+ if (IS_ERR(chg->hvdcp_disable_votable)) {
+ rc = PTR_ERR(chg->hvdcp_disable_votable);
+ return rc;
+ }
+
+ chg->apsd_disable_votable = create_votable("APSD_DISABLE",
+ VOTE_SET_ANY,
+ smblib_apsd_disable_vote_callback,
+ chg);
+ if (IS_ERR(chg->apsd_disable_votable)) {
+ rc = PTR_ERR(chg->apsd_disable_votable);
+ return rc;
+ }
+
return rc;
}
@@ -2448,6 +2809,8 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->usb_icl_votable);
if (chg->dc_icl_votable)
destroy_votable(chg->dc_icl_votable);
+ if (chg->pd_disallowed_votable_indirect)
+ destroy_votable(chg->pd_disallowed_votable_indirect);
if (chg->pd_allowed_votable)
destroy_votable(chg->pd_allowed_votable);
if (chg->awake_votable)
@@ -2458,6 +2821,8 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->chg_disable_votable);
if (chg->pl_enable_votable_indirect)
destroy_votable(chg->pl_enable_votable_indirect);
+ if (chg->apsd_disable_votable)
+ destroy_votable(chg->apsd_disable_votable);
}
static void smblib_iio_deinit(struct smb_charger *chg)
@@ -2491,14 +2856,14 @@ int smblib_init(struct smb_charger *chg)
case PARALLEL_MASTER:
rc = smblib_create_votables(chg);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't create votables rc=%d\n",
+ smblib_err(chg, "Couldn't create votables rc=%d\n",
rc);
return rc;
}
rc = smblib_register_notifier(chg);
if (rc < 0) {
- dev_err(chg->dev,
+ smblib_err(chg,
"Couldn't register notifier rc=%d\n", rc);
return rc;
}
@@ -2513,7 +2878,7 @@ int smblib_init(struct smb_charger *chg)
case PARALLEL_SLAVE:
break;
default:
- dev_err(chg->dev, "Unsupported mode %d\n", chg->mode);
+ smblib_err(chg, "Unsupported mode %d\n", chg->mode);
return -EINVAL;
}
@@ -2530,7 +2895,7 @@ int smblib_deinit(struct smb_charger *chg)
case PARALLEL_SLAVE:
break;
default:
- dev_err(chg->dev, "Unsupported mode %d\n", chg->mode);
+ smblib_err(chg, "Unsupported mode %d\n", chg->mode);
return -EINVAL;
}
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index 00975e6c1285..4be06ffcfb25 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -22,11 +22,13 @@ enum print_reason {
PR_INTERRUPT = BIT(0),
PR_REGISTER = BIT(1),
PR_MISC = BIT(2),
+ PR_PARALLEL = BIT(3),
};
#define DEFAULT_VOTER "DEFAULT_VOTER"
#define USER_VOTER "USER_VOTER"
#define PD_VOTER "PD_VOTER"
+#define USB_PSY_VOTER "USB_PSY_VOTER"
#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
@@ -37,6 +39,13 @@ enum print_reason {
#define TAPER_END_VOTER "TAPER_END_VOTER"
#define FCC_MAX_RESULT_VOTER "FCC_MAX_RESULT_VOTER"
#define THERMAL_DAEMON_VOTER "THERMAL_DAEMON_VOTER"
+#define CC_DETACHED_VOTER "CC_DETACHED_VOTER"
+#define HVDCP_TIMEOUT_VOTER "HVDCP_TIMEOUT_VOTER"
+#define PD_DISALLOWED_INDIRECT_VOTER "PD_DISALLOWED_INDIRECT_VOTER"
+#define PD_HARD_RESET_VOTER "PD_HARD_RESET_VOTER"
+#define VBUS_CC_SHORT_VOTER "VBUS_CC_SHORT_VOTER"
+#define LEGACY_CABLE_VOTER "LEGACY_CABLE_VOTER"
+#define PD_INACTIVE_VOTER "PD_INACTIVE_VOTER"
enum smb_mode {
PARALLEL_MASTER = 0,
@@ -89,13 +98,14 @@ struct smb_params {
struct smb_chg_param step_soc_threshold[4];
struct smb_chg_param step_soc;
struct smb_chg_param step_cc_delta[5];
+ struct smb_chg_param freq_buck;
};
struct parallel_params {
struct power_supply *psy;
- int *master_percent;
- int taper_percent;
- int slave_fcc;
+ int slave_pct;
+ int taper_pct;
+ int slave_fcc_ua;
};
struct smb_iio {
@@ -108,6 +118,7 @@ struct smb_iio {
struct smb_charger {
struct device *dev;
+ char *name;
struct regmap *regmap;
struct smb_params param;
struct smb_iio iio;
@@ -144,11 +155,14 @@ struct smb_charger {
struct votable *fv_votable;
struct votable *usb_icl_votable;
struct votable *dc_icl_votable;
+ struct votable *pd_disallowed_votable_indirect;
struct votable *pd_allowed_votable;
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
struct votable *pl_enable_votable_indirect;
+ struct votable *hvdcp_disable_votable;
+ struct votable *apsd_disable_votable;
/* work */
struct work_struct bms_update_work;
@@ -162,8 +176,9 @@ struct smb_charger {
/* cached status */
int voltage_min_uv;
int voltage_max_uv;
- bool pd_active;
+ int pd_active;
bool vbus_present;
+ bool system_suspend_supported;
int system_temp_level;
int thermal_levels;
@@ -176,6 +191,7 @@ struct smb_charger {
bool step_chg_enabled;
bool is_hdc;
bool chg_done;
+ int input_limited_fcc_ua;
/* workaround flag */
u32 wa_flags;
@@ -222,6 +238,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data);
irqreturn_t smblib_handle_usb_source_change(int irq, void *data);
irqreturn_t smblib_handle_icl_change(int irq, void *data);
irqreturn_t smblib_handle_usb_typec_change(int irq, void *data);
+irqreturn_t smblib_handle_dc_plugin(int irq, void *data);
irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data);
int smblib_get_prop_input_suspend(struct smb_charger *chg,
@@ -275,6 +292,8 @@ int smblib_get_prop_usb_suspend(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
union power_supply_propval *val);
+int smblib_get_prop_pd_current_max(struct smb_charger *chg,
+ union power_supply_propval *val);
int smblib_get_prop_usb_current_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_current_now(struct smb_charger *chg,
@@ -289,10 +308,16 @@ int smblib_get_prop_pd_allowed(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_current_settled(struct smb_charger *chg,
union power_supply_propval *val);
+int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
+ union power_supply_propval *val);
+int smblib_get_pe_start(struct smb_charger *chg,
+ union power_supply_propval *val);
int smblib_get_prop_charger_temp(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
union power_supply_propval *val);
+int smblib_set_prop_pd_current_max(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_set_prop_usb_current_max(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
@@ -303,6 +328,8 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_get_prop_slave_current_now(struct smb_charger *chg,
union power_supply_propval *val);
@@ -310,4 +337,3 @@ int smblib_get_prop_slave_current_now(struct smb_charger *chg,
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
#endif /* __SMB2_CHARGER_H */
-
diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h
index 8a49a8fb38ba..ba501761c209 100644
--- a/drivers/power/qcom-charger/smb-reg.h
+++ b/drivers/power/qcom-charger/smb-reg.h
@@ -52,6 +52,7 @@ enum {
#define CHARGER_ERROR_STATUS_BAT_OV_BIT BIT(5)
#define CHARGER_ERROR_STATUS_BAT_TERM_MISSING_BIT BIT(4)
#define BAT_TEMP_STATUS_MASK GENMASK(3, 0)
+#define BAT_TEMP_STATUS_SOFT_LIMIT_MASK GENMASK(3, 2)
#define BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT BIT(3)
#define BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT BIT(2)
#define BAT_TEMP_STATUS_TOO_HOT_BIT BIT(1)
@@ -506,6 +507,15 @@ enum {
#define CC_ORIENTATION_BIT BIT(1)
#define CC_ATTACHED_BIT BIT(0)
+#define TYPE_C_STATUS_5_REG (USBIN_BASE + 0x0F)
+#define TRY_SOURCE_FAILED_BIT BIT(6)
+#define TRY_SINK_FAILED_BIT BIT(5)
+#define TIMER_STAGE_2_BIT BIT(4)
+#define TYPEC_LEGACY_CABLE_STATUS_BIT BIT(3)
+#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT BIT(2)
+#define TYPEC_TRYSOURCE_DETECT_STATUS_BIT BIT(1)
+#define TYPEC_TRYSINK_DETECT_STATUS_BIT BIT(0)
+
/* USBIN Interrupt Bits */
#define TYPE_C_CHANGE_RT_STS_BIT BIT(7)
#define USBIN_ICL_CHANGE_RT_STS_BIT BIT(6)
@@ -555,6 +565,16 @@ enum {
#define TYPE_C_UFP_MODE_BIT BIT(1)
#define EN_80UA_180UA_CUR_SOURCE_BIT BIT(0)
+#define TYPE_C_CFG_3_REG (USBIN_BASE + 0x5A)
+#define TVBUS_DEBOUNCE_BIT BIT(7)
+#define TYPEC_LEGACY_CABLE_INT_EN_BIT BIT(6)
+#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT BIT(5)
+#define TYPEC_TRYSOURCE_DETECT_INT_EN_BIT BIT(4)
+#define TYPEC_TRYSINK_DETECT_INT_EN_BIT BIT(3)
+#define EN_TRYSINK_MODE_BIT BIT(2)
+#define EN_LEGACY_CABLE_DETECTION_BIT BIT(1)
+#define ALLOW_PD_DRING_UFP_TCCDB_BIT BIT(0)
+
#define USBIN_ADAPTER_ALLOW_CFG_REG (USBIN_BASE + 0x60)
#define USBIN_ADAPTER_ALLOW_MASK GENMASK(3, 0)
enum {
@@ -585,6 +605,7 @@ enum {
#define DCD_TIMEOUT_SEL_BIT BIT(5)
#define OCD_CURRENT_SEL_BIT BIT(4)
#define SLOW_PLUGIN_TIMER_EN_CFG_BIT BIT(3)
+#define FLOAT_OPTIONS_MASK GENMASK(2, 0)
#define FLOAT_DIS_CHGING_CFG_BIT BIT(2)
#define SUSPEND_FLOAT_CFG_BIT BIT(1)
#define FORCE_FLOAT_SDP_CFG_BIT BIT(0)
@@ -612,7 +633,7 @@ enum {
#define TYPEC_VBUS_ASSERT_INT_EN_BIT BIT(0)
#define TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG (USBIN_BASE + 0x68)
-#define EXIT_SNK_BASED_ON_CC BIT(7)
+#define EXIT_SNK_BASED_ON_CC_BIT BIT(7)
#define VCONN_EN_ORIENTATION_BIT BIT(6)
#define TYPEC_VCONN_OVERCURR_INT_EN_BIT BIT(5)
#define VCONN_EN_SRC_BIT BIT(4)
@@ -975,4 +996,6 @@ enum {
#define SYSOK_POL_BIT BIT(3)
#define SYSOK_OPTIONS_MASK GENMASK(2, 0)
+#define CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG (MISC_BASE + 0xA0)
+
#endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c
index e8ec2f49f7eb..3db295b3e6e8 100644
--- a/drivers/power/qcom-charger/smb138x-charger.c
+++ b/drivers/power/qcom-charger/smb138x-charger.c
@@ -72,6 +72,13 @@ static struct smb_params v1_params = {
.max_u = 6000000,
.step_u = 25000,
},
+ .freq_buck = {
+ .name = "buck switching frequency",
+ .reg = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG,
+ .min_u = 500,
+ .max_u = 2000,
+ .step_u = 100,
+ },
};
struct smb_dt_props {
@@ -471,6 +478,10 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
break;
+ case POWER_SUPPLY_PROP_BUCK_FREQ:
+ rc = smblib_set_charge_param(chg, &chg->param.freq_buck,
+ val->intval);
+ break;
default:
pr_err("parallel power supply set prop %d not supported\n",
prop);
@@ -1172,6 +1183,7 @@ static int smb138x_probe(struct platform_device *pdev)
chip->chg.dev = &pdev->dev;
chip->chg.debug_mask = &__debug_mask;
+ chip->chg.name = "SMB";
chip->chg.regmap = dev_get_regmap(chip->chg.dev->parent, NULL);
if (!chip->chg.regmap) {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 1a1dd804ffb3..873b4615d4a9 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -2567,16 +2567,19 @@ static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
kfree(testbus);
}
-static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
+static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
+ ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+
+ if (no_sleep)
+ return;
/* sleep a bit intermittently as we are dumping too much data */
- ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
usleep_range(1000, 1100);
ufs_qcom_testbus_read(hba);
usleep_range(1000, 1100);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 53fed74eaefc..862d56e78086 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -539,7 +539,7 @@ static void ufshcd_print_uic_err_hist(struct ufs_hba *hba,
}
}
-static void ufshcd_print_host_regs(struct ufs_hba *hba)
+static inline void __ufshcd_print_host_regs(struct ufs_hba *hba, bool no_sleep)
{
if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_REGS_EN))
return;
@@ -571,7 +571,12 @@ static void ufshcd_print_host_regs(struct ufs_hba *hba)
ufshcd_print_clk_freqs(hba);
- ufshcd_vops_dbg_register_dump(hba);
+ ufshcd_vops_dbg_register_dump(hba, no_sleep);
+}
+
+static void ufshcd_print_host_regs(struct ufs_hba *hba)
+{
+ __ufshcd_print_host_regs(hba, false);
}
static
@@ -5055,7 +5060,12 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
dev_err(hba->dev,
"OCS error from controller = %x for tag %d\n",
ocs, lrbp->task_tag);
- ufshcd_print_host_regs(hba);
+ /*
+ * This is called in interrupt context, hence avoid sleep
+ * while printing debug registers. Also print only the minimum
+ * debug registers needed to debug OCS failure.
+ */
+ __ufshcd_print_host_regs(hba, true);
ufshcd_print_host_state(hba);
break;
} /* end of switch */
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index cd15d67cf8d5..c0714b7bea72 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -335,7 +335,7 @@ struct ufs_hba_variant_ops {
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
int (*full_reset)(struct ufs_hba *);
- void (*dbg_register_dump)(struct ufs_hba *hba);
+ void (*dbg_register_dump)(struct ufs_hba *hba, bool no_sleep);
int (*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg);
u32 (*get_scale_down_gear)(struct ufs_hba *);
int (*set_bus_vote)(struct ufs_hba *, bool);
@@ -1244,10 +1244,11 @@ static inline int ufshcd_vops_full_reset(struct ufs_hba *hba)
}
-static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
+static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba,
+ bool no_sleep)
{
if (hba->var && hba->var->vops && hba->var->vops->dbg_register_dump)
- hba->var->vops->dbg_register_dump(hba);
+ hba->var->vops->dbg_register_dump(hba, no_sleep);
}
static inline int ufshcd_vops_update_sec_cfg(struct ufs_hba *hba,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2bc74941abc8..8c43effadc70 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -821,4 +821,12 @@ config QCOM_SMCINVOKE
Enable SMCInvoke driver which supports capability based secure
communication between QSEE and HLOS.
+config QCOM_EARLY_RANDOM
+ bool "Initialize random pool very early"
+ help
+ The standard random pool may not initialize until late in the boot
+ process which means that any calls to get random numbers before then
+ may not be truly random. Select this option to make an early call
+ to get some random data to put in the pool. If unsure, say N.
+
source "drivers/soc/qcom/memshare/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 434a114c000f..0105e03b082d 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -99,3 +99,4 @@ obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
obj-$(CONFIG_WCD_DSP_GLINK) += wcd-dsp-glink.o
obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
+obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o
diff --git a/drivers/soc/qcom/early_random.c b/drivers/soc/qcom/early_random.c
new file mode 100644
index 000000000000..d1ab39b16c81
--- /dev/null
+++ b/drivers/soc/qcom/early_random.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/random.h>
+
+#include <soc/qcom/scm.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+#define TZ_SVC_CRYPTO 10
+#define PRNG_CMD_ID 0x01
+
+struct tz_prng_data {
+ uint8_t *out_buf;
+ uint32_t out_buf_sz;
+} __packed;
+
+DEFINE_SCM_BUFFER(common_scm_buf)
+#define RANDOM_BUFFER_SIZE PAGE_SIZE
+char random_buffer[RANDOM_BUFFER_SIZE] __aligned(PAGE_SIZE);
+
+void __init init_random_pool(void)
+{
+ struct tz_prng_data data;
+ int ret;
+ u32 resp;
+ struct scm_desc desc;
+
+ data.out_buf = (uint8_t *) virt_to_phys(random_buffer);
+ desc.args[0] = (unsigned long) data.out_buf;
+ desc.args[1] = data.out_buf_sz = SZ_512;
+ desc.arginfo = SCM_ARGS(2, SCM_RW, SCM_VAL);
+
+ dmac_flush_range(random_buffer, random_buffer + RANDOM_BUFFER_SIZE);
+
+ if (!is_scm_armv8())
+ ret = scm_call_noalloc(TZ_SVC_CRYPTO, PRNG_CMD_ID, &data,
+ sizeof(data), &resp, sizeof(resp),
+ common_scm_buf,
+ SCM_BUFFER_SIZE(common_scm_buf));
+ else
+ ret = scm_call2(SCM_SIP_FNID(TZ_SVC_CRYPTO, PRNG_CMD_ID),
+ &desc);
+
+ if (!ret) {
+ dmac_inv_range(random_buffer, random_buffer +
+ RANDOM_BUFFER_SIZE);
+ add_device_randomness(random_buffer, SZ_512);
+ }
+}
+
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index f47d4a51fccd..2d3d96fe80e1 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -107,6 +107,18 @@ module_param(qmi_timeout, ulong, 0600);
#define WCSS_CLK_CTL_WCSS_CSS_GDSCR_HW_CONTROL BIT(1)
#define WCSS_CLK_CTL_WCSS_CSS_GDSCR_PWR_ON BIT(31)
+#define WCSS_CLK_CTL_NOC_CMD_RCGR_OFFSET 0x1D1030
+#define WCSS_CLK_CTL_NOC_CMD_RCGR_UPDATE BIT(0)
+
+#define WCSS_CLK_CTL_NOC_CFG_RCGR_OFFSET 0x1D1034
+#define WCSS_CLK_CTL_NOC_CFG_RCGR_SRC_SEL GENMASK(10, 8)
+
+#define WCSS_CLK_CTL_REF_CMD_RCGR_OFFSET 0x1D602C
+#define WCSS_CLK_CTL_REF_CMD_RCGR_UPDATE BIT(0)
+
+#define WCSS_CLK_CTL_REF_CFG_RCGR_OFFSET 0x1D6030
+#define WCSS_CLK_CTL_REF_CFG_RCGR_SRC_SEL GENMASK(10, 8)
+
/*
* Registers: WCSS_HM_A_WIFI_APB_3_A_WCMN_MAC_WCMN_REG
* Base Address: 0x18AF0000
@@ -1084,7 +1096,7 @@ static void icnss_hw_io_reset(struct icnss_priv *priv, bool on)
}
}
-int icnss_hw_reset_wlan_ss_power_down(struct icnss_priv *priv)
+static int icnss_hw_reset_wlan_ss_power_down(struct icnss_priv *priv)
{
u32 rdata;
@@ -1116,7 +1128,7 @@ int icnss_hw_reset_wlan_ss_power_down(struct icnss_priv *priv)
return 0;
}
-int icnss_hw_reset_common_ss_power_down(struct icnss_priv *priv)
+static int icnss_hw_reset_common_ss_power_down(struct icnss_priv *priv)
{
u32 rdata;
@@ -1161,7 +1173,7 @@ int icnss_hw_reset_common_ss_power_down(struct icnss_priv *priv)
}
-int icnss_hw_reset_wlan_rfactrl_power_down(struct icnss_priv *priv)
+static int icnss_hw_reset_wlan_rfactrl_power_down(struct icnss_priv *priv)
{
u32 rdata;
@@ -1191,7 +1203,7 @@ int icnss_hw_reset_wlan_rfactrl_power_down(struct icnss_priv *priv)
return 0;
}
-void icnss_hw_wsi_cmd_error_recovery(struct icnss_priv *priv)
+static void icnss_hw_wsi_cmd_error_recovery(struct icnss_priv *priv)
{
icnss_pr_dbg("RESET: WSI CMD Error recovery, state: 0x%lx\n",
priv->state);
@@ -1215,7 +1227,7 @@ void icnss_hw_wsi_cmd_error_recovery(struct icnss_priv *priv)
PMM_WSI_CMD_SW_BUS_SYNC, 0);
}
-u32 icnss_hw_rf_register_read_command(struct icnss_priv *priv, u32 addr)
+static u32 icnss_hw_rf_register_read_command(struct icnss_priv *priv, u32 addr)
{
u32 rdata = 0;
int ret;
@@ -1264,7 +1276,7 @@ u32 icnss_hw_rf_register_read_command(struct icnss_priv *priv, u32 addr)
return rdata;
}
-int icnss_hw_reset_rf_reset_cmd(struct icnss_priv *priv)
+static int icnss_hw_reset_rf_reset_cmd(struct icnss_priv *priv)
{
u32 rdata;
int ret;
@@ -1318,7 +1330,30 @@ int icnss_hw_reset_rf_reset_cmd(struct icnss_priv *priv)
return 0;
}
-int icnss_hw_reset_xo_disable_cmd(struct icnss_priv *priv)
+static int icnss_hw_reset_switch_to_cxo(struct icnss_priv *priv)
+{
+ icnss_pr_dbg("RESET: Switch to CXO, state: 0x%lx\n", priv->state);
+
+ icnss_hw_write_reg_field(priv->mem_base_va,
+ WCSS_CLK_CTL_NOC_CFG_RCGR_OFFSET,
+ WCSS_CLK_CTL_NOC_CFG_RCGR_SRC_SEL, 0);
+
+ icnss_hw_write_reg_field(priv->mem_base_va,
+ WCSS_CLK_CTL_NOC_CMD_RCGR_OFFSET,
+ WCSS_CLK_CTL_NOC_CMD_RCGR_UPDATE, 1);
+
+ icnss_hw_write_reg_field(priv->mem_base_va,
+ WCSS_CLK_CTL_REF_CFG_RCGR_OFFSET,
+ WCSS_CLK_CTL_REF_CFG_RCGR_SRC_SEL, 0);
+
+ icnss_hw_write_reg_field(priv->mem_base_va,
+ WCSS_CLK_CTL_REF_CMD_RCGR_OFFSET,
+ WCSS_CLK_CTL_REF_CMD_RCGR_UPDATE, 1);
+
+ return 0;
+}
+
+static int icnss_hw_reset_xo_disable_cmd(struct icnss_priv *priv)
{
int ret;
@@ -1366,7 +1401,7 @@ int icnss_hw_reset_xo_disable_cmd(struct icnss_priv *priv)
return 0;
}
-int icnss_hw_reset(struct icnss_priv *priv)
+static int icnss_hw_reset(struct icnss_priv *priv)
{
u32 rdata;
u32 rdata1;
@@ -1424,6 +1459,8 @@ int icnss_hw_reset(struct icnss_priv *priv)
icnss_hw_reset_rf_reset_cmd(priv);
+ icnss_hw_reset_switch_to_cxo(priv);
+
icnss_hw_reset_xo_disable_cmd(priv);
icnss_hw_write_reg_field(priv->mpm_config_va, MPM_WCSSAON_CONFIG_OFFSET,
@@ -2947,7 +2984,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops)
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
ICNSS_EVENT_SYNC, ops);
- if (ret == -ERESTARTSYS)
+ if (ret == -EINTR)
ret = 0;
out:
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index 504a3263253c..8cba88742cb8 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -462,7 +462,7 @@ static int ssr_event_notify(struct notifier_block *this,
struct qmi_client_info, ssr_notifier);
struct notif_data *notif = data;
switch (code) {
- case SUBSYS_AFTER_SHUTDOWN:
+ case SUBSYS_BEFORE_SHUTDOWN:
pr_debug("Root PD DOWN(SSR notification), crashed?%d\n",
notif->crashed);
if (notif->crashed)
@@ -605,8 +605,8 @@ void *service_notif_register_notifier(const char *service_path, int instance_id,
if (!service_path || !instance_id || !nb)
return ERR_PTR(-EINVAL);
- service_notif = _find_service_info(service_path);
mutex_lock(&notif_add_lock);
+ service_notif = _find_service_info(service_path);
if (!service_notif) {
service_notif = (struct service_notif_info *)add_service_notif(
service_path,
diff --git a/drivers/thermal/lmh_lite.c b/drivers/thermal/lmh_lite.c
index 32a573d22270..44ceb723d34c 100644
--- a/drivers/thermal/lmh_lite.c
+++ b/drivers/thermal/lmh_lite.c
@@ -70,8 +70,8 @@
int idx = 0; \
desc_arg.args[cmd_idx] = cmd_buf.list_start = next; \
trace_lmh_event_call("GET_TYPE enter"); \
- dmac_flush_range(payload, payload + sizeof(uint32_t) * \
- LMH_SCM_PAYLOAD_SIZE); \
+ dmac_flush_range(payload, (void *)payload + \
+ sizeof(uint32_t) * LMH_SCM_PAYLOAD_SIZE);\
if (!is_scm_armv8()) { \
ret = scm_call(SCM_SVC_LMH, cmd_id, \
(void *) &cmd_buf, SCM_BUFFER_SIZE(cmd_buf), \
@@ -321,7 +321,8 @@ static void lmh_read_and_update(struct lmh_driver_data *lmh_dat)
= SCM_BUFFER_SIZE(struct lmh_sensor_packet);
desc_arg.arginfo = SCM_ARGS(2, SCM_RW, SCM_VAL);
trace_lmh_event_call("GET_INTENSITY enter");
- dmac_flush_range(&payload, &payload + sizeof(struct lmh_sensor_packet));
+ dmac_flush_range(&payload, (void *)&payload +
+ sizeof(struct lmh_sensor_packet));
if (!is_scm_armv8())
ret = scm_call(SCM_SVC_LMH, LMH_GET_INTENSITY,
(void *) &cmd_buf, SCM_BUFFER_SIZE(cmd_buf), NULL, 0);
@@ -664,7 +665,7 @@ static int lmh_get_sensor_list(void)
lmh_sensor_packet);
desc_arg.arginfo = SCM_ARGS(2, SCM_RW, SCM_VAL);
trace_lmh_event_call("GET_SENSORS enter");
- dmac_flush_range(payload, payload + buf_size);
+ dmac_flush_range(payload, (void *)payload + buf_size);
if (!is_scm_armv8())
ret = scm_call(SCM_SVC_LMH, LMH_GET_SENSORS,
(void *) &cmd_buf,
@@ -898,7 +899,7 @@ static int lmh_debug_read(struct lmh_debug_ops *ops, uint32_t **buf)
desc_arg.args[1] = cmd_buf.buf_size = curr_size;
desc_arg.arginfo = SCM_ARGS(2, SCM_RW, SCM_VAL);
trace_lmh_event_call("GET_DEBUG_READ enter");
- dmac_flush_range(payload, payload + curr_size);
+ dmac_flush_range(payload, (void *)payload + curr_size);
if (!is_scm_armv8()) {
ret = scm_call(SCM_SVC_LMH, LMH_DEBUG_READ,
(void *) &cmd_buf, SCM_BUFFER_SIZE(cmd_buf),
@@ -968,7 +969,7 @@ static int lmh_debug_config_write(uint32_t cmd_id, uint32_t *buf, int size)
desc_arg.arginfo = SCM_ARGS(5, SCM_RO, SCM_VAL, SCM_VAL, SCM_VAL,
SCM_VAL);
trace_lmh_event_call("CONFIG_DEBUG_WRITE enter");
- dmac_flush_range(payload, payload + size_bytes);
+ dmac_flush_range(payload, (void *)payload + size_bytes);
if (!is_scm_armv8())
ret = scm_call(SCM_SVC_LMH, cmd_id, (void *) &cmd_buf,
SCM_BUFFER_SIZE(cmd_buf), NULL, 0);
diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c
index cd45eeccbfe7..fbe76eaa3867 100644
--- a/drivers/thermal/msm_lmh_dcvs.c
+++ b/drivers/thermal/msm_lmh_dcvs.c
@@ -164,7 +164,7 @@ static int msm_lmh_dcvs_write(uint32_t node_id, uint32_t fn,
desc_arg.arginfo = SCM_ARGS(5, SCM_RO, SCM_VAL, SCM_VAL,
SCM_VAL, SCM_VAL);
- dmac_flush_range(payload, payload + 5 * (sizeof(uint32_t)));
+ dmac_flush_range(payload, (void *)payload + 5 * (sizeof(uint32_t)));
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_LMH, MSM_LIMITS_DCVSH), &desc_arg);
kfree(payload);
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 17ecd61e9ee6..ced2f23addd4 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -1019,7 +1019,7 @@ static int msm_lmh_dcvs_write(uint32_t node_id, uint32_t fn, uint32_t setting,
desc_arg.arginfo = SCM_ARGS(5, SCM_RO, SCM_VAL, SCM_VAL,
SCM_VAL, SCM_VAL);
- dmac_flush_range(payload, payload + 5 * (sizeof(uint32_t)));
+ dmac_flush_range(payload, (void *)payload + 5 * (sizeof(uint32_t)));
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_LMH, MSM_LIMITS_DCVSH), &desc_arg);
kfree(payload);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index fa3c9e511663..ec9288791667 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3555,6 +3555,7 @@ static int msm_hs_probe(struct platform_device *pdev)
}
msm_serial_debugfs_init(msm_uport, pdev->id);
+ msm_hs_unconfig_uart_gpios(uport);
uport->line = pdev->id;
if (pdata->userid && pdata->userid <= UARTDM_NR)
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 0121bf7ca4ac..98d5908c1e2f 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1139,6 +1139,7 @@ static void f_midi_free(struct usb_function *f)
mutex_lock(&opts->lock);
for (i = opts->in_ports - 1; i >= 0; --i)
kfree(midi->in_port[i]);
+ opts->func_inst.f = NULL;
kfree(midi);
--opts->refcnt;
mutex_unlock(&opts->lock);
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c
index 316967415aa9..eb306529981f 100644
--- a/drivers/usb/gadget/function/f_qc_rndis.c
+++ b/drivers/usb/gadget/function/f_qc_rndis.c
@@ -1441,13 +1441,13 @@ bool rndis_qc_get_skip_ep_config(void)
return rndis_ipa_params.skip_ep_cfg;
}
-DECLARE_USB_FUNCTION_INIT(qcrndis, qcrndis_alloc_inst, qcrndis_alloc);
+DECLARE_USB_FUNCTION_INIT(rndis_bam, qcrndis_alloc_inst, qcrndis_alloc);
static int __init usb_qcrndis_init(void)
{
int ret;
- ret = usb_function_register(&qcrndisusb_func);
+ ret = usb_function_register(&rndis_bamusb_func);
if (ret) {
pr_err("%s: failed to register diag %d\n", __func__, ret);
return ret;
@@ -1457,7 +1457,7 @@ static int __init usb_qcrndis_init(void)
static void __exit usb_qcrndis_exit(void)
{
- usb_function_unregister(&qcrndisusb_func);
+ usb_function_unregister(&rndis_bamusb_func);
rndis_qc_cleanup();
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 7a1174b32a38..a72c874f19a5 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -459,6 +459,7 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos)
static int pd_eval_src_caps(struct usbpd *pd, const u32 *src_caps)
{
+ union power_supply_propval val;
u32 first_pdo = src_caps[0];
/* save the PDOs so userspace can further evaluate */
@@ -474,6 +475,10 @@ static int pd_eval_src_caps(struct usbpd *pd, const u32 *src_caps)
pd->peer_pr_swap = PD_SRC_PDO_FIXED_PR_SWAP(first_pdo);
pd->peer_dr_swap = PD_SRC_PDO_FIXED_DR_SWAP(first_pdo);
+ val.intval = PD_SRC_PDO_FIXED_USB_SUSP(first_pdo);
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);
+
/* Select the first PDO (vSafe5V) immediately. */
pd_select_pdo(pd, 1);
@@ -492,6 +497,7 @@ static void pd_send_hard_reset(struct usbpd *pd)
ret = pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
if (!ret)
pd->hard_reset = true;
+ pd->in_pr_swap = false;
}
static void kick_sm(struct usbpd *pd, int ms)
@@ -625,7 +631,10 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_STARTUP:
if (pd->current_dr == DR_NONE) {
pd->current_dr = DR_DFP;
- /* Defer starting USB host mode until after PD */
+ /*
+ * Defer starting USB host mode until PE_SRC_READY or
+ * when PE_SRC_SEND_CAPABILITIES fails
+ */
}
/* Set CC back to DRP toggle for the next disconnect */
@@ -660,7 +669,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->current_state = PE_SRC_SEND_CAPABILITIES;
if (pd->in_pr_swap) {
- pd->in_pr_swap = false;
kick_sm(pd, SWAP_SOURCE_START_TIME);
break;
}
@@ -820,6 +828,17 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
}
+ ret = power_supply_get_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_ALLOWED, &val);
+ if (ret) {
+ usbpd_err(&pd->dev, "Unable to read USB PROP_PD_ALLOWED: %d\n",
+ ret);
+ break;
+ }
+
+ if (!val.intval)
+ break;
+
/* Reset protocol layer */
pd->tx_msgid = 0;
pd->rx_msgid = -1;
@@ -847,7 +866,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->pd_phy_opened = true;
}
- pd->in_pr_swap = false;
pd->current_voltage = 5000000;
pd->current_state = PE_SNK_WAIT_FOR_CAPABILITIES;
@@ -896,8 +914,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
- pd->hard_reset = false;
-
if (pd->current_dr != DR_UFP) {
extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 0);
@@ -1373,11 +1389,11 @@ static void usbpd_sm(struct work_struct *w)
ctrl_recvd = pd->rx_msg_type;
/* Disconnect? */
- if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE && !pd->in_pr_swap) {
if (pd->current_state == PE_UNKNOWN)
goto sm_done;
- usbpd_info(&pd->dev, "USB PD disconnect\n");
+ usbpd_info(&pd->dev, "USB Type-C disconnect\n");
if (pd->pd_phy_opened) {
pd_phy_close();
@@ -1400,6 +1416,10 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED,
+ &val);
+
+ power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_ACTIVE, &val);
if (pd->current_pr == PR_SRC)
@@ -1441,6 +1461,7 @@ static void usbpd_sm(struct work_struct *w)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+ pd->in_pr_swap = false;
reset_vdm_state(pd);
if (pd->current_pr == PR_SINK)
@@ -1484,6 +1505,10 @@ static void usbpd_sm(struct work_struct *w)
}
break;
+ case PE_SRC_STARTUP:
+ usbpd_set_state(pd, PE_SRC_STARTUP);
+ break;
+
case PE_SRC_SEND_CAPABILITIES:
ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, default_src_caps,
ARRAY_SIZE(default_src_caps), SOP_MSG);
@@ -1621,6 +1646,10 @@ static void usbpd_sm(struct work_struct *w)
usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT);
break;
+ case PE_SNK_STARTUP:
+ usbpd_set_state(pd, PE_SNK_STARTUP);
+ break;
+
case PE_SNK_WAIT_FOR_CAPABILITIES:
if (data_recvd == MSG_SOURCE_CAPABILITIES) {
val.intval = 0;
@@ -1668,9 +1697,14 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_VOLTAGE_MIN,
&val);
- val.intval = 0; /* suspend charging */
+ /*
+ * disable charging; technically we are allowed to
+ * charge up to pSnkStdby (2.5 W) during this
+ * transition, but disable it just for simplicity.
+ */
+ val.intval = 0;
power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &val);
+ POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val);
pd->selected_pdo = pd->requested_pdo;
usbpd_set_state(pd, PE_SNK_TRANSITION_SINK);
@@ -1701,7 +1735,7 @@ static void usbpd_sm(struct work_struct *w)
/* resume charging */
val.intval = pd->requested_current * 1000; /* mA->uA */
power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &val);
+ POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val);
usbpd_set_state(pd, PE_SNK_READY);
} else {
@@ -1795,6 +1829,12 @@ static void usbpd_sm(struct work_struct *w)
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
+ pd->hard_reset = false;
+
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+
if (pd->vbus_present) {
usbpd_set_state(pd, PE_SNK_STARTUP);
} else {
@@ -1853,7 +1893,7 @@ static void usbpd_sm(struct work_struct *w)
if (pd->requested_current) {
val.intval = pd->requested_current = 0;
power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &val);
+ POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val);
}
val.intval = pd->requested_voltage;
@@ -2008,73 +2048,42 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
{
struct usbpd *pd = container_of(nb, struct usbpd, psy_nb);
union power_supply_propval val;
- bool pd_allowed;
enum power_supply_typec_mode typec_mode;
- enum power_supply_type psy_type;
int ret;
if (ptr != pd->usb_psy || evt != PSY_EVENT_PROP_CHANGED)
return 0;
ret = power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_ALLOWED, &val);
+ POWER_SUPPLY_PROP_TYPEC_MODE, &val);
if (ret) {
- usbpd_err(&pd->dev, "Unable to read USB PROP_PD_ALLOWED: %d\n",
- ret);
+ usbpd_err(&pd->dev, "Unable to read USB TYPEC_MODE: %d\n", ret);
return ret;
}
- pd_allowed = val.intval;
+ typec_mode = val.intval;
ret = power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &val);
+ POWER_SUPPLY_PROP_PE_START, &val);
if (ret) {
- usbpd_err(&pd->dev, "Unable to read USB PRESENT: %d\n", ret);
+ usbpd_err(&pd->dev, "Unable to read USB PROP_PE_START: %d\n",
+ ret);
return ret;
}
- pd->vbus_present = val.intval;
+ /* Don't proceed if PE_START=0 as other props may still change */
+ if (!val.intval && !pd->pd_connected &&
+ typec_mode != POWER_SUPPLY_TYPEC_NONE)
+ return 0;
ret = power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_TYPEC_MODE, &val);
+ POWER_SUPPLY_PROP_PRESENT, &val);
if (ret) {
- usbpd_err(&pd->dev, "Unable to read USB TYPEC_MODE: %d\n", ret);
+ usbpd_err(&pd->dev, "Unable to read USB PRESENT: %d\n", ret);
return ret;
}
- typec_mode = val.intval;
-
- /*
- * Don't proceed if cable is connected but PD_ALLOWED is false.
- * It means the PMIC may still be in the middle of performing
- * charger type detection.
- */
- if (!pd_allowed && typec_mode != POWER_SUPPLY_TYPEC_NONE)
- return 0;
-
- /*
- * Workaround for PMIC HW bug.
- *
- * During hard reset or PR swap (sink to source) when VBUS goes to 0
- * the CC logic will report this as a disconnection. In those cases it
- * can be ignored, however the downside is that pd->hard_reset can be
- * momentarily true even when a non-PD capable source is attached, and
- * can't be distinguished from a physical disconnect. In that case,
- * allow for the common case of disconnecting from an SDP.
- *
- * The less common case is a PD-capable SDP which will result in a
- * hard reset getting treated like a disconnect. We can live with this
- * until the HW bug is fixed: in which disconnection won't be reported
- * on VBUS loss alone unless pullup is also removed from CC.
- */
- if (typec_mode == POWER_SUPPLY_TYPEC_NONE &&
- (pd->in_pr_swap ||
- (pd->psy_type != POWER_SUPPLY_TYPE_USB &&
- pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT))) {
- usbpd_dbg(&pd->dev, "Ignoring disconnect due to %s\n",
- pd->in_pr_swap ? "PR swap" : "hard reset");
- return 0;
- }
+ pd->vbus_present = val.intval;
ret = power_supply_get_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPE, &val);
@@ -2083,23 +2092,51 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
return ret;
}
- psy_type = val.intval;
+ pd->psy_type = val.intval;
- usbpd_dbg(&pd->dev, "typec mode:%d present:%d type:%d orientation:%d\n",
- typec_mode, pd->vbus_present, psy_type,
- usbpd_get_plug_orientation(pd));
-
- /* any change? */
- if (pd->typec_mode == typec_mode && pd->psy_type == psy_type)
+ if (pd->typec_mode == typec_mode)
return 0;
pd->typec_mode = typec_mode;
- pd->psy_type = psy_type;
+
+ usbpd_dbg(&pd->dev, "typec mode:%d present:%d type:%d orientation:%d\n",
+ typec_mode, pd->vbus_present, pd->psy_type,
+ usbpd_get_plug_orientation(pd));
switch (typec_mode) {
/* Disconnect */
case POWER_SUPPLY_TYPEC_NONE:
- kick_sm(pd, 0);
+ if (pd->in_pr_swap) {
+ usbpd_dbg(&pd->dev, "Ignoring disconnect due to PR swap\n");
+ return 0;
+ }
+
+ /*
+ * Workaround for PMIC HW bug.
+ *
+ * During hard reset when VBUS goes to 0 the CC logic
+ * will report this as a disconnection. In those cases
+ * it can be ignored, however the downside is that
+ * pd->hard_reset can be momentarily true even when a
+ * non-PD capable source is attached, and can't be
+ * distinguished from a physical disconnect. In that
+ * case, allow for the common case of disconnecting
+ * from an SDP.
+ *
+ * The less common case is a PD-capable SDP which will
+ * result in a hard reset getting treated like a
+ * disconnect. We can live with this until the HW bug
+ * is fixed: in which disconnection won't be reported
+ * on VBUS loss alone unless pullup is also removed
+ * from CC.
+ */
+ if (pd->psy_type != POWER_SUPPLY_TYPE_USB &&
+ pd->current_state ==
+ PE_SNK_TRANSITION_TO_DEFAULT) {
+ usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n");
+ return 0;
+ }
+
break;
/* Sink states */
@@ -2108,11 +2145,8 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
usbpd_info(&pd->dev, "Type-C Source (%s) connected\n",
src_current(typec_mode));
- if (pd->current_pr != PR_SINK ||
- pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) {
- pd->current_pr = PR_SINK;
- kick_sm(pd, 0);
- }
+ pd->current_pr = PR_SINK;
+ pd->in_pr_swap = false;
break;
/* Source states */
@@ -2121,10 +2155,8 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
usbpd_info(&pd->dev, "Type-C Sink%s connected\n",
typec_mode == POWER_SUPPLY_TYPEC_SINK ?
"" : " (powered)");
- if (pd->current_pr != PR_SRC) {
- pd->current_pr = PR_SRC;
- kick_sm(pd, 0);
- }
+ pd->current_pr = PR_SRC;
+ pd->in_pr_swap = false;
break;
case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY:
@@ -2134,10 +2166,13 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
usbpd_info(&pd->dev, "Type-C Analog Audio Adapter connected\n");
break;
default:
- usbpd_warn(&pd->dev, "Unsupported typec mode:%d\n", typec_mode);
+ usbpd_warn(&pd->dev, "Unsupported typec mode:%d\n",
+ typec_mode);
break;
}
+ /* queue state machine due to CC state change */
+ kick_sm(pd, 0);
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 55918d47a21a..1e93a5b2e9ba 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -460,6 +460,7 @@ struct mdss_data_type {
u32 nmax_concurrent_ad_hw;
struct workqueue_struct *ad_calc_wq;
u32 ad_debugen;
+ bool mem_retain;
struct mdss_intr hist_intr;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 4e68952d33a9..b246204f3181 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1157,23 +1157,46 @@ exit:
return ret;
}
-int mdss_dp_off(struct mdss_panel_data *pdata)
+static void mdss_dp_mainlink_off(struct mdss_panel_data *pdata)
{
struct mdss_dp_drv_pdata *dp_drv = NULL;
+ const int idle_pattern_completion_timeout_ms = 3 * HZ / 100;
dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
panel_data);
if (!dp_drv) {
pr_err("Invalid input data\n");
- return -EINVAL;
+ return;
}
- pr_debug("Entered++, cont_splash=%d\n", dp_drv->cont_splash);
+ pr_debug("Entered++\n");
/* wait until link training is completed */
mutex_lock(&dp_drv->train_mutex);
reinit_completion(&dp_drv->idle_comp);
mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE);
+ if (!wait_for_completion_timeout(&dp_drv->idle_comp,
+ idle_pattern_completion_timeout_ms))
+ pr_warn("PUSH_IDLE pattern timedout\n");
+
+ mutex_unlock(&dp_drv->train_mutex);
+ pr_debug("mainlink off done\n");
+}
+
+int mdss_dp_off(struct mdss_panel_data *pdata)
+{
+ struct mdss_dp_drv_pdata *dp_drv = NULL;
+
+ dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
+ panel_data);
+ if (!dp_drv) {
+ pr_err("Invalid input data\n");
+ return -EINVAL;
+ }
+ pr_debug("Entered++, cont_splash=%d\n", dp_drv->cont_splash);
+
+ /* wait until link training is completed */
+ mutex_lock(&dp_drv->train_mutex);
if (dp_drv->link_clks_on)
mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false);
@@ -1187,6 +1210,13 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
mdss_dp_config_gpios(dp_drv, false);
mdss_dp_pinctrl_set_state(dp_drv, false);
+ /*
+ * The global reset will need DP link ralated clocks to be
+ * running. Add the global reset just before disabling the
+ * link clocks and core clocks.
+ */
+ mdss_dp_ctrl_reset(&dp_drv->ctrl_io);
+
/* Make sure DP is disabled before clk disable */
wmb();
mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, false);
@@ -1360,6 +1390,7 @@ edid_error:
mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false);
clk_error:
mdss_dp_regulator_ctrl(dp_drv, false);
+ mdss_dp_config_gpios(dp_drv, false);
vreg_error:
return ret;
}
@@ -1616,7 +1647,7 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
return -EINVAL;
}
- pr_debug("event=%d\n", event);
+ pr_debug("event=%s\n", mdss_panel_intf_event_to_string(event));
dp = container_of(pdata, struct mdss_dp_drv_pdata,
panel_data);
@@ -1639,6 +1670,7 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
case MDSS_EVENT_BLANK:
if (ops && ops->off)
ops->off(dp->hdcp_data);
+ mdss_dp_mainlink_off(pdata);
break;
case MDSS_EVENT_FB_REGISTERED:
fbi = (struct fb_info *)arg;
@@ -1803,7 +1835,7 @@ static void mdss_dp_event_work(struct work_struct *work)
dp->current_event = 0;
spin_unlock_irqrestore(&dp->event_lock, flag);
- pr_debug("todo=%x\n", todo);
+ pr_debug("todo=%s\n", mdss_dp_ev_event_to_string(todo));
switch (todo) {
case EV_EDID_READ:
@@ -1964,10 +1996,50 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr)
pr_debug("cable disconnected\n");
mutex_lock(&dp_drv->pd_msg_mutex);
dp_drv->cable_connected = false;
+ dp_drv->alt_mode.current_state = UNKNOWN_STATE;
mutex_unlock(&dp_drv->pd_msg_mutex);
mdss_dp_notify_clients(dp_drv, false);
}
+static int mdss_dp_validate_callback(u8 cmd,
+ enum usbpd_svdm_cmd_type cmd_type, int num_vdos)
+{
+ int ret = 0;
+
+ if (cmd_type == SVDM_CMD_TYPE_RESP_NAK) {
+ pr_err("error: NACK\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (cmd_type == SVDM_CMD_TYPE_RESP_BUSY) {
+ pr_err("error: BUSY\n");
+ ret = -EBUSY;
+ goto end;
+ }
+
+ if (cmd == USBPD_SVDM_ATTENTION) {
+ if (cmd_type != SVDM_CMD_TYPE_INITIATOR) {
+ pr_err("error: invalid cmd type for attention\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (!num_vdos) {
+ pr_err("error: no vdo provided\n");
+ ret = -EINVAL;
+ goto end;
+ }
+ } else {
+ if (cmd_type != SVDM_CMD_TYPE_RESP_ACK) {
+ pr_err("error: invalid cmd type\n");
+ ret = -EINVAL;
+ }
+ }
+end:
+ return ret;
+}
+
static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
enum usbpd_svdm_cmd_type cmd_type,
const u32 *vdos, int num_vdos)
@@ -1983,80 +2055,51 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
pr_debug("callback -> cmd: 0x%x, *vdos = 0x%x, num_vdos = %d\n",
cmd, *vdos, num_vdos);
+ if (mdss_dp_validate_callback(cmd, cmd_type, num_vdos))
+ return;
+
switch (cmd) {
case USBPD_SVDM_DISCOVER_MODES:
- if (cmd_type == SVDM_CMD_TYPE_RESP_ACK) {
- dp_drv->alt_mode.dp_cap.response = *vdos;
- mdss_dp_usbpd_ext_capabilities
- (&dp_drv->alt_mode.dp_cap);
- dp_drv->alt_mode.current_state = DISCOVER_MODES_DONE;
- dp_send_events(dp_drv, EV_USBPD_ENTER_MODE);
- } else {
- pr_err("unknown response: %d for Discover_modes\n",
- cmd_type);
- }
+ dp_drv->alt_mode.dp_cap.response = *vdos;
+ mdss_dp_usbpd_ext_capabilities(&dp_drv->alt_mode.dp_cap);
+ dp_drv->alt_mode.current_state |= DISCOVER_MODES_DONE;
+ dp_send_events(dp_drv, EV_USBPD_ENTER_MODE);
break;
case USBPD_SVDM_ENTER_MODE:
- if (cmd_type == SVDM_CMD_TYPE_RESP_ACK) {
- dp_drv->alt_mode.current_state = ENTER_MODE_DONE;
- dp_send_events(dp_drv, EV_USBPD_DP_STATUS);
- } else {
- pr_err("unknown response: %d for Enter_mode\n",
- cmd_type);
- }
+ dp_drv->alt_mode.current_state |= ENTER_MODE_DONE;
+ dp_send_events(dp_drv, EV_USBPD_DP_STATUS);
break;
case USBPD_SVDM_ATTENTION:
- if (cmd_type == SVDM_CMD_TYPE_INITIATOR) {
- pr_debug("Attention. cmd_type=%d\n",
- cmd_type);
- if (!(dp_drv->alt_mode.current_state
- == ENTER_MODE_DONE)) {
- pr_debug("sending discover_mode\n");
- dp_send_events(dp_drv, EV_USBPD_DISCOVER_MODES);
- break;
- }
- if (num_vdos == 1) {
- dp_drv->alt_mode.dp_status.response = *vdos;
- mdss_dp_usbpd_ext_dp_status
- (&dp_drv->alt_mode.dp_status);
- if (dp_drv->alt_mode.dp_status.hpd_high) {
- pr_debug("HPD high\n");
- dp_drv->alt_mode.current_state =
- DP_STATUS_DONE;
- dp_send_events
- (dp_drv, EV_USBPD_DP_CONFIGURE);
- }
- }
- } else {
- pr_debug("unknown response: %d for Attention\n",
- cmd_type);
- }
+ dp_drv->alt_mode.dp_status.response = *vdos;
+ mdss_dp_usbpd_ext_dp_status(&dp_drv->alt_mode.dp_status);
+
+ if (!dp_drv->alt_mode.dp_status.hpd_high)
+ return;
+
+ pr_debug("HPD high\n");
+
+ dp_drv->alt_mode.current_state |= DP_STATUS_DONE;
+
+ if (dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)
+ mdss_dp_host_init(&dp_drv->panel_data);
+ else
+ dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
break;
case DP_VDM_STATUS:
- if (cmd_type == SVDM_CMD_TYPE_RESP_ACK) {
- dp_drv->alt_mode.dp_status.response = *vdos;
- mdss_dp_usbpd_ext_dp_status
- (&dp_drv->alt_mode.dp_status);
- if (dp_drv->alt_mode.dp_status.hpd_high) {
- pr_debug("HDP high\n");
- dp_drv->alt_mode.current_state =
- DP_STATUS_DONE;
- dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
- }
- } else {
- pr_err("unknown response: %d for DP_Status\n",
- cmd_type);
+ dp_drv->alt_mode.dp_status.response = *vdos;
+ mdss_dp_usbpd_ext_dp_status(&dp_drv->alt_mode.dp_status);
+
+ if (!(dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)) {
+ dp_drv->alt_mode.current_state |= DP_STATUS_DONE;
+ dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
}
break;
case DP_VDM_CONFIGURE:
- if (cmd_type == SVDM_CMD_TYPE_RESP_ACK) {
- dp_drv->alt_mode.current_state = DP_CONFIGURE_DONE;
- pr_debug("config USBPD to DP done\n");
+ dp_drv->alt_mode.current_state |= DP_CONFIGURE_DONE;
+ pr_debug("config USBPD to DP done\n");
+
+ if (dp_drv->alt_mode.dp_status.hpd_high)
mdss_dp_host_init(&dp_drv->panel_data);
- } else {
- pr_err("unknown response: %d for DP_Configure\n",
- cmd_type);
- }
break;
default:
pr_err("unknown cmd: %d\n", cmd);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index 6c391f6f7de0..8d5af4dc5bf3 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -105,6 +105,7 @@
EDP_INTR_FRAME_END | EDP_INTR_CRC_UPDATED)
#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2)
+#define EV_EVENT_STR(x) #x
struct edp_buf {
char *start; /* buffer start addr */
@@ -170,12 +171,12 @@ struct usbpd_dp_status {
};
enum dp_alt_mode_state {
- ALT_MODE_INIT_STATE = 0,
- DISCOVER_MODES_DONE,
- ENTER_MODE_DONE,
- DP_STATUS_DONE,
- DP_CONFIGURE_DONE,
- UNKNOWN_STATE,
+ UNKNOWN_STATE = 0,
+ ALT_MODE_INIT_STATE = BIT(0),
+ DISCOVER_MODES_DONE = BIT(1),
+ ENTER_MODE_DONE = BIT(2),
+ DP_STATUS_DONE = BIT(3),
+ DP_CONFIGURE_DONE = BIT(4),
};
struct dp_alt_mode {
@@ -465,6 +466,28 @@ static inline const char *__mdss_dp_pm_supply_node_name(
}
}
+static inline char *mdss_dp_ev_event_to_string(int event)
+{
+ switch (event) {
+ case EV_EDP_AUX_SETUP:
+ return EV_EVENT_STR(EV_EDP_AUX_SETUP);
+ case EV_EDID_READ:
+ return EV_EVENT_STR(EV_EDID_READ);
+ case EV_DPCD_CAP_READ:
+ return EV_EVENT_STR(EV_DPCD_CAP_READ);
+ case EV_DPCD_STATUS_READ:
+ return EV_EVENT_STR(EV_DPCD_STATUS_READ);
+ case EV_LINK_TRAIN:
+ return EV_EVENT_STR(EV_LINK_TRAIN);
+ case EV_IDLE_PATTERNS_SENT:
+ return EV_EVENT_STR(EV_IDLE_PATTERNS_SENT);
+ case EV_VIDEO_READY:
+ return EV_EVENT_STR(EV_VIDEO_READY);
+ default:
+ return "unknown";
+ }
+}
+
void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp);
void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp);
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 119e2a2b05cf..3c525b0dac4f 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -1174,8 +1174,9 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
pr_debug("Entered++");
dp_host_train_set(ep, 0x01); /* train_1 */
- dp_voltage_pre_emphasise_set(ep);
+ dp_cap_lane_rate_set(ep);
dp_train_pattern_set_write(ep, 0x21); /* train_1 */
+ dp_voltage_pre_emphasise_set(ep);
tries = 0;
old_v_level = ep->v_level;
@@ -1336,7 +1337,6 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp)
train_start:
dp->v_level = 0; /* start from default level */
dp->p_level = 0;
- dp_cap_lane_rate_set(dp);
mdss_dp_config_ctrl(dp);
mdss_dp_state_ctrl(&dp->ctrl_io, 0);
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index 92acb910e0c3..b1eb8e0c9579 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -495,6 +495,14 @@ void mdss_dp_usbpd_ext_dp_status(struct usbpd_dp_status *dp_status)
dp_status->hpd_irq =
(buf & BIT(8)) ? true : false;
+ pr_debug("low_pow_st = %d, adaptor_dp_en = %d, multi_func = %d\n",
+ dp_status->low_pow_st, dp_status->adaptor_dp_en,
+ dp_status->multi_func);
+ pr_debug("switch_to_usb_config = %d, exit_dp_mode = %d, hpd_high =%d\n",
+ dp_status->switch_to_usb_config,
+ dp_status->exit_dp_mode, dp_status->hpd_high);
+ pr_debug("hpd_irq = %d\n", dp_status->hpd_irq);
+
mdss_dp_initialize_s_port(&dp_status->c_port, port);
}
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index ace796163fa4..94cc2f2dc370 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -3566,54 +3566,6 @@ static int hdmi_tx_hdcp_off(struct hdmi_tx_ctrl *hdmi_ctrl)
return rc;
}
-static char *hdmi_tx_get_event_name(int event)
-{
- switch (event) {
- case MDSS_EVENT_RESET:
- return HDMI_TX_EVT_STR(MDSS_EVENT_RESET);
- case MDSS_EVENT_LINK_READY:
- return HDMI_TX_EVT_STR(MDSS_EVENT_LINK_READY);
- case MDSS_EVENT_UNBLANK:
- return HDMI_TX_EVT_STR(MDSS_EVENT_UNBLANK);
- case MDSS_EVENT_PANEL_ON:
- return HDMI_TX_EVT_STR(MDSS_EVENT_PANEL_ON);
- case MDSS_EVENT_BLANK:
- return HDMI_TX_EVT_STR(MDSS_EVENT_BLANK);
- case MDSS_EVENT_PANEL_OFF:
- return HDMI_TX_EVT_STR(MDSS_EVENT_PANEL_OFF);
- case MDSS_EVENT_CLOSE:
- return HDMI_TX_EVT_STR(MDSS_EVENT_CLOSE);
- case MDSS_EVENT_SUSPEND:
- return HDMI_TX_EVT_STR(MDSS_EVENT_SUSPEND);
- case MDSS_EVENT_RESUME:
- return HDMI_TX_EVT_STR(MDSS_EVENT_RESUME);
- case MDSS_EVENT_CHECK_PARAMS:
- return HDMI_TX_EVT_STR(MDSS_EVENT_CHECK_PARAMS);
- case MDSS_EVENT_CONT_SPLASH_BEGIN:
- return HDMI_TX_EVT_STR(MDSS_EVENT_CONT_SPLASH_BEGIN);
- case MDSS_EVENT_CONT_SPLASH_FINISH:
- return HDMI_TX_EVT_STR(MDSS_EVENT_CONT_SPLASH_FINISH);
- case MDSS_EVENT_PANEL_UPDATE_FPS:
- return HDMI_TX_EVT_STR(MDSS_EVENT_PANEL_UPDATE_FPS);
- case MDSS_EVENT_FB_REGISTERED:
- return HDMI_TX_EVT_STR(MDSS_EVENT_FB_REGISTERED);
- case MDSS_EVENT_PANEL_CLK_CTRL:
- return HDMI_TX_EVT_STR(MDSS_EVENT_PANEL_CLK_CTRL);
- case MDSS_EVENT_DSI_CMDLIST_KOFF:
- return HDMI_TX_EVT_STR(MDSS_EVENT_DSI_CMDLIST_KOFF);
- case MDSS_EVENT_ENABLE_PARTIAL_ROI:
- return HDMI_TX_EVT_STR(MDSS_EVENT_ENABLE_PARTIAL_ROI);
- case MDSS_EVENT_DSI_STREAM_SIZE:
- return HDMI_TX_EVT_STR(MDSS_EVENT_DSI_STREAM_SIZE);
- case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
- return HDMI_TX_EVT_STR(MDSS_EVENT_DSI_DYNAMIC_SWITCH);
- case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
- return HDMI_TX_EVT_STR(MDSS_EVENT_REGISTER_RECOVERY_HANDLER);
- default:
- return "unknown";
- }
-}
-
static void hdmi_tx_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl)
{
void *pdata = pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
@@ -3918,7 +3870,8 @@ static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data,
hdmi_ctrl->evt_arg = arg;
DEV_DBG("%s: event = %s suspend=%d, hpd_feature=%d\n", __func__,
- hdmi_tx_get_event_name(event), hdmi_ctrl->panel_suspend,
+ mdss_panel_intf_event_to_string(event),
+ hdmi_ctrl->panel_suspend,
hdmi_ctrl->hpd_feature_on);
handler = hdmi_ctrl->evt_handler[event];
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 6845b386807b..a0637109c7b3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1345,7 +1345,12 @@ int mdss_iommu_ctrl(int enable)
return mdata->iommu_ref_cnt;
}
-static void mdss_mdp_memory_retention_enter(void)
+#define MEM_RETAIN_ON 1
+#define MEM_RETAIN_OFF 0
+#define PERIPH_RETAIN_ON 1
+#define PERIPH_RETAIN_OFF 0
+
+static void mdss_mdp_memory_retention_ctrl(bool mem_ctrl, bool periph_ctrl)
{
struct clk *mdss_mdp_clk = NULL;
struct clk *mdp_vote_clk = mdss_mdp_get_clk(MDSS_CLK_MDP_CORE);
@@ -1366,49 +1371,35 @@ static void mdss_mdp_memory_retention_enter(void)
__mdss_mdp_reg_access_clk_enable(mdata, true);
if (mdss_mdp_clk) {
- clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(mdss_mdp_clk, CLKFLAG_PERIPH_OFF_SET);
- clk_set_flags(mdss_mdp_clk, CLKFLAG_NORETAIN_PERIPH);
- }
-
- if (mdss_mdp_lut_clk) {
- clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_SET);
- clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_NORETAIN_PERIPH);
- }
- __mdss_mdp_reg_access_clk_enable(mdata, false);
-}
-
-static void mdss_mdp_memory_retention_exit(void)
-{
- struct clk *mdss_mdp_clk = NULL;
- struct clk *mdp_vote_clk = mdss_mdp_get_clk(MDSS_CLK_MDP_CORE);
- struct clk *mdss_mdp_lut_clk = NULL;
- struct clk *mdp_lut_vote_clk = mdss_mdp_get_clk(MDSS_CLK_MDP_LUT);
- struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ if (mem_ctrl)
+ clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM);
+ else
+ clk_set_flags(mdss_mdp_clk, CLKFLAG_NORETAIN_MEM);
- if (mdp_vote_clk) {
- if (test_bit(MDSS_CAPS_MDP_VOTE_CLK_NOT_SUPPORTED,
- mdata->mdss_caps_map)) {
- mdss_mdp_clk = mdp_vote_clk;
- mdss_mdp_lut_clk = mdp_lut_vote_clk;
+ if (periph_ctrl) {
+ clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_PERIPH);
+ clk_set_flags(mdss_mdp_clk, CLKFLAG_PERIPH_OFF_CLEAR);
} else {
- mdss_mdp_clk = clk_get_parent(mdp_vote_clk);
- mdss_mdp_lut_clk = clk_get_parent(mdp_lut_vote_clk);
+ clk_set_flags(mdss_mdp_clk, CLKFLAG_PERIPH_OFF_SET);
+ clk_set_flags(mdss_mdp_clk, CLKFLAG_NORETAIN_PERIPH);
}
}
- __mdss_mdp_reg_access_clk_enable(mdata, true);
- if (mdss_mdp_clk) {
- clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_PERIPH);
- clk_set_flags(mdss_mdp_clk, CLKFLAG_PERIPH_OFF_CLEAR);
- }
-
if (mdss_mdp_lut_clk) {
- clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_PERIPH);
- clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_CLEAR);
+ if (mem_ctrl)
+ clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_MEM);
+ else
+ clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_NORETAIN_MEM);
+
+ if (periph_ctrl) {
+ clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_PERIPH);
+ clk_set_flags(mdss_mdp_lut_clk,
+ CLKFLAG_PERIPH_OFF_CLEAR);
+ } else {
+ clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_SET);
+ clk_set_flags(mdss_mdp_lut_clk,
+ CLKFLAG_NORETAIN_PERIPH);
+ }
}
__mdss_mdp_reg_access_clk_enable(mdata, false);
}
@@ -1441,17 +1432,21 @@ static int mdss_mdp_idle_pc_restore(void)
mdss_hw_init(mdata);
mdss_iommu_ctrl(0);
- /**
- * sleep 10 microseconds to make sure AD auto-reinitialization
- * is done
- */
- udelay(10);
- mdss_mdp_memory_retention_exit();
-
mdss_mdp_ctl_restore(true);
mdata->idle_pc = false;
end:
+ if (mdata->mem_retain) {
+ /**
+ * sleep 10 microseconds to make sure AD auto-reinitialization
+ * is done
+ */
+ udelay(10);
+ mdss_mdp_memory_retention_ctrl(MEM_RETAIN_ON,
+ PERIPH_RETAIN_ON);
+ mdata->mem_retain = false;
+ }
+
mutex_unlock(&mdp_fs_idle_pc_lock);
return rc;
}
@@ -1980,7 +1975,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
case MDSS_MDP_HW_REV_300:
case MDSS_MDP_HW_REV_301:
mdata->max_target_zorder = 7; /* excluding base layer */
- mdata->max_cursor_size = 384;
+ mdata->max_cursor_size = 512;
mdata->per_pipe_ib_factor.numer = 8;
mdata->per_pipe_ib_factor.denom = 5;
mdata->apply_post_scale_bytes = false;
@@ -4912,10 +4907,12 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
* Turning off GDSC while overlays are still
* active.
*/
+
+ mdss_mdp_memory_retention_ctrl(MEM_RETAIN_ON,
+ PERIPH_RETAIN_OFF);
mdata->idle_pc = true;
pr_debug("idle pc. active overlays=%d\n",
active_cnt);
- mdss_mdp_memory_retention_enter();
} else {
/*
* Advise RPM to turn MMSS GDSC off during
@@ -4927,7 +4924,11 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
mdss_mdp_cx_ctrl(mdata, false);
mdss_mdp_batfet_ctrl(mdata, false);
+ mdss_mdp_memory_retention_ctrl(
+ MEM_RETAIN_OFF,
+ PERIPH_RETAIN_OFF);
}
+ mdata->mem_retain = true;
if (mdata->en_svs_high)
mdss_mdp_config_cx_voltage(mdata, false);
regulator_disable(mdata->fs);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 0f0df2256f74..e26b3843d7b0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -1618,8 +1618,8 @@ static bool __multirect_validate_rects(struct mdp_input_layer **layers,
/* resolution related validation */
if (mdss_rect_overlap_check(&dst[0], &dst[1])) {
pr_err("multirect dst overlap is not allowed. input: %d,%d,%d,%d paired %d,%d,%d,%d\n",
- dst[0].x, dst[0].y, dst[0].w, dst[0].y,
- dst[1].x, dst[1].y, dst[1].w, dst[1].y);
+ dst[0].x, dst[0].y, dst[0].w, dst[0].h,
+ dst[1].x, dst[1].y, dst[1].w, dst[1].h);
return false;
}
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 463d26643dde..be0491195263 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -54,6 +54,7 @@ struct panel_id {
#define DP_PANEL 12 /* LVDS */
#define DSC_PPS_LEN 128
+#define INTF_EVENT_STR(x) #x
static inline const char *mdss_panel2str(u32 panel)
{
@@ -270,6 +271,78 @@ enum mdss_intf_events {
MDSS_EVENT_MAX,
};
+/**
+ * mdss_panel_intf_event_to_string() - converts interface event enum to string
+ * @event: interface event to be converted to string representation
+ */
+static inline char *mdss_panel_intf_event_to_string(int event)
+{
+ switch (event) {
+ case MDSS_EVENT_RESET:
+ return INTF_EVENT_STR(MDSS_EVENT_RESET);
+ case MDSS_EVENT_LINK_READY:
+ return INTF_EVENT_STR(MDSS_EVENT_LINK_READY);
+ case MDSS_EVENT_UNBLANK:
+ return INTF_EVENT_STR(MDSS_EVENT_UNBLANK);
+ case MDSS_EVENT_PANEL_ON:
+ return INTF_EVENT_STR(MDSS_EVENT_PANEL_ON);
+ case MDSS_EVENT_POST_PANEL_ON:
+ return INTF_EVENT_STR(MDSS_EVENT_POST_PANEL_ON);
+ case MDSS_EVENT_BLANK:
+ return INTF_EVENT_STR(MDSS_EVENT_BLANK);
+ case MDSS_EVENT_PANEL_OFF:
+ return INTF_EVENT_STR(MDSS_EVENT_PANEL_OFF);
+ case MDSS_EVENT_CLOSE:
+ return INTF_EVENT_STR(MDSS_EVENT_CLOSE);
+ case MDSS_EVENT_SUSPEND:
+ return INTF_EVENT_STR(MDSS_EVENT_SUSPEND);
+ case MDSS_EVENT_RESUME:
+ return INTF_EVENT_STR(MDSS_EVENT_RESUME);
+ case MDSS_EVENT_CHECK_PARAMS:
+ return INTF_EVENT_STR(MDSS_EVENT_CHECK_PARAMS);
+ case MDSS_EVENT_CONT_SPLASH_BEGIN:
+ return INTF_EVENT_STR(MDSS_EVENT_CONT_SPLASH_BEGIN);
+ case MDSS_EVENT_CONT_SPLASH_FINISH:
+ return INTF_EVENT_STR(MDSS_EVENT_CONT_SPLASH_FINISH);
+ case MDSS_EVENT_PANEL_UPDATE_FPS:
+ return INTF_EVENT_STR(MDSS_EVENT_PANEL_UPDATE_FPS);
+ case MDSS_EVENT_FB_REGISTERED:
+ return INTF_EVENT_STR(MDSS_EVENT_FB_REGISTERED);
+ case MDSS_EVENT_PANEL_CLK_CTRL:
+ return INTF_EVENT_STR(MDSS_EVENT_PANEL_CLK_CTRL);
+ case MDSS_EVENT_DSI_CMDLIST_KOFF:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_CMDLIST_KOFF);
+ case MDSS_EVENT_ENABLE_PARTIAL_ROI:
+ return INTF_EVENT_STR(MDSS_EVENT_ENABLE_PARTIAL_ROI);
+ case MDSS_EVENT_DSC_PPS_SEND:
+ return INTF_EVENT_STR(MDSS_EVENT_DSC_PPS_SEND);
+ case MDSS_EVENT_DSI_STREAM_SIZE:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_STREAM_SIZE);
+ case MDSS_EVENT_DSI_UPDATE_PANEL_DATA:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_UPDATE_PANEL_DATA);
+ case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
+ return INTF_EVENT_STR(MDSS_EVENT_REGISTER_RECOVERY_HANDLER);
+ case MDSS_EVENT_REGISTER_MDP_CALLBACK:
+ return INTF_EVENT_STR(MDSS_EVENT_REGISTER_MDP_CALLBACK);
+ case MDSS_EVENT_DSI_PANEL_STATUS:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_PANEL_STATUS);
+ case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_DYNAMIC_SWITCH);
+ case MDSS_EVENT_DSI_RECONFIG_CMD:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_RECONFIG_CMD);
+ case MDSS_EVENT_DSI_RESET_WRITE_PTR:
+ return INTF_EVENT_STR(MDSS_EVENT_DSI_RESET_WRITE_PTR);
+ case MDSS_EVENT_PANEL_TIMING_SWITCH:
+ return INTF_EVENT_STR(MDSS_EVENT_PANEL_TIMING_SWITCH);
+ case MDSS_EVENT_DEEP_COLOR:
+ return INTF_EVENT_STR(MDSS_EVENT_DEEP_COLOR);
+ case MDSS_EVENT_DISABLE_PANEL:
+ return INTF_EVENT_STR(MDSS_EVENT_DISABLE_PANEL);
+ default:
+ return "unknown";
+ }
+}
+
struct lcd_panel_info {
u32 h_back_porch;
u32 h_front_porch;
diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h
index b80ea0c31597..251b7e314238 100644
--- a/include/dt-bindings/clock/msm-clocks-cobalt.h
+++ b/include/dt-bindings/clock/msm-clocks-cobalt.h
@@ -447,7 +447,9 @@
#define clk_dsi0pll_pclk_src 0x5efd85d4
#define clk_dsi0pll_pclk_src_mux 0x84b14663
#define clk_dsi0pll_post_bit_div 0xf46dcf27
-#define clk_dsi0pll_post_vco_div 0x8ee956ff
+#define clk_dsi0pll_post_vco_mux 0xfaf9bd1f
+#define clk_dsi0pll_post_vco_div1 0xabb50b2a
+#define clk_dsi0pll_post_vco_div4 0xbe51c091
#define clk_dsi0pll_bitclk_src 0x36c3c437
#define clk_dsi0pll_vco_clk 0x15940d40
@@ -457,7 +459,9 @@
#define clk_dsi1pll_pclk_src 0xeddcd80e
#define clk_dsi1pll_pclk_src_mux 0x3651feb3
#define clk_dsi1pll_post_bit_div 0x712f0260
-#define clk_dsi1pll_post_vco_div 0x623e04de
+#define clk_dsi1pll_post_vco_mux 0xc6a90d20
+#define clk_dsi1pll_post_vco_div1 0x6f47ca7d
+#define clk_dsi1pll_post_vco_div4 0x90628974
#define clk_dsi1pll_bitclk_src 0x13ab045b
#define clk_dsi1pll_vco_clk 0x99797b50
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 218cd875ee5a..18e1a979db76 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -198,6 +198,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_FLASH_CURRENT_MAX,
POWER_SUPPLY_PROP_UPDATE_NOW,
POWER_SUPPLY_PROP_ESR_COUNT,
+ POWER_SUPPLY_PROP_BUCK_FREQ,
POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE,
POWER_SUPPLY_PROP_CHARGE_DONE,
POWER_SUPPLY_PROP_FLASH_ACTIVE,
@@ -222,6 +223,8 @@ enum power_supply_property {
POWER_SUPPLY_PROP_CHARGER_TEMP,
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_PARALLEL_DISABLE,
+ POWER_SUPPLY_PROP_PARALLEL_PERCENT,
+ POWER_SUPPLY_PROP_PE_START,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a395d8a9ff73..06acefeffd4c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -356,7 +356,7 @@ extern int lockdep_tasklist_lock_is_held(void);
extern void sched_init(void);
extern void sched_init_smp(void);
extern asmlinkage void schedule_tail(struct task_struct *prev);
-extern void init_idle(struct task_struct *idle, int cpu);
+extern void init_idle(struct task_struct *idle, int cpu, bool hotplug);
extern void init_idle_bootup_task(struct task_struct *idle);
extern cpumask_var_t cpu_isolated_map;
@@ -1332,11 +1332,15 @@ struct ravg {
* sysctl_sched_ravg_hist_size windows. 'demand' could drive frequency
* demand for tasks.
*
- * 'curr_window' represents task's contribution to cpu busy time
- * statistics (rq->curr_runnable_sum) in current window
+ * 'curr_window_cpu' represents task's contribution to cpu busy time on
+ * various CPUs in the current window
*
- * 'prev_window' represents task's contribution to cpu busy time
- * statistics (rq->prev_runnable_sum) in previous window
+ * 'prev_window_cpu' represents task's contribution to cpu busy time on
+ * various CPUs in the previous window
+ *
+ * 'curr_window' represents the sum of all entries in curr_window_cpu
+ *
+ * 'prev_window' represents the sum of all entries in prev_window_cpu
*
* 'pred_demand' represents task's current predicted cpu busy time
*
@@ -1346,6 +1350,7 @@ struct ravg {
u64 mark_start;
u32 sum, demand;
u32 sum_history[RAVG_HIST_SIZE_MAX];
+ u32 *curr_window_cpu, *prev_window_cpu;
u32 curr_window, prev_window;
u16 active_windows;
u32 pred_demand;
diff --git a/kernel/sched/core_ctl.h b/include/linux/sched/core_ctl.h
index 3b0c12acb9c0..98d7cb3e899b 100644
--- a/kernel/sched/core_ctl.h
+++ b/include/linux/sched/core_ctl.h
@@ -16,9 +16,12 @@
#ifdef CONFIG_SCHED_CORE_CTL
void core_ctl_check(u64 wallclock);
-void core_ctl_set_boost(bool boost);
+int core_ctl_set_boost(bool boost);
#else
static inline void core_ctl_check(u64 wallclock) {}
-static inline void core_ctl_set_boost(bool boost) {}
+static inline int core_ctl_set_boost(bool boost)
+{
+ return 0;
+}
#endif
#endif
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 9fe71c774543..6848454c5447 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -44,6 +44,7 @@ extern unsigned int sysctl_sched_wake_to_idle;
#ifdef CONFIG_SCHED_HMP
extern int sysctl_sched_freq_inc_notify;
extern int sysctl_sched_freq_dec_notify;
+extern unsigned int sysctl_sched_freq_reporting_policy;
extern unsigned int sysctl_sched_window_stats_policy;
extern unsigned int sysctl_sched_ravg_hist_size;
extern unsigned int sysctl_sched_cpu_high_irqload;
diff --git a/include/linux/types.h b/include/linux/types.h
index 70dd3dfde631..9f2d2f46b459 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -9,6 +9,9 @@
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
+#define DECLARE_BITMAP_ARRAY(name,nr,bits) \
+ unsigned long name[nr][BITS_TO_LONGS(bits)]
+
typedef __u32 __kernel_dev_t;
typedef __kernel_fd_set fd_set;
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index daf69b7df534..7778ff3947de 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -260,6 +260,30 @@ TRACE_EVENT(sched_set_boost,
TP_printk("ref_count=%d", __entry->ref_count)
);
+#if defined(CREATE_TRACE_POINTS) && defined(CONFIG_SCHED_HMP)
+static inline void __window_data(u32 *dst, u32 *src)
+{
+ if (src)
+ memcpy(dst, src, nr_cpu_ids * sizeof(u32));
+ else
+ memset(dst, 0, nr_cpu_ids * sizeof(u32));
+}
+
+struct trace_seq;
+const char *__window_print(struct trace_seq *p, const u32 *buf, int buf_len)
+{
+ int i;
+ const char *ret = p->buffer + seq_buf_used(&p->seq);
+
+ for (i = 0; i < buf_len; i++)
+ trace_seq_printf(p, "%u ", buf[i]);
+
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+#endif
+
TRACE_EVENT(sched_update_task_ravg,
TP_PROTO(struct task_struct *p, struct rq *rq, enum task_event evt,
@@ -288,13 +312,17 @@ TRACE_EVENT(sched_update_task_ravg,
__field( u64, rq_ps )
__field( u64, grp_cs )
__field( u64, grp_ps )
- __field( u64, grp_nt_cs )
- __field( u64, grp_nt_ps )
+ __field( u64, grp_nt_cs )
+ __field( u64, grp_nt_ps )
__field( u32, curr_window )
__field( u32, prev_window )
+ __dynamic_array(u32, curr_sum, nr_cpu_ids )
+ __dynamic_array(u32, prev_sum, nr_cpu_ids )
__field( u64, nt_cs )
__field( u64, nt_ps )
__field( u32, active_windows )
+ __field( u8, curr_top )
+ __field( u8, prev_top )
),
TP_fast_assign(
@@ -321,22 +349,30 @@ TRACE_EVENT(sched_update_task_ravg,
__entry->grp_nt_ps = cpu_time ? cpu_time->nt_prev_runnable_sum : 0;
__entry->curr_window = p->ravg.curr_window;
__entry->prev_window = p->ravg.prev_window;
+ __window_data(__get_dynamic_array(curr_sum), p->ravg.curr_window_cpu);
+ __window_data(__get_dynamic_array(prev_sum), p->ravg.prev_window_cpu);
__entry->nt_cs = rq->nt_curr_runnable_sum;
__entry->nt_ps = rq->nt_prev_runnable_sum;
__entry->active_windows = p->ravg.active_windows;
+ __entry->curr_top = rq->curr_top;
+ __entry->prev_top = rq->prev_top;
),
- TP_printk("wc %llu ws %llu delta %llu event %s cpu %d cur_freq %u cur_pid %d task %d (%s) ms %llu delta %llu demand %u sum %u irqtime %llu pred_demand %u rq_cs %llu rq_ps %llu cur_window %u prev_window %u nt_cs %llu nt_ps %llu active_wins %u grp_cs %lld grp_ps %lld, grp_nt_cs %llu, grp_nt_ps: %llu"
- , __entry->wallclock, __entry->win_start, __entry->delta,
+ TP_printk("wc %llu ws %llu delta %llu event %s cpu %d cur_freq %u cur_pid %d task %d (%s) ms %llu delta %llu demand %u sum %u irqtime %llu pred_demand %u rq_cs %llu rq_ps %llu cur_window %u (%s) prev_window %u (%s) nt_cs %llu nt_ps %llu active_wins %u grp_cs %lld grp_ps %lld, grp_nt_cs %llu, grp_nt_ps: %llu curr_top %u prev_top %u",
+ __entry->wallclock, __entry->win_start, __entry->delta,
task_event_names[__entry->evt], __entry->cpu,
__entry->cur_freq, __entry->cur_pid,
__entry->pid, __entry->comm, __entry->mark_start,
__entry->delta_m, __entry->demand,
__entry->sum, __entry->irqtime, __entry->pred_demand,
__entry->rq_cs, __entry->rq_ps, __entry->curr_window,
- __entry->prev_window, __entry->nt_cs, __entry->nt_ps,
+ __window_print(p, __get_dynamic_array(curr_sum), nr_cpu_ids),
+ __entry->prev_window,
+ __window_print(p, __get_dynamic_array(prev_sum), nr_cpu_ids),
+ __entry->nt_cs, __entry->nt_ps,
__entry->active_windows, __entry->grp_cs,
- __entry->grp_ps, __entry->grp_nt_cs, __entry->grp_nt_ps)
+ __entry->grp_ps, __entry->grp_nt_cs, __entry->grp_nt_ps,
+ __entry->curr_top, __entry->prev_top)
);
TRACE_EVENT(sched_get_task_cpu_cycles,
@@ -1287,6 +1323,21 @@ TRACE_EVENT(core_ctl_set_busy,
__entry->is_busy)
);
+TRACE_EVENT(core_ctl_set_boost,
+
+ TP_PROTO(u32 refcount, s32 ret),
+ TP_ARGS(refcount, ret),
+ TP_STRUCT__entry(
+ __field(u32, refcount)
+ __field(s32, ret)
+ ),
+ TP_fast_assign(
+ __entry->refcount = refcount;
+ __entry->ret = ret;
+ ),
+ TP_printk("refcount=%u, ret=%d", __entry->refcount, __entry->ret)
+);
+
/**
* sched_isolate - called when cores are isolated/unisolated
*
diff --git a/init/main.c b/init/main.c
index fbafa271531c..7d4532bff5da 100644
--- a/init/main.c
+++ b/init/main.c
@@ -505,11 +505,6 @@ asmlinkage __visible void __init start_kernel(void)
smp_setup_processor_id();
debug_objects_early_init();
- /*
- * Set up the the initial canary ASAP:
- */
- boot_init_stack_canary();
-
cgroup_init_early();
local_irq_disable();
@@ -523,6 +518,10 @@ asmlinkage __visible void __init start_kernel(void)
page_address_init();
pr_notice("%s", linux_banner);
setup_arch(&command_line);
+ /*
+ * Set up the the initial canary ASAP:
+ */
+ boot_init_stack_canary();
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
setup_nr_cpu_ids();
diff --git a/kernel/fork.c b/kernel/fork.c
index e89d0bae6f20..8a5962276788 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1684,7 +1684,7 @@ struct task_struct *fork_idle(int cpu)
task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0, 0);
if (!IS_ERR(task)) {
init_idle_pids(task->pids);
- init_idle(task, cpu);
+ init_idle(task, cpu, false);
}
return task;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 024fb1007c78..53f7b50b7541 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -75,6 +75,7 @@
#include <linux/context_tracking.h>
#include <linux/compiler.h>
#include <linux/irq.h>
+#include <linux/sched/core_ctl.h>
#include <asm/switch_to.h>
#include <asm/tlb.h>
@@ -85,7 +86,6 @@
#endif
#include "sched.h"
-#include "core_ctl.h"
#include "../workqueue_internal.h"
#include "../smpboot.h"
@@ -2255,13 +2255,13 @@ void __dl_clear_params(struct task_struct *p)
void sched_exit(struct task_struct *p)
{
unsigned long flags;
- int cpu = get_cpu();
- struct rq *rq = cpu_rq(cpu);
+ struct rq *rq;
u64 wallclock;
sched_set_group_id(p, 0);
- raw_spin_lock_irqsave(&rq->lock, flags);
+ rq = task_rq_lock(p, &flags);
+
/* rq->curr == p */
wallclock = sched_ktime_clock();
update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
@@ -2269,11 +2269,13 @@ void sched_exit(struct task_struct *p)
reset_task_stats(p);
p->ravg.mark_start = wallclock;
p->ravg.sum_history[0] = EXITING_TASK_MARKER;
+
+ kfree(p->ravg.curr_window_cpu);
+ kfree(p->ravg.prev_window_cpu);
+
enqueue_task(rq, p, 0);
clear_ed_task(p, rq);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-
- put_cpu();
+ task_rq_unlock(rq, p, &flags);
}
#endif /* CONFIG_SCHED_HMP */
@@ -2377,6 +2379,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
int cpu = get_cpu();
__sched_fork(clone_flags, p);
+ init_new_task_load(p, false);
/*
* We mark the process as running here. This guarantees that
* nobody will actually run it, and a signal or other external
@@ -2562,7 +2565,6 @@ void wake_up_new_task(struct task_struct *p)
struct rq *rq;
raw_spin_lock_irqsave(&p->pi_lock, flags);
- init_new_task_load(p);
add_new_task_to_grp(p);
/* Initialize new task's runnable average */
init_entity_runnable_average(&p->se);
@@ -5210,17 +5212,21 @@ void init_idle_bootup_task(struct task_struct *idle)
* init_idle - set up an idle thread for a given CPU
* @idle: task in question
* @cpu: cpu the idle task belongs to
+ * @cpu_up: differentiate between initial boot vs hotplug
*
* NOTE: this function does not set the idle thread's NEED_RESCHED
* flag, to make booting more robust.
*/
-void init_idle(struct task_struct *idle, int cpu)
+void init_idle(struct task_struct *idle, int cpu, bool cpu_up)
{
struct rq *rq = cpu_rq(cpu);
unsigned long flags;
__sched_fork(0, idle);
+ if (!cpu_up)
+ init_new_task_load(idle, true);
+
raw_spin_lock_irqsave(&idle->pi_lock, flags);
raw_spin_lock(&rq->lock);
@@ -8009,6 +8015,22 @@ void __init sched_init(void)
rq->old_estimated_time = 0;
rq->old_busy_time_group = 0;
rq->hmp_stats.pred_demands_sum = 0;
+ rq->curr_table = 0;
+ rq->prev_top = 0;
+ rq->curr_top = 0;
+
+ for (j = 0; j < NUM_TRACKED_WINDOWS; j++) {
+ memset(&rq->load_subs[j], 0,
+ sizeof(struct load_subtractions));
+
+ rq->top_tasks[j] = kcalloc(NUM_LOAD_INDICES,
+ sizeof(u8), GFP_NOWAIT);
+
+ /* No other choice */
+ BUG_ON(!rq->top_tasks[j]);
+
+ clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]);
+ }
#endif
rq->max_idle_balance_cost = sysctl_sched_migration_cost;
@@ -8051,7 +8073,7 @@ void __init sched_init(void)
* but because we are the idle thread, we just pick up running again
* when this runqueue becomes "idle".
*/
- init_idle(current, smp_processor_id());
+ init_idle(current, smp_processor_id(), false);
calc_load_update = jiffies + LOAD_FREQ;
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index d81886da7ca2..0db85a4fa9c8 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -45,7 +45,7 @@ struct cluster_data {
bool nrrun_changed;
struct task_struct *core_ctl_thread;
unsigned int first_cpu;
- bool boost;
+ unsigned int boost;
struct kobject kobj;
};
@@ -652,17 +652,40 @@ static bool do_check(u64 wallclock)
return do_check;
}
-void core_ctl_set_boost(bool boost)
+int core_ctl_set_boost(bool boost)
{
unsigned int index = 0;
struct cluster_data *cluster;
+ unsigned long flags;
+ int ret = 0;
+ bool boost_state_changed = false;
+ spin_lock_irqsave(&state_lock, flags);
for_each_cluster(cluster, index) {
- if (cluster->is_big_cluster && cluster->boost != boost) {
- cluster->boost = boost;
- apply_need(cluster);
+ if (cluster->is_big_cluster) {
+ if (boost) {
+ boost_state_changed = !cluster->boost;
+ ++cluster->boost;
+ } else {
+ if (!cluster->boost) {
+ pr_err("Error turning off boost. Boost already turned off\n");
+ ret = -EINVAL;
+ } else {
+ --cluster->boost;
+ boost_state_changed = !cluster->boost;
+ }
+ }
+ break;
}
}
+ spin_unlock_irqrestore(&state_lock, flags);
+
+ if (boost_state_changed)
+ apply_need(cluster);
+
+ trace_core_ctl_set_boost(cluster->boost, ret);
+
+ return ret;
}
void core_ctl_check(u64 wallclock)
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index b6dc131f36a6..c8c4272c61d8 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -418,6 +418,7 @@ static void sched_debug_header(struct seq_file *m)
P(min_capacity);
P(max_capacity);
P(sched_ravg_window);
+ P(sched_load_granule);
#endif
#undef PN
#undef P
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 6362b864e2b1..e32d4d7903b0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3056,7 +3056,8 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats)
static inline bool
wake_to_waker_cluster(struct cpu_select_env *env)
{
- return !env->need_idle && !env->reason && env->sync &&
+ return env->boost_type == SCHED_BOOST_NONE &&
+ !env->need_idle && !env->reason && env->sync &&
task_load(current) > sched_big_waker_task_load &&
task_load(env->p) < sched_small_wakee_task_load;
}
@@ -3189,8 +3190,8 @@ retry:
}
}
p->last_cpu_selected_ts = sched_ktime_clock();
- sbc_flag |= env.sbc_best_cluster_flag;
out:
+ sbc_flag |= env.sbc_best_cluster_flag;
rcu_read_unlock();
trace_sched_task_load(p, sched_boost(), env.reason, env.sync,
env.need_idle, sbc_flag, target);
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 3d5de8ba70a2..d220482f4dbc 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -18,9 +18,9 @@
#include <linux/list_sort.h>
#include <linux/syscore_ops.h>
#include <linux/of.h>
+#include <linux/sched/core_ctl.h>
#include "sched.h"
-#include "core_ctl.h"
#include <trace/events/sched.h>
@@ -201,7 +201,7 @@ int sched_update_freq_max_load(const cpumask_t *cpumask)
entry = &max_load->freqs[i];
freq = costs[i].freq;
hpct = get_freq_max_load(cpu, freq);
- if (hpct <= 0 && hpct > 100)
+ if (hpct <= 0 || hpct > 100)
hpct = 100;
hfreq = div64_u64((u64)freq * hpct, 100);
entry->hdemand =
@@ -590,6 +590,7 @@ static struct sched_cluster *alloc_new_cluster(const struct cpumask *cpus)
cluster->dstate_wakeup_latency = 0;
cluster->freq_init_done = false;
+ raw_spin_lock_init(&cluster->load_lock);
cluster->cpus = *cpus;
cluster->efficiency = arch_get_cpu_efficiency(cpumask_first(cpus));
@@ -647,6 +648,7 @@ void init_clusters(void)
{
bitmap_clear(all_cluster_ids, 0, NR_CPUS);
init_cluster.cpus = *cpu_possible_mask;
+ raw_spin_lock_init(&init_cluster.load_lock);
INIT_LIST_HEAD(&cluster_head);
}
@@ -788,6 +790,12 @@ __read_mostly unsigned int sysctl_sched_new_task_windows = 5;
#define SCHED_FREQ_ACCOUNT_WAIT_TIME 0
/*
+ * This governs what load needs to be used when reporting CPU busy time
+ * to the cpufreq governor.
+ */
+__read_mostly unsigned int sysctl_sched_freq_reporting_policy;
+
+/*
* For increase, send notification if
* freq_required - cur_freq > sysctl_sched_freq_inc_notify
*/
@@ -823,15 +831,15 @@ unsigned int max_possible_capacity = 1024; /* max(rq->max_possible_capacity) */
unsigned int
min_max_possible_capacity = 1024; /* min(rq->max_possible_capacity) */
-/* Window size (in ns) */
-__read_mostly unsigned int sched_ravg_window = 10000000;
-
/* Min window size (in ns) = 10ms */
#define MIN_SCHED_RAVG_WINDOW 10000000
/* Max window size (in ns) = 1s */
#define MAX_SCHED_RAVG_WINDOW 1000000000
+/* Window size (in ns) */
+__read_mostly unsigned int sched_ravg_window = MIN_SCHED_RAVG_WINDOW;
+
/* Temporarily disable window-stats activity on all cpus */
unsigned int __read_mostly sched_disable_window_stats;
@@ -851,6 +859,21 @@ static DEFINE_RWLOCK(related_thread_group_lock);
list_for_each_entry(grp, &related_thread_groups, list)
/*
+ * Task load is categorized into buckets for the purpose of top task tracking.
+ * The entire range of load from 0 to sched_ravg_window needs to be covered
+ * in NUM_LOAD_INDICES number of buckets. Therefore the size of each bucket
+ * is given by sched_ravg_window / NUM_LOAD_INDICES. Since the default value
+ * of sched_ravg_window is MIN_SCHED_RAVG_WINDOW, use that to compute
+ * sched_load_granule.
+ */
+__read_mostly unsigned int sched_load_granule =
+ MIN_SCHED_RAVG_WINDOW / NUM_LOAD_INDICES;
+
+/* Size of bitmaps maintained to track top tasks */
+static const unsigned int top_tasks_bitmap_size =
+ BITS_TO_LONGS(NUM_LOAD_INDICES + 1) * sizeof(unsigned long);
+
+/*
* Demand aggregation for frequency purpose:
*
* 'sched_freq_aggregate' controls aggregation of cpu demand of related threads
@@ -1505,7 +1528,7 @@ static inline int invalid_value(unsigned int *data)
/*
* Handle "atomic" update of sysctl_sched_window_stats_policy,
- * sysctl_sched_ravg_hist_size and sched_freq_legacy_mode variables.
+ * sysctl_sched_ravg_hist_size variables.
*/
int sched_window_update_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
@@ -1611,7 +1634,7 @@ unsigned int cpu_temp(int cpu)
return 0;
}
-void init_new_task_load(struct task_struct *p)
+void init_new_task_load(struct task_struct *p, bool idle_task)
{
int i;
u32 init_load_windows = sched_init_task_load_windows;
@@ -1623,6 +1646,15 @@ void init_new_task_load(struct task_struct *p)
memset(&p->ravg, 0, sizeof(struct ravg));
p->cpu_cycles = 0;
+ p->ravg.curr_window_cpu = kcalloc(nr_cpu_ids, sizeof(u32), GFP_ATOMIC);
+ p->ravg.prev_window_cpu = kcalloc(nr_cpu_ids, sizeof(u32), GFP_ATOMIC);
+
+ /* Don't have much choice. CPU frequency would be bogus */
+ BUG_ON(!p->ravg.curr_window_cpu || !p->ravg.prev_window_cpu);
+
+ if (idle_task)
+ return;
+
if (init_load_pct)
init_load_windows = div64_u64((u64)init_load_pct *
(u64)sched_ravg_window, 100);
@@ -2161,6 +2193,174 @@ void update_task_pred_demand(struct rq *rq, struct task_struct *p, int event)
p->ravg.pred_demand = new;
}
+void clear_top_tasks_bitmap(unsigned long *bitmap)
+{
+ memset(bitmap, 0, top_tasks_bitmap_size);
+ __set_bit(NUM_LOAD_INDICES, bitmap);
+}
+
+/*
+ * Special case the last index and provide a fast path for index = 0.
+ * Note that sched_load_granule can change underneath us if we are not
+ * holding any runqueue locks while calling the two functions below.
+ */
+static u32 top_task_load(struct rq *rq)
+{
+ int index = rq->prev_top;
+ u8 prev = 1 - rq->curr_table;
+
+ if (!index) {
+ int msb = NUM_LOAD_INDICES - 1;
+
+ if (!test_bit(msb, rq->top_tasks_bitmap[prev]))
+ return 0;
+ else
+ return sched_load_granule;
+ } else if (index == NUM_LOAD_INDICES - 1) {
+ return sched_ravg_window;
+ } else {
+ return (index + 1) * sched_load_granule;
+ }
+}
+
+static int load_to_index(u32 load)
+{
+ if (load < sched_load_granule)
+ return 0;
+ else if (load >= sched_ravg_window)
+ return NUM_LOAD_INDICES - 1;
+ else
+ return load / sched_load_granule;
+}
+
+static void update_top_tasks(struct task_struct *p, struct rq *rq,
+ u32 old_curr_window, int new_window, bool full_window)
+{
+ u8 curr = rq->curr_table;
+ u8 prev = 1 - curr;
+ u8 *curr_table = rq->top_tasks[curr];
+ u8 *prev_table = rq->top_tasks[prev];
+ int old_index, new_index, update_index;
+ u32 curr_window = p->ravg.curr_window;
+ u32 prev_window = p->ravg.prev_window;
+ bool zero_index_update;
+
+ if (old_curr_window == curr_window && !new_window)
+ return;
+
+ old_index = load_to_index(old_curr_window);
+ new_index = load_to_index(curr_window);
+
+ if (!new_window) {
+ zero_index_update = !old_curr_window && curr_window;
+ if (old_index != new_index || zero_index_update) {
+ if (old_curr_window)
+ curr_table[old_index] -= 1;
+ if (curr_window)
+ curr_table[new_index] += 1;
+ if (new_index > rq->curr_top)
+ rq->curr_top = new_index;
+ }
+
+ if (!curr_table[old_index])
+ __clear_bit(NUM_LOAD_INDICES - old_index - 1,
+ rq->top_tasks_bitmap[curr]);
+
+ if (curr_table[new_index] == 1)
+ __set_bit(NUM_LOAD_INDICES - new_index - 1,
+ rq->top_tasks_bitmap[curr]);
+
+ return;
+ }
+
+ /*
+ * The window has rolled over for this task. By the time we get
+ * here, curr/prev swaps would has already occurred. So we need
+ * to use prev_window for the new index.
+ */
+ update_index = load_to_index(prev_window);
+
+ if (full_window) {
+ /*
+ * Two cases here. Either 'p' ran for the entire window or
+ * it didn't run at all. In either case there is no entry
+ * in the prev table. If 'p' ran the entire window, we just
+ * need to create a new entry in the prev table. In this case
+ * update_index will be correspond to sched_ravg_window
+ * so we can unconditionally update the top index.
+ */
+ if (prev_window) {
+ prev_table[update_index] += 1;
+ rq->prev_top = update_index;
+ }
+
+ if (prev_table[update_index] == 1)
+ __set_bit(NUM_LOAD_INDICES - update_index - 1,
+ rq->top_tasks_bitmap[prev]);
+ } else {
+ zero_index_update = !old_curr_window && prev_window;
+ if (old_index != update_index || zero_index_update) {
+ if (old_curr_window)
+ prev_table[old_index] -= 1;
+
+ prev_table[update_index] += 1;
+
+ if (update_index > rq->prev_top)
+ rq->prev_top = update_index;
+
+ if (!prev_table[old_index])
+ __clear_bit(NUM_LOAD_INDICES - old_index - 1,
+ rq->top_tasks_bitmap[prev]);
+
+ if (prev_table[update_index] == 1)
+ __set_bit(NUM_LOAD_INDICES - update_index - 1,
+ rq->top_tasks_bitmap[prev]);
+ }
+ }
+
+ if (curr_window) {
+ curr_table[new_index] += 1;
+
+ if (new_index > rq->curr_top)
+ rq->curr_top = new_index;
+
+ if (curr_table[new_index] == 1)
+ __set_bit(NUM_LOAD_INDICES - new_index - 1,
+ rq->top_tasks_bitmap[curr]);
+ }
+}
+
+static inline void clear_top_tasks_table(u8 *table)
+{
+ memset(table, 0, NUM_LOAD_INDICES * sizeof(u8));
+}
+
+static u32 empty_windows[NR_CPUS];
+
+static void rollover_task_window(struct task_struct *p, bool full_window)
+{
+ u32 *curr_cpu_windows = empty_windows;
+ u32 curr_window;
+ int i;
+
+ /* Rollover the sum */
+ curr_window = 0;
+
+ if (!full_window) {
+ curr_window = p->ravg.curr_window;
+ curr_cpu_windows = p->ravg.curr_window_cpu;
+ }
+
+ p->ravg.prev_window = curr_window;
+ p->ravg.curr_window = 0;
+
+ /* Roll over individual CPU contributions */
+ for (i = 0; i < nr_cpu_ids; i++) {
+ p->ravg.prev_window_cpu[i] = curr_cpu_windows[i];
+ p->ravg.curr_window_cpu[i] = 0;
+ }
+}
+
/*
* Account cpu activity in its busy time counters (rq->curr/prev_runnable_sum)
*/
@@ -2181,6 +2381,8 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
int prev_sum_reset = 0;
bool new_task;
struct related_thread_group *grp;
+ int cpu = rq->cpu;
+ u32 old_curr_window;
new_window = mark_start < window_start;
if (new_window) {
@@ -2240,57 +2442,43 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
* Handle per-task window rollover. We don't care about the idle
* task or exiting tasks.
*/
- if (new_window && !is_idle_task(p) && !exiting_task(p)) {
- u32 curr_window = 0;
+ if (!is_idle_task(p) && !exiting_task(p)) {
+ old_curr_window = p->ravg.curr_window;
- if (!full_window)
- curr_window = p->ravg.curr_window;
-
- p->ravg.prev_window = curr_window;
- p->ravg.curr_window = 0;
+ if (new_window)
+ rollover_task_window(p, full_window);
}
if (flip_counters) {
u64 curr_sum = *curr_runnable_sum;
u64 nt_curr_sum = *nt_curr_runnable_sum;
+ u8 curr_table = rq->curr_table;
+ u8 prev_table = 1 - curr_table;
+ int curr_top = rq->curr_top;
- if (prev_sum_reset)
+ clear_top_tasks_table(rq->top_tasks[prev_table]);
+ clear_top_tasks_bitmap(rq->top_tasks_bitmap[prev_table]);
+
+ if (prev_sum_reset) {
curr_sum = nt_curr_sum = 0;
+ curr_top = 0;
+ clear_top_tasks_table(rq->top_tasks[curr_table]);
+ clear_top_tasks_bitmap(
+ rq->top_tasks_bitmap[curr_table]);
+ }
*prev_runnable_sum = curr_sum;
*nt_prev_runnable_sum = nt_curr_sum;
*curr_runnable_sum = 0;
*nt_curr_runnable_sum = 0;
+ rq->curr_table = prev_table;
+ rq->prev_top = curr_top;
+ rq->curr_top = 0;
}
- if (!account_busy_for_cpu_time(rq, p, irqtime, event)) {
- /*
- * account_busy_for_cpu_time() = 0, so no update to the
- * task's current window needs to be made. This could be
- * for example
- *
- * - a wakeup event on a task within the current
- * window (!new_window below, no action required),
- * - switching to a new task from idle (PICK_NEXT_TASK)
- * in a new window where irqtime is 0 and we aren't
- * waiting on IO
- */
-
- if (!new_window)
- return;
-
- /*
- * A new window has started. The RQ demand must be rolled
- * over if p is the current task.
- */
- if (p_is_curr_task) {
- /* p is idle task */
- BUG_ON(p != rq->idle);
- }
-
- return;
- }
+ if (!account_busy_for_cpu_time(rq, p, irqtime, event))
+ goto done;
if (!new_window) {
/*
@@ -2310,10 +2498,12 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
if (new_task)
*nt_curr_runnable_sum += delta;
- if (!is_idle_task(p) && !exiting_task(p))
+ if (!is_idle_task(p) && !exiting_task(p)) {
p->ravg.curr_window += delta;
+ p->ravg.curr_window_cpu[cpu] += delta;
+ }
- return;
+ goto done;
}
if (!p_is_curr_task) {
@@ -2336,8 +2526,10 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
* contribution to previous completed window.
*/
delta = scale_exec_time(window_start - mark_start, rq);
- if (!exiting_task(p))
+ if (!exiting_task(p)) {
p->ravg.prev_window += delta;
+ p->ravg.prev_window_cpu[cpu] += delta;
+ }
} else {
/*
* Since at least one full window has elapsed,
@@ -2345,8 +2537,10 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
* full window (window_size).
*/
delta = scale_exec_time(window_size, rq);
- if (!exiting_task(p))
+ if (!exiting_task(p)) {
p->ravg.prev_window = delta;
+ p->ravg.prev_window_cpu[cpu] = delta;
+ }
}
*prev_runnable_sum += delta;
@@ -2359,10 +2553,12 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
if (new_task)
*nt_curr_runnable_sum += delta;
- if (!exiting_task(p))
+ if (!exiting_task(p)) {
p->ravg.curr_window = delta;
+ p->ravg.curr_window_cpu[cpu] = delta;
+ }
- return;
+ goto done;
}
if (!irqtime || !is_idle_task(p) || cpu_is_waiting_on_io(rq)) {
@@ -2386,8 +2582,10 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
* contribution to previous completed window.
*/
delta = scale_exec_time(window_start - mark_start, rq);
- if (!is_idle_task(p) && !exiting_task(p))
+ if (!is_idle_task(p) && !exiting_task(p)) {
p->ravg.prev_window += delta;
+ p->ravg.prev_window_cpu[cpu] += delta;
+ }
} else {
/*
* Since at least one full window has elapsed,
@@ -2395,8 +2593,10 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
* full window (window_size).
*/
delta = scale_exec_time(window_size, rq);
- if (!is_idle_task(p) && !exiting_task(p))
+ if (!is_idle_task(p) && !exiting_task(p)) {
p->ravg.prev_window = delta;
+ p->ravg.prev_window_cpu[cpu] = delta;
+ }
}
/*
@@ -2413,10 +2613,12 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
if (new_task)
*nt_curr_runnable_sum += delta;
- if (!is_idle_task(p) && !exiting_task(p))
+ if (!is_idle_task(p) && !exiting_task(p)) {
p->ravg.curr_window = delta;
+ p->ravg.curr_window_cpu[cpu] = delta;
+ }
- return;
+ goto done;
}
if (irqtime) {
@@ -2461,7 +2663,10 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
return;
}
- BUG();
+done:
+ if (!is_idle_task(p) && !exiting_task(p))
+ update_top_tasks(p, rq, old_curr_window,
+ new_window, full_window);
}
static inline u32 predict_and_update_buckets(struct rq *rq,
@@ -2829,11 +3034,23 @@ void sched_account_irqstart(int cpu, struct task_struct *curr, u64 wallclock)
void reset_task_stats(struct task_struct *p)
{
u32 sum = 0;
+ u32 *curr_window_ptr = NULL;
+ u32 *prev_window_ptr = NULL;
- if (exiting_task(p))
+ if (exiting_task(p)) {
sum = EXITING_TASK_MARKER;
+ } else {
+ curr_window_ptr = p->ravg.curr_window_cpu;
+ prev_window_ptr = p->ravg.prev_window_cpu;
+ memset(curr_window_ptr, 0, sizeof(u32) * nr_cpu_ids);
+ memset(prev_window_ptr, 0, sizeof(u32) * nr_cpu_ids);
+ }
memset(&p->ravg, 0, sizeof(struct ravg));
+
+ p->ravg.curr_window_cpu = curr_window_ptr;
+ p->ravg.prev_window_cpu = prev_window_ptr;
+
/* Retain EXITING_TASK marker */
p->ravg.sum_history[0] = sum;
}
@@ -2889,7 +3106,9 @@ static void reset_all_task_stats(void)
read_lock(&tasklist_lock);
do_each_thread(g, p) {
+ raw_spin_lock(&p->pi_lock);
reset_task_stats(p);
+ raw_spin_unlock(&p->pi_lock);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
}
@@ -2934,7 +3153,7 @@ const char *sched_window_reset_reasons[] = {
/* Called with IRQs enabled */
void reset_all_window_stats(u64 window_start, unsigned int window_size)
{
- int cpu;
+ int cpu, i;
unsigned long flags;
u64 start_ts = sched_ktime_clock();
int reason = WINDOW_CHANGE;
@@ -2968,6 +3187,7 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size)
if (window_size) {
sched_ravg_window = window_size * TICK_NSEC;
set_hmp_defaults();
+ sched_load_granule = sched_ravg_window / NUM_LOAD_INDICES;
}
enable_window_stats();
@@ -2979,6 +3199,16 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size)
rq->window_start = window_start;
rq->curr_runnable_sum = rq->prev_runnable_sum = 0;
rq->nt_curr_runnable_sum = rq->nt_prev_runnable_sum = 0;
+ for (i = 0; i < NUM_TRACKED_WINDOWS; i++) {
+ memset(&rq->load_subs[i], 0,
+ sizeof(struct load_subtractions));
+ clear_top_tasks_table(rq->top_tasks[i]);
+ clear_top_tasks_bitmap(rq->top_tasks_bitmap[i]);
+ }
+
+ rq->curr_table = 0;
+ rq->curr_top = 0;
+ rq->prev_top = 0;
reset_cpu_hmp_stats(cpu, 1);
}
@@ -3011,6 +3241,59 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size)
sched_ktime_clock() - start_ts, reason, old, new);
}
+/*
+ * In this function we match the accumulated subtractions with the current
+ * and previous windows we are operating with. Ignore any entries where
+ * the window start in the load_subtraction struct does not match either
+ * the curent or the previous window. This could happen whenever CPUs
+ * become idle or busy with interrupts disabled for an extended period.
+ */
+static inline void account_load_subtractions(struct rq *rq)
+{
+ u64 ws = rq->window_start;
+ u64 prev_ws = ws - sched_ravg_window;
+ struct load_subtractions *ls = rq->load_subs;
+ int i;
+
+ for (i = 0; i < NUM_TRACKED_WINDOWS; i++) {
+ if (ls[i].window_start == ws) {
+ rq->curr_runnable_sum -= ls[i].subs;
+ rq->nt_curr_runnable_sum -= ls[i].new_subs;
+ } else if (ls[i].window_start == prev_ws) {
+ rq->prev_runnable_sum -= ls[i].subs;
+ rq->nt_prev_runnable_sum -= ls[i].new_subs;
+ }
+
+ ls[i].subs = 0;
+ ls[i].new_subs = 0;
+ }
+
+ BUG_ON((s64)rq->prev_runnable_sum < 0);
+ BUG_ON((s64)rq->curr_runnable_sum < 0);
+ BUG_ON((s64)rq->nt_prev_runnable_sum < 0);
+ BUG_ON((s64)rq->nt_curr_runnable_sum < 0);
+}
+
+static inline u64 freq_policy_load(struct rq *rq, u64 load)
+{
+ unsigned int reporting_policy = sysctl_sched_freq_reporting_policy;
+
+ switch (reporting_policy) {
+ case FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK:
+ load = max_t(u64, load, top_task_load(rq));
+ break;
+ case FREQ_REPORT_TOP_TASK:
+ load = top_task_load(rq);
+ break;
+ case FREQ_REPORT_CPU_LOAD:
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ return load;
+}
+
static inline void
sync_window_start(struct rq *rq, struct group_cpu_time *cpu_time);
@@ -3033,6 +3316,7 @@ void sched_get_cpus_busy(struct sched_load *busy,
struct related_thread_group *grp;
u64 total_group_load = 0, total_ngload = 0;
bool aggregate_load = false;
+ struct sched_cluster *cluster = cpu_cluster(cpumask_first(query_cpus));
if (unlikely(cpus == 0))
return;
@@ -3050,6 +3334,13 @@ void sched_get_cpus_busy(struct sched_load *busy,
window_size = sched_ravg_window;
+ /*
+ * We don't really need the cluster lock for this entire for loop
+ * block. However, there is no advantage in optimizing this as rq
+ * locks are held regardless and would prevent migration anyways
+ */
+ raw_spin_lock(&cluster->load_lock);
+
for_each_cpu(cpu, query_cpus) {
rq = cpu_rq(cpu);
@@ -3057,6 +3348,7 @@ void sched_get_cpus_busy(struct sched_load *busy,
0);
cur_freq[i] = cpu_cycles_to_freq(rq->cc.cycles, rq->cc.time);
+ account_load_subtractions(rq);
load[i] = rq->old_busy_time = rq->prev_runnable_sum;
nload[i] = rq->nt_prev_runnable_sum;
pload[i] = rq->hmp_stats.pred_demands_sum;
@@ -3083,6 +3375,8 @@ void sched_get_cpus_busy(struct sched_load *busy,
i++;
}
+ raw_spin_unlock(&cluster->load_lock);
+
for_each_related_thread_group(grp) {
for_each_cpu(cpu, query_cpus) {
/* Protected by rq_lock */
@@ -3117,6 +3411,8 @@ void sched_get_cpus_busy(struct sched_load *busy,
load[i] += group_load[i];
nload[i] += ngload[i];
+
+ load[i] = freq_policy_load(rq, load[i]);
/*
* Scale load in reference to cluster max_possible_freq.
*
@@ -3237,6 +3533,189 @@ int sched_set_window(u64 window_start, unsigned int window_size)
return 0;
}
+static inline void create_subtraction_entry(struct rq *rq, u64 ws, int index)
+{
+ rq->load_subs[index].window_start = ws;
+ rq->load_subs[index].subs = 0;
+ rq->load_subs[index].new_subs = 0;
+}
+
+static bool get_subtraction_index(struct rq *rq, u64 ws)
+{
+ int i;
+ u64 oldest = ULLONG_MAX;
+ int oldest_index = 0;
+
+ for (i = 0; i < NUM_TRACKED_WINDOWS; i++) {
+ u64 entry_ws = rq->load_subs[i].window_start;
+
+ if (ws == entry_ws)
+ return i;
+
+ if (entry_ws < oldest) {
+ oldest = entry_ws;
+ oldest_index = i;
+ }
+ }
+
+ create_subtraction_entry(rq, ws, oldest_index);
+ return oldest_index;
+}
+
+static void update_rq_load_subtractions(int index, struct rq *rq,
+ u32 sub_load, bool new_task)
+{
+ rq->load_subs[index].subs += sub_load;
+ if (new_task)
+ rq->load_subs[index].new_subs += sub_load;
+}
+
+static void update_cluster_load_subtractions(struct task_struct *p,
+ int cpu, u64 ws, bool new_task)
+{
+ struct sched_cluster *cluster = cpu_cluster(cpu);
+ struct cpumask cluster_cpus = cluster->cpus;
+ u64 prev_ws = ws - sched_ravg_window;
+ int i;
+
+ cpumask_clear_cpu(cpu, &cluster_cpus);
+ raw_spin_lock(&cluster->load_lock);
+
+ for_each_cpu(i, &cluster_cpus) {
+ struct rq *rq = cpu_rq(i);
+ int index;
+
+ if (p->ravg.curr_window_cpu[i]) {
+ index = get_subtraction_index(rq, ws);
+ update_rq_load_subtractions(index, rq,
+ p->ravg.curr_window_cpu[i], new_task);
+ p->ravg.curr_window_cpu[i] = 0;
+ }
+
+ if (p->ravg.prev_window_cpu[i]) {
+ index = get_subtraction_index(rq, prev_ws);
+ update_rq_load_subtractions(index, rq,
+ p->ravg.prev_window_cpu[i], new_task);
+ p->ravg.prev_window_cpu[i] = 0;
+ }
+ }
+
+ raw_spin_unlock(&cluster->load_lock);
+}
+
+static inline void inter_cluster_migration_fixup
+ (struct task_struct *p, int new_cpu, int task_cpu, bool new_task)
+{
+ struct rq *dest_rq = cpu_rq(new_cpu);
+ struct rq *src_rq = cpu_rq(task_cpu);
+
+ if (same_freq_domain(new_cpu, task_cpu))
+ return;
+
+ p->ravg.curr_window_cpu[new_cpu] = p->ravg.curr_window;
+ p->ravg.prev_window_cpu[new_cpu] = p->ravg.prev_window;
+
+ dest_rq->curr_runnable_sum += p->ravg.curr_window;
+ dest_rq->prev_runnable_sum += p->ravg.prev_window;
+
+ src_rq->curr_runnable_sum -= p->ravg.curr_window_cpu[task_cpu];
+ src_rq->prev_runnable_sum -= p->ravg.prev_window_cpu[task_cpu];
+
+ if (new_task) {
+ dest_rq->nt_curr_runnable_sum += p->ravg.curr_window;
+ dest_rq->nt_prev_runnable_sum += p->ravg.prev_window;
+
+ src_rq->nt_curr_runnable_sum -=
+ p->ravg.curr_window_cpu[task_cpu];
+ src_rq->nt_prev_runnable_sum -=
+ p->ravg.prev_window_cpu[task_cpu];
+ }
+
+ p->ravg.curr_window_cpu[task_cpu] = 0;
+ p->ravg.prev_window_cpu[task_cpu] = 0;
+
+ update_cluster_load_subtractions(p, task_cpu,
+ src_rq->window_start, new_task);
+
+ BUG_ON((s64)src_rq->prev_runnable_sum < 0);
+ BUG_ON((s64)src_rq->curr_runnable_sum < 0);
+ BUG_ON((s64)src_rq->nt_prev_runnable_sum < 0);
+ BUG_ON((s64)src_rq->nt_curr_runnable_sum < 0);
+}
+
+static int get_top_index(unsigned long *bitmap, unsigned long old_top)
+{
+ int index = find_next_bit(bitmap, NUM_LOAD_INDICES, old_top);
+
+ if (index == NUM_LOAD_INDICES)
+ return 0;
+
+ return NUM_LOAD_INDICES - 1 - index;
+}
+
+static void
+migrate_top_tasks(struct task_struct *p, struct rq *src_rq, struct rq *dst_rq)
+{
+ int index;
+ int top_index;
+ u32 curr_window = p->ravg.curr_window;
+ u32 prev_window = p->ravg.prev_window;
+ u8 src = src_rq->curr_table;
+ u8 dst = dst_rq->curr_table;
+ u8 *src_table;
+ u8 *dst_table;
+
+ if (curr_window) {
+ src_table = src_rq->top_tasks[src];
+ dst_table = dst_rq->top_tasks[dst];
+ index = load_to_index(curr_window);
+ src_table[index] -= 1;
+ dst_table[index] += 1;
+
+ if (!src_table[index])
+ __clear_bit(NUM_LOAD_INDICES - index - 1,
+ src_rq->top_tasks_bitmap[src]);
+
+ if (dst_table[index] == 1)
+ __set_bit(NUM_LOAD_INDICES - index - 1,
+ dst_rq->top_tasks_bitmap[dst]);
+
+ if (index > dst_rq->curr_top)
+ dst_rq->curr_top = index;
+
+ top_index = src_rq->curr_top;
+ if (index == top_index && !src_table[index])
+ src_rq->curr_top = get_top_index(
+ src_rq->top_tasks_bitmap[src], top_index);
+ }
+
+ if (prev_window) {
+ src = 1 - src;
+ dst = 1 - dst;
+ src_table = src_rq->top_tasks[src];
+ dst_table = dst_rq->top_tasks[dst];
+ index = load_to_index(prev_window);
+ src_table[index] -= 1;
+ dst_table[index] += 1;
+
+ if (!src_table[index])
+ __clear_bit(NUM_LOAD_INDICES - index - 1,
+ src_rq->top_tasks_bitmap[src]);
+
+ if (dst_table[index] == 1)
+ __set_bit(NUM_LOAD_INDICES - index - 1,
+ dst_rq->top_tasks_bitmap[dst]);
+
+ if (index > dst_rq->prev_top)
+ dst_rq->prev_top = index;
+
+ top_index = src_rq->prev_top;
+ if (index == top_index && !src_table[index])
+ src_rq->prev_top = get_top_index(
+ src_rq->top_tasks_bitmap[src], top_index);
+ }
+}
+
void fixup_busy_time(struct task_struct *p, int new_cpu)
{
struct rq *src_rq = task_rq(p);
@@ -3246,8 +3725,6 @@ void fixup_busy_time(struct task_struct *p, int new_cpu)
u64 *src_prev_runnable_sum, *dst_prev_runnable_sum;
u64 *src_nt_curr_runnable_sum, *dst_nt_curr_runnable_sum;
u64 *src_nt_prev_runnable_sum, *dst_nt_prev_runnable_sum;
- int migrate_type;
- struct migration_sum_data d;
bool new_task;
struct related_thread_group *grp;
@@ -3281,75 +3758,62 @@ void fixup_busy_time(struct task_struct *p, int new_cpu)
new_task = is_new_task(p);
/* Protected by rq_lock */
grp = p->grp;
+
+ /*
+ * For frequency aggregation, we continue to do migration fixups
+ * even for intra cluster migrations. This is because, the aggregated
+ * load has to reported on a single CPU regardless.
+ */
if (grp && sched_freq_aggregate) {
struct group_cpu_time *cpu_time;
- migrate_type = GROUP_TO_GROUP;
- /* Protected by rq_lock */
cpu_time = _group_cpu_time(grp, cpu_of(src_rq));
- d.src_rq = NULL;
- d.src_cpu_time = cpu_time;
src_curr_runnable_sum = &cpu_time->curr_runnable_sum;
src_prev_runnable_sum = &cpu_time->prev_runnable_sum;
src_nt_curr_runnable_sum = &cpu_time->nt_curr_runnable_sum;
src_nt_prev_runnable_sum = &cpu_time->nt_prev_runnable_sum;
- /* Protected by rq_lock */
cpu_time = _group_cpu_time(grp, cpu_of(dest_rq));
- d.dst_rq = NULL;
- d.dst_cpu_time = cpu_time;
dst_curr_runnable_sum = &cpu_time->curr_runnable_sum;
dst_prev_runnable_sum = &cpu_time->prev_runnable_sum;
dst_nt_curr_runnable_sum = &cpu_time->nt_curr_runnable_sum;
dst_nt_prev_runnable_sum = &cpu_time->nt_prev_runnable_sum;
sync_window_start(dest_rq, cpu_time);
- } else {
- migrate_type = RQ_TO_RQ;
- d.src_rq = src_rq;
- d.src_cpu_time = NULL;
- d.dst_rq = dest_rq;
- d.dst_cpu_time = NULL;
- src_curr_runnable_sum = &src_rq->curr_runnable_sum;
- src_prev_runnable_sum = &src_rq->prev_runnable_sum;
- src_nt_curr_runnable_sum = &src_rq->nt_curr_runnable_sum;
- src_nt_prev_runnable_sum = &src_rq->nt_prev_runnable_sum;
-
- dst_curr_runnable_sum = &dest_rq->curr_runnable_sum;
- dst_prev_runnable_sum = &dest_rq->prev_runnable_sum;
- dst_nt_curr_runnable_sum = &dest_rq->nt_curr_runnable_sum;
- dst_nt_prev_runnable_sum = &dest_rq->nt_prev_runnable_sum;
- }
- if (p->ravg.curr_window) {
- *src_curr_runnable_sum -= p->ravg.curr_window;
- *dst_curr_runnable_sum += p->ravg.curr_window;
- if (new_task) {
- *src_nt_curr_runnable_sum -= p->ravg.curr_window;
- *dst_nt_curr_runnable_sum += p->ravg.curr_window;
+ if (p->ravg.curr_window) {
+ *src_curr_runnable_sum -= p->ravg.curr_window;
+ *dst_curr_runnable_sum += p->ravg.curr_window;
+ if (new_task) {
+ *src_nt_curr_runnable_sum -=
+ p->ravg.curr_window;
+ *dst_nt_curr_runnable_sum +=
+ p->ravg.curr_window;
+ }
}
- }
- if (p->ravg.prev_window) {
- *src_prev_runnable_sum -= p->ravg.prev_window;
- *dst_prev_runnable_sum += p->ravg.prev_window;
- if (new_task) {
- *src_nt_prev_runnable_sum -= p->ravg.prev_window;
- *dst_nt_prev_runnable_sum += p->ravg.prev_window;
+ if (p->ravg.prev_window) {
+ *src_prev_runnable_sum -= p->ravg.prev_window;
+ *dst_prev_runnable_sum += p->ravg.prev_window;
+ if (new_task) {
+ *src_nt_prev_runnable_sum -=
+ p->ravg.prev_window;
+ *dst_nt_prev_runnable_sum +=
+ p->ravg.prev_window;
+ }
}
+ } else {
+ inter_cluster_migration_fixup(p, new_cpu,
+ task_cpu(p), new_task);
}
+ migrate_top_tasks(p, src_rq, dest_rq);
+
if (p == src_rq->ed_task) {
src_rq->ed_task = NULL;
if (!dest_rq->ed_task)
dest_rq->ed_task = p;
}
- trace_sched_migration_update_sum(p, migrate_type, &d);
- BUG_ON((s64)*src_prev_runnable_sum < 0);
- BUG_ON((s64)*src_curr_runnable_sum < 0);
- BUG_ON((s64)*src_nt_prev_runnable_sum < 0);
- BUG_ON((s64)*src_nt_curr_runnable_sum < 0);
-
done:
if (p->state == TASK_WAKING)
double_rq_unlock(src_rq, dest_rq);
@@ -3501,6 +3965,9 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp,
u64 *src_nt_prev_runnable_sum, *dst_nt_prev_runnable_sum;
struct migration_sum_data d;
int migrate_type;
+ int cpu = cpu_of(rq);
+ bool new_task = is_new_task(p);
+ int i;
if (!sched_freq_aggregate)
return;
@@ -3511,7 +3978,7 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp,
update_task_ravg(p, rq, TASK_UPDATE, wallclock, 0);
/* cpu_time protected by related_thread_group_lock, grp->lock rq_lock */
- cpu_time = _group_cpu_time(grp, cpu_of(rq));
+ cpu_time = _group_cpu_time(grp, cpu);
if (event == ADD_TASK) {
sync_window_start(rq, cpu_time);
migrate_type = RQ_TO_GROUP;
@@ -3528,6 +3995,19 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp,
dst_nt_curr_runnable_sum = &cpu_time->nt_curr_runnable_sum;
src_nt_prev_runnable_sum = &rq->nt_prev_runnable_sum;
dst_nt_prev_runnable_sum = &cpu_time->nt_prev_runnable_sum;
+
+ *src_curr_runnable_sum -= p->ravg.curr_window_cpu[cpu];
+ *src_prev_runnable_sum -= p->ravg.prev_window_cpu[cpu];
+ if (new_task) {
+ *src_nt_curr_runnable_sum -=
+ p->ravg.curr_window_cpu[cpu];
+ *src_nt_prev_runnable_sum -=
+ p->ravg.prev_window_cpu[cpu];
+ }
+
+ update_cluster_load_subtractions(p, cpu,
+ rq->window_start, new_task);
+
} else {
migrate_type = GROUP_TO_RQ;
d.src_rq = NULL;
@@ -3550,21 +4030,42 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp,
dst_nt_curr_runnable_sum = &rq->nt_curr_runnable_sum;
src_nt_prev_runnable_sum = &cpu_time->nt_prev_runnable_sum;
dst_nt_prev_runnable_sum = &rq->nt_prev_runnable_sum;
+
+ *src_curr_runnable_sum -= p->ravg.curr_window;
+ *src_prev_runnable_sum -= p->ravg.prev_window;
+ if (new_task) {
+ *src_nt_curr_runnable_sum -= p->ravg.curr_window;
+ *src_nt_prev_runnable_sum -= p->ravg.prev_window;
+ }
+
+ /*
+ * Need to reset curr/prev windows for all CPUs, not just the
+ * ones in the same cluster. Since inter cluster migrations
+ * did not result in the appropriate book keeping, the values
+ * per CPU would be inaccurate.
+ */
+ for_each_possible_cpu(i) {
+ p->ravg.curr_window_cpu[i] = 0;
+ p->ravg.prev_window_cpu[i] = 0;
+ }
}
- *src_curr_runnable_sum -= p->ravg.curr_window;
*dst_curr_runnable_sum += p->ravg.curr_window;
-
- *src_prev_runnable_sum -= p->ravg.prev_window;
*dst_prev_runnable_sum += p->ravg.prev_window;
-
- if (is_new_task(p)) {
- *src_nt_curr_runnable_sum -= p->ravg.curr_window;
+ if (new_task) {
*dst_nt_curr_runnable_sum += p->ravg.curr_window;
- *src_nt_prev_runnable_sum -= p->ravg.prev_window;
*dst_nt_prev_runnable_sum += p->ravg.prev_window;
}
+ /*
+ * When a task enter or exits a group, it's curr and prev windows are
+ * moved to a single CPU. This behavior might be sub-optimal in the
+ * exit case, however, it saves us the overhead of handling inter
+ * cluster migration fixups while the task is part of a related group.
+ */
+ p->ravg.curr_window_cpu[cpu] = p->ravg.curr_window;
+ p->ravg.prev_window_cpu[cpu] = p->ravg.prev_window;
+
trace_sched_migration_update_sum(p, migrate_type, &d);
BUG_ON((s64)*src_curr_runnable_sum < 0);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 27b28369440d..471dc9faab35 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -351,13 +351,23 @@ struct cfs_bandwidth { };
#ifdef CONFIG_SCHED_HMP
+#define NUM_TRACKED_WINDOWS 2
+#define NUM_LOAD_INDICES 1000
+
struct hmp_sched_stats {
int nr_big_tasks;
u64 cumulative_runnable_avg;
u64 pred_demands_sum;
};
+struct load_subtractions {
+ u64 window_start;
+ u64 subs;
+ u64 new_subs;
+};
+
struct sched_cluster {
+ raw_spinlock_t load_lock;
struct list_head list;
struct cpumask cpus;
int id;
@@ -742,6 +752,13 @@ struct rq {
u64 prev_runnable_sum;
u64 nt_curr_runnable_sum;
u64 nt_prev_runnable_sum;
+ struct load_subtractions load_subs[NUM_TRACKED_WINDOWS];
+ DECLARE_BITMAP_ARRAY(top_tasks_bitmap,
+ NUM_TRACKED_WINDOWS, NUM_LOAD_INDICES);
+ u8 *top_tasks[NUM_TRACKED_WINDOWS];
+ u8 curr_table;
+ int prev_top;
+ int curr_top;
#endif
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
@@ -1017,6 +1034,10 @@ static inline void sched_ttwu_pending(void) { }
#define WINDOW_STATS_AVG 3
#define WINDOW_STATS_INVALID_POLICY 4
+#define FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK 0
+#define FREQ_REPORT_CPU_LOAD 1
+#define FREQ_REPORT_TOP_TASK 2
+
#define MAJOR_TASK_PCT 85
#define SCHED_UPMIGRATE_MIN_NICE 15
#define EXITING_TASK_MARKER 0xdeaddead
@@ -1056,8 +1077,9 @@ extern unsigned int __read_mostly sched_spill_load;
extern unsigned int __read_mostly sched_upmigrate;
extern unsigned int __read_mostly sched_downmigrate;
extern unsigned int __read_mostly sysctl_sched_spill_nr_run;
+extern unsigned int __read_mostly sched_load_granule;
-extern void init_new_task_load(struct task_struct *p);
+extern void init_new_task_load(struct task_struct *p, bool idle_task);
extern u64 sched_ktime_clock(void);
extern int got_boost_kick(void);
extern int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb);
@@ -1401,6 +1423,7 @@ extern int cpu_upmigrate_discourage_write_u64(struct cgroup_subsys_state *css,
struct cftype *cft, u64 upmigrate_discourage);
extern void sched_hmp_parse_dt(void);
extern void init_sched_hmp_boost_policy(void);
+extern void clear_top_tasks_bitmap(unsigned long *bitmap);
#else /* CONFIG_SCHED_HMP */
@@ -1503,7 +1526,9 @@ static inline struct sched_cluster *rq_cluster(struct rq *rq)
return NULL;
}
-static inline void init_new_task_load(struct task_struct *p) { }
+static inline void init_new_task_load(struct task_struct *p, bool idle_task)
+{
+}
static inline u64 scale_load_to_cpu(u64 load, int cpu)
{
@@ -1570,8 +1595,6 @@ static inline int update_preferred_cluster(struct related_thread_group *grp,
static inline void add_new_task_to_grp(struct task_struct *new) {}
#define sched_enable_hmp 0
-#define sched_freq_legacy_mode 1
-#define sched_migration_fixup 0
#define PRED_DEMAND_DELTA (0)
static inline void
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index 6949476a118f..3a0415803b09 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -32,7 +32,7 @@ struct task_struct *idle_thread_get(unsigned int cpu)
if (!tsk)
return ERR_PTR(-ENOMEM);
- init_idle(tsk, cpu);
+ init_idle(tsk, cpu, true);
return tsk;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 587dbe09c47d..c72cb2053da7 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -297,6 +297,14 @@ static struct ctl_table kern_table[] = {
},
#ifdef CONFIG_SCHED_HMP
{
+ .procname = "sched_freq_reporting_policy",
+ .data = &sysctl_sched_freq_reporting_policy,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ },
+ {
.procname = "sched_freq_inc_notify",
.data = &sysctl_sched_freq_inc_notify,
.maxlen = sizeof(unsigned int),
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 0a9c283c250c..70be9c98b481 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -80,7 +80,9 @@
/* Word sizes and min/max lengths */
#define WCD_SPI_WORD_BYTE_CNT (4)
#define WCD_SPI_RW_MULTI_MIN_LEN (16)
-#define WCD_SPI_RW_MULTI_MAX_LEN (64 * 1024)
+
+/* Max size is closest multiple of 16 less than 64Kbytes */
+#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 16)
/* Alignment requirements */
#define WCD_SPI_RW_MIN_ALIGN WCD_SPI_WORD_BYTE_CNT
@@ -104,6 +106,12 @@
mutex_unlock(&lock); \
}
+struct wcd_spi_debug_data {
+ struct dentry *dir;
+ u32 addr;
+ u32 size;
+};
+
struct wcd_spi_priv {
struct spi_device *spi;
u32 mem_base_addr;
@@ -133,6 +141,9 @@ struct wcd_spi_priv {
struct device *m_dev;
struct wdsp_mgr_ops *m_ops;
+
+ /* Debugfs related information */
+ struct wcd_spi_debug_data debug_data;
};
enum xfer_request {
@@ -642,11 +653,10 @@ static int wcd_spi_init(struct spi_device *spi)
regmap_write(wcd_spi->regmap, WCD_SPI_SLAVE_CONFIG,
0x0F3D0800);
- /* Write the MTU to 64K */
+ /* Write the MTU to max allowed size */
regmap_update_bits(wcd_spi->regmap,
WCD_SPI_SLAVE_TRNS_LEN,
- 0xFFFF0000,
- (WCD_SPI_RW_MULTI_MAX_LEN / 4) << 16);
+ 0xFFFF0000, 0xFFFF0000);
err_wr_en:
wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE,
WCD_SPI_CLK_FLAG_IMMEDIATE);
@@ -1012,20 +1022,81 @@ static const struct file_operations state_fops = {
.release = single_release,
};
+static ssize_t wcd_spi_debugfs_mem_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct spi_device *spi = file->private_data;
+ struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+ struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data;
+ struct wcd_spi_msg msg;
+ ssize_t buf_size, read_count = 0;
+ char *buf;
+ int ret;
+
+ if (*ppos < 0 || !count)
+ return -EINVAL;
+
+ if (dbg_data->size == 0 || dbg_data->addr == 0) {
+ dev_err(&spi->dev,
+ "%s: Invalid request, size = %u, addr = 0x%x\n",
+ __func__, dbg_data->size, dbg_data->addr);
+ return 0;
+ }
+
+ buf_size = count < dbg_data->size ? count : dbg_data->size;
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ msg.data = buf;
+ msg.remote_addr = dbg_data->addr;
+ msg.len = buf_size;
+ msg.flags = 0;
+
+ ret = wcd_spi_data_read(spi, &msg);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(&spi->dev,
+ "%s: Failed to read %zu bytes from addr 0x%x\n",
+ __func__, buf_size, msg.remote_addr);
+ goto done;
+ }
+
+ read_count = simple_read_from_buffer(ubuf, count, ppos, buf, buf_size);
+
+done:
+ kfree(buf);
+ if (ret < 0)
+ return ret;
+ else
+ return read_count;
+}
+
+static const struct file_operations mem_read_fops = {
+ .open = simple_open,
+ .read = wcd_spi_debugfs_mem_read,
+};
+
static int wcd_spi_debugfs_init(struct spi_device *spi)
{
+ struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+ struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data;
int rc = 0;
- struct dentry *dir;
- dir = debugfs_create_dir("wcd_spi", NULL);
- if (IS_ERR_OR_NULL(dir)) {
- dir = NULL;
+ dbg_data->dir = debugfs_create_dir("wcd_spi", NULL);
+ if (IS_ERR_OR_NULL(dbg_data->dir)) {
+ dbg_data->dir = NULL;
rc = -ENODEV;
goto done;
}
- debugfs_create_file("state", 0444, dir, spi, &state_fops);
+ debugfs_create_file("state", 0444, dbg_data->dir, spi, &state_fops);
+ debugfs_create_u32("addr", S_IRUGO | S_IWUSR, dbg_data->dir,
+ &dbg_data->addr);
+ debugfs_create_u32("size", S_IRUGO | S_IWUSR, dbg_data->dir,
+ &dbg_data->size);
+ debugfs_create_file("mem_read", S_IRUGO, dbg_data->dir,
+ spi, &mem_read_fops);
done:
return rc;
}
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 9394ee52cad0..b2d4e08a55cc 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -842,6 +842,9 @@ struct tasha_priv {
int rx_8_count;
bool clk_mode;
bool clk_internal;
+
+ /* Lock to protect mclk enablement */
+ struct mutex mclk_lock;
};
static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
@@ -1152,13 +1155,14 @@ static int tasha_cdc_req_mclk_enable(struct tasha_priv *tasha,
{
int ret = 0;
+ mutex_lock(&tasha->mclk_lock);
if (enable) {
tasha_cdc_sido_ccl_enable(tasha, true);
ret = clk_prepare_enable(tasha->wcd_ext_clk);
if (ret) {
dev_err(tasha->dev, "%s: ext clk enable failed\n",
__func__);
- goto err;
+ goto unlock_mutex;
}
/* get BG */
wcd_resmgr_enable_master_bias(tasha->resmgr);
@@ -1172,7 +1176,8 @@ static int tasha_cdc_req_mclk_enable(struct tasha_priv *tasha,
clk_disable_unprepare(tasha->wcd_ext_clk);
tasha_cdc_sido_ccl_enable(tasha, false);
}
-err:
+unlock_mutex:
+ mutex_unlock(&tasha->mclk_lock);
return ret;
}
@@ -14114,6 +14119,7 @@ static int tasha_probe(struct platform_device *pdev)
mutex_init(&tasha->swr_read_lock);
mutex_init(&tasha->swr_write_lock);
mutex_init(&tasha->swr_clk_lock);
+ mutex_init(&tasha->mclk_lock);
cdc_pwr = devm_kzalloc(&pdev->dev, sizeof(struct wcd9xxx_power_region),
GFP_KERNEL);
@@ -14199,6 +14205,7 @@ err_clk:
err_resmgr:
devm_kfree(&pdev->dev, cdc_pwr);
err_cdc_pwr:
+ mutex_destroy(&tasha->mclk_lock);
devm_kfree(&pdev->dev, tasha);
return ret;
}
@@ -14213,6 +14220,7 @@ static int tasha_remove(struct platform_device *pdev)
clk_put(tasha->wcd_ext_clk);
if (tasha->wcd_native_clk)
clk_put(tasha->wcd_native_clk);
+ mutex_destroy(&tasha->mclk_lock);
devm_kfree(&pdev->dev, tasha);
snd_soc_unregister_codec(&pdev->dev);
return 0;
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index c0996e24e3d6..a526e1afdd28 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -358,6 +358,15 @@ enum {
ASRC_MAX,
};
+enum {
+ CONV_88P2K_TO_384K,
+ CONV_96K_TO_352P8K,
+ CONV_352P8K_TO_384K,
+ CONV_384K_TO_352P8K,
+ CONV_384K_TO_384K,
+ CONV_96K_TO_384K,
+};
+
static struct afe_param_slimbus_slave_port_cfg tavil_slimbus_slave_port_cfg = {
.minor_version = 1,
.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
@@ -577,7 +586,7 @@ struct tavil_priv {
/* num of slim ports required */
struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
/* Port values for Rx and Tx codec_dai */
- unsigned int rx_port_value;
+ unsigned int rx_port_value[WCD934X_RX_MAX];
unsigned int tx_port_value;
struct wcd9xxx_resmgr_v2 *resmgr;
@@ -616,6 +625,7 @@ struct tavil_priv {
int native_clk_users;
/* ASRC users count */
int asrc_users[ASRC_MAX];
+ int asrc_output_mode[ASRC_MAX];
/* Main path clock users count */
int main_clk_users[WCD934X_NUM_INTERPOLATORS];
struct tavil_dsd_config *dsd_config;
@@ -1298,7 +1308,8 @@ static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.enumerated.item[0] = tavil_p->rx_port_value;
+ ucontrol->value.enumerated.item[0] =
+ tavil_p->rx_port_value[widget->shift];
return 0;
}
@@ -1313,17 +1324,20 @@ static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
+ unsigned int rx_port_value;
u32 port_id = widget->shift;
+ tavil_p->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
+ rx_port_value = tavil_p->rx_port_value[port_id];
+
mutex_lock(&tavil_p->codec_mutex);
- tavil_p->rx_port_value = ucontrol->value.enumerated.item[0];
dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
__func__, widget->name, ucontrol->id.name,
- tavil_p->rx_port_value, widget->shift,
+ rx_port_value, widget->shift,
ucontrol->value.integer.value[0]);
/* value need to match the Virtual port and AIF number */
- switch (tavil_p->rx_port_value) {
+ switch (rx_port_value) {
case 0:
list_del_init(&core->rx_chs[port_id].list);
break;
@@ -1372,13 +1386,13 @@ static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
&tavil_p->dai[AIF4_PB].wcd9xxx_ch_list);
break;
default:
- dev_err(codec->dev, "Unknown AIF %d\n", tavil_p->rx_port_value);
+ dev_err(codec->dev, "Unknown AIF %d\n", rx_port_value);
goto err;
}
rtn:
mutex_unlock(&tavil_p->codec_mutex);
snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
- tavil_p->rx_port_value, e, update);
+ rx_port_value, e, update);
return 0;
err:
@@ -2592,6 +2606,45 @@ done:
return rc;
}
+static int tavil_get_asrc_mode(struct tavil_priv *tavil, int asrc,
+ u8 main_sr, u8 mix_sr)
+{
+ u8 asrc_output_mode;
+ int asrc_mode = CONV_88P2K_TO_384K;
+
+ if ((asrc < 0) || (asrc >= ASRC_MAX))
+ return 0;
+
+ asrc_output_mode = tavil->asrc_output_mode[asrc];
+
+ if (asrc_output_mode) {
+ /*
+ * If Mix sample rate is < 96KHz, use 96K to 352.8K
+ * conversion, or else use 384K to 352.8K conversion
+ */
+ if (mix_sr < 5)
+ asrc_mode = CONV_96K_TO_352P8K;
+ else
+ asrc_mode = CONV_384K_TO_352P8K;
+ } else {
+ /* Integer main and Fractional mix path */
+ if (main_sr < 8 && mix_sr > 9) {
+ asrc_mode = CONV_352P8K_TO_384K;
+ } else if (main_sr > 8 && mix_sr < 8) {
+ /* Fractional main and Integer mix path */
+ if (mix_sr < 5)
+ asrc_mode = CONV_96K_TO_352P8K;
+ else
+ asrc_mode = CONV_384K_TO_352P8K;
+ } else if (main_sr < 8 && mix_sr < 8) {
+ /* Integer main and Integer mix path */
+ asrc_mode = CONV_96K_TO_384K;
+ }
+ }
+
+ return asrc_mode;
+}
+
static int tavil_codec_enable_asrc(struct snd_soc_codec *codec,
int asrc_in, int event)
{
@@ -2658,19 +2711,8 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec,
main_sr = snd_soc_read(codec, ctl_reg) & 0x0F;
mix_ctl_reg = ctl_reg + 5;
mix_sr = snd_soc_read(codec, mix_ctl_reg) & 0x0F;
- /* Integer main and Fractional mix path */
- if (main_sr < 8 && mix_sr > 9) {
- asrc_mode = 2;
- } else if (main_sr > 8 && mix_sr < 8) {
- /* Fractional main and Integer mix path */
- if (mix_sr < 5)
- asrc_mode = 1;
- else
- asrc_mode = 3;
- } else if (main_sr < 8 && mix_sr < 8) {
- /* Integer main and Integer mix path */
- asrc_mode = 5;
- }
+ asrc_mode = tavil_get_asrc_mode(tavil, asrc,
+ main_sr, mix_sr);
dev_dbg(codec->dev, "%s: main_sr:%d mix_sr:%d asrc_mode %d\n",
__func__, main_sr, mix_sr, asrc_mode);
snd_soc_update_bits(codec, asrc_ctl, 0x07, asrc_mode);
@@ -3560,7 +3602,7 @@ static void tavil_tx_hpf_corner_freq_callback(struct work_struct *work)
struct hpf_work *hpf_work;
struct tavil_priv *tavil;
struct snd_soc_codec *codec;
- u16 dec_cfg_reg, amic_reg;
+ u16 dec_cfg_reg, amic_reg, go_bit_reg;
u8 hpf_cut_off_freq;
int amic_n;
@@ -3571,6 +3613,7 @@ static void tavil_tx_hpf_corner_freq_callback(struct work_struct *work)
hpf_cut_off_freq = hpf_work->hpf_cut_off_freq;
dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator;
+ go_bit_reg = dec_cfg_reg + 7;
dev_dbg(codec->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n",
__func__, hpf_work->decimator, hpf_cut_off_freq);
@@ -3582,6 +3625,10 @@ static void tavil_tx_hpf_corner_freq_callback(struct work_struct *work)
}
snd_soc_update_bits(codec, dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
hpf_cut_off_freq << 5);
+ snd_soc_update_bits(codec, go_bit_reg, 0x02, 0x02);
+ /* Minimum 1 clk cycle delay is required as per HW spec */
+ usleep_range(1000, 1010);
+ snd_soc_update_bits(codec, go_bit_reg, 0x02, 0x00);
}
static void tavil_tx_mute_update_callback(struct work_struct *work)
@@ -3601,7 +3648,6 @@ static void tavil_tx_mute_update_callback(struct work_struct *work)
16 * tx_mute_dwork->decimator;
hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 +
16 * tx_mute_dwork->decimator;
- snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x01);
snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00);
}
@@ -3688,20 +3734,27 @@ static int tavil_codec_enable_dec(struct snd_soc_dapm_widget *w,
break;
}
}
+ /* Enable TX PGA Mute */
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
hpf_cut_off_freq = (snd_soc_read(codec, dec_cfg_reg) &
TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
tavil->tx_hpf_work[decimator].hpf_cut_off_freq =
hpf_cut_off_freq;
- if (hpf_cut_off_freq != CF_MIN_3DB_150HZ)
+ if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
snd_soc_update_bits(codec, dec_cfg_reg,
TX_HPF_CUT_OFF_FREQ_MASK,
CF_MIN_3DB_150HZ << 5);
- /* Enable TX PGA Mute */
- snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
- break;
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x00);
+ snd_soc_update_bits(codec, hpf_gate_reg, 0x02, 0x02);
+ /*
+ * Minimum 1 clk cycle delay is required as per
+ * HW spec.
+ */
+ usleep_range(1000, 1010);
+ snd_soc_update_bits(codec, hpf_gate_reg, 0x02, 0x00);
+ }
/* schedule work queue to Remove Mute */
schedule_delayed_work(&tavil->tx_mute_dwork[decimator].dwork,
msecs_to_jiffies(tx_unmute_delay));
@@ -3718,10 +3771,20 @@ static int tavil_codec_enable_dec(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
if (cancel_delayed_work_sync(
&tavil->tx_hpf_work[decimator].dwork)) {
- if (hpf_cut_off_freq != CF_MIN_3DB_150HZ)
+ if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
snd_soc_update_bits(codec, dec_cfg_reg,
TX_HPF_CUT_OFF_FREQ_MASK,
hpf_cut_off_freq << 5);
+ snd_soc_update_bits(codec, hpf_gate_reg,
+ 0x02, 0x02);
+ /*
+ * Minimum 1 clk cycle delay is required as per
+ * HW spec.
+ */
+ usleep_range(1000, 1010);
+ snd_soc_update_bits(codec, hpf_gate_reg,
+ 0x02, 0x00);
+ }
}
cancel_delayed_work_sync(
&tavil->tx_mute_dwork[decimator].dwork);
@@ -4752,6 +4815,46 @@ static int tavil_compander_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int tavil_hph_asrc_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+ int index = -EINVAL;
+
+ if (!strcmp(kcontrol->id.name, "ASRC0 Output Mode"))
+ index = ASRC0;
+ if (!strcmp(kcontrol->id.name, "ASRC1 Output Mode"))
+ index = ASRC1;
+
+ if (tavil && (index >= 0) && (index < ASRC_MAX))
+ tavil->asrc_output_mode[index] =
+ ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int tavil_hph_asrc_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+ int val = 0;
+ int index = -EINVAL;
+
+ if (!strcmp(kcontrol->id.name, "ASRC0 Output Mode"))
+ index = ASRC0;
+ if (!strcmp(kcontrol->id.name, "ASRC1 Output Mode"))
+ index = ASRC1;
+
+ if (tavil && (index >= 0) && (index < ASRC_MAX))
+ val = tavil->asrc_output_mode[index];
+
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
static int tavil_hph_idle_detect_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -5146,6 +5249,10 @@ static const char * const hph_idle_detect_text[] = {
"OFF", "ON"
};
+static const char * const asrc_mode_text[] = {
+ "INT", "FRAC"
+};
+
static const char * const tavil_ear_pa_gain_text[] = {
"G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
"G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB"
@@ -5161,6 +5268,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(tavil_ear_spkr_pa_gain_enum,
tavil_ear_spkr_pa_gain_text);
static SOC_ENUM_SINGLE_EXT_DECL(amic_pwr_lvl_enum, amic_pwr_lvl_text);
static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text);
+static SOC_ENUM_SINGLE_EXT_DECL(asrc_mode_enum, asrc_mode_text);
static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, WCD934X_CDC_TX0_TX_PATH_CFG0, 5,
cf_text);
static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, WCD934X_CDC_TX1_TX_PATH_CFG0, 5,
@@ -5395,6 +5503,11 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = {
SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0,
tavil_compander_get, tavil_compander_put),
+ SOC_ENUM_EXT("ASRC0 Output Mode", asrc_mode_enum,
+ tavil_hph_asrc_mode_get, tavil_hph_asrc_mode_put),
+ SOC_ENUM_EXT("ASRC1 Output Mode", asrc_mode_enum,
+ tavil_hph_asrc_mode_get, tavil_hph_asrc_mode_put),
+
SOC_ENUM_EXT("HPH Idle Detect", hph_idle_detect_enum,
tavil_hph_idle_detect_get, tavil_hph_idle_detect_put),
diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c
index a2bd3be62175..524f737360d8 100644
--- a/sound/soc/msm/msmcobalt.c
+++ b/sound/soc/msm/msmcobalt.c
@@ -3180,8 +3180,10 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
* Send speaker configuration only for WSA8810.
* Defalut configuration is for WSA8815.
*/
+ pr_debug("%s: Number of aux devices: %d\n",
+ __func__, rtd->card->num_aux_devs);
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
- if (rtd_aux && rtd_aux->component)
+ if (rtd->card->num_aux_devs && rtd_aux && rtd_aux->component)
if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
!strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
tavil_set_spkr_mode(rtd->codec, SPKR_MODE_1);
@@ -3200,7 +3202,7 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
pdata->codec_root = entry;
tavil_codec_info_create_codec_entry(pdata->codec_root, codec);
} else {
- if (rtd_aux && rtd_aux->component)
+ if (rtd->card->num_aux_devs && rtd_aux && rtd_aux->component)
if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
!strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index 8337d11bad12..3a108eba3b01 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -50,7 +50,7 @@
#define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE)
#define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE)
-#define MAX_XFER_BUFF_LEN (2 * PAGE_SIZE)
+#define MAX_XFER_BUFF_LEN (24 * PAGE_SIZE)
struct iova_info {
struct list_head list;