diff options
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(¬if_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; |
