diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-02 08:08:02 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-11-02 08:08:03 -0600 |
| commit | 65485bf038afb364645dcdd28f151fa26f5023cd (patch) | |
| tree | a55cb4ff53db127becb54b0c1225d614cc9ea159 | |
| parent | 4c3ff3848cb4ee9c56418e6892ca52e265d1fa13 (diff) | |
| parent | b67bb93f565e831efbcdea58a6751737064d3fc6 (diff) | |
Promotion of kernel.lnx.4.4-161102.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1068171 Ic0f2a51b5af661fd23576ae5135c920b92f0cdfd dt-bindings: power: reset: add document for reboot-mode
1082552 If27cb2bb3fcaafa5c8435f3c2e0e4be9b8f1e987 sched/hmp: Disable interrupts when resetting all task st
1082652 Ic4791164cee1dea0cc36c8445f546b9ec56785d4 drivers: cpuidle: lpm-levels: Enable Sleep prediction
1068171 Id65f6b9186e7a5209542a380bae31a1d8933b931 power: reset: add reboot mode driver
1070301 I619272c5d0439427061541f5658cfd305a4ebd46 usb: xhci-plat: Enable wakeup for the root hubs
1082708 I0228967ca3b33a56489a80833c0565ba2dfe8c2a msm: ipa3: fix send_cmd_timeout logic
1080024 I00c612be2b8c22dd5afb65a739551df91cb324fc ANDROID: dm verity fec: initialize recursion level
1083755 Iea068907241b42846d95d8e62e59409cdd29ca42 ASoC: wcd9335: Enable standalone ldo_h
1084195 I7c3d321f9f062037d85efba437a3fc1012b64d4b pmic-voter: Add the votable name in debugfs
1077457 If2bb1900c07af1ea162da362c913d4880b0bc755 msm: crypto: Fix integer over flow check in qce driver
1072781 Ie6b5a511f5b3077adae7d464de437f2aa893b0c9 msm: kgsl: Clear the interrupt immediately
1082598 I2a49535786ac61c4da0bebe300aff33a556e485d ARM: dts: msm: fix WLED sink configuration for msmcobalt
1066400 Id08f7b2e109b6b2963b19dfe07f07cbfb424202b spmi-pmic-arb: fix a possible null pointer dereference
1082630 I490b5679de4cb4837f5ed5d4e40d339e12c8ecc9 icnss: Shutdown Adrastea before remapping MSA0
1080024 I7ce9f38d8c7a62361392c5a8ccebb288f8a3a2ea ANDROID: dm: allow adb disable-verity only in userdebug
1082196 I1f53c9536b6896111707b77954d2b6cf4d227db8 usb: dwc3: Turn on memory core and periphery upon resume
1081279 I30cd3fb0435e085e76a60043b80b6ff7aded2819 clk: msm: Add COMMON_CLK branch memory flags
1080024 Id27cf5231aebcdd14f4fb25dd44052f829e0427e Revert "dm-verity: Add a temporary dummy opaque struct d
1080024 Idb88b901e0209c2cccc9c0796689f780592d58f9 ANDROID: dm verity fec: fix RS block calculation
1081637 I0a34f0bbc9f2049b826777a31e14d2cf62cdc211 qseecom: check error return value of ion_map_kernel
1080024 I2d9354e240d36ea06fc68c2d18d8e87b823a4c2f ANDROID: dm: fix signature verification flag
1082349 I0d8e9bdc15d052458e366cef13a6d2d8c7420ff2 arm64: Implement optimised IP checksum helpers
1083795 Ifa59335033f8b9bda6fb0ca4b071387fdaa8f6f9 ASoC: wcd934x: Restore CPR defaults after SSR
1080024 Ib34d25c0854202f3e70df0a6d0ef1d96f0250c8e ANDROID: dm: android-verity: Verify header before fetchi
1049512 Id254a12ba8fc2d57951d158c8fce80168375586d Bluetooth:Add ioctl to power control connectivity chip
1080024 I8f5c2289b842b820ca04f5773525e5449bb3f355 ANDROID: dm: mount as linear target if eng build
1080024 I4a377e417b00afd9ecccdb3e605fea31a7df112e ANDROID: dm: rename dm-linear methods for dm-android-ver
1082804 I7901df15ec03273304c5e4d417f272497ad1523c clk: msm: clock-osm: Request Nominal Fmax frequency afte
1083524 Iabc11506074511ee71463e9d287f6e460dca451e ARM: dts: msm: Add initial support for msmcobalt v2 QRD
1080024 I506c89b053d835ab579e703eef2bc1f8487250de ANDROID: dm: use default verity public key
1083708 Ifdd0089a6a970792ebd84665178bd4de86eae2fb soc: qcom: signal buffer response after glink_rx_done()
1083306 I018729af22dbd787f42fc3788cbff018be7b4014 ARM: dts: msm: correct pmicobalt_bob regulator name for
1068949 Iba43e192905ab37d196aea4b5d00861b9cb7c347 msm: ipa3: Support IPA-USB suspend sequence without remo
1082304 I04008d0bfc9a874e08b45f78a937004e9f37527d usb: pd: Fix sink hard reset looping bug
1080024 Icfdc3e7b3ead5de335a059cade1aca70414db415 ANDROID: dm-android-verity: Rebase on top of 4.1
1080024 Ie04c8cf2dd755f54d02dbdc4e734a13d6f6507b5 ANDROID: dm: android-verity: Remove fec_header location
1080024 I82a911cf963367b1f311c5035bf894a380a76e54 dm-verity: Add a temporary dummy opaque struct declarati
1067432 I2cd3b87aca032d4c5868cc9db35987213349a337 msm: ADSPRPC: Do not pass offset for secure buffers
1080024 I0a7ebff331d259c59a5e03c81918cc1613c3a766 ANDROID: dm verity fec: limit error correction recursion
1081779 I321bd79d04e135030764dcdf83a58fee3c4e72c8 msm: mdss: Add Rec2020 YUV conversion to CSC tables
1082870 Iea0a8cd64fcce14a99b828cadb0f07664ce858f0 usb: pd: Observe PSHardResetTimer for source hard reset
1082940 Idfc139ff63f6268f836694e0680c1e44582dfbb3 ARM: qcom: add board entries for msmtriton
1083675 I0ba41c9564c12b0b2c419222b54fa0e05be93b75 msm: ipa3: wait for uC load before USB disconnect
1056777 Ibee5689216d9115cb4888fb8593734eaef6c7f9f ARM: dts: msm: add support for etm and cpu-cti on msmfal
1080024 I7e99644a0960ac8279f02c0158ed20999510ea97 ANDROID: dm: Add android verity target
1082643 I1aae776d5e6cc8f1cc2af9278c0e3d6ac37804a9 icnss: Enable PMM_TCXO_CLK before switch to cxo
1066017 Ibe0053e8bd4d8219098ba09041d66fcd5b4592fd binder: prevent kptr leak by using %pK format specifier
1080024 Idb84453e70cc11abd5ef3a0adfbb16f8b5feaf07 ANDROID: dm: use name_to_dev_t
1083760 I2d3f3a299939a061a43b4f552aedc7cac897d8b7 smb138x-charger: Fix FCC and FV parameters
1051250 Ia5cc4a6bbf6b6d0d86e13cec7da167f8a49b859d leds: qpnp-wled: Update AMOLED_VOUT programming
1054930 Id9273e546d3565935a7b1150c27993f02c5734e3 wil6210: prevent XTAL off in device bootloader
1080024 Ic64950c3b55f0a6eaa570bcedc2ace83bbf3005e ANDROID: dm-verity: adopt changes made to dm callbacks
1078627 I55bff36d8504f5fd3041f0dad42a077f25976966 power: reset: Do not disable SDI during reset
1080024 Ic0f7c17e4889c5580d70b52d9a709a37165a5747 ANDROID: dm verity fec: add missing release from fec_kty
1044007 Ia706e7184ab31c5e4e3bb2668a1ab7660ca3c6ce Don't show empty tag stats for unprivileged uids
1083199 Ib19d78f0834803c75b255ee3a119e043ffb8a988 ASoC: wcd934x: fix default value for FLL threshold
1081102 I9665dfc1c52d77dc8953042101d726e7f7ba1807 msm: vidc: Add Colorspace in sequence change event
1080024 Ic41ca4b8908fb2777263799cf3a3e25934d70f18 ANDROID: dm: Mounting root as linear device when verity
1075843 Ibc69706ae1dc878de5cbdaf283f0d71aff8000a1 leds: qpnp-wled: add support for configuring ILIM in pmi
1080024 Iceca2eb6daa55f0acb936eafe1d59f65f7cfcd55 init: do_mounts: Add a dummy definition for dm_table_put
1080024 I157170eebe3c0f89a68ae05870a1060f188d0da0 ANDROID: dm: Minor cleanup
1025311 Ic4c7f66e84c8898d9db630d373b8a3cc8472e826 cfg80211: pass struct to interface combination check/ite
1083198 Ibbca465192c58deba3618d70e36089119c7f3994 ASoC: wcd934x: Add impedance detection controls
Change-Id: Id0fc440d2bfff0c915eaf17a6dd1335053a7d24f
CRs-Fixed: 1083708, 1044007, 1083198, 1083199, 1083760, 1049512, 1082349, 1082304, 1070301, 1066017, 1081637, 1068949, 1082552, 1082870, 1083795, 1025311, 1082630, 1077457, 1080024, 1083524, 1066400, 1082196, 1081102, 1075843, 1083755, 1072781, 1083306, 1082652, 1084195, 1083675, 1051250, 1082940, 1054930, 1056777, 1081779, 1082598, 1082804, 1068171, 1067432, 1082643, 1078627, 1082708, 1081279
85 files changed, 3423 insertions, 505 deletions
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index 1ca2b6dd6d5c..ebbcfe5b2fd0 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -33,7 +33,15 @@ Optional properties for WLED: - 31100, 29600, 19600, 18100 for pmicobalt/pm2falcon. Should only be used if qcom,disp-type-amoled is not specified. -- qcom,ilim-ma : maximum current limiter in ma. default is 980. +- qcom,ilim-ma : Current limit threshold in mA. + For pmi8994/8952/8996, default value for LCD is 980mA + and AMOLED is 385mA. + Supported values are: + - 105, 385, 660, 980, 1150, 1420, 1700, 1980. + For pmicobalt/pm2falcon, default value for LCD is + 970mA and AMOLED is 620mA. + Supported values are: + - 105, 280, 450, 620, 970, 1150, 1300, 1500. - qcom,boost-duty-ns : maximum boost duty cycle in ns. default is 104. - qcom,mod-freq-khz : modulation frequency in khz. default is 9600. - qcom,dim-mode : dimming mode. supporting dimming modes are "analog", @@ -61,10 +69,13 @@ Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: - qcom,loop-ea-gm : control the gm for gm stage in control loop. default is 3. - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. - qcom,vref-psm-mv : reference psm voltage in mv. default for amoled is 450. -- qcom,avdd-target-voltage-mv: The target voltage desired for the AVDD module in mV. - The supported values are: - 7900, 7600, 7300, 6400, 6100, 5800. - If not specified, default value used is 7600. +- qcom,avdd-mode-spmi: Boolean property to enable AMOLED_VOUT programming via SPMI. If not specified, + AMOLED_VOUT is programmed via S-wire. This can be specified only for newer + PMICs like pmicobalt/pm2falcon. +- qcom,avdd-target-voltage-mv: The voltage required for AMOLED_VOUT. Accepted values are in the range + of 5650 to 7900 in steps of 150. Default value is 7600. Unit is in mV. + For old revisions, accepted values are: 7900, 7600, 7300, 6400, 6100, + 5800. Example: qcom,leds@d800 { diff --git a/Documentation/devicetree/bindings/power/reset/reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/reboot-mode.txt new file mode 100644 index 000000000000..de34f27d509e --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/reboot-mode.txt @@ -0,0 +1,25 @@ +Generic reboot mode core map driver + +This driver get reboot mode arguments and call the write +interface to store the magic value in special register +or ram. Then the bootloader can read it and take different +action according to the argument stored. + +All mode properties are vendor specific, it is a indication to tell +the bootloader what to do when the system reboots, and should be named +as mode-xxx = <magic> (xxx is mode name, magic should be a none-zero value). + +For example modes common on Android platform: +- mode-normal: Normal reboot mode, system reboot with command "reboot". +- mode-recovery: Android Recovery mode, it is a mode to format the device or update a new image. +- mode-bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device. +- mode-loader: A bootloader mode, it's a mode used to download image on Rockchip platform, + usually used in development. + +Example: + reboot-mode { + mode-normal = <BOOT_NORMAL>; + mode-recovery = <BOOT_RECOVERY>; + mode-bootloader = <BOOT_FASTBOOT>; + mode-loader = <BOOT_BL_DOWNLOAD>; + } diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt new file mode 100644 index 000000000000..f7ce1d8af04a --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt @@ -0,0 +1,35 @@ +SYSCON reboot mode driver + +This driver gets reboot mode magic value form reboot-mode driver +and stores it in a SYSCON mapped register. Then the bootloader +can read it and take different action according to the magic +value stored. + +This DT node should be represented as a sub-node of a "syscon", "simple-mfd" +node. + +Required properties: +- compatible: should be "syscon-reboot-mode" +- offset: offset in the register map for the storage register (in bytes) + +Optional property: +- mask: bits mask of the bits in the register to store the reboot mode magic value, + default set to 0xffffffff if missing. + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + pmu: pmu@20004000 { + compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd"; + reg = <0x20004000 0x100>; + + reboot-mode { + compatible = "syscon-reboot-mode"; + offset = <0x40>; + mode-normal = <BOOT_NORMAL>; + mode-recovery = <BOOT_RECOVERY>; + mode-bootloader = <BOOT_FASTBOOT>; + mode-loader = <BOOT_BL_DOWNLOAD>; + }; + }; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index bffa21a06462..f884e0ece735 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -114,6 +114,7 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ msmcobalt-v2-qrd.dtb \ msmcobalt-qrd-skuk.dtb \ msmcobalt-qrd-vr1.dtb \ + msmcobalt-v2-qrd-vr1.dtb \ apqcobalt-mtp.dtb \ apqcobalt-cdp.dtb \ apqcobalt-v2-mtp.dtb \ diff --git a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi index 91b4cc351010..41589d02f6fc 100644 --- a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi @@ -237,7 +237,7 @@ qcom,vref-mv = <350>; qcom,switch-freq-khz = <800>; qcom,ovp-mv = <29600>; - qcom,ilim-ma = <980>; + qcom,ilim-ma = <970>; qcom,boost-duty-ns = <26>; qcom,mod-freq-khz = <9600>; qcom,dim-mode = "hybrid"; diff --git a/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi b/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi index 7a8e71d14291..7243a6b1d6d4 100644 --- a/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi @@ -592,7 +592,7 @@ regulator-bob { compatible = "qcom,rpm-smd-regulator"; - regulator-name = "pmcobalt_bob"; + regulator-name = "pmicobalt_bob"; qcom,set = <3>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index ad56f1d3dd74..a5243aff4282 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -597,7 +597,7 @@ qcom,vref-mv = <350>; qcom,switch-freq-khz = <800>; qcom,ovp-mv = <29600>; - qcom,ilim-ma = <980>; + qcom,ilim-ma = <970>; qcom,boost-duty-ns = <26>; qcom,mod-freq-khz = <9600>; qcom,dim-mode = "hybrid"; @@ -741,7 +741,7 @@ qcom,led-mask = <3>; qcom,default-led-trigger = "switch0_trigger"; reg0 { - regulator-name = "pmcobalt_bob"; + regulator-name = "pmicobalt_bob"; max-voltage-uv = <3600000>; }; }; @@ -752,7 +752,7 @@ qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; reg0 { - regulator-name = "pmcobalt_bob"; + regulator-name = "pmicobalt_bob"; max-voltage-uv = <3600000>; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts index ee6a58a41b4f..e53912071502 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts @@ -21,32 +21,3 @@ 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 f8069856f3d8..f0607ac3a34a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi @@ -99,4 +99,31 @@ debounce-interval = <15>; }; }; + + 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.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi index 7d5509f0016c..682ea8a260ef 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi @@ -264,7 +264,7 @@ }; &pmicobalt_wled { - qcom,led-strings-list = [00 01]; + qcom,led-strings-list = [01 02]; }; &dsi_dual_nt35597_video { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 2a61cccad273..bb72cf3a0d2c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -501,7 +501,7 @@ }; pmicobalt_bob_pin1: regulator-bob-pin1 { compatible = "qcom,rpm-smd-regulator"; - regulator-name = "pmcobalt_bob_pin1"; + regulator-name = "pmicobalt_bob_pin1"; qcom,set = <3>; regulator-min-microvolt = <3312000>; regulator-max-microvolt = <3600000>; @@ -509,7 +509,7 @@ }; pmicobalt_bob_pin2: regulator-bob-pin2 { compatible = "qcom,rpm-smd-regulator"; - regulator-name = "pmcobalt_bob_pin2"; + regulator-name = "pmicobalt_bob_pin2"; qcom,set = <3>; regulator-min-microvolt = <3312000>; regulator-max-microvolt = <3600000>; @@ -517,7 +517,7 @@ }; pmicobalt_bob_pin3: regulator-bob-pin3 { compatible = "qcom,rpm-smd-regulator"; - regulator-name = "pmcobalt_bob_pin3"; + regulator-name = "pmicobalt_bob_pin3"; qcom,set = <3>; regulator-min-microvolt = <3312000>; regulator-max-microvolt = <3600000>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts new file mode 100644 index 000000000000..15dd2d550b31 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts @@ -0,0 +1,23 @@ +/* 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. + */ + + +/dts-v1/; + +#include "msmcobalt-v2.dtsi" +#include "msmcobalt-qrd-vr1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM COBALT V2 VR1 Board"; + compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd"; + qcom,board-id = <0x02000b 0x80>; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi index 3826b00bf09e..2f1ef974811e 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi @@ -138,6 +138,14 @@ <&funnel_in0_out_funnel_merg>; }; }; + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1:endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; }; }; @@ -183,6 +191,167 @@ }; }; + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + port@5 { + reg = <6>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + }; + }; + + funnel_apss_merg: funnel@7b70000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7b70000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + funnel_apss: funnel@7b60000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7b60000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + stm: stm@6002000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b962>; @@ -204,6 +373,166 @@ }; }; + etm0: etm@7840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7840000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7940000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7a40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7a40000 0x1000>; + cpu = <&CPU2>; + + coresight-name = "coresight-etm2"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7b40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7b40000 0x1000>; + cpu = <&CPU3>; + + coresight-name = "coresight-etm3"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7c40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7c40000 0x1000>; + cpu = <&CPU4>; + + coresight-name = "coresight-etm4"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7d40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7d40000 0x1000>; + cpu = <&CPU5>; + + coresight-name = "coresight-etm5"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7e40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7e40000 0x1000>; + cpu = <&CPU6>; + + coresight-name = "coresight-etm6"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7f40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b95d>; + + reg = <0x7f40000 0x1000>; + cpu = <&CPU7>; + + coresight-name = "coresight-etm7"; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + cti0: cti@6010000 { compatible = "arm,coresight-cti"; reg = <0x6010000 0x1000>; @@ -396,6 +725,110 @@ clock-names = "core_clk", "core_a_clk"; }; + cti_cpu0: cti@7820000 { + compatible = "arm,coresight-cti"; + reg = <0x7820000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu1: cti@7920000 { + compatible = "arm,coresight-cti"; + reg = <0x7920000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu2: cti@7a20000 { + compatible = "arm,coresight-cti"; + reg = <0x7a20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu3: cti@7b20000 { + compatible = "arm,coresight-cti"; + reg = <0x7b20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu4: cti@7c20000 { + compatible = "arm,coresight-cti"; + reg = <0x7c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu5: cti@7d20000 { + compatible = "arm,coresight-cti"; + reg = <0x7d20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu6: cti@7e20000 { + compatible = "arm,coresight-cti"; + reg = <0x7e20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + + cti_cpu7: cti@7f20000 { + compatible = "arm,coresight-cti"; + reg = <0x7f20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_rpmcc RPM_QDSS_CLK>, + <&clock_rpmcc RPM_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + }; + funnel_qatb: funnel@6005000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index fffad9374a69..7a5d83a12bfa 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -447,7 +447,7 @@ <0x10b4000 0x800>; reg-names = "dcc-base", "dcc-ram-base"; - clocks = <&clock_rpmcc RPM_QDSS_CLK>; + clocks = <&clock_rpmcc GCC_DCC_AHB_CLK>; clock-names = "dcc_clk"; }; diff --git a/arch/arm/mach-qcom/board-falcon.c b/arch/arm/mach-qcom/board-falcon.c index e9374050b2cb..aec16886308d 100644 --- a/arch/arm/mach-qcom/board-falcon.c +++ b/arch/arm/mach-qcom/board-falcon.c @@ -31,3 +31,20 @@ DT_MACHINE_START(MSMFALCON_DT, .init_machine = msmfalcon_init, .dt_compat = msmfalcon_dt_match, MACHINE_END + +static const char *msmtriton_dt_match[] __initconst = { + "qcom,msmtriton", + "qcom,apqtriton", + NULL +}; + +static void __init msmtriton_init(void) +{ + board_dt_populate(NULL); +} + +DT_MACHINE_START(MSMTRITON_DT, + "Qualcomm Technologies, Inc. MSM TRITON (Flattened Device Tree)") + .init_machine = msmtriton_init, + .dt_compat = msmtriton_dt_match, +MACHINE_END diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index 861ed8acdc3f..d49e164867e1 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild @@ -2,7 +2,6 @@ generic-y += bug.h generic-y += bugs.h -generic-y += checksum.h generic-y += clkdev.h generic-y += cputime.h generic-y += current.h diff --git a/arch/arm64/include/asm/checksum.h b/arch/arm64/include/asm/checksum.h new file mode 100644 index 000000000000..09f65339d66d --- /dev/null +++ b/arch/arm64/include/asm/checksum.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_CHECKSUM_H +#define __ASM_CHECKSUM_H + +#include <linux/types.h> + +static inline __sum16 csum_fold(__wsum csum) +{ + u32 sum = (__force u32)csum; + sum += (sum >> 16) | (sum << 16); + return ~(__force __sum16)(sum >> 16); +} +#define csum_fold csum_fold + +static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + __uint128_t tmp; + u64 sum; + + tmp = *(const __uint128_t *)iph; + iph += 16; + ihl -= 4; + tmp += ((tmp >> 64) | (tmp << 64)); + sum = tmp >> 64; + do { + sum += *(const u32 *)iph; + iph += 4; + } while (--ihl); + + sum += ((sum >> 32) | (sum << 32)); + return csum_fold(sum >> 32); +} +#define ip_fast_csum ip_fast_csum + +#include <asm-generic/checksum.h> + +#endif /* __ASM_CHECKSUM_H */ diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 20d17906fc9b..f80cfc36a354 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3444,7 +3444,7 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { - seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", + seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n", ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", ref->node->debug_id, ref->strong, ref->weak, ref->death); } diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 1317ddaa3c23..b05b999fbbdc 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -46,6 +46,7 @@ static const struct of_device_id bt_power_match_table[] = { static struct bluetooth_power_platform_data *bt_power_pdata; static struct platform_device *btpdev; static bool previous; +static int pwr_state; struct class *bt_class; static int bt_major; @@ -636,6 +637,7 @@ static int bt_power_probe(struct platform_device *pdev) memcpy(bt_power_pdata, pdev->dev.platform_data, sizeof(struct bluetooth_power_platform_data)); + pwr_state = 0; } else { BT_PWR_ERR("Failed to get platform data"); goto free_pdata; @@ -680,7 +682,7 @@ int bt_register_slimdev(struct device *dev) static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret; + int ret, pwr_cntrl = 0; switch (cmd) { case BT_CMD_SLIM_TEST: @@ -692,6 +694,18 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) bt_power_pdata->slim_dev->platform_data ); break; + case BT_CMD_PWR_CTRL: + pwr_cntrl = (int)arg; + BT_PWR_ERR("BT_CMD_PWR_CTRL pwr_cntrl:%d", pwr_cntrl); + if (pwr_state != pwr_cntrl) { + ret = bluetooth_power(pwr_cntrl); + if (!ret) + pwr_state = pwr_cntrl; + } else { + BT_PWR_ERR("BT chip state is already :%d no change d\n" + , pwr_state); + } + break; default: return -EINVAL; } @@ -711,6 +725,7 @@ static struct platform_driver bt_power_driver = { static const struct file_operations bt_dev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = bt_ioctl, + .compat_ioctl = bt_ioctl, }; static int __init bluetooth_power_init(void) @@ -733,7 +748,7 @@ static int __init bluetooth_power_init(void) if (device_create(bt_class, NULL, MKDEV(bt_major, 0), - NULL, "pintest") == NULL) { + NULL, "btpower") == NULL) { BTFMSLIM_ERR("failed to allocate char dev\n"); goto chrdev_unreg; } diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 67c1207d35be..ef8aaac6e0a2 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1070,7 +1070,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) int idx = list[i].pgidx; if (map->attr & FASTRPC_ATTR_NOVA) { - offset = (uintptr_t)lpra[i].buf.pv; + offset = 0; } else { down_read(¤t->mm->mmap_sem); VERIFY(err, NULL != (vma = find_vma(current->mm, diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index b1c9a24c4087..5391ef456aae 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -2748,33 +2748,26 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) } clk_prepare_enable(&sys_apcsaux_clk_gcc.c); - /* Set boot rate */ - rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ? - MSMCOBALTV1_PWRCL_BOOT_RATE : - MSMCOBALTV2_PWRCL_BOOT_RATE); + rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate); if (rc) { - dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n", + dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n", rc); - clk_disable_unprepare(&sys_apcsaux_clk_gcc.c); - return rc; + goto exit2; } - rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ? - MSMCOBALTV1_PERFCL_BOOT_RATE : - MSMCOBALTV2_PERFCL_BOOT_RATE); + /* Make sure index zero is selected */ + rc = clk_set_rate(&pwrcl_clk.c, init_rate); if (rc) { - dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n", + dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n", rc); - clk_disable_unprepare(&sys_apcsaux_clk_gcc.c); - return rc; + goto exit2; } - rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate); + rc = clk_set_rate(&perfcl_clk.c, init_rate); if (rc) { - dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n", + dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n", rc); - clk_disable_unprepare(&sys_apcsaux_clk_gcc.c); - return rc; + goto exit2; } get_online_cpus(); @@ -2785,6 +2778,25 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) "Failed to enable clock for cpu %d\n", cpu); } + /* Set final boot rate */ + rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ? + MSMCOBALTV1_PWRCL_BOOT_RATE : + MSMCOBALTV2_PWRCL_BOOT_RATE); + if (rc) { + dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n", + rc); + goto exit2; + } + + rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ? + MSMCOBALTV1_PERFCL_BOOT_RATE : + MSMCOBALTV2_PERFCL_BOOT_RATE); + if (rc) { + dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n", + rc); + goto exit2; + } + pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG); perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG); @@ -2801,6 +2813,8 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return 0; +exit2: + clk_disable_unprepare(&sys_apcsaux_clk_gcc.c); exit: dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", rc); diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 37e504381313..de033cc37a15 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -85,7 +85,9 @@ struct lpm_debug { struct lpm_cluster *lpm_root_node; -static bool lpm_prediction; +#define MAXSAMPLES 5 + +static bool lpm_prediction = true; module_param_named(lpm_prediction, lpm_prediction, bool, S_IRUGO | S_IWUSR | S_IWGRP); diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c index 7ddbb1938400..4cf95b90a2df 100644 --- a/drivers/crypto/msm/qce.c +++ b/drivers/crypto/msm/qce.c @@ -1,6 +1,6 @@ /* Qualcomm Crypto Engine driver. * - * 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 @@ -1962,8 +1962,8 @@ int qce_aead_req(void *handle, struct qce_req *q_req) else q_req->cryptlen = areq->cryptlen - authsize; - if ((q_req->cryptlen > ULONG_MAX - ivsize) || - (q_req->cryptlen + ivsize > ULONG_MAX - areq->assoclen)) { + if ((q_req->cryptlen > UINT_MAX - ivsize) || + (q_req->cryptlen + ivsize > UINT_MAX - areq->assoclen)) { pr_err("Integer overflow on total aead req length.\n"); return -EINVAL; } diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 9940f7a7c2b7..6160aa567fbf 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -589,11 +589,21 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_irq *irq_params = gpudev->irq; irqreturn_t ret = IRQ_NONE; - unsigned int status = 0, tmp; + unsigned int status = 0, tmp, int_bit; int i; adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status); + /* + * Clear all the interrupt bits but ADRENO_INT_RBBM_AHB_ERROR. Because + * even if we clear it here, it will stay high until it is cleared + * in its respective handler. Otherwise, the interrupt handler will + * fire again. + */ + int_bit = ADRENO_INT_BIT(adreno_dev, ADRENO_INT_RBBM_AHB_ERROR); + adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD, + status & ~int_bit); + /* Loop through all set interrupts and call respective handlers */ for (tmp = status; tmp != 0;) { i = fls(tmp) - 1; @@ -612,9 +622,14 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) gpudev->irq_trace(adreno_dev, status); - if (status) + /* + * Clear ADRENO_INT_RBBM_AHB_ERROR bit after this interrupt has been + * cleared in its respective handler + */ + if (status & int_bit) adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD, - status); + int_bit); + return ret; } diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 0f3403cb0095..a2af26c81f50 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -198,6 +198,10 @@ struct adreno_gpudev; /* Time to allow preemption to complete (in ms) */ #define ADRENO_PREEMPT_TIMEOUT 10000 +#define ADRENO_INT_BIT(a, _bit) (((a)->gpucore->gpudev->int_bits) ? \ + (adreno_get_int(a, _bit) < 0 ? 0 : \ + BIT(adreno_get_int(a, _bit))) : 0) + /** * enum adreno_preempt_states * ADRENO_PREEMPT_NONE: No preemption is scheduled @@ -574,6 +578,11 @@ enum adreno_regs { ADRENO_REG_REGISTER_MAX, }; +enum adreno_int_bits { + ADRENO_INT_RBBM_AHB_ERROR, + ADRENO_INT_BITS_MAX, +}; + /** * adreno_reg_offsets: Holds array of register offsets * @offsets: Offset array of size defined by enum adreno_regs @@ -589,6 +598,7 @@ struct adreno_reg_offsets { #define ADRENO_REG_UNUSED 0xFFFFFFFF #define ADRENO_REG_SKIP 0xFFFFFFFE #define ADRENO_REG_DEFINE(_offset, _reg) [_offset] = _reg +#define ADRENO_INT_DEFINE(_offset, _val) ADRENO_REG_DEFINE(_offset, _val) /* * struct adreno_vbif_data - Describes vbif register value pair @@ -726,6 +736,7 @@ struct adreno_gpudev { * so define them in the structure and use them as variables. */ const struct adreno_reg_offsets *reg_offsets; + unsigned int *const int_bits; const struct adreno_ft_perf_counters *ft_perf_counters; unsigned int ft_perf_counters_count; @@ -1101,6 +1112,23 @@ static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev, return gpudev->reg_offsets->offsets[offset_name]; } +/* + * adreno_get_int() - Returns the offset value of an interrupt bit from + * the interrupt bit array in the gpudev node + * @adreno_dev: Pointer to the the adreno device + * @bit_name: The interrupt bit enum whose bit is returned + */ +static inline unsigned int adreno_get_int(struct adreno_device *adreno_dev, + enum adreno_int_bits bit_name) +{ + struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + + if (bit_name >= ADRENO_INT_BITS_MAX) + return -ERANGE; + + return gpudev->int_bits[bit_name]; +} + /** * adreno_gpu_fault() - Return the current state of the GPU * @adreno_dev: A pointer to the adreno_device to query diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 97e71464c2df..3f5a9c6318f6 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1425,6 +1425,10 @@ static struct adreno_coresight a3xx_coresight = { .groups = a3xx_coresight_groups, }; +static unsigned int a3xx_int_bits[ADRENO_INT_BITS_MAX] = { + ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A3XX_INT_RBBM_AHB_ERROR), +}; + /* Register offset defines for A3XX */ static unsigned int a3xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, A3XX_CP_ME_RAM_WADDR), @@ -1853,6 +1857,7 @@ int a3xx_microcode_load(struct adreno_device *adreno_dev, struct adreno_gpudev adreno_a3xx_gpudev = { .reg_offsets = &a3xx_reg_offsets, + .int_bits = a3xx_int_bits, .ft_perf_counters = a3xx_ft_perf_counters, .ft_perf_counters_count = ARRAY_SIZE(a3xx_ft_perf_counters), .perfcounters = &a3xx_perfcounters, diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index bfbdb0e7ac1f..5ca04e522270 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -739,6 +739,10 @@ static void a4xx_err_callback(struct adreno_device *adreno_dev, int bit) } } +static unsigned int a4xx_int_bits[ADRENO_INT_BITS_MAX] = { + ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A4XX_INT_RBBM_AHB_ERROR), +}; + /* Register offset defines for A4XX, in order of enum adreno_regs */ static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, A4XX_CP_ME_RAM_WADDR), @@ -1765,6 +1769,7 @@ static struct adreno_snapshot_data a4xx_snapshot_data = { struct adreno_gpudev adreno_a4xx_gpudev = { .reg_offsets = &a4xx_reg_offsets, + .int_bits = a4xx_int_bits, .ft_perf_counters = a4xx_ft_perf_counters, .ft_perf_counters_count = ARRAY_SIZE(a4xx_ft_perf_counters), .perfcounters = &a4xx_perfcounters, diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 2891940b8f5b..860f6d2925f1 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2872,6 +2872,10 @@ static struct adreno_ft_perf_counters a5xx_ft_perf_counters[] = { {KGSL_PERFCOUNTER_GROUP_TSE, A5XX_TSE_INPUT_PRIM_NUM}, }; +static unsigned int a5xx_int_bits[ADRENO_INT_BITS_MAX] = { + ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A5XX_INT_RBBM_AHB_ERROR), +}; + /* Register offset defines for A5XX, in order of enum adreno_regs */ static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A5XX_CP_WFI_PEND_CTR), @@ -3504,6 +3508,7 @@ static struct adreno_coresight a5xx_coresight = { struct adreno_gpudev adreno_a5xx_gpudev = { .reg_offsets = &a5xx_reg_offsets, + .int_bits = a5xx_int_bits, .ft_perf_counters = a5xx_ft_perf_counters, .ft_perf_counters_count = ARRAY_SIZE(a5xx_ft_perf_counters), .coresight = &a5xx_coresight, diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 18d968d3711d..894c1d88b3ef 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -45,11 +45,13 @@ #define QPNP_WLED_SWITCH_FREQ_REG(b) (b + 0x4C) #define QPNP_WLED_OVP_REG(b) (b + 0x4D) #define QPNP_WLED_ILIM_REG(b) (b + 0x4E) +#define QPNP_WLED_AMOLED_VOUT_REG(b) (b + 0x4F) #define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53) #define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55) #define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56) #define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B) #define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E) +#define QPNP_WLED_SWIRE_AVDD_REG(b) (b + 0x5F) #define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF) #define QPNP_WLED_TEST1_REG(b) (b + 0xE2) #define QPNP_WLED_TEST4_REG(b) (b + 0xE5) @@ -83,12 +85,15 @@ #define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450 #define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80 -#define QPNP_WLED_ILIM_MASK 0xF8 -#define QPNP_WLED_ILIM_MIN_MA 105 -#define QPNP_WLED_ILIM_MAX_MA 1980 -#define QPNP_WLED_ILIM_STEP_MA 280 -#define QPNP_WLED_DFLT_ILIM_MA 980 -#define QPNP_WLED_ILIM_OVERWRITE 0x80 +#define QPNP_WLED_ILIM_MASK GENMASK(2, 0) +#define QPNP_WLED_ILIM_OVERWRITE BIT(7) +#define PMI8994_WLED_ILIM_MIN_MA 105 +#define PMI8994_WLED_ILIM_MAX_MA 1980 +#define PMI8994_WLED_DFLT_ILIM_MA 980 +#define PMI8994_AMOLED_DFLT_ILIM_MA 385 +#define PMICOBALT_WLED_ILIM_MAX_MA 1500 +#define PMICOBALT_WLED_DFLT_ILIM_MA 970 +#define PMICOBALT_AMOLED_DFLT_ILIM_MA 620 #define QPNP_WLED_BOOST_DUTY_MASK 0xFC #define QPNP_WLED_BOOST_DUTY_STEP_NS 52 #define QPNP_WLED_BOOST_DUTY_MIN_NS 26 @@ -196,11 +201,19 @@ #define NUM_SUPPORTED_AVDD_VOLTAGES 6 #define QPNP_WLED_DFLT_AVDD_MV 7600 +#define QPNP_WLED_AVDD_MIN_MV 5650 +#define QPNP_WLED_AVDD_MAX_MV 7900 +#define QPNP_WLED_AVDD_STEP_MV 150 #define QPNP_WLED_AVDD_MIN_TRIM_VAL 0x0 #define QPNP_WLED_AVDD_MAX_TRIM_VAL 0xF +#define QPNP_WLED_AVDD_SEL_SPMI_BIT BIT(7) #define QPNP_WLED_AVDD_SET_BIT BIT(4) #define NUM_SUPPORTED_OVP_THRESHOLDS 4 +#define NUM_SUPPORTED_ILIM_THRESHOLDS 8 + +#define QPNP_WLED_AVDD_MV_TO_REG(val) \ + ((val - QPNP_WLED_AVDD_MIN_MV) / QPNP_WLED_AVDD_STEP_MV) /* output feedback mode */ enum qpnp_wled_fdbk_op { @@ -254,6 +267,14 @@ static int qpnp_wled_ovp_thresholds_pmicobalt[NUM_SUPPORTED_OVP_THRESHOLDS] = { 31100, 29600, 19600, 18100, }; +static int qpnp_wled_ilim_settings_pmi8994[NUM_SUPPORTED_ILIM_THRESHOLDS] = { + 105, 385, 660, 980, 1150, 1420, 1700, 1980, +}; + +static int qpnp_wled_ilim_settings_pmicobalt[NUM_SUPPORTED_ILIM_THRESHOLDS] = { + 105, 280, 450, 620, 970, 1150, 1300, 1500, +}; + /** * qpnp_wled - wed data structure * @ cdev - led class device @@ -288,6 +309,7 @@ static int qpnp_wled_ovp_thresholds_pmicobalt[NUM_SUPPORTED_OVP_THRESHOLDS] = { * @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC * @ strings - supported list of strings * @ num_strings - number of strings + * @ avdd_mode_spmi - enable avdd programming via spmi * @ en_9b_dim_res - enable or disable 9bit dimming * @ en_phase_stag - enable or disable phase staggering * @ en_cabc - enable or disable cabc @@ -330,6 +352,7 @@ struct qpnp_wled { u16 cons_sync_write_delay_us; u8 strings[QPNP_WLED_MAX_STRINGS]; u8 num_strings; + bool avdd_mode_spmi; bool en_9b_dim_res; bool en_phase_stag; bool en_cabc; @@ -1089,6 +1112,142 @@ static int qpnp_wled_ovp_config(struct qpnp_wled *wled) return 0; } +static int qpnp_wled_avdd_trim_config(struct qpnp_wled *wled) +{ + int rc, i; + u8 reg; + + for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) { + if (wled->avdd_target_voltage_mv == + qpnp_wled_avdd_target_voltages[i]) + break; + } + + if (i == NUM_SUPPORTED_AVDD_VOLTAGES) { + dev_err(&wled->pdev->dev, + "Invalid avdd target voltage specified in device tree\n"); + return -EINVAL; + } + + /* Update WLED_OVP register based on desired target voltage */ + reg = qpnp_wled_ovp_reg_settings[i]; + rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_OVP_MASK, ®, + QPNP_WLED_OVP_REG(wled->ctrl_base)); + if (rc) + return rc; + + /* Update WLED_TRIM register based on desired target voltage */ + rc = qpnp_wled_read_reg(wled, ®, + QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); + if (rc) + return rc; + + reg += qpnp_wled_avdd_trim_adjustments[i]; + if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL || + (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VAL) { + dev_dbg(&wled->pdev->dev, + "adjusted trim %d is not within range, capping it\n", + (s8)reg); + if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL) + reg = QPNP_WLED_AVDD_MIN_TRIM_VAL; + else + reg = QPNP_WLED_AVDD_MAX_TRIM_VAL; + } + + reg &= QPNP_WLED_7P7_TRIM_MASK; + rc = qpnp_wled_sec_write_reg(wled, reg, + QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); + if (rc < 0) + dev_err(&wled->pdev->dev, "Write to 7P7_TRIM register failed, rc=%d\n", + rc); + return rc; +} + +static int qpnp_wled_avdd_mode_config(struct qpnp_wled *wled) +{ + int rc; + u8 reg = 0; + + /* + * At present, configuring the mode to SPMI/SWIRE for controlling + * AVDD voltage is available only in pmicobalt/pm2falcon. + */ + if (wled->pmic_rev_id->pmic_subtype != PMICOBALT_SUBTYPE && + wled->pmic_rev_id->pmic_subtype != PM2FALCON_SUBTYPE) + return 0; + + /* AMOLED_VOUT should be configured for AMOLED */ + if (!wled->disp_type_amoled) + return 0; + + /* Configure avdd register */ + if (wled->avdd_target_voltage_mv > QPNP_WLED_AVDD_MAX_MV) { + dev_dbg(&wled->pdev->dev, "Capping avdd target voltage to %d\n", + QPNP_WLED_AVDD_MAX_MV); + wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_MAX_MV; + } else if (wled->avdd_target_voltage_mv < QPNP_WLED_AVDD_MIN_MV) { + dev_info(&wled->pdev->dev, "Capping avdd target voltage to %d\n", + QPNP_WLED_AVDD_MIN_MV); + wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_MIN_MV; + } + + reg = QPNP_WLED_AVDD_MV_TO_REG(wled->avdd_target_voltage_mv); + + if (wled->avdd_mode_spmi) { + reg |= QPNP_WLED_AVDD_SEL_SPMI_BIT; + rc = qpnp_wled_write_reg(wled, reg, + QPNP_WLED_AMOLED_VOUT_REG(wled->ctrl_base)); + } else { + rc = qpnp_wled_write_reg(wled, reg, + QPNP_WLED_SWIRE_AVDD_REG(wled->ctrl_base)); + } + + if (rc < 0) + dev_err(&wled->pdev->dev, "Write to VOUT/AVDD register failed, rc=%d\n", + rc); + return rc; +} + +static int qpnp_wled_ilim_config(struct qpnp_wled *wled) +{ + int rc, i, *ilim_table; + u8 reg; + + if (wled->ilim_ma < PMI8994_WLED_ILIM_MIN_MA) + wled->ilim_ma = PMI8994_WLED_ILIM_MIN_MA; + + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + ilim_table = qpnp_wled_ilim_settings_pmicobalt; + if (wled->ilim_ma > PMICOBALT_WLED_ILIM_MAX_MA) + wled->ilim_ma = PMICOBALT_WLED_ILIM_MAX_MA; + } else { + ilim_table = qpnp_wled_ilim_settings_pmi8994; + if (wled->ilim_ma > PMI8994_WLED_ILIM_MAX_MA) + wled->ilim_ma = PMI8994_WLED_ILIM_MAX_MA; + } + + for (i = 0; i < NUM_SUPPORTED_ILIM_THRESHOLDS; i++) { + if (wled->ilim_ma == ilim_table[i]) + break; + } + + if (i == NUM_SUPPORTED_ILIM_THRESHOLDS) { + dev_err(&wled->pdev->dev, + "Invalid ilim threshold specified in device tree\n"); + return -EINVAL; + } + + reg = (i & QPNP_WLED_ILIM_MASK) | QPNP_WLED_ILIM_OVERWRITE; + rc = qpnp_wled_masked_write_reg(wled, + QPNP_WLED_ILIM_MASK | QPNP_WLED_ILIM_OVERWRITE, + ®, QPNP_WLED_ILIM_REG(wled->ctrl_base)); + if (rc < 0) + dev_err(&wled->pdev->dev, "Write to ILIM register failed, rc=%d\n", + rc); + return rc; +} + /* Configure WLED registers */ static int qpnp_wled_config(struct qpnp_wled *wled) { @@ -1131,24 +1290,10 @@ static int qpnp_wled_config(struct qpnp_wled *wled) return rc; /* Configure the ILIM register */ - if (wled->ilim_ma < QPNP_WLED_ILIM_MIN_MA) - wled->ilim_ma = QPNP_WLED_ILIM_MIN_MA; - else if (wled->ilim_ma > QPNP_WLED_ILIM_MAX_MA) - wled->ilim_ma = QPNP_WLED_ILIM_MAX_MA; - - rc = qpnp_wled_read_reg(wled, ®, - QPNP_WLED_ILIM_REG(wled->ctrl_base)); - if (rc < 0) + rc = qpnp_wled_ilim_config(wled); + if (rc < 0) { + pr_err("Error in configuring wled ilim, rc=%d\n", rc); return rc; - temp = (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA); - if (temp != (reg & ~QPNP_WLED_ILIM_MASK)) { - reg &= QPNP_WLED_ILIM_MASK; - reg |= temp; - reg |= QPNP_WLED_ILIM_OVERWRITE; - rc = qpnp_wled_write_reg(wled, reg, - QPNP_WLED_ILIM_REG(wled->ctrl_base)); - if (rc) - return rc; } /* Configure the Soft start Ramp delay: for AMOLED - 0,for LCD - 2 */ @@ -1199,50 +1344,15 @@ static int qpnp_wled_config(struct qpnp_wled *wled) } if (is_avdd_trim_adjustment_required(wled)) { - for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) { - if (wled->avdd_target_voltage_mv == - qpnp_wled_avdd_target_voltages[i]) - break; - } - - if (i == NUM_SUPPORTED_AVDD_VOLTAGES) { - dev_err(&wled->pdev->dev, - "Invalid avdd target voltage specified in device tree\n"); - return -EINVAL; - } - - /* Update WLED_OVP register based on desired target voltage */ - reg = qpnp_wled_ovp_reg_settings[i]; - rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_OVP_MASK, ®, - QPNP_WLED_OVP_REG(wled->ctrl_base)); - if (rc) - return rc; - - /* Update WLED_TRIM register based on desired target voltage */ - rc = qpnp_wled_read_reg(wled, ®, - QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); - if (rc) - return rc; - - reg += qpnp_wled_avdd_trim_adjustments[i]; - if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL || - (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VAL) { - dev_info(&wled->pdev->dev, - "adjusted trim %d is not within range, capping it\n", - (s8)reg); - if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL) - reg = QPNP_WLED_AVDD_MIN_TRIM_VAL; - else - reg = QPNP_WLED_AVDD_MAX_TRIM_VAL; - } - - reg &= QPNP_WLED_7P7_TRIM_MASK; - rc = qpnp_wled_sec_write_reg(wled, reg, - QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); - if (rc) + rc = qpnp_wled_avdd_trim_config(wled); + if (rc < 0) return rc; } + rc = qpnp_wled_avdd_mode_config(wled); + if (rc < 0) + return rc; + /* Configure the MODULATION register */ if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ; @@ -1561,6 +1671,9 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) return rc; } + wled->avdd_mode_spmi = of_property_read_bool(pdev->dev.of_node, + "qcom,avdd-mode-spmi"); + wled->avdd_target_voltage_mv = QPNP_WLED_DFLT_AVDD_MV; rc = of_property_read_u32(pdev->dev.of_node, "qcom,avdd-target-voltage-mv", &temp_val); @@ -1635,7 +1748,19 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) return rc; } - wled->ilim_ma = QPNP_WLED_DFLT_ILIM_MA; + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + if (wled->disp_type_amoled) + wled->ilim_ma = PMICOBALT_AMOLED_DFLT_ILIM_MA; + else + wled->ilim_ma = PMICOBALT_WLED_DFLT_ILIM_MA; + } else { + if (wled->disp_type_amoled) + wled->ilim_ma = PMI8994_AMOLED_DFLT_ILIM_MA; + else + wled->ilim_ma = PMI8994_WLED_DFLT_ILIM_MA; + } + rc = of_property_read_u32(pdev->dev.of_node, "qcom,ilim-ma", &temp_val); if (!rc) { diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 998bd1ec0415..e562bdedfb07 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -517,4 +517,20 @@ config DM_LOG_WRITES If unsure, say N. +config DM_ANDROID_VERITY + bool "Android verity target support" + depends on DM_VERITY + depends on X509_CERTIFICATE_PARSER + depends on SYSTEM_TRUSTED_KEYRING + depends on PUBLIC_KEY_ALGO_RSA + depends on KEYS + depends on ASYMMETRIC_KEY_TYPE + depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE + ---help--- + This device-mapper target is virtually a VERITY target. This + target is setup by reading the metadata contents piggybacked + to the actual data blocks in the block device. The signature + of the metadata contents are verified against the key included + in the system keyring. Upon success, the underlying verity + target is setup. endif # MD diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d470143dcf40..ce7cf06d0e8a 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -69,3 +69,7 @@ endif ifeq ($(CONFIG_DM_VERITY_FEC),y) dm-verity-objs += dm-verity-fec.o endif + +ifeq ($(CONFIG_DM_ANDROID_VERITY),y) +dm-verity-objs += dm-android-verity.o +endif diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c new file mode 100644 index 000000000000..bb6c1285e499 --- /dev/null +++ b/drivers/md/dm-android-verity.c @@ -0,0 +1,925 @@ +/* + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/buffer_head.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/device-mapper.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/fcntl.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/key.h> +#include <linux/module.h> +#include <linux/mount.h> +#include <linux/namei.h> +#include <linux/of.h> +#include <linux/reboot.h> +#include <linux/string.h> +#include <linux/vmalloc.h> + +#include <asm/setup.h> +#include <crypto/hash.h> +#include <crypto/public_key.h> +#include <crypto/sha.h> +#include <keys/asymmetric-type.h> +#include <keys/system_keyring.h> + +#include "dm-verity.h" +#include "dm-android-verity.h" + +static char verifiedbootstate[VERITY_COMMANDLINE_PARAM_LENGTH]; +static char veritymode[VERITY_COMMANDLINE_PARAM_LENGTH]; +static char veritykeyid[VERITY_DEFAULT_KEY_ID_LENGTH]; +static char buildvariant[BUILD_VARIANT]; + +static bool target_added; +static bool verity_enabled = true; +struct dentry *debug_dir; +static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv); + +static struct target_type android_verity_target = { + .name = "android-verity", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = android_verity_ctr, + .dtr = verity_dtr, + .map = verity_map, + .status = verity_status, + .prepare_ioctl = verity_prepare_ioctl, + .iterate_devices = verity_iterate_devices, + .io_hints = verity_io_hints, +}; + +static int __init verified_boot_state_param(char *line) +{ + strlcpy(verifiedbootstate, line, sizeof(verifiedbootstate)); + return 1; +} + +__setup("androidboot.verifiedbootstate=", verified_boot_state_param); + +static int __init verity_mode_param(char *line) +{ + strlcpy(veritymode, line, sizeof(veritymode)); + return 1; +} + +__setup("androidboot.veritymode=", verity_mode_param); + +static int __init verity_keyid_param(char *line) +{ + strlcpy(veritykeyid, line, sizeof(veritykeyid)); + return 1; +} + +__setup("veritykeyid=", verity_keyid_param); + +static int __init verity_buildvariant(char *line) +{ + strlcpy(buildvariant, line, sizeof(buildvariant)); + return 1; +} + +__setup("buildvariant=", verity_buildvariant); + +static inline bool default_verity_key_id(void) +{ + return veritykeyid[0] != '\0'; +} + +static inline bool is_eng(void) +{ + static const char typeeng[] = "eng"; + + return !strncmp(buildvariant, typeeng, sizeof(typeeng)); +} + +static inline bool is_userdebug(void) +{ + static const char typeuserdebug[] = "userdebug"; + + return !strncmp(buildvariant, typeuserdebug, sizeof(typeuserdebug)); +} + + +static int table_extract_mpi_array(struct public_key_signature *pks, + const void *data, size_t len) +{ + MPI mpi = mpi_read_raw_data(data, len); + + if (!mpi) { + DMERR("Error while allocating mpi array"); + return -ENOMEM; + } + + pks->mpi[0] = mpi; + pks->nr_mpi = 1; + return 0; +} + +static struct public_key_signature *table_make_digest( + enum hash_algo hash, + const void *table, + unsigned long table_len) +{ + struct public_key_signature *pks = NULL; + struct crypto_shash *tfm; + struct shash_desc *desc; + size_t digest_size, desc_size; + int ret; + + /* Allocate the hashing algorithm we're going to need and find out how + * big the hash operational data will be. + */ + tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); + if (IS_ERR(tfm)) + return ERR_CAST(tfm); + + desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); + digest_size = crypto_shash_digestsize(tfm); + + /* We allocate the hash operational data storage on the end of out + * context data and the digest output buffer on the end of that. + */ + ret = -ENOMEM; + pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); + if (!pks) + goto error; + + pks->pkey_hash_algo = hash; + pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; + pks->digest_size = digest_size; + + desc = (struct shash_desc *)(pks + 1); + desc->tfm = tfm; + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_init(desc); + if (ret < 0) + goto error; + + ret = crypto_shash_finup(desc, table, table_len, pks->digest); + if (ret < 0) + goto error; + + crypto_free_shash(tfm); + return pks; + +error: + kfree(pks); + crypto_free_shash(tfm); + return ERR_PTR(ret); +} + +static int read_block_dev(struct bio_read *payload, struct block_device *bdev, + sector_t offset, int length) +{ + struct bio *bio; + int err = 0, i; + + payload->number_of_pages = DIV_ROUND_UP(length, PAGE_SIZE); + + bio = bio_alloc(GFP_KERNEL, payload->number_of_pages); + if (!bio) { + DMERR("Error while allocating bio"); + return -ENOMEM; + } + + bio->bi_bdev = bdev; + bio->bi_iter.bi_sector = offset; + + payload->page_io = kzalloc(sizeof(struct page *) * + payload->number_of_pages, GFP_KERNEL); + if (!payload->page_io) { + DMERR("page_io array alloc failed"); + err = -ENOMEM; + goto free_bio; + } + + for (i = 0; i < payload->number_of_pages; i++) { + payload->page_io[i] = alloc_page(GFP_KERNEL); + if (!payload->page_io[i]) { + DMERR("alloc_page failed"); + err = -ENOMEM; + goto free_pages; + } + if (!bio_add_page(bio, payload->page_io[i], PAGE_SIZE, 0)) { + DMERR("bio_add_page error"); + err = -EIO; + goto free_pages; + } + } + + if (!submit_bio_wait(READ, bio)) + /* success */ + goto free_bio; + DMERR("bio read failed"); + err = -EIO; + +free_pages: + for (i = 0; i < payload->number_of_pages; i++) + if (payload->page_io[i]) + __free_page(payload->page_io[i]); + kfree(payload->page_io); +free_bio: + bio_put(bio); + return err; +} + +static inline u64 fec_div_round_up(u64 x, u64 y) +{ + u64 remainder; + + return div64_u64_rem(x, y, &remainder) + + (remainder > 0 ? 1 : 0); +} + +static inline void populate_fec_metadata(struct fec_header *header, + struct fec_ecc_metadata *ecc) +{ + ecc->blocks = fec_div_round_up(le64_to_cpu(header->inp_size), + FEC_BLOCK_SIZE); + ecc->roots = le32_to_cpu(header->roots); + ecc->start = le64_to_cpu(header->inp_size); +} + +static inline int validate_fec_header(struct fec_header *header, u64 offset) +{ + /* move offset to make the sanity check work for backup header + * as well. */ + offset -= offset % FEC_BLOCK_SIZE; + if (le32_to_cpu(header->magic) != FEC_MAGIC || + le32_to_cpu(header->version) != FEC_VERSION || + le32_to_cpu(header->size) != sizeof(struct fec_header) || + le32_to_cpu(header->roots) == 0 || + le32_to_cpu(header->roots) >= FEC_RSM) + return -EINVAL; + + return 0; +} + +static int extract_fec_header(dev_t dev, struct fec_header *fec, + struct fec_ecc_metadata *ecc) +{ + u64 device_size; + struct bio_read payload; + int i, err = 0; + struct block_device *bdev; + + bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL); + + if (IS_ERR_OR_NULL(bdev)) { + DMERR("bdev get error"); + return PTR_ERR(bdev); + } + + device_size = i_size_read(bdev->bd_inode); + + /* fec metadata size is a power of 2 and PAGE_SIZE + * is a power of 2 as well. + */ + BUG_ON(FEC_BLOCK_SIZE > PAGE_SIZE); + /* 512 byte sector alignment */ + BUG_ON(((device_size - FEC_BLOCK_SIZE) % (1 << SECTOR_SHIFT)) != 0); + + err = read_block_dev(&payload, bdev, (device_size - + FEC_BLOCK_SIZE) / (1 << SECTOR_SHIFT), FEC_BLOCK_SIZE); + if (err) { + DMERR("Error while reading verity metadata"); + goto error; + } + + BUG_ON(sizeof(struct fec_header) > PAGE_SIZE); + memcpy(fec, page_address(payload.page_io[0]), + sizeof(*fec)); + + ecc->valid = true; + if (validate_fec_header(fec, device_size - FEC_BLOCK_SIZE)) { + /* Try the backup header */ + memcpy(fec, page_address(payload.page_io[0]) + FEC_BLOCK_SIZE + - sizeof(*fec) , + sizeof(*fec)); + if (validate_fec_header(fec, device_size - + sizeof(struct fec_header))) + ecc->valid = false; + } + + if (ecc->valid) + populate_fec_metadata(fec, ecc); + + for (i = 0; i < payload.number_of_pages; i++) + __free_page(payload.page_io[i]); + kfree(payload.page_io); + +error: + blkdev_put(bdev, FMODE_READ); + return err; +} +static void find_metadata_offset(struct fec_header *fec, + struct block_device *bdev, u64 *metadata_offset) +{ + u64 device_size; + + device_size = i_size_read(bdev->bd_inode); + + if (le32_to_cpu(fec->magic) == FEC_MAGIC) + *metadata_offset = le64_to_cpu(fec->inp_size) - + VERITY_METADATA_SIZE; + else + *metadata_offset = device_size - VERITY_METADATA_SIZE; +} + +static int find_size(dev_t dev, u64 *device_size) +{ + struct block_device *bdev; + + bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL); + if (IS_ERR_OR_NULL(bdev)) { + DMERR("blkdev_get_by_dev failed"); + return PTR_ERR(bdev); + } + + *device_size = i_size_read(bdev->bd_inode); + *device_size >>= SECTOR_SHIFT; + + DMINFO("blkdev size in sectors: %llu", *device_size); + blkdev_put(bdev, FMODE_READ); + return 0; +} + +static int verify_header(struct android_metadata_header *header) +{ + int retval = -EINVAL; + + if (is_userdebug() && le32_to_cpu(header->magic_number) == + VERITY_METADATA_MAGIC_DISABLE) + return VERITY_STATE_DISABLE; + + if (!(le32_to_cpu(header->magic_number) == + VERITY_METADATA_MAGIC_NUMBER) || + (le32_to_cpu(header->magic_number) == + VERITY_METADATA_MAGIC_DISABLE)) { + DMERR("Incorrect magic number"); + return retval; + } + + if (le32_to_cpu(header->protocol_version) != + VERITY_METADATA_VERSION) { + DMERR("Unsupported version %u", + le32_to_cpu(header->protocol_version)); + return retval; + } + + return 0; +} + +static int extract_metadata(dev_t dev, struct fec_header *fec, + struct android_metadata **metadata, + bool *verity_enabled) +{ + struct block_device *bdev; + struct android_metadata_header *header; + int i; + u32 table_length, copy_length, offset; + u64 metadata_offset; + struct bio_read payload; + int err = 0; + + bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL); + + if (IS_ERR_OR_NULL(bdev)) { + DMERR("blkdev_get_by_dev failed"); + return -ENODEV; + } + + find_metadata_offset(fec, bdev, &metadata_offset); + + /* Verity metadata size is a power of 2 and PAGE_SIZE + * is a power of 2 as well. + * PAGE_SIZE is also a multiple of 512 bytes. + */ + if (VERITY_METADATA_SIZE > PAGE_SIZE) + BUG_ON(VERITY_METADATA_SIZE % PAGE_SIZE != 0); + /* 512 byte sector alignment */ + BUG_ON(metadata_offset % (1 << SECTOR_SHIFT) != 0); + + err = read_block_dev(&payload, bdev, metadata_offset / + (1 << SECTOR_SHIFT), VERITY_METADATA_SIZE); + if (err) { + DMERR("Error while reading verity metadata"); + goto blkdev_release; + } + + header = kzalloc(sizeof(*header), GFP_KERNEL); + if (!header) { + DMERR("kzalloc failed for header"); + err = -ENOMEM; + goto free_payload; + } + + memcpy(header, page_address(payload.page_io[0]), + sizeof(*header)); + + DMINFO("bio magic_number:%u protocol_version:%d table_length:%u", + le32_to_cpu(header->magic_number), + le32_to_cpu(header->protocol_version), + le32_to_cpu(header->table_length)); + + err = verify_header(header); + + if (err == VERITY_STATE_DISABLE) { + DMERR("Mounting root with verity disabled"); + *verity_enabled = false; + /* we would still have to read the metadata to figure out + * the data blocks size. Or may be could map the entire + * partition similar to mounting the device. + * + * Reset error as well as the verity_enabled flag is changed. + */ + err = 0; + } else if (err) + goto free_header; + + *metadata = kzalloc(sizeof(**metadata), GFP_KERNEL); + if (!*metadata) { + DMERR("kzalloc for metadata failed"); + err = -ENOMEM; + goto free_header; + } + + (*metadata)->header = header; + table_length = le32_to_cpu(header->table_length); + + if (table_length == 0 || + table_length > (VERITY_METADATA_SIZE - + sizeof(struct android_metadata_header))) { + DMERR("table_length too long"); + err = -EINVAL; + goto free_metadata; + } + + (*metadata)->verity_table = kzalloc(table_length + 1, GFP_KERNEL); + + if (!(*metadata)->verity_table) { + DMERR("kzalloc verity_table failed"); + err = -ENOMEM; + goto free_metadata; + } + + if (sizeof(struct android_metadata_header) + + table_length <= PAGE_SIZE) { + memcpy((*metadata)->verity_table, + page_address(payload.page_io[0]) + + sizeof(struct android_metadata_header), + table_length); + } else { + copy_length = PAGE_SIZE - + sizeof(struct android_metadata_header); + memcpy((*metadata)->verity_table, + page_address(payload.page_io[0]) + + sizeof(struct android_metadata_header), + copy_length); + table_length -= copy_length; + offset = copy_length; + i = 1; + while (table_length != 0) { + if (table_length > PAGE_SIZE) { + memcpy((*metadata)->verity_table + offset, + page_address(payload.page_io[i]), + PAGE_SIZE); + offset += PAGE_SIZE; + table_length -= PAGE_SIZE; + } else { + memcpy((*metadata)->verity_table + offset, + page_address(payload.page_io[i]), + table_length); + table_length = 0; + } + i++; + } + } + (*metadata)->verity_table[table_length] = '\0'; + + DMINFO("verity_table: %s", (*metadata)->verity_table); + goto free_payload; + +free_metadata: + kfree(*metadata); +free_header: + kfree(header); +free_payload: + for (i = 0; i < payload.number_of_pages; i++) + if (payload.page_io[i]) + __free_page(payload.page_io[i]); + kfree(payload.page_io); +blkdev_release: + blkdev_put(bdev, FMODE_READ); + return err; +} + +/* helper functions to extract properties from dts */ +const char *find_dt_value(const char *name) +{ + struct device_node *firmware; + const char *value; + + firmware = of_find_node_by_path("/firmware/android"); + if (!firmware) + return NULL; + value = of_get_property(firmware, name, NULL); + of_node_put(firmware); + + return value; +} + +static int verity_mode(void) +{ + static const char enforcing[] = "enforcing"; + static const char verified_mode_prop[] = "veritymode"; + const char *value; + + value = find_dt_value(verified_mode_prop); + if (!value) + value = veritymode; + if (!strncmp(value, enforcing, sizeof(enforcing) - 1)) + return DM_VERITY_MODE_RESTART; + + return DM_VERITY_MODE_EIO; +} + +static int verify_verity_signature(char *key_id, + struct android_metadata *metadata) +{ + key_ref_t key_ref; + struct key *key; + struct public_key_signature *pks = NULL; + int retval = -EINVAL; + + key_ref = keyring_search(make_key_ref(system_trusted_keyring, 1), + &key_type_asymmetric, key_id); + + if (IS_ERR(key_ref)) { + DMERR("keyring: key not found"); + return -ENOKEY; + } + + key = key_ref_to_ptr(key_ref); + + pks = table_make_digest(HASH_ALGO_SHA256, + (const void *)metadata->verity_table, + le32_to_cpu(metadata->header->table_length)); + + if (IS_ERR(pks)) { + DMERR("hashing failed"); + goto error; + } + + retval = table_extract_mpi_array(pks, &metadata->header->signature[0], + RSANUMBYTES); + if (retval < 0) { + DMERR("Error extracting mpi %d", retval); + goto error; + } + + retval = verify_signature(key, pks); + mpi_free(pks->rsa.s); +error: + kfree(pks); + key_put(key); + + return retval; +} + +static void handle_error(void) +{ + int mode = verity_mode(); + if (mode == DM_VERITY_MODE_RESTART) { + DMERR("triggering restart"); + kernel_restart("dm-verity device corrupted"); + } else { + DMERR("Mounting verity root failed"); + } +} + +static inline bool test_mult_overflow(sector_t a, u32 b) +{ + sector_t r = (sector_t)~0ULL; + + sector_div(r, b); + return a > r; +} + +static int add_as_linear_device(struct dm_target *ti, char *dev) +{ + /*Move to linear mapping defines*/ + char *linear_table_args[DM_LINEAR_ARGS] = {dev, + DM_LINEAR_TARGET_OFFSET}; + int err = 0; + + android_verity_target.dtr = dm_linear_dtr, + android_verity_target.map = dm_linear_map, + android_verity_target.status = dm_linear_status, + android_verity_target.prepare_ioctl = dm_linear_prepare_ioctl, + android_verity_target.iterate_devices = dm_linear_iterate_devices, + android_verity_target.io_hints = NULL; + + err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args); + + if (!err) { + DMINFO("Added android-verity as a linear target"); + target_added = true; + } else + DMERR("Failed to add android-verity as linear target"); + + return err; +} + +/* + * Target parameters: + * <key id> Key id of the public key in the system keyring. + * Verity metadata's signature would be verified against + * this. If the key id contains spaces, replace them + * with '#'. + * <block device> The block device for which dm-verity is being setup. + */ +static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) +{ + dev_t uninitialized_var(dev); + struct android_metadata *metadata = NULL; + int err = 0, i, mode; + char *key_id, *table_ptr, dummy, *target_device, + *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS]; + /* One for specifying number of opt args and one for mode */ + sector_t data_sectors; + u32 data_block_size; + unsigned int no_of_args = VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS; + struct fec_header uninitialized_var(fec); + struct fec_ecc_metadata uninitialized_var(ecc); + char buf[FEC_ARG_LENGTH], *buf_ptr; + unsigned long long tmpll; + u64 uninitialized_var(device_size); + + if (argc == 1) { + /* Use the default keyid */ + if (default_verity_key_id()) + key_id = veritykeyid; + else if (!is_eng()) { + DMERR("veritykeyid= is not set"); + handle_error(); + return -EINVAL; + } + } else if (argc == 2) + key_id = argv[1]; + else { + DMERR("Incorrect number of arguments"); + handle_error(); + return -EINVAL; + } + + target_device = argv[0]; + + dev = name_to_dev_t(target_device); + if (!dev) { + DMERR("no dev found for %s", target_device); + handle_error(); + return -EINVAL; + } + + if (is_eng()) { + err = find_size(dev, &device_size); + if (err) { + DMERR("error finding bdev size"); + handle_error(); + return err; + } + + ti->len = device_size; + err = add_as_linear_device(ti, target_device); + if (err) { + handle_error(); + return err; + } + verity_enabled = false; + return 0; + } + + strreplace(key_id, '#', ' '); + + DMINFO("key:%s dev:%s", key_id, target_device); + + if (extract_fec_header(dev, &fec, &ecc)) { + DMERR("Error while extracting fec header"); + handle_error(); + return -EINVAL; + } + + err = extract_metadata(dev, &fec, &metadata, &verity_enabled); + + if (err) { + DMERR("Error while extracting metadata"); + handle_error(); + goto free_metadata; + } + + if (verity_enabled) { + err = verify_verity_signature(key_id, metadata); + + if (err) { + DMERR("Signature verification failed"); + handle_error(); + goto free_metadata; + } else + DMINFO("Signature verification success"); + } + + table_ptr = metadata->verity_table; + + for (i = 0; i < VERITY_TABLE_ARGS; i++) { + verity_table_args[i] = strsep(&table_ptr, " "); + if (verity_table_args[i] == NULL) + break; + } + + if (i != VERITY_TABLE_ARGS) { + DMERR("Verity table not in the expected format"); + err = -EINVAL; + handle_error(); + goto free_metadata; + } + + if (sscanf(verity_table_args[5], "%llu%c", &tmpll, &dummy) + != 1) { + DMERR("Verity table not in the expected format"); + handle_error(); + err = -EINVAL; + goto free_metadata; + } + + if (tmpll > ULONG_MAX) { + DMERR("<num_data_blocks> too large. Forgot to turn on CONFIG_LBDAF?"); + handle_error(); + err = -EINVAL; + goto free_metadata; + } + + data_sectors = tmpll; + + if (sscanf(verity_table_args[3], "%u%c", &data_block_size, &dummy) + != 1) { + DMERR("Verity table not in the expected format"); + handle_error(); + err = -EINVAL; + goto free_metadata; + } + + if (test_mult_overflow(data_sectors, data_block_size >> + SECTOR_SHIFT)) { + DMERR("data_sectors too large"); + handle_error(); + err = -EOVERFLOW; + goto free_metadata; + } + + data_sectors *= data_block_size >> SECTOR_SHIFT; + DMINFO("Data sectors %llu", (unsigned long long)data_sectors); + + /* update target length */ + ti->len = data_sectors; + + /* Setup linear target and free */ + if (!verity_enabled) { + err = add_as_linear_device(ti, target_device); + goto free_metadata; + } + + /*substitute data_dev and hash_dev*/ + verity_table_args[1] = target_device; + verity_table_args[2] = target_device; + + mode = verity_mode(); + + if (ecc.valid && IS_BUILTIN(CONFIG_DM_VERITY_FEC)) { + if (mode) { + err = snprintf(buf, FEC_ARG_LENGTH, + "%u %s " VERITY_TABLE_OPT_FEC_FORMAT, + 1 + VERITY_TABLE_OPT_FEC_ARGS, + mode == DM_VERITY_MODE_RESTART ? + VERITY_TABLE_OPT_RESTART : + VERITY_TABLE_OPT_LOGGING, + target_device, + ecc.start / FEC_BLOCK_SIZE, ecc.blocks, + ecc.roots); + } else { + err = snprintf(buf, FEC_ARG_LENGTH, + "%u " VERITY_TABLE_OPT_FEC_FORMAT, + VERITY_TABLE_OPT_FEC_ARGS, target_device, + ecc.start / FEC_BLOCK_SIZE, ecc.blocks, + ecc.roots); + } + } else if (mode) { + err = snprintf(buf, FEC_ARG_LENGTH, + "2 " VERITY_TABLE_OPT_IGNZERO " %s", + mode == DM_VERITY_MODE_RESTART ? + VERITY_TABLE_OPT_RESTART : VERITY_TABLE_OPT_LOGGING); + } else { + err = snprintf(buf, FEC_ARG_LENGTH, "1 %s", + "ignore_zero_blocks"); + } + + if (err < 0 || err >= FEC_ARG_LENGTH) + goto free_metadata; + + buf_ptr = buf; + + for (i = VERITY_TABLE_ARGS; i < (VERITY_TABLE_ARGS + + VERITY_TABLE_OPT_FEC_ARGS + 2); i++) { + verity_table_args[i] = strsep(&buf_ptr, " "); + if (verity_table_args[i] == NULL) { + no_of_args = i; + break; + } + } + + err = verity_ctr(ti, no_of_args, verity_table_args); + + if (err) + DMERR("android-verity failed to mount as verity target"); + else { + target_added = true; + DMINFO("android-verity mounted as verity target"); + } + +free_metadata: + if (metadata) { + kfree(metadata->header); + kfree(metadata->verity_table); + } + kfree(metadata); + return err; +} + +static int __init dm_android_verity_init(void) +{ + int r; + struct dentry *file; + + r = dm_register_target(&android_verity_target); + if (r < 0) + DMERR("register failed %d", r); + + /* Tracks the status of the last added target */ + debug_dir = debugfs_create_dir("android_verity", NULL); + + if (IS_ERR_OR_NULL(debug_dir)) { + DMERR("Cannot create android_verity debugfs directory: %ld", + PTR_ERR(debug_dir)); + goto end; + } + + file = debugfs_create_bool("target_added", S_IRUGO, debug_dir, + &target_added); + + if (IS_ERR_OR_NULL(file)) { + DMERR("Cannot create android_verity debugfs directory: %ld", + PTR_ERR(debug_dir)); + debugfs_remove_recursive(debug_dir); + goto end; + } + + file = debugfs_create_bool("verity_enabled", S_IRUGO, debug_dir, + &verity_enabled); + + if (IS_ERR_OR_NULL(file)) { + DMERR("Cannot create android_verity debugfs directory: %ld", + PTR_ERR(debug_dir)); + debugfs_remove_recursive(debug_dir); + } + +end: + return r; +} + +static void __exit dm_android_verity_exit(void) +{ + if (!IS_ERR_OR_NULL(debug_dir)) + debugfs_remove_recursive(debug_dir); + + dm_unregister_target(&android_verity_target); +} + +module_init(dm_android_verity_init); +module_exit(dm_android_verity_exit); diff --git a/drivers/md/dm-android-verity.h b/drivers/md/dm-android-verity.h new file mode 100644 index 000000000000..0fcd54aaf5f6 --- /dev/null +++ b/drivers/md/dm-android-verity.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef DM_ANDROID_VERITY_H +#define DM_ANDROID_VERITY_H + +#include <crypto/sha.h> + +#define RSANUMBYTES 256 +#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 +#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 +#define VERITY_METADATA_VERSION 0 +#define VERITY_STATE_DISABLE 1 +#define DATA_BLOCK_SIZE (4 * 1024) +#define VERITY_METADATA_SIZE (8 * DATA_BLOCK_SIZE) +#define VERITY_TABLE_ARGS 10 +#define VERITY_COMMANDLINE_PARAM_LENGTH 20 +#define BUILD_VARIANT 20 + +/* + * <subject>:<sha1-id> is the format for the identifier. + * subject can either be the Common Name(CN) + Organization Name(O) or + * just the CN if the it is prefixed with O + * From https://tools.ietf.org/html/rfc5280#appendix-A + * ub-organization-name-length INTEGER ::= 64 + * ub-common-name-length INTEGER ::= 64 + * + * http://lxr.free-electrons.com/source/crypto/asymmetric_keys/x509_cert_parser.c?v=3.9#L278 + * ctx->o_size + 2 + ctx->cn_size + 1 + * + 41 characters for ":" and sha1 id + * 64 + 2 + 64 + 1 + 1 + 40 (172) + * setting VERITY_DEFAULT_KEY_ID_LENGTH to 200 characters. + */ +#define VERITY_DEFAULT_KEY_ID_LENGTH 200 + +#define FEC_MAGIC 0xFECFECFE +#define FEC_BLOCK_SIZE (4 * 1024) +#define FEC_VERSION 0 +#define FEC_RSM 255 +#define FEC_ARG_LENGTH 300 + +#define VERITY_TABLE_OPT_RESTART "restart_on_corruption" +#define VERITY_TABLE_OPT_LOGGING "ignore_corruption" +#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks" + +#define VERITY_TABLE_OPT_FEC_FORMAT \ + "use_fec_from_device %s fec_start %llu fec_blocks %llu fec_roots %u ignore_zero_blocks" +#define VERITY_TABLE_OPT_FEC_ARGS 9 + +#define VERITY_DEBUG 0 + +#define DM_MSG_PREFIX "android-verity" + +#define DM_LINEAR_ARGS 2 +#define DM_LINEAR_TARGET_OFFSET "0" + +/* + * There can be two formats. + * if fec is present + * <data_blocks> <verity_tree> <verity_metdata_32K><fec_data><fec_data_4K> + * if fec is not present + * <data_blocks> <verity_tree> <verity_metdata_32K> + */ +/* TODO: rearrange structure to reduce memory holes + * depends on userspace change. + */ +struct fec_header { + __le32 magic; + __le32 version; + __le32 size; + __le32 roots; + __le32 fec_size; + __le64 inp_size; + u8 hash[SHA256_DIGEST_SIZE]; +}; + +struct android_metadata_header { + __le32 magic_number; + __le32 protocol_version; + char signature[RSANUMBYTES]; + __le32 table_length; +}; + +struct android_metadata { + struct android_metadata_header *header; + char *verity_table; +}; + +struct fec_ecc_metadata { + bool valid; + u32 roots; + u64 blocks; + u64 rounds; + u64 start; +}; + +struct bio_read { + struct page **page_io; + int number_of_pages; +}; + +extern struct target_type linear_target; + +extern void dm_linear_dtr(struct dm_target *ti); +extern int dm_linear_map(struct dm_target *ti, struct bio *bio); +extern void dm_linear_status(struct dm_target *ti, status_type_t type, + unsigned status_flags, char *result, unsigned maxlen); +extern int dm_linear_prepare_ioctl(struct dm_target *ti, + struct block_device **bdev, fmode_t *mode); +extern int dm_linear_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data); +extern int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv); +#endif /* DM_ANDROID_VERITY_H */ diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 05c35aacb3aa..8505a771de42 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -25,7 +25,7 @@ struct linear_c { /* * Construct a linear mapping: <dev_path> <offset> */ -static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) +int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct linear_c *lc; unsigned long long tmp; @@ -67,7 +67,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) return ret; } -static void linear_dtr(struct dm_target *ti) +void dm_linear_dtr(struct dm_target *ti) { struct linear_c *lc = (struct linear_c *) ti->private; @@ -92,14 +92,14 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio) linear_map_sector(ti, bio->bi_iter.bi_sector); } -static int linear_map(struct dm_target *ti, struct bio *bio) +int dm_linear_map(struct dm_target *ti, struct bio *bio) { linear_map_bio(ti, bio); return DM_MAPIO_REMAPPED; } -static void linear_status(struct dm_target *ti, status_type_t type, +void dm_linear_status(struct dm_target *ti, status_type_t type, unsigned status_flags, char *result, unsigned maxlen) { struct linear_c *lc = (struct linear_c *) ti->private; @@ -116,7 +116,7 @@ static void linear_status(struct dm_target *ti, status_type_t type, } } -static int linear_prepare_ioctl(struct dm_target *ti, +int dm_linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev, fmode_t *mode) { struct linear_c *lc = (struct linear_c *) ti->private; @@ -133,7 +133,7 @@ static int linear_prepare_ioctl(struct dm_target *ti, return 0; } -static int linear_iterate_devices(struct dm_target *ti, +int dm_linear_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { struct linear_c *lc = ti->private; @@ -145,12 +145,12 @@ static struct target_type linear_target = { .name = "linear", .version = {1, 2, 1}, .module = THIS_MODULE, - .ctr = linear_ctr, - .dtr = linear_dtr, - .map = linear_map, - .status = linear_status, - .prepare_ioctl = linear_prepare_ioctl, - .iterate_devices = linear_iterate_devices, + .ctr = dm_linear_ctr, + .dtr = dm_linear_dtr, + .map = dm_linear_map, + .status = dm_linear_status, + .prepare_ioctl = dm_linear_prepare_ioctl, + .iterate_devices = dm_linear_iterate_devices, }; int __init dm_linear_init(void) diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index ad10d6d8ed28..1dd667b97530 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -442,6 +442,13 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, if (!verity_fec_is_enabled(v)) return -EOPNOTSUPP; + if (fio->level >= DM_VERITY_FEC_MAX_RECURSION) { + DMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name); + return -EIO; + } + + fio->level++; + if (type == DM_VERITY_BLOCK_TYPE_METADATA) block += v->data_blocks; @@ -456,9 +463,7 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, */ offset = block << v->data_dev_block_bits; - - res = offset; - div64_u64(res, v->fec->rounds << v->data_dev_block_bits); + res = div64_u64(offset, v->fec->rounds << v->data_dev_block_bits); /* * The base RS block we can feed to the interleaver to find out all @@ -475,7 +480,7 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, if (r < 0) { r = fec_decode_rsb(v, io, fio, rsb, offset, true); if (r < 0) - return r; + goto done; } if (dest) @@ -485,6 +490,8 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, r = verity_for_bv_block(v, io, iter, fec_bv_copy); } +done: + fio->level--; return r; } @@ -525,6 +532,7 @@ void verity_fec_init_io(struct dm_verity_io *io) memset(fio->bufs, 0, sizeof(fio->bufs)); fio->nbufs = 0; fio->output = NULL; + fio->level = 0; } /* @@ -680,7 +688,8 @@ static struct attribute *fec_attrs[] = { static struct kobj_type fec_ktype = { .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = fec_attrs + .default_attrs = fec_attrs, + .release = dm_kobject_release }; /* diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h index 8c4bee052a73..b8e21cef3ad1 100644 --- a/drivers/md/dm-verity-fec.h +++ b/drivers/md/dm-verity-fec.h @@ -28,6 +28,9 @@ #define DM_VERITY_FEC_BUF_MAX \ (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS)) +/* maximum recursion level for verity_fec_decode */ +#define DM_VERITY_FEC_MAX_RECURSION 4 + #define DM_VERITY_OPT_FEC_DEV "use_fec_from_device" #define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks" #define DM_VERITY_OPT_FEC_START "fec_start" @@ -61,6 +64,7 @@ struct dm_verity_fec_io { unsigned nbufs; /* number of buffers allocated */ u8 *output; /* buffer for corrected output */ size_t output_pos; + unsigned level; /* recursion level */ }; #ifdef CONFIG_DM_VERITY_FEC diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 5c5d30cb6ec5..5214ed2c7507 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -551,7 +551,7 @@ static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io) * Bio map function. It allocates dm_verity_io structure and bio vector and * fills them. Then it issues prefetches and the I/O. */ -static int verity_map(struct dm_target *ti, struct bio *bio) +int verity_map(struct dm_target *ti, struct bio *bio) { struct dm_verity *v = ti->private; struct dm_verity_io *io; @@ -596,7 +596,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio) /* * Status: V (valid) or C (corruption found) */ -static void verity_status(struct dm_target *ti, status_type_t type, +void verity_status(struct dm_target *ti, status_type_t type, unsigned status_flags, char *result, unsigned maxlen) { struct dm_verity *v = ti->private; @@ -656,7 +656,7 @@ static void verity_status(struct dm_target *ti, status_type_t type, } } -static int verity_prepare_ioctl(struct dm_target *ti, +int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev, fmode_t *mode) { struct dm_verity *v = ti->private; @@ -669,7 +669,7 @@ static int verity_prepare_ioctl(struct dm_target *ti, return 0; } -static int verity_iterate_devices(struct dm_target *ti, +int verity_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { struct dm_verity *v = ti->private; @@ -677,7 +677,7 @@ static int verity_iterate_devices(struct dm_target *ti, return fn(ti, v->data_dev, v->data_start, ti->len, data); } -static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits) +void verity_io_hints(struct dm_target *ti, struct queue_limits *limits) { struct dm_verity *v = ti->private; @@ -690,7 +690,7 @@ static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits) blk_limits_io_min(limits, limits->logical_block_size); } -static void verity_dtr(struct dm_target *ti) +void verity_dtr(struct dm_target *ti) { struct dm_verity *v = ti->private; @@ -817,7 +817,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v) * <digest> * <salt> Hex string or "-" if no salt. */ -static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) +int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) { struct dm_verity *v; struct dm_arg_set as; diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index fb419f422d73..75effca400a3 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -126,4 +126,14 @@ extern int verity_hash(struct dm_verity *v, struct shash_desc *desc, extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, sector_t block, u8 *digest, bool *is_zero); +extern void verity_status(struct dm_target *ti, status_type_t type, + unsigned status_flags, char *result, unsigned maxlen); +extern int verity_prepare_ioctl(struct dm_target *ti, + struct block_device **bdev, fmode_t *mode); +extern int verity_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data); +extern void verity_io_hints(struct dm_target *ti, struct queue_limits *limits); +extern void verity_dtr(struct dm_target *ti); +extern int verity_ctr(struct dm_target *ti, unsigned argc, char **argv); +extern int verity_map(struct dm_target *ti, struct bio *bio); #endif /* DM_VERITY_H */ diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index a18840b1a1a4..88a3b4b6f7ba 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -112,6 +112,7 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, u8 *data_ptr; int prop_id; enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth; + struct hfi_colour_space *colour_info; if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) { dprintk(VIDC_ERR, @@ -205,6 +206,18 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, data_ptr += sizeof(struct hfi_pic_struct); break; + case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + data_ptr = data_ptr + sizeof(u32); + colour_info = + (struct hfi_colour_space *) data_ptr; + event_notify.colour_space = + colour_info->colour_space; + dprintk(VIDC_DBG, + "Colour space value is: %d\n", + colour_info->colour_space); + data_ptr += + sizeof(struct hfi_colour_space); + break; default: dprintk(VIDC_ERR, "%s cmd: %#x not supported\n", diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index b12eeddc678f..93e32ef4ac35 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1172,6 +1172,7 @@ void *msm_vidc_open(int core_id, int session_type) inst->bit_depth = MSM_VIDC_BIT_DEPTH_8; inst->instant_bitrate = 0; inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE; + inst->colour_space = MSM_VIDC_BT601_6_525; for (i = SESSION_MSG_INDEX(SESSION_MSG_START); i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index d1cc08d53017..3671d5fa6479 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1200,29 +1200,46 @@ static void handle_event_change(enum hal_command_response cmd, void *data) * ptr[2] = flag to indicate bit depth or/and pic struct changed * ptr[3] = bit depth * ptr[4] = pic struct (progressive or interlaced) + * ptr[5] = colour space */ ptr = (u32 *)seq_changed_event.u.data; - ptr[2] = 0x0; - ptr[3] = inst->bit_depth; - ptr[4] = inst->pic_struct; - if (inst->bit_depth != event_notify->bit_depth) { - inst->bit_depth = event_notify->bit_depth; - ptr[2] |= V4L2_EVENT_BITDEPTH_FLAG; + if (ptr != NULL) { + ptr[2] = 0x0; ptr[3] = inst->bit_depth; - event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; - dprintk(VIDC_DBG, - "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to bit-depth change\n"); - } - - if (inst->pic_struct != event_notify->pic_struct) { - inst->pic_struct = event_notify->pic_struct; - event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; - ptr[2] |= V4L2_EVENT_PICSTRUCT_FLAG; ptr[4] = inst->pic_struct; - dprintk(VIDC_DBG, - "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to pic-struct change\n"); + ptr[5] = inst->colour_space; + + if (inst->bit_depth != event_notify->bit_depth) { + inst->bit_depth = event_notify->bit_depth; + ptr[2] |= V4L2_EVENT_BITDEPTH_FLAG; + ptr[3] = inst->bit_depth; + event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; + dprintk(VIDC_DBG, + "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to bit-depth change\n"); + } + + if (inst->pic_struct != event_notify->pic_struct) { + inst->pic_struct = event_notify->pic_struct; + event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; + ptr[2] |= V4L2_EVENT_PICSTRUCT_FLAG; + ptr[4] = inst->pic_struct; + dprintk(VIDC_DBG, + "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to pic-struct change\n"); + } + + if (inst->bit_depth == MSM_VIDC_BIT_DEPTH_10 + && inst->colour_space != + event_notify->colour_space) { + inst->colour_space = event_notify->colour_space; + event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; + ptr[2] |= V4L2_EVENT_COLOUR_SPACE_FLAG; + ptr[5] = inst->colour_space; + dprintk(VIDC_DBG, + "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to colour space change\n"); + } + } if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 161e94f99040..ffe4456570e3 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -297,6 +297,7 @@ struct msm_vidc_inst { u32 buffers_held_in_driver; atomic_t in_flush; u32 pic_struct; + u32 colour_space; }; extern struct msm_vidc_drv *vidc_driver; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 34ab36a4647b..aa566159c393 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -1357,6 +1357,7 @@ struct msm_vidc_cb_event { ion_phys_addr_t packet_buffer; ion_phys_addr_t extra_data_buffer; u32 pic_struct; + u32 colour_space; }; struct msm_vidc_cb_data_done { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 23240746baf1..5e5ef6abc303 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -293,6 +293,8 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x007) #define HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT \ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x009) +#define HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00A) #define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \ @@ -435,6 +437,10 @@ struct hfi_bitrate { u32 layer_id; }; +struct hfi_colour_space { + u32 colour_space; +}; + #define HFI_CAPABILITY_FRAME_WIDTH (HFI_COMMON_BASE + 0x1) #define HFI_CAPABILITY_FRAME_HEIGHT (HFI_COMMON_BASE + 0x2) #define HFI_CAPABILITY_MBS_PER_FRAME (HFI_COMMON_BASE + 0x3) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 862d72cb86cf..ff838ebefba6 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1065,6 +1065,10 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc, } /* Populate the structure for sending scm call to load image */ svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle); + if (IS_ERR_OR_NULL(svc->sb_virt)) { + pr_err("ION memory mapping for listener shared buffer failed\n"); + return -ENOMEM; + } svc->sb_phys = (phys_addr_t)pa; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -1522,6 +1526,10 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, /* Populate the structure for sending scm call to load image */ data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, data->client.ihandle); + if (IS_ERR_OR_NULL(data->client.sb_virt)) { + pr_err("ION memory mapping for client shared buf failed\n"); + return -ENOMEM; + } data->client.sb_phys = (phys_addr_t)pa; data->client.sb_length = req.sb_len; data->client.user_virt_sb_base = (uintptr_t)req.virt_sb_base; @@ -4203,6 +4211,11 @@ int qseecom_start_app(struct qseecom_handle **handle, /* Populate the structure for sending scm call to load image */ data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, data->client.ihandle); + if (IS_ERR_OR_NULL(data->client.sb_virt)) { + pr_err("ION memory mapping for client shared buf failed\n"); + ret = -ENOMEM; + goto err; + } data->client.user_virt_sb_base = (uintptr_t)data->client.sb_virt; data->client.sb_phys = (phys_addr_t)pa; (*handle)->dev = (void *)data; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 64046e0bd0a2..c3853a63b083 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -141,7 +141,7 @@ static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp) unmask_halp ? WIL6210_IMC_MISC : WIL6210_IMC_MISC_NO_HALP); } -static void wil6210_unmask_halp(struct wil6210_priv *wil) +void wil6210_unmask_halp(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); @@ -149,7 +149,7 @@ static void wil6210_unmask_halp(struct wil6210_priv *wil) BIT_DMA_EP_MISC_ICR_HALP); } -static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) +void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 5285ebc8b9af..94e5b67abd59 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -875,19 +875,29 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); + wil6210_unmask_irq_pseudo(wil); + wil6210_unmask_halp(wil); + wil_halp_vote(wil); + wil_bl_crash_info(wil, false); rc = wil_target_reset(wil); + /* wil_target_reset clears the HALP IRQ, need to set it again. + * Call wil_halp_unvote to clear the HALP reference counter + * and unmask the HALP interrupt before setting it again + */ + wil_halp_unvote(wil); + wil_halp_vote(wil); wil_rx_fini(wil); if (rc) { wil_bl_crash_info(wil, true); - return rc; + goto out; } rc = wil_get_bl_info(wil); if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ rc = 0; if (rc) - return rc; + goto out; wil_set_oob_mode(wil, oob_mode); if (load_fw) { @@ -899,14 +909,19 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* Loading f/w from the file */ rc = wil_request_firmware(wil, WIL_FW_NAME, true); if (rc) - return rc; + goto out; rc = wil_request_firmware(wil, WIL_FW2_NAME, true); if (rc) - return rc; + goto out; /* Mark FW as loaded from host */ wil_s(wil, RGF_USER_USAGE_6, 1); + /* Clear the HALP while in BL, before clearing all the IRQs + * and running the FW. + */ + wil_halp_unvote(wil); + /* clear any interrupts which on-card-firmware * may have set */ @@ -917,6 +932,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); wil_release_cpu(wil); + } else { + /* Allow XTAL off when going down */ + wil_halp_unvote(wil); } /* init after reset */ @@ -955,6 +973,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) } return rc; + +out: + wil_halp_unvote(wil); + return rc; } void wil_fw_error_recovery(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a19dba5b9e5f..8961b4ce4898 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -837,6 +837,7 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil); void wil_disable_irq(struct wil6210_priv *wil); void wil_enable_irq(struct wil6210_priv *wil); void wil6210_mask_halp(struct wil6210_priv *wil); +void wil6210_unmask_halp(struct wil6210_priv *wil); /* P2P */ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request); @@ -902,6 +903,8 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil); void wil_rx_handle(struct wil6210_priv *wil, int *quota); void wil6210_unmask_irq_rx(struct wil6210_priv *wil); +void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil); + int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index d18308344431..293371b88ab9 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -127,6 +127,7 @@ enum ipa3_usb_state { IPA_USB_SUSPEND_REQUESTED, IPA_USB_SUSPEND_IN_PROGRESS, IPA_USB_SUSPENDED, + IPA_USB_SUSPENDED_NO_RWAKEUP, IPA_USB_RESUME_IN_PROGRESS }; @@ -152,6 +153,12 @@ struct finish_suspend_work_context { u32 ul_clnt_hdl; }; +struct ipa3_usb_teth_prot_conn_params { + u32 usb_to_ipa_clnt_hdl; + u32 ipa_to_usb_clnt_hdl; + struct ipa_usb_teth_prot_params params; +}; + /** * Transport type - could be either data tethering or DPL * Each transport has it's own RM resources and statuses @@ -163,6 +170,7 @@ struct ipa3_usb_transport_type_ctx { enum ipa3_usb_state state; struct finish_suspend_work_context finish_suspend_work; struct ipa_usb_xdci_chan_params ch_params; + struct ipa3_usb_teth_prot_conn_params teth_conn_params; }; struct ipa3_usb_smmu_reg_map { @@ -189,14 +197,15 @@ struct ipa3_usb_context { }; enum ipa3_usb_op { - IPA_USB_INIT_TETH_PROT, - IPA_USB_REQUEST_CHANNEL, - IPA_USB_CONNECT, - IPA_USB_DISCONNECT, - IPA_USB_RELEASE_CHANNEL, - IPA_USB_DEINIT_TETH_PROT, - IPA_USB_SUSPEND, - IPA_USB_RESUME + IPA_USB_OP_INIT_TETH_PROT, + IPA_USB_OP_REQUEST_CHANNEL, + IPA_USB_OP_CONNECT, + IPA_USB_OP_DISCONNECT, + IPA_USB_OP_RELEASE_CHANNEL, + IPA_USB_OP_DEINIT_TETH_PROT, + IPA_USB_OP_SUSPEND, + IPA_USB_OP_SUSPEND_NO_RWAKEUP, + IPA_USB_OP_RESUME }; struct ipa3_usb_status_dbg_info { @@ -228,22 +237,24 @@ struct ipa3_usb_context *ipa3_usb_ctx; static char *ipa3_usb_op_to_string(enum ipa3_usb_op op) { switch (op) { - case IPA_USB_INIT_TETH_PROT: - return "IPA_USB_INIT_TETH_PROT"; - case IPA_USB_REQUEST_CHANNEL: - return "IPA_USB_REQUEST_CHANNEL"; - case IPA_USB_CONNECT: - return "IPA_USB_CONNECT"; - case IPA_USB_DISCONNECT: - return "IPA_USB_DISCONNECT"; - case IPA_USB_RELEASE_CHANNEL: - return "IPA_USB_RELEASE_CHANNEL"; - case IPA_USB_DEINIT_TETH_PROT: - return "IPA_USB_DEINIT_TETH_PROT"; - case IPA_USB_SUSPEND: - return "IPA_USB_SUSPEND"; - case IPA_USB_RESUME: - return "IPA_USB_RESUME"; + case IPA_USB_OP_INIT_TETH_PROT: + return "IPA_USB_OP_INIT_TETH_PROT"; + case IPA_USB_OP_REQUEST_CHANNEL: + return "IPA_USB_OP_REQUEST_CHANNEL"; + case IPA_USB_OP_CONNECT: + return "IPA_USB_OP_CONNECT"; + case IPA_USB_OP_DISCONNECT: + return "IPA_USB_OP_DISCONNECT"; + case IPA_USB_OP_RELEASE_CHANNEL: + return "IPA_USB_OP_RELEASE_CHANNEL"; + case IPA_USB_OP_DEINIT_TETH_PROT: + return "IPA_USB_OP_DEINIT_TETH_PROT"; + case IPA_USB_OP_SUSPEND: + return "IPA_USB_OP_SUSPEND"; + case IPA_USB_OP_SUSPEND_NO_RWAKEUP: + return "IPA_USB_OP_SUSPEND_NO_RWAKEUP"; + case IPA_USB_OP_RESUME: + return "IPA_USB_OP_RESUME"; } return "UNSUPPORTED"; @@ -266,6 +277,8 @@ static char *ipa3_usb_state_to_string(enum ipa3_usb_state state) return "IPA_USB_SUSPEND_IN_PROGRESS"; case IPA_USB_SUSPENDED: return "IPA_USB_SUSPENDED"; + case IPA_USB_SUSPENDED_NO_RWAKEUP: + return "IPA_USB_SUSPENDED_NO_RWAKEUP"; case IPA_USB_RESUME_IN_PROGRESS: return "IPA_USB_RESUME_IN_PROGRESS"; } @@ -312,6 +325,7 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED || state == IPA_USB_RESUME_IN_PROGRESS || + state == IPA_USB_SUSPENDED_NO_RWAKEUP || /* * In case of failure during suspend request * handling, state is reverted to connected. @@ -327,7 +341,8 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, case IPA_USB_STOPPED: if (state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_CONNECTED || - state == IPA_USB_SUSPENDED) + state == IPA_USB_SUSPENDED || + state == IPA_USB_SUSPENDED_NO_RWAKEUP) state_legal = true; break; case IPA_USB_SUSPEND_REQUESTED: @@ -354,6 +369,10 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, (err_permit && state == IPA_USB_RESUME_IN_PROGRESS)) state_legal = true; break; + case IPA_USB_SUSPENDED_NO_RWAKEUP: + if (state == IPA_USB_CONNECTED) + state_legal = true; + break; case IPA_USB_RESUME_IN_PROGRESS: if (state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED) @@ -418,32 +437,33 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); state = ipa3_usb_ctx->ttype_ctx[ttype].state; switch (op) { - case IPA_USB_INIT_TETH_PROT: + case IPA_USB_OP_INIT_TETH_PROT: if (state == IPA_USB_INVALID || (!is_dpl && state == IPA_USB_INITIALIZED)) is_legal = true; break; - case IPA_USB_REQUEST_CHANNEL: + case IPA_USB_OP_REQUEST_CHANNEL: if (state == IPA_USB_INITIALIZED) is_legal = true; break; - case IPA_USB_CONNECT: + case IPA_USB_OP_CONNECT: if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED) is_legal = true; break; - case IPA_USB_DISCONNECT: + case IPA_USB_OP_DISCONNECT: if (state == IPA_USB_CONNECTED || state == IPA_USB_SUSPEND_IN_PROGRESS || - state == IPA_USB_SUSPENDED) + state == IPA_USB_SUSPENDED || + state == IPA_USB_SUSPENDED_NO_RWAKEUP) is_legal = true; break; - case IPA_USB_RELEASE_CHANNEL: + case IPA_USB_OP_RELEASE_CHANNEL: /* when releasing 1st channel state will be changed already */ if (state == IPA_USB_STOPPED || (!is_dpl && state == IPA_USB_INITIALIZED)) is_legal = true; break; - case IPA_USB_DEINIT_TETH_PROT: + case IPA_USB_OP_DEINIT_TETH_PROT: /* * For data tethering we should allow deinit an inited protocol * always. E.g. rmnet is inited and rndis is connected. @@ -453,13 +473,18 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, if (!is_dpl || state == IPA_USB_INITIALIZED) is_legal = true; break; - case IPA_USB_SUSPEND: + case IPA_USB_OP_SUSPEND: if (state == IPA_USB_CONNECTED) is_legal = true; break; - case IPA_USB_RESUME: + case IPA_USB_OP_SUSPEND_NO_RWAKEUP: + if (state == IPA_USB_CONNECTED) + is_legal = true; + break; + case IPA_USB_OP_RESUME: if (state == IPA_USB_SUSPENDED || - state == IPA_USB_SUSPEND_IN_PROGRESS) + state == IPA_USB_SUSPEND_IN_PROGRESS || + state == IPA_USB_SUSPENDED_NO_RWAKEUP) is_legal = true; break; default: @@ -638,6 +663,7 @@ static int ipa3_usb_cons_request_resource_cb_do( ipa3_usb_ctx->ttype_ctx[ttype].state)); switch (ipa3_usb_ctx->ttype_ctx[ttype].state) { case IPA_USB_CONNECTED: + case IPA_USB_SUSPENDED_NO_RWAKEUP: rm_ctx->cons_state = IPA_USB_CONS_GRANTED; result = 0; break; @@ -717,6 +743,7 @@ static int ipa3_usb_cons_release_resource_cb_do( break; case IPA_USB_STOPPED: case IPA_USB_RESUME_IN_PROGRESS: + case IPA_USB_SUSPENDED_NO_RWAKEUP: if (rm_ctx->cons_requested) rm_ctx->cons_requested = false; break; @@ -886,7 +913,7 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, ttype = IPA3_USB_GET_TTYPE(teth_prot); - if (!ipa3_usb_check_legal_op(IPA_USB_INIT_TETH_PROT, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; @@ -1204,7 +1231,7 @@ static int ipa3_usb_request_xdci_channel( ttype = IPA3_USB_GET_TTYPE(params->teth_prot); - if (!ipa3_usb_check_legal_op(IPA_USB_REQUEST_CHANNEL, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) { IPA_USB_ERR("Illegal operation\n"); return -EPERM; } @@ -1347,7 +1374,7 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, return -EINVAL; } - if (!ipa3_usb_check_legal_op(IPA_USB_RELEASE_CHANNEL, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) { IPA_USB_ERR("Illegal operation.\n"); return -EPERM; } @@ -1511,81 +1538,79 @@ static int ipa3_usb_connect_dpl(void) return 0; } -static int ipa3_usb_connect_teth_prot( - struct ipa_usb_xdci_connect_params_internal *params, - enum ipa3_usb_transport_type ttype) +static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) { int result; struct teth_bridge_connect_params teth_bridge_params; + struct ipa3_usb_teth_prot_conn_params *teth_conn_params; + enum ipa3_usb_transport_type ttype; - IPA_USB_DBG("connecting protocol = %d\n", - params->teth_prot); - switch (params->teth_prot) { + IPA_USB_DBG("connecting protocol = %s\n", + ipa3_usb_teth_prot_to_string(teth_prot)); + + ttype = IPA3_USB_GET_TTYPE(teth_prot); + + teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params); + + switch (teth_prot) { case IPA_USB_RNDIS: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data; result = rndis_ipa_pipe_connect_notify( - params->usb_to_ipa_clnt_hdl, - params->ipa_to_usb_clnt_hdl, - params->teth_prot_params.max_xfer_size_bytes_to_dev, - params->teth_prot_params.max_packet_number_to_dev, - params->teth_prot_params.max_xfer_size_bytes_to_host, + teth_conn_params->usb_to_ipa_clnt_hdl, + teth_conn_params->ipa_to_usb_clnt_hdl, + teth_conn_params->params.max_xfer_size_bytes_to_dev, + teth_conn_params->params.max_packet_number_to_dev, + teth_conn_params->params.max_xfer_size_bytes_to_host, ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS]. teth_prot_params.rndis.private); if (result) { IPA_USB_ERR("failed to connect %s.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state = IPA_USB_TETH_PROT_CONNECTED; IPA_USB_DBG("%s is connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_ECM: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data; - result = ecm_ipa_connect(params->usb_to_ipa_clnt_hdl, - params->ipa_to_usb_clnt_hdl, + result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl, + teth_conn_params->ipa_to_usb_clnt_hdl, ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM]. teth_prot_params.ecm.private); if (result) { IPA_USB_ERR("failed to connect %s.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state = IPA_USB_TETH_PROT_CONNECTED; IPA_USB_DBG("%s is connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_RMNET: case IPA_USB_MBIM: - if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state == + if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; } result = ipa3_usb_init_teth_bridge(); @@ -1593,14 +1618,14 @@ static int ipa3_usb_connect_teth_prot( return result; ipa3_usb_ctx->ttype_ctx[ttype].user_data = - ipa3_usb_ctx->teth_prot_ctx[params->teth_prot]. + ipa3_usb_ctx->teth_prot_ctx[teth_prot]. user_data; teth_bridge_params.ipa_usb_pipe_hdl = - params->ipa_to_usb_clnt_hdl; + teth_conn_params->ipa_to_usb_clnt_hdl; teth_bridge_params.usb_ipa_pipe_hdl = - params->usb_to_ipa_clnt_hdl; + teth_conn_params->usb_to_ipa_clnt_hdl; teth_bridge_params.tethering_mode = - (params->teth_prot == IPA_USB_RMNET) ? + (teth_prot == IPA_USB_RMNET) ? (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM); teth_bridge_params.client_type = IPA_CLIENT_USB_PROD; result = ipa3_usb_connect_teth_bridge(&teth_bridge_params); @@ -1608,27 +1633,23 @@ static int ipa3_usb_connect_teth_prot( ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } - ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state = + ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); IPA_USB_DBG("%s (%s) is connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot), - ipa3_usb_teth_bridge_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot), + ipa3_usb_teth_bridge_prot_to_string(teth_prot)); break; case IPA_USB_DIAG: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = - ipa3_usb_ctx->teth_prot_ctx[params->teth_prot]. - user_data; + ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data; result = ipa3_usb_connect_dpl(); if (result) { IPA_USB_ERR("Failed connecting DPL result=%d\n", @@ -1640,8 +1661,7 @@ static int ipa3_usb_connect_teth_prot( IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); IPA_USB_DBG("%s is connected.\n", - ipa3_usb_teth_prot_to_string( - params->teth_prot)); + ipa3_usb_teth_prot_to_string(teth_prot)); break; default: IPA_USB_ERR("Invalid tethering protocol\n"); @@ -1775,11 +1795,19 @@ static int ipa3_usb_xdci_connect_internal( ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH; - if (!ipa3_usb_check_legal_op(IPA_USB_CONNECT, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); return -EPERM; } + ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl + = params->ipa_to_usb_clnt_hdl; + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) + ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params. + usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl; + ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params + = params->teth_prot_params; + /* Set EE xDCI specific scratch */ result = ipa3_set_usb_max_packet_size(params->max_pkt_size); if (result) { @@ -1816,7 +1844,7 @@ static int ipa3_usb_xdci_connect_internal( if (params->teth_prot != IPA_USB_DIAG) { /* Start UL channel */ - result = ipa3_xdci_connect(params->usb_to_ipa_clnt_hdl, + result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl, params->usb_to_ipa_xferrscidx, params->usb_to_ipa_xferrscidx_valid); if (result) { @@ -1826,7 +1854,7 @@ static int ipa3_usb_xdci_connect_internal( } /* Start DL/DPL channel */ - result = ipa3_xdci_connect(params->ipa_to_usb_clnt_hdl, + result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl, params->ipa_to_usb_xferrscidx, params->ipa_to_usb_xferrscidx_valid); if (result) { @@ -1835,7 +1863,7 @@ static int ipa3_usb_xdci_connect_internal( } /* Connect tethering protocol */ - result = ipa3_usb_connect_teth_prot(params, ttype); + result = ipa3_usb_connect_teth_prot(params->teth_prot); if (result) { IPA_USB_ERR("failed to connect teth protocol\n"); goto connect_teth_prot_fail; @@ -2164,6 +2192,70 @@ static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot) return 0; } +/* Assumes lock already acquired */ +static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl, + enum ipa_usb_teth_prot teth_prot) +{ + int result = 0; + enum ipa3_usb_transport_type ttype; + + ttype = IPA3_USB_GET_TTYPE(teth_prot); + + IPA_USB_DBG_LOW("entry\n"); + + /* Reset DL channel */ + result = ipa3_reset_gsi_channel(dl_clnt_hdl); + if (result) { + IPA_USB_ERR("failed to reset DL channel.\n"); + return result; + } + + /* Reset DL event ring */ + result = ipa3_reset_gsi_event_ring(dl_clnt_hdl); + if (result) { + IPA_USB_ERR("failed to reset DL event ring.\n"); + return result; + } + + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { + /* Reset UL channel */ + result = ipa3_reset_gsi_channel(ul_clnt_hdl); + if (result) { + IPA_USB_ERR("failed to reset UL channel.\n"); + return result; + } + + /* Reset UL event ring */ + result = ipa3_reset_gsi_event_ring(ul_clnt_hdl); + if (result) { + IPA_USB_ERR("failed to reset UL event ring.\n"); + return result; + } + } + + /* Change state to STOPPED */ + if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) + IPA_USB_ERR("failed to change state to stopped\n"); + + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { + result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); + if (result) { + IPA_USB_ERR("failed to release UL channel.\n"); + return result; + } + } + + result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); + if (result) { + IPA_USB_ERR("failed to release DL channel.\n"); + return result; + } + + IPA_USB_DBG_LOW("exit\n"); + + return 0; +} + int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { @@ -2175,20 +2267,31 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); - if (ipa3_usb_check_disconnect_prot(teth_prot)) { - result = -EINVAL; - goto bad_params; - } ttype = IPA3_USB_GET_TTYPE(teth_prot); - if (!ipa3_usb_check_legal_op(IPA_USB_DISCONNECT, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; } spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); + if (ipa3_usb_ctx->ttype_ctx[ttype].state == + IPA_USB_SUSPENDED_NO_RWAKEUP) { + spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); + result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl, + teth_prot); + mutex_unlock(&ipa3_usb_ctx->general_mutex); + return result; + } + + if (ipa3_usb_check_disconnect_prot(teth_prot)) { + spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); + result = -EINVAL; + goto bad_params; + } + if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); /* Stop DL/DPL channel */ @@ -2227,53 +2330,10 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, } else spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); - /* Reset DL channel */ - result = ipa3_reset_gsi_channel(dl_clnt_hdl); - if (result) { - IPA_USB_ERR("failed to reset DL channel.\n"); - goto bad_params; - } - - /* Reset DL event ring */ - result = ipa3_reset_gsi_event_ring(dl_clnt_hdl); - if (result) { - IPA_USB_ERR("failed to reset DL event ring.\n"); - goto bad_params; - } - - if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { - /* Reset UL channel */ - result = ipa3_reset_gsi_channel(ul_clnt_hdl); - if (result) { - IPA_USB_ERR("failed to reset UL channel.\n"); - goto bad_params; - } - - /* Reset UL event ring */ - result = ipa3_reset_gsi_event_ring(ul_clnt_hdl); - if (result) { - IPA_USB_ERR("failed to reset UL event ring.\n"); - goto bad_params; - } - } - - /* Change state to STOPPED */ - if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) - IPA_USB_ERR("failed to change state to stopped\n"); - - if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { - result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); - if (result) { - IPA_USB_ERR("failed to release UL channel.\n"); - goto bad_params; - } - } - - result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); - if (result) { - IPA_USB_ERR("failed to release DL channel.\n"); + result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl, + teth_prot); + if (result) goto bad_params; - } /* Disconnect tethering protocol */ result = ipa3_usb_disconnect_teth_prot(teth_prot); @@ -2315,7 +2375,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) ttype = IPA3_USB_GET_TTYPE(teth_prot); - if (!ipa3_usb_check_legal_op(IPA_USB_DEINIT_TETH_PROT, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; @@ -2411,25 +2471,104 @@ bad_params: } EXPORT_SYMBOL(ipa_usb_deinit_teth_prot); -int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, +/* Assumes lock already acquired */ +static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = 0; + enum ipa3_usb_transport_type ttype; + + ttype = IPA3_USB_GET_TTYPE(teth_prot); + + if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) { + IPA_USB_ERR("Illegal operation.\n"); + result = -EPERM; + goto fail_exit; + } + + IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n", + IPA3_USB_IS_TTYPE_DPL(ttype) ? + "DPL channel":"Data Tethering channels"); + + if (ipa3_usb_check_disconnect_prot(teth_prot)) { + result = -EINVAL; + goto fail_exit; + } + + /* Stop DL/DPL channel */ + result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); + if (result) { + IPA_USB_ERR("failed to disconnect DL/DPL channel.\n"); + goto fail_exit; + } + + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { + /* Stop UL channel */ + result = ipa3_xdci_disconnect(ul_clnt_hdl, true, + ipa3_usb_ctx->qmi_req_id); + if (result) { + IPA_USB_ERR("failed disconnect UL channel\n"); + goto start_dl; + } + ipa3_usb_ctx->qmi_req_id++; + } + + /* Disconnect tethering protocol */ + result = ipa3_usb_disconnect_teth_prot(teth_prot); + if (result) + goto start_ul; + + result = ipa3_usb_release_prod(ttype); + if (result) { + IPA_USB_ERR("failed to release PROD.\n"); + goto connect_teth; + } + + /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */ + if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype)) + IPA_USB_ERR("failed to change state to suspend no rwakeup\n"); + + IPA_USB_DBG_LOW("exit\n"); + return 0; + +connect_teth: + (void)ipa3_usb_connect_teth_prot(teth_prot); +start_ul: + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) + (void)ipa3_xdci_connect(ul_clnt_hdl); +start_dl: + (void)ipa3_xdci_connect(dl_clnt_hdl); +fail_exit: + return result; +} + +int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, + enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup) +{ + int result = 0; unsigned long flags; enum ipa3_usb_cons_state curr_cons_state; enum ipa3_usb_transport_type ttype; mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); + if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameters.\n"); result = -EINVAL; goto bad_params; } + if (!with_remote_wakeup) { + result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl, + dl_clnt_hdl, teth_prot); + mutex_unlock(&ipa3_usb_ctx->general_mutex); + return result; + } + ttype = IPA3_USB_GET_TTYPE(teth_prot); - if (!ipa3_usb_check_legal_op(IPA_USB_SUSPEND, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; @@ -2538,6 +2677,72 @@ bad_params: } EXPORT_SYMBOL(ipa_usb_xdci_suspend); +/* Assumes lock already acquired */ +static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, + enum ipa_usb_teth_prot teth_prot) +{ + int result = -EFAULT; + enum ipa3_usb_transport_type ttype; + + ttype = IPA3_USB_GET_TTYPE(teth_prot); + + IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n", + IPA3_USB_IS_TTYPE_DPL(ttype) ? + "DPL channel":"Data Tethering channels"); + + /* Request USB_PROD */ + result = ipa3_usb_request_prod(ttype); + if (result) + goto fail_exit; + + /* Connect tethering protocol */ + result = ipa3_usb_connect_teth_prot(teth_prot); + if (result) { + IPA_USB_ERR("failed to connect teth protocol\n"); + goto release_prod; + } + + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { + /* Start UL channel */ + result = ipa3_xdci_connect(ul_clnt_hdl); + if (result) { + IPA_USB_ERR("failed to start UL channel.\n"); + goto disconn_teth; + } + } + + /* Start DL/DPL channel */ + result = ipa3_xdci_connect(dl_clnt_hdl); + if (result) { + IPA_USB_ERR("failed to start DL/DPL channel.\n"); + goto stop_ul; + } + + /* Change state to CONNECTED */ + if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) { + IPA_USB_ERR("failed to change state to connected\n"); + result = -EFAULT; + goto stop_dl; + } + + return 0; + +stop_dl: + (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); +stop_ul: + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { + (void)ipa3_xdci_disconnect(ul_clnt_hdl, true, + ipa3_usb_ctx->qmi_req_id); + ipa3_usb_ctx->qmi_req_id++; + } +disconn_teth: + (void)ipa3_usb_disconnect_teth_prot(teth_prot); +release_prod: + (void)ipa3_usb_release_prod(ttype); +fail_exit: + return result; +} + int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { @@ -2557,19 +2762,25 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, ttype = IPA3_USB_GET_TTYPE(teth_prot); - if (!ipa3_usb_check_legal_op(IPA_USB_RESUME, ttype)) { + if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; } - IPA_USB_DBG_LOW("Start resume sequence: %s\n", - IPA3_USB_IS_TTYPE_DPL(ttype) ? - "DPL channel" : "Data Tethering channels"); - spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state; spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); + if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) { + result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl, + dl_clnt_hdl, teth_prot); + mutex_unlock(&ipa3_usb_ctx->general_mutex); + return result; + } + + IPA_USB_DBG("Start resume sequence: %s\n", + IPA3_USB_IS_TTYPE_DPL(ttype) ? + "DPL channel" : "Data Tethering channels"); /* Change state to RESUME_IN_PROGRESS */ if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index ab62dbcddd22..8676b35914e2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -3790,6 +3790,12 @@ static int ipa3_gsi_pre_fw_load_init(void) return 0; } +static void ipa3_uc_is_loaded(void) +{ + IPADBG("\n"); + complete_all(&ipa3_ctx->uc_loaded_completion_obj); +} + static enum gsi_ver ipa3_get_gsi_ver(enum ipa_hw_type ipa_hw_type) { enum gsi_ver gsi_ver; @@ -3842,6 +3848,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, int result; struct sps_bam_props bam_props = { 0 }; struct gsi_per_props gsi_props; + struct ipa3_uc_hdlrs uc_hdlrs = { 0 }; if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { memset(&gsi_props, 0, sizeof(gsi_props)); @@ -3918,6 +3925,9 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, else IPADBG(":ipa Uc interface init ok\n"); + uc_hdlrs.ipa_uc_loaded_hdlr = ipa3_uc_is_loaded; + ipa3_uc_register_handlers(IPA_HW_FEATURE_COMMON, &uc_hdlrs); + result = ipa3_wdi_init(); if (result) IPAERR(":wdi init failed (%d)\n", -result); @@ -4609,6 +4619,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, INIT_LIST_HEAD(&ipa3_ctx->ipa_ready_cb_list); init_completion(&ipa3_ctx->init_completion_obj); + init_completion(&ipa3_ctx->uc_loaded_completion_obj); /* * For GSI, we can't register the GSI driver yet, as it expects diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 8326c3fdd9d1..26bd180624f1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -61,7 +61,7 @@ int ipa3_enable_data_path(u32 clnt_hdl) !ipa3_should_pipe_be_suspended(ep->client))) { memset(&ep_cfg_ctrl, 0 , sizeof(ep_cfg_ctrl)); ep_cfg_ctrl.ipa_ep_suspend = false; - ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); + res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); } /* Assign the resource group for pipe */ @@ -99,9 +99,21 @@ int ipa3_disable_data_path(u32 clnt_hdl) /* Suspend the pipe */ if (IPA_CLIENT_IS_CONS(ep->client)) { + /* + * for RG10 workaround uC needs to be loaded before pipe can + * be suspended in this case. + */ + if (ipa3_ctx->apply_rg10_wa && ipa3_uc_state_check()) { + IPADBG("uC is not loaded yet, waiting...\n"); + res = wait_for_completion_timeout( + &ipa3_ctx->uc_loaded_completion_obj, 60 * HZ); + if (res == 0) + IPADBG("timeout waiting for uC to load\n"); + } + memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl)); ep_cfg_ctrl.ipa_ep_suspend = true; - ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); + res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); } udelay(IPA_PKT_FLUSH_TO_US); @@ -1311,7 +1323,46 @@ int ipa3_set_usb_max_packet_size( return 0; } -int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid) +int ipa3_xdci_connect(u32 clnt_hdl) +{ + int result; + struct ipa3_ep_context *ep; + + IPADBG("entry\n"); + + if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || + ipa3_ctx->ep[clnt_hdl].valid == 0) { + IPAERR("Bad parameter.\n"); + return -EINVAL; + } + + ep = &ipa3_ctx->ep[clnt_hdl]; + IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); + + result = ipa3_start_gsi_channel(clnt_hdl); + if (result) { + IPAERR("failed to start gsi channel clnt_hdl=%u\n", clnt_hdl); + goto exit; + } + + result = ipa3_enable_data_path(clnt_hdl); + if (result) { + IPAERR("enable data path failed res=%d clnt_hdl=%d.\n", result, + clnt_hdl); + goto stop_ch; + } + + IPADBG("exit\n"); + goto exit; + +stop_ch: + (void)ipa3_stop_gsi_channel(clnt_hdl); +exit: + IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); + return result; +} + +int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid) { struct ipa3_ep_context *ep; int result = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 09c7c1b0fd05..cc1cb456ab8a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -767,6 +767,30 @@ static void ipa3_transport_irq_cmd_ack(void *user1, int user2) } /** + * ipa3_transport_irq_cmd_ack_free - callback function which will be + * called by SPS/GSI driver after an immediate command is complete. + * This function will also free the completion object once it is done. + * @tag_comp: pointer to the completion object + * @ignored: parameter not used + * + * Complete the immediate commands completion object, this will release the + * thread which waits on this completion object (ipa3_send_cmd()) + */ +static void ipa3_transport_irq_cmd_ack_free(void *tag_comp, int ignored) +{ + struct ipa3_tag_completion *comp = tag_comp; + + if (!comp) { + IPAERR("comp is NULL\n"); + return; + } + + complete(&comp->comp); + if (atomic_dec_return(&comp->cnt) == 0) + kfree(comp); +} + +/** * ipa3_send_cmd - send immediate commands * @num_desc: number of descriptors within the desc struct * @descr: descriptor structure @@ -778,7 +802,58 @@ 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); + struct ipa3_desc *desc; + int i, result = 0; + struct ipa3_sys_context *sys; + int ep_idx; + + for (i = 0; i < num_desc; i++) + IPADBG("sending imm cmd %d\n", descr[i].opcode); + + ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_CMD_PROD); + if (-1 == ep_idx) { + IPAERR("Client %u is not mapped\n", + IPA_CLIENT_APPS_CMD_PROD); + return -EFAULT; + } + + sys = ipa3_ctx->ep[ep_idx].sys; + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + if (num_desc == 1) { + init_completion(&descr->xfer_done); + + if (descr->callback || descr->user1) + WARN_ON(1); + + descr->callback = ipa3_transport_irq_cmd_ack; + descr->user1 = descr; + if (ipa3_send_one(sys, descr, true)) { + IPAERR("fail to send immediate command\n"); + result = -EFAULT; + goto bail; + } + wait_for_completion(&descr->xfer_done); + } else { + desc = &descr[num_desc - 1]; + init_completion(&desc->xfer_done); + + if (desc->callback || desc->user1) + WARN_ON(1); + + desc->callback = ipa3_transport_irq_cmd_ack; + desc->user1 = desc; + if (ipa3_send(sys, num_desc, descr, true)) { + IPAERR("fail to send multiple immediate command set\n"); + result = -EFAULT; + goto bail; + } + wait_for_completion(&desc->xfer_done); + } + +bail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return result; } /** @@ -800,6 +875,7 @@ int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout) struct ipa3_sys_context *sys; int ep_idx; int completed; + struct ipa3_tag_completion *comp; for (i = 0; i < num_desc; i++) IPADBG("sending imm cmd %d\n", descr[i].opcode); @@ -810,55 +886,56 @@ int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout) IPA_CLIENT_APPS_CMD_PROD); return -EFAULT; } + + comp = kzalloc(sizeof(*comp), GFP_ATOMIC); + if (!comp) { + IPAERR("no mem\n"); + return -ENOMEM; + } + init_completion(&comp->comp); + + /* completion needs to be released from both here and in ack callback */ + atomic_set(&comp->cnt, 2); + sys = ipa3_ctx->ep[ep_idx].sys; IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (num_desc == 1) { - init_completion(&descr->xfer_done); - if (descr->callback || descr->user1) WARN_ON(1); - descr->callback = ipa3_transport_irq_cmd_ack; - descr->user1 = descr; + descr->callback = ipa3_transport_irq_cmd_ack_free; + descr->user1 = comp; if (ipa3_send_one(sys, descr, true)) { IPAERR("fail to send immediate command\n"); + kfree(comp); result = -EFAULT; goto bail; } - 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); if (desc->callback || desc->user1) WARN_ON(1); - desc->callback = ipa3_transport_irq_cmd_ack; - desc->user1 = desc; + desc->callback = ipa3_transport_irq_cmd_ack_free; + desc->user1 = comp; if (ipa3_send(sys, num_desc, descr, true)) { IPAERR("fail to send multiple immediate command set\n"); + kfree(comp); result = -EFAULT; goto bail; } - 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); - } - } + completed = wait_for_completion_timeout( + &comp->comp, msecs_to_jiffies(timeout)); + if (!completed) + IPADBG("timeout waiting for imm-cmd ACK\n"); + + if (atomic_dec_return(&comp->cnt) == 0) + kfree(comp); + bail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 33be22f98b9d..40f1e93653f9 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1232,6 +1232,7 @@ struct ipa3_context { bool ipa_initialization_complete; struct list_head ipa_ready_cb_list; struct completion init_completion_obj; + struct completion uc_loaded_completion_obj; struct ipa3_smp2p_info smp2p_info; u32 ipa_tz_unlock_reg_num; struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg; @@ -1482,7 +1483,9 @@ int ipa3_reset_gsi_event_ring(u32 clnt_hdl); int ipa3_set_usb_max_packet_size( enum ipa_usb_max_usb_packet_size usb_max_packet_size); -int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid); +int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid); + +int ipa3_xdci_connect(u32 clnt_hdl); int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index c0a6e8b00d71..4ea68ae1e95c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3522,7 +3522,7 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) goto end_sequence; IPADBG("Inject a DMA_TASK with 1B packet to IPA and retry\n"); - /* Send a 1B packet DMA_RASK to IPA and try again*/ + /* Send a 1B packet DMA_TASK to IPA and try again */ res = ipa3_inject_dma_task_for_gsi(); if (res) { IPAERR("Failed to inject DMA TASk for GSI\n"); diff --git a/drivers/power/qcom-charger/pmic-voter.c b/drivers/power/qcom-charger/pmic-voter.c index d0bad7dec094..8072b63f53fe 100644 --- a/drivers/power/qcom-charger/pmic-voter.c +++ b/drivers/power/qcom-charger/pmic-voter.c @@ -421,6 +421,7 @@ static int show_votable_clients(struct seq_file *m, void *data) lock_votable(votable); + seq_printf(m, "%s:\n", votable->name); seq_puts(m, "Clients:\n"); for (i = 0; i < votable->num_clients; i++) { if (votable->client_strs[i]) { diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index 3db295b3e6e8..9a87ff5fb081 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -48,14 +48,14 @@ static struct smb_params v1_params = { .name = "fast charge current", .reg = FAST_CHARGE_CURRENT_CFG_REG, .min_u = 0, - .max_u = 4500000, + .max_u = 6000000, .step_u = 25000, }, .fv = { .name = "float voltage", .reg = FLOAT_VOLTAGE_CFG_REG, - .min_u = 2500000, - .max_u = 5000000, + .min_u = 2450000, + .max_u = 4950000, .step_u = 10000, }, .usb_icl = { diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 17c8a5b00843..7569e35b59e0 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -183,5 +183,19 @@ config POWER_RESET_ZX help Reboot support for ZTE SoCs. +config REBOOT_MODE + tristate + +config SYSCON_REBOOT_MODE + tristate "Generic SYSCON regmap reboot mode driver" + depends on OF + select REBOOT_MODE + select MFD_SYSCON + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in SYSCON mapped + register, then the bootloader can read it to take different + action according to the mode. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 3904e7977d07..66568c4497a4 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -20,3 +20,5 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o +obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o +obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 2f109013f723..d32f293695bb 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -380,7 +380,6 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) msm_trigger_wdog_bite(); #endif - scm_disable_sdi(); halt_spmi_pmic_arbiter(); deassert_ps_hold(); diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c new file mode 100644 index 000000000000..2dfbbce0f817 --- /dev/null +++ b/drivers/power/reset/reboot-mode.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/reboot.h> +#include "reboot-mode.h" + +#define PREFIX "mode-" + +struct mode_info { + const char *mode; + u32 magic; + struct list_head list; +}; + +static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, + const char *cmd) +{ + const char *normal = "normal"; + int magic = 0; + struct mode_info *info; + + if (!cmd) + cmd = normal; + + list_for_each_entry(info, &reboot->head, list) { + if (!strcmp(info->mode, cmd)) { + magic = info->magic; + break; + } + } + + return magic; +} + +static int reboot_mode_notify(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct reboot_mode_driver *reboot; + unsigned int magic; + + reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); + magic = get_reboot_mode_magic(reboot, cmd); + if (magic) + reboot->write(reboot, magic); + + return NOTIFY_DONE; +} + +/** + * reboot_mode_register - register a reboot mode driver + * @reboot: reboot mode driver + * + * Returns: 0 on success or a negative error code on failure. + */ +int reboot_mode_register(struct reboot_mode_driver *reboot) +{ + struct mode_info *info; + struct property *prop; + struct device_node *np = reboot->dev->of_node; + size_t len = strlen(PREFIX); + int ret; + + INIT_LIST_HEAD(&reboot->head); + + for_each_property_of_node(np, prop) { + if (strncmp(prop->name, PREFIX, len)) + continue; + + info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto error; + } + + if (of_property_read_u32(np, prop->name, &info->magic)) { + dev_err(reboot->dev, "reboot mode %s without magic number\n", + info->mode); + devm_kfree(reboot->dev, info); + continue; + } + + info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); + if (!info->mode) { + ret = -ENOMEM; + goto error; + } else if (info->mode[0] == '\0') { + kfree_const(info->mode); + ret = -EINVAL; + dev_err(reboot->dev, "invalid mode name(%s): too short!\n", + prop->name); + goto error; + } + + list_add_tail(&info->list, &reboot->head); + } + + reboot->reboot_notifier.notifier_call = reboot_mode_notify; + register_reboot_notifier(&reboot->reboot_notifier); + + return 0; + +error: + list_for_each_entry(info, &reboot->head, list) + kfree_const(info->mode); + + return ret; +} +EXPORT_SYMBOL_GPL(reboot_mode_register); + +/** + * reboot_mode_unregister - unregister a reboot mode driver + * @reboot: reboot mode driver + */ +int reboot_mode_unregister(struct reboot_mode_driver *reboot) +{ + struct mode_info *info; + + unregister_reboot_notifier(&reboot->reboot_notifier); + + list_for_each_entry(info, &reboot->head, list) + kfree_const(info->mode); + + return 0; +} +EXPORT_SYMBOL_GPL(reboot_mode_unregister); + +MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com"); +MODULE_DESCRIPTION("System reboot mode core library"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/reboot-mode.h b/drivers/power/reset/reboot-mode.h new file mode 100644 index 000000000000..2491bb71f591 --- /dev/null +++ b/drivers/power/reset/reboot-mode.h @@ -0,0 +1,14 @@ +#ifndef __REBOOT_MODE_H__ +#define __REBOOT_MODE_H__ + +struct reboot_mode_driver { + struct device *dev; + struct list_head head; + int (*write)(struct reboot_mode_driver *reboot, unsigned int magic); + struct notifier_block reboot_notifier; +}; + +int reboot_mode_register(struct reboot_mode_driver *reboot); +int reboot_mode_unregister(struct reboot_mode_driver *reboot); + +#endif diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c new file mode 100644 index 000000000000..9e1cba5dd58e --- /dev/null +++ b/drivers/power/reset/syscon-reboot-mode.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include "reboot-mode.h" + +struct syscon_reboot_mode { + struct regmap *map; + struct reboot_mode_driver reboot; + u32 offset; + u32 mask; +}; + +static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + struct syscon_reboot_mode *syscon_rbm; + int ret; + + syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot); + + ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset, + syscon_rbm->mask, magic); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + + return ret; +} + +static int syscon_reboot_mode_probe(struct platform_device *pdev) +{ + int ret; + struct syscon_reboot_mode *syscon_rbm; + + syscon_rbm = devm_kzalloc(&pdev->dev, sizeof(*syscon_rbm), GFP_KERNEL); + if (!syscon_rbm) + return -ENOMEM; + + syscon_rbm->reboot.dev = &pdev->dev; + syscon_rbm->reboot.write = syscon_reboot_mode_write; + syscon_rbm->mask = 0xffffffff; + + dev_set_drvdata(&pdev->dev, syscon_rbm); + + syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(syscon_rbm->map)) + return PTR_ERR(syscon_rbm->map); + + if (of_property_read_u32(pdev->dev.of_node, "offset", + &syscon_rbm->offset)) + return -EINVAL; + + of_property_read_u32(pdev->dev.of_node, "mask", &syscon_rbm->mask); + + ret = reboot_mode_register(&syscon_rbm->reboot); + if (ret) + dev_err(&pdev->dev, "can't register reboot mode\n"); + + return ret; +} + +static int syscon_reboot_mode_remove(struct platform_device *pdev) +{ + struct syscon_reboot_mode *syscon_rbm = dev_get_drvdata(&pdev->dev); + + return reboot_mode_unregister(&syscon_rbm->reboot); +} + +static const struct of_device_id syscon_reboot_mode_of_match[] = { + { .compatible = "syscon-reboot-mode" }, + {} +}; + +static struct platform_driver syscon_reboot_mode_driver = { + .probe = syscon_reboot_mode_probe, + .remove = syscon_reboot_mode_remove, + .driver = { + .name = "syscon-reboot-mode", + .of_match_table = syscon_reboot_mode_of_match, + }, +}; +module_platform_driver(syscon_reboot_mode_driver); + +MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com"); +MODULE_DESCRIPTION("SYSCON reboot mode driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index f1d3c7e99a4c..feeed645fc47 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -131,6 +131,9 @@ module_param(qmi_timeout, ulong, 0600); * Registers: WCSS_HM_A_PMM_PMM * Base Address: 0x18880000 */ +#define WCSS_HM_A_PMM_ROOT_CLK_ENABLE 0x80010 +#define PMM_TCXO_CLK_ENABLE BIT(13) + #define PMM_COMMON_IDLEREQ_CSR_OFFSET 0x80120 #define PMM_COMMON_IDLEREQ_CSR_SW_WNOC_IDLEREQ_SET BIT(16) #define PMM_COMMON_IDLEREQ_CSR_WNOC_IDLEACK BIT(26) @@ -1332,8 +1335,28 @@ static int icnss_hw_reset_rf_reset_cmd(struct icnss_priv *priv) static int icnss_hw_reset_switch_to_cxo(struct icnss_priv *priv) { + u32 rdata; + icnss_pr_dbg("RESET: Switch to CXO, state: 0x%lx\n", priv->state); + rdata = icnss_hw_read_reg(priv->mem_base_va, + WCSS_HM_A_PMM_ROOT_CLK_ENABLE); + + icnss_pr_dbg("RESET: PMM_TCXO_CLK_ENABLE : 0x%05lx\n", + rdata & PMM_TCXO_CLK_ENABLE); + + if ((rdata & PMM_TCXO_CLK_ENABLE) == 0) { + icnss_pr_dbg("RESET: Set PMM_TCXO_CLK_ENABLE to 1\n"); + + icnss_hw_write_reg_field(priv->mem_base_va, + WCSS_HM_A_PMM_ROOT_CLK_ENABLE, + PMM_TCXO_CLK_ENABLE, 1); + icnss_hw_poll_reg_field(priv->mem_base_va, + WCSS_HM_A_PMM_ROOT_CLK_ENABLE, + PMM_TCXO_CLK_ENABLE, 1, 10, + ICNSS_HW_REG_RETRY); + } + 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); @@ -1464,6 +1487,26 @@ static int icnss_hw_reset(struct icnss_priv *priv) icnss_hw_reset_switch_to_cxo(priv); + for (i = 0; i < ICNSS_HW_REG_RETRY; i++) { + rdata = icnss_hw_read_reg(priv->mem_base_va, SR_PMM_SR_MSB); + usleep_range(5, 10); + rdata1 = icnss_hw_read_reg(priv->mem_base_va, SR_PMM_SR_MSB); + + icnss_pr_dbg("RESET: SR_PMM_SR_MSB: 0x%08x/0x%08x, XO: 0x%05lx/0x%05lx, AHB: 0x%05lx/0x%05lx\n", + rdata, rdata1, + rdata & SR_PMM_SR_MSB_XO_CLOCK_MASK, + rdata1 & SR_PMM_SR_MSB_XO_CLOCK_MASK, + rdata & SR_PMM_SR_MSB_AHB_CLOCK_MASK, + rdata1 & SR_PMM_SR_MSB_AHB_CLOCK_MASK); + + if ((rdata & SR_PMM_SR_MSB_AHB_CLOCK_MASK) != + (rdata1 & SR_PMM_SR_MSB_AHB_CLOCK_MASK) && + (rdata & SR_PMM_SR_MSB_XO_CLOCK_MASK) != + (rdata1 & SR_PMM_SR_MSB_XO_CLOCK_MASK)) + break; + usleep_range(5, 10); + } + ret = icnss_hw_reset_xo_disable_cmd(priv); if (ret) goto top_level_reset; @@ -2612,10 +2655,10 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, icnss_call_driver_remove(priv); out: - icnss_remove_msa_permissions(priv); - ret = icnss_hw_power_off(priv); + icnss_remove_msa_permissions(priv); + kfree(data); return ret; diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 97d922fa5724..6bc815862541 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -161,8 +161,8 @@ static void wdsp_glink_notify_rx(void *handle, const void *priv, wpriv->rsp_cnt = ++rsp_cnt; mutex_unlock(&wpriv->rsp_mutex); - complete(&wpriv->rsp_complete); glink_rx_done(handle, ptr, true); + complete(&wpriv->rsp_complete); } /* diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index b02e48185355..c0b936d802ef 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1005,6 +1005,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pa->spmic = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); + if (!res) { + dev_err(&pdev->dev, "core resource not specified\n"); + err = -EINVAL; + goto err_put_ctrl; + } + pa->core_size = resource_size(res); if (pa->core_size <= 0x800) { dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n"); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index e5a88adfce59..add035269ae7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2073,6 +2073,11 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) clk_prepare_enable(mdwc->iface_clk); clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); clk_prepare_enable(mdwc->core_clk); + + /* set Memory core: ON, Memory periphery: ON */ + clk_set_flags(mdwc->core_clk, CLKFLAG_RETAIN_MEM); + clk_set_flags(mdwc->core_clk, CLKFLAG_RETAIN_PERIPH); + clk_prepare_enable(mdwc->utmi_clk); if (mdwc->bus_aggr_clk) clk_prepare_enable(mdwc->bus_aggr_clk); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index c298c95d4ba0..738f20d935d6 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -497,7 +497,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) log_event_dbg("%s: Calling xdci_suspend", __func__); ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, - gsi->d_port.in_channel_handle, gsi->prot_id); + gsi->d_port.in_channel_handle, gsi->prot_id, + true); if (!ret) { d_port->sm_state = STATE_SUSPENDED; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3e49861a09a2..5193bf5eb8c3 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -241,10 +241,14 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; + device_wakeup_enable(&hcd->self.root_hub->dev); + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT); if (ret) goto dealloc_usb2_hcd; + device_wakeup_enable(&xhci->shared_hcd->self.root_hub->dev); + ret = device_create_file(&pdev->dev, &dev_attr_config_imod); if (ret) dev_err(&pdev->dev, "%s: unable to create imod sysfs entry\n", diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 2bc70d1cf6fa..e193182af225 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -274,7 +274,7 @@ struct usbpd { struct extcon_dev *extcon; enum usbpd_state current_state; - bool hard_reset; + bool hard_reset_recvd; u8 rx_msg_type; u8 rx_msg_len; u32 rx_payload[7]; @@ -487,16 +487,12 @@ static int pd_eval_src_caps(struct usbpd *pd, const u32 *src_caps) static void pd_send_hard_reset(struct usbpd *pd) { - int ret; - usbpd_dbg(&pd->dev, "send hard reset"); /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); pd->hard_reset_count++; - ret = pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */ - if (!ret) - pd->hard_reset = true; + pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */ pd->in_pr_swap = false; } @@ -522,7 +518,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); - pd->hard_reset = true; + pd->hard_reset_recvd = true; kick_sm(pd, 0); } @@ -753,40 +749,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); break; - case PE_SRC_TRANSITION_TO_DEFAULT: - pd->hard_reset = false; - - if (pd->vconn_enabled) - regulator_disable(pd->vconn); - regulator_disable(pd->vbus); - - if (pd->current_dr != DR_DFP) { - extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0); - pd->current_dr = DR_DFP; - pd_phy_update_roles(pd->current_dr, pd->current_pr); - } - - msleep(SRC_RECOVER_TIME); - - ret = regulator_enable(pd->vbus); - if (ret) - usbpd_err(&pd->dev, "Unable to enable vbus\n"); - - if (pd->vconn_enabled) { - ret = regulator_enable(pd->vconn); - if (ret) { - usbpd_err(&pd->dev, "Unable to enable vconn\n"); - pd->vconn_enabled = false; - } - } - - val.intval = 0; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - - usbpd_set_state(pd, PE_SRC_STARTUP); - break; - case PE_SRC_HARD_RESET: case PE_SNK_HARD_RESET: /* hard reset may sleep; handle it in the workqueue */ @@ -1403,7 +1365,7 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = false; pd->pd_connected = false; pd->in_explicit_contract = false; - pd->hard_reset = false; + pd->hard_reset_recvd = false; pd->caps_count = 0; pd->hard_reset_count = 0; pd->src_cap_id = 0; @@ -1456,7 +1418,9 @@ static void usbpd_sm(struct work_struct *w) } /* Hard reset? */ - if (pd->hard_reset) { + if (pd->hard_reset_recvd) { + pd->hard_reset_recvd = false; + val.intval = 1; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); @@ -1464,10 +1428,12 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = false; reset_vdm_state(pd); - if (pd->current_pr == PR_SINK) + if (pd->current_pr == PR_SINK) { usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT); - else - usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT); + } else { + pd->current_state = PE_SRC_TRANSITION_TO_DEFAULT; + kick_sm(pd, PS_HARD_RESET_TIME); + } goto sm_done; } @@ -1632,6 +1598,38 @@ static void usbpd_sm(struct work_struct *w) } break; + case PE_SRC_TRANSITION_TO_DEFAULT: + if (pd->vconn_enabled) + regulator_disable(pd->vconn); + regulator_disable(pd->vbus); + + if (pd->current_dr != DR_DFP) { + extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0); + pd->current_dr = DR_DFP; + pd_phy_update_roles(pd->current_dr, pd->current_pr); + } + + msleep(SRC_RECOVER_TIME); + + ret = regulator_enable(pd->vbus); + if (ret) + usbpd_err(&pd->dev, "Unable to enable vbus\n"); + + if (pd->vconn_enabled) { + ret = regulator_enable(pd->vconn); + if (ret) { + usbpd_err(&pd->dev, "Unable to enable vconn\n"); + pd->vconn_enabled = false; + } + } + + val.intval = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); + + usbpd_set_state(pd, PE_SRC_STARTUP); + break; + case PE_SRC_HARD_RESET: val.intval = 1; power_supply_set_property(pd->usb_psy, @@ -1641,9 +1639,8 @@ static void usbpd_sm(struct work_struct *w) pd->in_explicit_contract = false; reset_vdm_state(pd); - usleep_range(PS_HARD_RESET_TIME * USEC_PER_MSEC, - (PS_HARD_RESET_TIME + 5) * USEC_PER_MSEC); - usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT); + pd->current_state = PE_SRC_TRANSITION_TO_DEFAULT; + kick_sm(pd, PS_HARD_RESET_TIME); break; case PE_SNK_STARTUP: @@ -1829,8 +1826,6 @@ 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); @@ -2117,11 +2112,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) * 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. + * we can also happen to be in the SNK_Transition_to_default + * state due to a hard reset attempt even with a non-PD + * capable source, in which a physical disconnect may get + * masked. In that case, allow for the common case of + * disconnecting from an SDP. * * The less common case is a PD-capable SDP which will * result in a hard reset getting treated like a diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index a561fed80ce6..93f5f9a51a63 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -235,9 +235,13 @@ enum mdss_mdp_csc_type { MDSS_MDP_CSC_YUV2RGB_601L, MDSS_MDP_CSC_YUV2RGB_601FR, MDSS_MDP_CSC_YUV2RGB_709L, + MDSS_MDP_CSC_YUV2RGB_2020L, + MDSS_MDP_CSC_YUV2RGB_2020FR, MDSS_MDP_CSC_RGB2YUV_601L, MDSS_MDP_CSC_RGB2YUV_601FR, MDSS_MDP_CSC_RGB2YUV_709L, + MDSS_MDP_CSC_RGB2YUV_2020L, + MDSS_MDP_CSC_RGB2YUV_2020FR, MDSS_MDP_CSC_YUV2YUV, MDSS_MDP_CSC_RGB2RGB, MDSS_MDP_MAX_CSC @@ -1408,6 +1412,10 @@ static inline uint8_t pp_vig_csc_pipe_val(struct mdss_mdp_pipe *pipe) return MDSS_MDP_CSC_YUV2RGB_601L; case MDP_CSC_ITU_R_601_FR: return MDSS_MDP_CSC_YUV2RGB_601FR; + case MDP_CSC_ITU_R_2020: + return MDSS_MDP_CSC_YUV2RGB_2020L; + case MDP_CSC_ITU_R_2020_FR: + return MDSS_MDP_CSC_YUV2RGB_2020FR; case MDP_CSC_ITU_R_709: default: return MDSS_MDP_CSC_YUV2RGB_709L; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 47edc320233a..f79212ea740d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -60,6 +60,30 @@ struct mdp_csc_cfg mdp_csc_8bit_convert[MDSS_MDP_MAX_CSC] = { { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, }, + [MDSS_MDP_CSC_YUV2RGB_2020L] = { + 0, + { + 0x0256, 0x0000, 0x035e, + 0x0256, 0xffa0, 0xfeb2, + 0x0256, 0x044c, 0x0000, + }, + { 0xfff0, 0xff80, 0xff80,}, + { 0x0, 0x0, 0x0,}, + { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, + }, + [MDSS_MDP_CSC_YUV2RGB_2020FR] = { + 0, + { + 0x0200, 0x0000, 0x02f3, + 0x0200, 0xffac, 0xfedb, + 0x0200, 0x03c3, 0x0000, + }, + { 0x0000, 0xff80, 0xff80,}, + { 0x0, 0x0, 0x0,}, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, + }, [MDSS_MDP_CSC_RGB2YUV_601L] = { 0, { @@ -96,6 +120,30 @@ struct mdp_csc_cfg mdp_csc_8bit_convert[MDSS_MDP_MAX_CSC] = { { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,}, }, + [MDSS_MDP_CSC_RGB2YUV_2020L] = { + 0, + { + 0x0073, 0x0129, 0x001a, + 0xffc1, 0xff5e, 0x00e0, + 0x00e0, 0xff32, 0xffee + }, + { 0x0, 0x0, 0x0,}, + { 0x0010, 0x0080, 0x0080,}, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, + { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,}, + }, + [MDSS_MDP_CSC_RGB2YUV_2020FR] = { + 0, + { + 0x0086, 0x015b, 0x001e, + 0xffb9, 0xff47, 0x0100, + 0x0100, 0xff15, 0xffeb + }, + { 0x0, 0x0, 0x0,}, + { 0x0, 0x0080, 0x0080,}, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,}, + }, [MDSS_MDP_CSC_YUV2YUV] = { 0, { @@ -159,6 +207,30 @@ struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = { { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, }, + [MDSS_MDP_CSC_YUV2RGB_2020L] = { + 0, + { + 0x0256, 0x0000, 0x035e, + 0x0256, 0xffa0, 0xfeb2, + 0x0256, 0x044c, 0x0000, + }, + { 0xffc0, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + }, + [MDSS_MDP_CSC_YUV2RGB_2020FR] = { + 0, + { + 0x0200, 0x0000, 0x02f3, + 0x0200, 0xffac, 0xfedb, + 0x0200, 0x03c3, 0x0000, + }, + { 0x0000, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + }, [MDSS_MDP_CSC_RGB2YUV_601L] = { 0, { @@ -195,6 +267,30 @@ struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = { { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,}, }, + [MDSS_MDP_CSC_RGB2YUV_2020L] = { + 0, + { + 0x0073, 0x0129, 0x001a, + 0xffc1, 0xff5e, 0x00e0, + 0x00e0, 0xff32, 0xffee + }, + { 0x0, 0x0, 0x0,}, + { 0x0040, 0x0200, 0x0200,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,}, + }, + [MDSS_MDP_CSC_RGB2YUV_2020FR] = { + 0, + { + 0x0086, 0x015b, 0x001e, + 0xffb9, 0xff47, 0x0100, + 0x0100, 0xff15, 0xffeb + }, + { 0x0, 0x0, 0x0,}, + { 0x0, 0x0200, 0x0200,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + }, [MDSS_MDP_CSC_YUV2YUV] = { 0, { diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h index 7be94d298b88..a822ba8c07d1 100644 --- a/include/linux/bluetooth-power.h +++ b/include/linux/bluetooth-power.h @@ -85,4 +85,5 @@ struct bluetooth_power_platform_data { int bt_register_slimdev(struct device *dev); #define BT_CMD_SLIM_TEST 0xbfac +#define BT_CMD_PWR_CTRL 0xbfad #endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/include/linux/clk/msm-clk.h b/include/linux/clk/msm-clk.h index 22587e8852e2..964909d25021 100644 --- a/include/linux/clk/msm-clk.h +++ b/include/linux/clk/msm-clk.h @@ -14,6 +14,16 @@ #include <linux/notifier.h> +#if defined(CONFIG_COMMON_CLK_QCOM) +enum branch_mem_flags { + CLKFLAG_RETAIN_PERIPH, + CLKFLAG_NORETAIN_PERIPH, + CLKFLAG_RETAIN_MEM, + CLKFLAG_NORETAIN_MEM, + CLKFLAG_PERIPH_OFF_SET, + CLKFLAG_PERIPH_OFF_CLEAR, +}; +#elif defined(CONFIG_COMMON_CLK_MSM) #define CLKFLAG_INVERT 0x00000001 #define CLKFLAG_NOINVERT 0x00000002 #define CLKFLAG_NONEST 0x00000004 @@ -32,6 +42,7 @@ #define CLKFLAG_EPROBE_DEFER 0x00010000 #define CLKFLAG_PERIPH_OFF_SET 0x00020000 #define CLKFLAG_PERIPH_OFF_CLEAR 0x00040000 +#endif struct clk_lookup; struct clk; diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h index 0fe0e36c551f..de1163348c05 100644 --- a/include/linux/ipa_usb.h +++ b/include/linux/ipa_usb.h @@ -253,6 +253,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot); * @dl_clnt_hdl: client handle previously obtained from * ipa_usb_xdci_connect() for IN channel * @teth_prot: tethering protocol + * @with_remote_wakeup: Does host support remote wakeup? * * Note: Should not be called from atomic context * Note: for DPL, the ul will be ignored as irrelevant @@ -260,7 +261,8 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot); * @Return 0 on success, negative on failure */ int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot); + enum ipa_usb_teth_prot teth_prot, + bool with_remote_wakeup); /** * ipa_usb_xdci_resume - Peripheral should call this function to resume @@ -313,7 +315,8 @@ static inline int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) } static inline int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot) + enum ipa_usb_teth_prot teth_prot, + bool with_remote_wakeup) { return -EPERM; } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9076fd9f92b2..35c527c7d2e4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -784,6 +784,26 @@ struct cfg80211_csa_settings { }; /** + * struct iface_combination_params - input parameters for interface combinations + * + * Used to pass interface combination parameters + * + * @num_different_channels: the number of different channels we want + * to use for verification + * @radar_detect: a bitmap where each bit corresponds to a channel + * width where radar detection is needed, as in the definition of + * &struct ieee80211_iface_combination.@radar_detect_widths + * @iftype_num: array with the number of interfaces of each interface + * type. The index is the interface type as specified in &enum + * nl80211_iftype. + */ +struct iface_combination_params { + int num_different_channels; + u8 radar_detect; + int iftype_num[NUM_NL80211_IFTYPES]; +}; + +/** * enum station_parameters_apply_mask - station parameter values to apply * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) * @STATION_PARAM_APPLY_CAPABILITY: apply new capability @@ -5333,36 +5353,20 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy); * cfg80211_check_combinations - check interface combinations * * @wiphy: the wiphy - * @num_different_channels: the number of different channels we want - * to use for verification - * @radar_detect: a bitmap where each bit corresponds to a channel - * width where radar detection is needed, as in the definition of - * &struct ieee80211_iface_combination.@radar_detect_widths - * @iftype_num: array with the numbers of interfaces of each interface - * type. The index is the interface type as specified in &enum - * nl80211_iftype. - * + * @params: the interface combinations parameter +* * This function can be called by the driver to check whether a * combination of interfaces and their types are allowed according to * the interface combinations. */ int cfg80211_check_combinations(struct wiphy *wiphy, - const int num_different_channels, - const u8 radar_detect, - const int iftype_num[NUM_NL80211_IFTYPES]); + struct iface_combination_params *params); /** * cfg80211_iter_combinations - iterate over matching combinations * * @wiphy: the wiphy - * @num_different_channels: the number of different channels we want - * to use for verification - * @radar_detect: a bitmap where each bit corresponds to a channel - * width where radar detection is needed, as in the definition of - * &struct ieee80211_iface_combination.@radar_detect_widths - * @iftype_num: array with the numbers of interfaces of each interface - * type. The index is the interface type as specified in &enum - * nl80211_iftype. + * @params: the interface combinations parameter * @iter: function to call for each matching combination * @data: pointer to pass to iter function * @@ -5371,9 +5375,7 @@ int cfg80211_check_combinations(struct wiphy *wiphy, * purposes. */ int cfg80211_iter_combinations(struct wiphy *wiphy, - const int num_different_channels, - const u8 radar_detect, - const int iftype_num[NUM_NL80211_IFTYPES], + struct iface_combination_params *params, void (*iter)(const struct ieee80211_iface_combination *c, void *data), void *data); diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h index 1df65c7f90b3..f0ac02e9c7a8 100644 --- a/include/uapi/linux/msm_mdp.h +++ b/include/uapi/linux/msm_mdp.h @@ -1406,12 +1406,21 @@ enum { MDP_WRITEBACK_MIRROR_RESUME, }; +/* + * The enum values are continued below as preprocessor macro definitions + */ enum mdp_color_space { MDP_CSC_ITU_R_601, MDP_CSC_ITU_R_601_FR, MDP_CSC_ITU_R_709, }; +/* + * These definitions are a continuation of the mdp_color_space enum above + */ +#define MDP_CSC_ITU_R_2020 (MDP_CSC_ITU_R_709 + 1) +#define MDP_CSC_ITU_R_2020_FR (MDP_CSC_ITU_R_2020 + 1) + enum { mdp_igc_v1_7 = 1, mdp_igc_vmax, diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 4a3b35f10257..7be4c28cc1ca 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -2161,6 +2161,7 @@ struct v4l2_streamparm { #define V4L2_EVENT_BITDEPTH_FLAG 0x1 #define V4L2_EVENT_PICSTRUCT_FLAG 0x2 +#define V4L2_EVENT_COLOUR_SPACE_FLAG 0x4 #define V4L2_EVENT_MSM_VIDC_START (V4L2_EVENT_PRIVATE_START + 0x00001000) #define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_MSM_VIDC_START + 1) diff --git a/init/do_mounts.h b/init/do_mounts.h index f5b978a9bb92..375835f1d258 100644 --- a/init/do_mounts.h +++ b/init/do_mounts.h @@ -13,6 +13,9 @@ void mount_block_root(char *name, int flags); void mount_root(void); extern int root_mountflags; +struct dm_table; +static inline void dm_table_put(struct dm_table *t) { } + static inline int create_dev(char *name, dev_t dev) { sys_unlink(name); diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 50a6d8e0d4d4..1d55e226196f 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -3106,9 +3106,9 @@ static void reset_all_task_stats(void) read_lock(&tasklist_lock); do_each_thread(g, p) { - raw_spin_lock(&p->pi_lock); + raw_spin_lock_irq(&p->pi_lock); reset_task_stats(p); - raw_spin_unlock(&p->pi_lock); + raw_spin_unlock_irq(&p->pi_lock); } while_each_thread(g, p); read_unlock(&tasklist_lock); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 33344f5a66a8..9ea2cc098ad1 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3198,10 +3198,11 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *sdata_iter; enum nl80211_iftype iftype = sdata->wdev.iftype; - int num[NUM_NL80211_IFTYPES]; struct ieee80211_chanctx *ctx; - int num_different_channels = 0; int total = 1; + struct iface_combination_params params = { + .radar_detect = radar_detect, + }; lockdep_assert_held(&local->chanctx_mtx); @@ -3212,9 +3213,6 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, !chandef->chan)) return -EINVAL; - if (chandef) - num_different_channels = 1; - if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) return -EINVAL; @@ -3225,24 +3223,26 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, return 0; } - memset(num, 0, sizeof(num)); + if (chandef) + params.num_different_channels = 1; if (iftype != NL80211_IFTYPE_UNSPECIFIED) - num[iftype] = 1; + params.iftype_num[iftype] = 1; list_for_each_entry(ctx, &local->chanctx_list, list) { if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) continue; - radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); + params.radar_detect |= + ieee80211_chanctx_radar_detect(local, ctx); if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { - num_different_channels++; + params.num_different_channels++; continue; } if (chandef && chanmode == IEEE80211_CHANCTX_SHARED && cfg80211_chandef_compatible(chandef, &ctx->conf.def)) continue; - num_different_channels++; + params.num_different_channels++; } list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) { @@ -3255,16 +3255,14 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype)) continue; - num[wdev_iter->iftype]++; + params.iftype_num[wdev_iter->iftype]++; total++; } - if (total == 1 && !radar_detect) + if (total == 1 && !params.radar_detect) return 0; - return cfg80211_check_combinations(local->hw.wiphy, - num_different_channels, - radar_detect, num); + return cfg80211_check_combinations(local->hw.wiphy, ¶ms); } static void @@ -3280,12 +3278,10 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c, int ieee80211_max_num_channels(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; - int num[NUM_NL80211_IFTYPES] = {}; struct ieee80211_chanctx *ctx; - int num_different_channels = 0; - u8 radar_detect = 0; u32 max_num_different_channels = 1; int err; + struct iface_combination_params params = {0}; lockdep_assert_held(&local->chanctx_mtx); @@ -3293,17 +3289,17 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) continue; - num_different_channels++; + params.num_different_channels++; - radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); + params.radar_detect |= + ieee80211_chanctx_radar_detect(local, ctx); } list_for_each_entry_rcu(sdata, &local->interfaces, list) - num[sdata->wdev.iftype]++; + params.iftype_num[sdata->wdev.iftype]++; - err = cfg80211_iter_combinations(local->hw.wiphy, - num_different_channels, radar_detect, - num, ieee80211_iter_max_chans, + err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms, + ieee80211_iter_max_chans, &max_num_different_channels); if (err < 0) return err; diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index dca5cacc51f0..ececa65868ef 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -2536,8 +2536,7 @@ static int pp_stats_line(struct seq_file *m, struct tag_stat *ts_entry, uid_t stat_uid = get_uid_from_tag(tag); struct proc_print_info *ppi = m->private; /* Detailed tags are not available to everybody */ - if (get_atag_from_tag(tag) && !can_read_other_uid_stats( - make_kuid(&init_user_ns,stat_uid))) { + if (!can_read_other_uid_stats(make_kuid(&init_user_ns,stat_uid))) { CT_DEBUG("qtaguid: stats line: " "%s 0x%llx %u: insufficient priv " "from pid=%u tgid=%u uid=%u stats.gid=%u\n", diff --git a/net/wireless/util.c b/net/wireless/util.c index a5b20d75017e..6822b4e57fad 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1504,9 +1504,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, } int cfg80211_iter_combinations(struct wiphy *wiphy, - const int num_different_channels, - const u8 radar_detect, - const int iftype_num[NUM_NL80211_IFTYPES], + struct iface_combination_params *params, void (*iter)(const struct ieee80211_iface_combination *c, void *data), void *data) @@ -1517,7 +1515,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, int num_interfaces = 0; u32 used_iftypes = 0; - if (radar_detect) { + if (params->radar_detect) { rcu_read_lock(); regdom = rcu_dereference(cfg80211_regdomain); if (regdom) @@ -1526,8 +1524,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, } for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { - num_interfaces += iftype_num[iftype]; - if (iftype_num[iftype] > 0 && + num_interfaces += params->iftype_num[iftype]; + if (params->iftype_num[iftype] > 0 && !(wiphy->software_iftypes & BIT(iftype))) used_iftypes |= BIT(iftype); } @@ -1541,7 +1539,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, if (num_interfaces > c->max_interfaces) continue; - if (num_different_channels > c->num_different_channels) + if (params->num_different_channels > c->num_different_channels) continue; limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, @@ -1556,16 +1554,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, all_iftypes |= limits[j].types; if (!(limits[j].types & BIT(iftype))) continue; - if (limits[j].max < iftype_num[iftype]) + if (limits[j].max < params->iftype_num[iftype]) goto cont; - limits[j].max -= iftype_num[iftype]; + limits[j].max -= params->iftype_num[iftype]; } } - if (radar_detect != (c->radar_detect_widths & radar_detect)) + if (params->radar_detect != + (c->radar_detect_widths & params->radar_detect)) goto cont; - if (radar_detect && c->radar_detect_regions && + if (params->radar_detect && c->radar_detect_regions && !(c->radar_detect_regions & BIT(region))) goto cont; @@ -1599,14 +1598,11 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c, } int cfg80211_check_combinations(struct wiphy *wiphy, - const int num_different_channels, - const u8 radar_detect, - const int iftype_num[NUM_NL80211_IFTYPES]) + struct iface_combination_params *params) { int err, num = 0; - err = cfg80211_iter_combinations(wiphy, num_different_channels, - radar_detect, iftype_num, + err = cfg80211_iter_combinations(wiphy, params, cfg80211_iter_sum_ifcombs, &num); if (err) return err; @@ -1625,14 +1621,15 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, u8 radar_detect) { struct wireless_dev *wdev_iter; - int num[NUM_NL80211_IFTYPES]; struct ieee80211_channel *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; struct ieee80211_channel *ch; enum cfg80211_chan_mode chmode; - int num_different_channels = 0; int total = 1; int i; + struct iface_combination_params params = { + .radar_detect = radar_detect, + }; ASSERT_RTNL(); @@ -1649,10 +1646,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, return 0; } - memset(num, 0, sizeof(num)); memset(used_channels, 0, sizeof(used_channels)); - num[iftype] = 1; + params.iftype_num[iftype] = 1; /* TODO: We'll probably not need this anymore, since this * should only be called with CHAN_MODE_UNDEFINED. There are @@ -1665,10 +1661,10 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, case CHAN_MODE_SHARED: WARN_ON(!chan); used_channels[0] = chan; - num_different_channels++; + params.num_different_channels++; break; case CHAN_MODE_EXCLUSIVE: - num_different_channels++; + params.num_different_channels++; break; } @@ -1696,7 +1692,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, */ mutex_lock_nested(&wdev_iter->mtx, 1); __acquire(wdev_iter->mtx); - cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); + cfg80211_get_chan_state(wdev_iter, &ch, &chmode, + ¶ms.radar_detect); wdev_unlock(wdev_iter); switch (chmode) { @@ -1712,23 +1709,22 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, if (used_channels[i] == NULL) { used_channels[i] = ch; - num_different_channels++; + params.num_different_channels++; } break; case CHAN_MODE_EXCLUSIVE: - num_different_channels++; + params.num_different_channels++; break; } - num[wdev_iter->iftype]++; + params.iftype_num[wdev_iter->iftype]++; total++; } - if (total == 1 && !radar_detect) + if (total == 1 && !params.radar_detect) return 0; - return cfg80211_check_combinations(&rdev->wiphy, num_different_channels, - radar_detect, num); + return cfg80211_check_combinations(&rdev->wiphy, ¶ms); } int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 8f6276f1f3d4..281db1d07f57 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -143,6 +143,7 @@ static int cpe_debug_mode; #define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone" #define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone" +#define DAPM_LDO_H_STANDALONE "LDO_H" module_param(cpe_debug_mode, int, S_IRUGO | S_IWUSR | S_IWGRP); MODULE_PARM_DESC(cpe_debug_mode, "boot cpe in debug mode"); @@ -6186,6 +6187,55 @@ static int __tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, return 0; } +static int tasha_codec_ldo_h_control(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + tasha->ldo_h_users++; + + if (tasha->ldo_h_users == 1) + snd_soc_update_bits(codec, WCD9335_LDOH_MODE, + 0x80, 0x80); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + tasha->ldo_h_users--; + + if (tasha->ldo_h_users < 0) + tasha->ldo_h_users = 0; + + if (tasha->ldo_h_users == 0) + snd_soc_update_bits(codec, WCD9335_LDOH_MODE, + 0x80, 0x00); + } + + return 0; +} + +static int tasha_codec_force_enable_ldo_h(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_resmgr_enable_master_bias(tasha->resmgr); + tasha_codec_ldo_h_control(w, event); + break; + case SND_SOC_DAPM_POST_PMD: + tasha_codec_ldo_h_control(w, event); + wcd_resmgr_disable_master_bias(tasha->resmgr); + break; + } + + return 0; +} + static int tasha_codec_force_enable_micbias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -6218,6 +6268,29 @@ static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, return __tasha_codec_enable_micbias(w, event); } +static int tasha_codec_enable_standalone_ldo_h(struct snd_soc_codec *codec, + bool enable) +{ + int rc; + + if (enable) + rc = snd_soc_dapm_force_enable_pin( + snd_soc_codec_get_dapm(codec), + DAPM_LDO_H_STANDALONE); + else + rc = snd_soc_dapm_disable_pin( + snd_soc_codec_get_dapm(codec), + DAPM_LDO_H_STANDALONE); + + if (!rc) + snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec)); + else + dev_err(codec->dev, "%s: ldo_h force %s pin failed\n", + __func__, (enable ? "enable" : "disable")); + + return rc; +} + /* * tasha_codec_enable_standalone_micbias - enable micbias standalone * @codec: pointer to codec instance @@ -7772,6 +7845,34 @@ static const struct soc_enum tasha_conn_mad_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_conn_mad_text), tasha_conn_mad_text); +static int tasha_enable_ldo_h_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + u8 val = 0; + + if (codec) + val = snd_soc_read(codec, WCD9335_LDOH_MODE) & 0x80; + + ucontrol->value.integer.value[0] = !!val; + + return 0; +} + +static int tasha_enable_ldo_h_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int value = ucontrol->value.integer.value[0]; + bool enable; + + enable = !!value; + if (codec) + tasha_codec_enable_standalone_ldo_h(codec, enable); + + return 0; +} + static int tasha_mad_input_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -8516,6 +8617,8 @@ static const struct snd_kcontrol_new tasha_snd_controls[] = { SOC_ENUM_EXT("MAD Input", tasha_conn_mad_enum, tasha_mad_input_get, tasha_mad_input_put), + SOC_SINGLE_EXT("LDO_H Enable", SND_SOC_NOPM, 0, 1, 0, + tasha_enable_ldo_h_get, tasha_enable_ldo_h_put), SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0, tasha_pinctl_mode_get, tasha_pinctl_mode_put), @@ -10750,6 +10853,9 @@ static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = { SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0, tasha_codec_force_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_LDO_H_STANDALONE, SND_SOC_NOPM, 0, 0, + tasha_codec_force_enable_ldo_h, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("ANC0 FB MUX", SND_SOC_NOPM, 0, 0, &anc0_fb_mux), SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux), diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c index d713edbbb355..64c33c082b4b 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c +++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c @@ -870,11 +870,41 @@ static int tavil_get_hph_type(struct snd_kcontrol *kcontrol, return 0; } +static int tavil_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t zl, zr; + bool hphr; + struct soc_multi_mixer_control *mc; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec); + + if (!wcd934x_mbhc) { + dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + mc = (struct soc_multi_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + wcd_mbhc_get_impedance(&wcd934x_mbhc->wcd_mbhc, &zl, &zr); + dev_dbg(codec->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr); + ucontrol->value.integer.value[0] = hphr ? zr : zl; + + return 0; +} + static const struct snd_kcontrol_new hph_type_detect_controls[] = { SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, tavil_get_hph_type, NULL), }; +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + tavil_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + tavil_hph_impedance_get, NULL), +}; + /* * tavil_mbhc_hs_detect: starts mbhc insertion/removal functionality * @codec: handle to snd_soc_codec * @@ -985,6 +1015,8 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec, 0; } + snd_soc_add_codec_controls(codec, impedance_detect_controls, + ARRAY_SIZE(impedance_detect_controls)); snd_soc_add_codec_controls(codec, hph_type_detect_controls, ARRAY_SIZE(hph_type_detect_controls)); diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 0213d9ba4a59..5d6119c6d86a 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -8039,6 +8039,7 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { {WCD934X_HPH_OCP_CTL, 0xFF, 0x3A}, /* OCP current limit */ {WCD934X_HPH_L_TEST, 0x01, 0x01}, {WCD934X_HPH_R_TEST, 0x01, 0x01}, + {WCD934X_CPE_FLL_CONFIG_CTL_2, 0xFF, 0x20}, }; static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = { @@ -8676,6 +8677,8 @@ static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx) regcache_sync(codec->component.regmap); __tavil_cdc_mclk_enable(tavil, false); + tavil_update_cpr_defaults(tavil); + pdata = dev_get_platdata(codec->dev->parent); ret = tavil_handle_pdata(tavil, pdata); if (IS_ERR_VALUE(ret)) |
