diff options
188 files changed, 3731 insertions, 6299 deletions
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt index 6eadd564a247..2ad68dbbaaae 100644 --- a/Documentation/DMA-attributes.txt +++ b/Documentation/DMA-attributes.txt @@ -132,6 +132,11 @@ DMA_ATTR_FORCE_COHERENT When passed to a DMA map call the DMA_ATTR_FORCE_COHERENT DMA attribute can be used to force a buffer to be mapped as IO coherent. + +When the DMA_ATTR_FORCE_COHERENT attribute is set during a map call ensure +that it is also set during for the matching unmap call to ensure that the +correct cache maintenance is carried out. + This DMA attribute is only currently supported for arm64 stage 1 IOMMU mappings. @@ -143,5 +148,9 @@ coherent. The DMA_ATTR_FORCE_NON_COHERENT DMA attribute overrides the buffer IO coherency configuration set by making the device IO coherent. +When the DMA_ATTR_FORCE_NON_COHERENT attribute is set during a map call +ensure that it is also set during for the matching unmap call to ensure +that the correct cache maintenance is carried out. + This DMA attribute is only currently supported for arm64 stage 1 IOMMU mappings. diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 02431aeca15f..eaadf60f4692 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -137,6 +137,7 @@ !Finclude/net/cfg80211.h cfg80211_ibss_joined !Finclude/net/cfg80211.h cfg80211_connect_result !Finclude/net/cfg80211.h cfg80211_connect_bss +!Finclude/net/cfg80211.h cfg80211_connect_timeout !Finclude/net/cfg80211.h cfg80211_roamed !Finclude/net/cfg80211.h cfg80211_disconnected !Finclude/net/cfg80211.h cfg80211_ready_on_channel diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt index 4b70e670798d..c801e8486f87 100644 --- a/Documentation/devicetree/bindings/cnss/icnss.txt +++ b/Documentation/devicetree/bindings/cnss/icnss.txt @@ -17,14 +17,14 @@ Required properties: - iommus: SMMUs and corresponding Stream IDs needed by WLAN - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length> format to be used for allocations associated between WLAN and SMMU - - <supply-name>-supply: phandle to the regulator device tree node - Required "supply-name" is "vdd-0.8-cx-mx". - - qcom,<supply>-config: Specifies voltage levels for supply. Should be - specified in pairs (min, max), units uV. There can - be optional load in uA and Regulator settle delay in - uS. Optional properties: + - <supply-name>-supply: phandle to the regulator device tree node + optional "supply-name" is "vdd-0.8-cx-mx". + - qcom,<supply>-config: Specifies voltage levels for supply. Should be + specified in pairs (min, max), units uV. There can + be optional load in uA and Regulator settle delay in + uS. - qcom,icnss-vadc: VADC handle for vph_pwr read APIs. - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs. - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 1ca89b587077..d8c3a7c35465 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -150,6 +150,11 @@ Optional Properties: baseAddr - base address of the gpu channels in the qdss stm memory region size - size of the gpu stm region +- qcom,gpu-qtimer: + <baseAddr size> + baseAddr - base address of the qtimer memory region + size - size of the qtimer region + - qcom,tsens-name: Specify the name of GPU temperature sensor. This name will be used to get the temperature from the thermal driver API. diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt deleted file mode 100644 index bde115155eba..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt +++ /dev/null @@ -1,104 +0,0 @@ -Goodix GT9xx series touch controller - -The Goodix GT9xx series touch controller is connected to the host processor via -I2C. The controller generates interrupts when the user touches the panel. The -host controller is expected to read the touch coordinates over I2C and pass -the coordinates to the rest of the system. - -Required properties: - - - compatible : Should be "goodix,gt9xx" - - reg : I2C slave address of the device. - - interrupt-parent : Parent of interrupt. - - interrupts : Configuration of touch panel controller interrupt - GPIO. - - goodix,product-id : Product identification of the controller. - - interrupt-gpios : Interrupt gpio which is to provide interrupts to - host, same as "interrupts" node. - - reset-gpios : Reset gpio to control the reset of chip. - - goodix,display-coords : Display coordinates in pixels. It is a four - tuple consisting of min x, min y, max x and - max y values. - -Optional properties: - - - avdd-supply : Power supply needed to power up the device, this is - for fixed voltage external regulator. - - vdd-supply : Power supply needed to power up the device, when use - external regulator, do not add this property. - - vcc-i2c-supply : Power source required to power up i2c bus. - GT9xx series can provide 1.8V from internal - LDO, add this properties base on hardware - design. - - goodix,panel-coords : Panel coordinates for the chip in pixels. - It is a four tuple consisting of min x, - min y, max x and max y values. - - goodix,i2c-pull-up : To specify pull up is required. - - goodix,force-update : To specify force update is allowed. - - goodix,enable-power-off : Power off touchscreen during suspend. - - goodix,button-map : Button map of key codes. The number of key codes - depend on panel. - - goodix,cfg-data0 : Touch screen controller config data group 0. Ask vendor - to provide that. - Driver supports maximum six config groups. If more than one - groups are defined, driver will select config group depending - on hardware configuration. If only config group 0 is defined, - it will be used for all hardware configurations. - Touch screen controller will use its onchip default config data - if this property is not present. - - goodix,cfg-data1 : Touch screen controller config data group 1. Ask vendor - to provide that. - - goodix,cfg-data2 : Touch screen controller config data group 2. Ask vendor - to provide that. - - goodix,cfg-data3 : Touch screen controller config data group 3. Ask vendor - to provide that. - - goodix,cfg-data4 : Touch screen controller config data group 4. Ask vendor - to provide that. - - goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor - to provide that. - - goodix,fw-name : Touch screen controller firmware file name. - - goodix,slide-wakeup : To specify slide-wakeup property is enabled or not. - - goodix,dbl-clk-wakeup : To specify dbl-clk-wakeup property is enabled or not. - - goodix,change-x2y : To specify change-x2y property is enabled or not. - - goodix,driver-send-cfg : To specify driver-send-cfg property is enabled or not. - - goodix,have-touch-key : To specify have-touch-key property is enabled or not. - - goodix,with-pen : To specify with-pen property is enabled or not. -Example: -i2c@f9927000 { - goodix@5d { - compatible = "goodix,gt9xx"; - reg = <0x5d>; - interrupt-parent = <&msmgpio>; - interrupts = <17 0x2008>; - reset-gpios = <&msmgpio 16 0x00>; - interrupt-gpios = <&msmgpio 17 0x00>; - avdd-supply = <&tp_power>; - goodix,panel-coords = <0 0 720 1200>; - goodix,display-coords = <0 0 720 1080>; - goodix,button-map= <158 102 139>; - goodix,product-id = "915"; - goodix,cfg-data0 = [ - 41 D0 02 00 05 0A 05 01 01 08 - 12 58 50 41 03 05 00 00 00 00 - 00 00 00 00 00 00 00 8C 2E 0E - 28 24 73 13 00 00 00 83 03 1D - 40 02 00 00 00 03 64 32 00 00 - 00 1A 38 94 C0 02 00 00 00 04 - 9E 1C 00 8D 20 00 7A 26 00 6D - 2C 00 60 34 00 60 10 38 68 00 - F0 50 35 FF FF 27 00 00 00 00 - 00 01 1B 14 0C 14 00 00 01 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 02 04 06 08 0A 0C 0E 10 - 12 14 16 18 1A 1C FF FF FF FF - FF FF FF FF FF FF FF FF FF FF - FF FF 00 02 04 06 08 0A 0C 0F - 10 12 13 14 16 18 1C 1D 1E 1F - 20 21 22 24 26 28 29 2A FF FF - FF FF FF FF FF FF FF 22 22 22 - 22 22 22 FF 07 01]; - goodix,fw_name = "gtp_fw.bin"; - goodix,have-touch-key; - goodix,driver-send-cfg; - }; -}; diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt index 2bd9fb840830..450e4d6ee8f0 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cpp.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt @@ -70,6 +70,13 @@ Optional properties: The first entry is register offset and second entry is register value. - qcom,micro-reset: Boolean flag indicating if micro reset need to be enabled. This needs to present on platforms that support this feature. +- qcom,cpp-cx-ipeak: To handle Cx peak current limit. + <phandle bit> + phandle - phandle of cx ipeak device node + bit - bit number of client in relevant register + This is used to access Cx ipeak HW module to limit the current drawn by + various subsystem blocks on Cx power rail. CPP set their bit in tcsr register + if it is going to cross its own threshold. Example: @@ -105,6 +112,7 @@ Example: "micro_iface_clk", "camss_ahb_clk"; "smmu_cpp_axi_clk", "cpp_vbif_ahb_clk"; qcom,clock-rates = <0 0 0 0 465000000 0 0 465000000 0 0 0 0>; + qcom,cpp-cx-ipeak = <&cx_ipeak_lm 2>; qcom,min-clock-rate = <320000000>; qcom,bus-master = <1>; qcom,vbif-qos-setting = <0x20 0x10000000>, diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt index dac22f30bf1d..aaf13442fcf1 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt @@ -23,6 +23,7 @@ Required properties for child node: Only needed for child node. - "vfe" - Required. - "vfe_vbif" - Optional for "vfe32". Required for "vfe40". + - "vfe_fuse" - Optional. - interrupts : should contain the vfe interrupt. - interrupt-names : should specify relevant names to each interrupts property defined. @@ -52,9 +53,10 @@ Example: vfe0: qcom,vfe0@fda10000 { cell-index = <0>; compatible = "qcom,vfe44"; - reg = <0xfda10000 0x1000>; - <0xfda40000 0x200>; - reg-names = "vfe", "vfe_vbif"; + reg = <0xfda10000 0x1000>, + <0xfda40000 0x200>, + <0x7801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; interrupts = <0 57 0>; interrupt-names = "vfe"; vdd-supply = <&gdsc_vfe>; @@ -105,9 +107,10 @@ vfe0: qcom,vfe0@fda10000 { vfe1: qcom,vfe1@fda14000 { cell-index = <1>; compatible = "qcom,vfe44"; - reg = <0xfda14000 0x1000>; - <0xfda40000 0x200>; - reg-names = "vfe", "vfe_vbif"; + reg = <0xfda14000 0x1000>, + <0xfda40000 0x200>, + <0x7801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; interrupts = <0 58 0>; interrupt-names = "vfe"; vdd-supply = <&gdsc_vfe>; diff --git a/Documentation/devicetree/bindings/misc/qpnp-misc.txt b/Documentation/devicetree/bindings/misc/qpnp-misc.txt index 9de6857a2643..a34cbde456e4 100644 --- a/Documentation/devicetree/bindings/misc/qpnp-misc.txt +++ b/Documentation/devicetree/bindings/misc/qpnp-misc.txt @@ -17,23 +17,9 @@ Optional properties: "qcom,pwm-sel" property. Example: - qcom,spmi@fc4c0000 { - #address-cells = <1>; - #size-cells = <0>; - interrupt-controller; - #interrupt-cells = <3>; - - qcom,pm8941@0 { - spmi-slave-container; - reg = <0x0>; - #address-cells = <1>; - #size-cells = <1>; - - qcom,misc@900 { - compatible = "qcom,qpnp-misc"; - reg = <0x900 0x100>; - qcom,pwm-sel = <2>; - qcom,enable-gp-driver; - }; - } + qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + qcom,pwm-sel = <2>; + qcom,enable-gp-driver; }; diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt index a7848153f83c..6574cfe30ce5 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt @@ -10,6 +10,7 @@ pwm(pulse width modulation) and audio. Required Properties: - compatible: must be "qcom,qpnp-haptic" - reg: address of device + - qcom,pmic-revid : phandle to fetch PMIC revid - qcom,actuator-type: must be one of "erm" or "lra" - qcom,play-mode : must be one of "buffer", "direct", "pwm" or "audio" @@ -63,7 +64,13 @@ Optional properties when qcom,actuator-type is "lra" "max-qwd" : Maximum QWD "zxd-eop" : ZXD + End of pattern (This is the Default) - qcom,lra-high-z : High Z configuration for auto resonance. Possible string values are - "none", "opt1", "opt2" and "opt3" (default) + "none", "opt1", "opt2" and "opt3" (default). For PM660, + "opt0" is valid value for 1 LRA period. + - qcom,lra-qwd-drive-duration : Drive duration of LRA in QWD mode for PM660. + Possible values are: 0: 1/4 LRA PERIOD and 1: 3/8 LRA PERIOD + - qcom,lra-calibrate-at-eop : To calibrate at End of Pattern for PM660. + Possible values are: 0 to disable and 1 to enable Calibration + at End of Pattern - qcom,lra-res-cal-period : Auto resonance calibration period. The values range from 4 to 32(default) - qcom,perform-lra-auto-resonance-search : boolean, define this property if: @@ -109,6 +116,7 @@ Example: interrupts = <0x3 0xc0 0x0>, <0x3 0xc0 0x1>; interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pm660_revid>; vcc_pon-supply = <&pon_perph_reg>; qcom,play-mode = "direct"; qcom,wave-play-rate-us = <5263>; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index db37dc6f31bb..a2e7311705e3 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -123,6 +123,7 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ apq8998-v2-mtp.dtb \ apq8998-v2-cdp.dtb \ apq8998-v2-qrd.dtb \ + apq8998-v2-qrd-skuk-hdk.dtb \ msm8998-v2.1-mtp.dtb \ msm8998-v2.1-cdp.dtb \ msm8998-v2.1-qrd.dtb \ diff --git a/arch/arm/boot/dts/qcom/apq8998-v2-qrd-skuk-hdk.dts b/arch/arm/boot/dts/qcom/apq8998-v2-qrd-skuk-hdk.dts new file mode 100644 index 000000000000..6406fe52242d --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8998-v2-qrd-skuk-hdk.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "apq8998-v2.dtsi" +#include "msm8998-qrd-skuk-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ 8998 SKUK HDK"; + compatible = "qcom,msm8998-qrd", "qcom,msm8998", "qcom,qrd"; + qcom,board-id = <0x06000b 0x10>; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi index ebd73ceaa8ce..f4829eb7f799 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -82,7 +82,6 @@ 15 01 00 00 10 00 02 ff 24 15 01 00 00 10 00 02 fb 01 15 01 00 00 10 00 02 c6 06 - 15 01 00 00 10 00 02 9d 30 /* Enable IMGSWAP */ 15 01 00 00 10 00 02 ff 10 05 01 00 00 a0 00 02 11 00 05 01 00 00 a0 00 02 29 00]; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi new file mode 100644 index 000000000000..8757dad98b3e --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi @@ -0,0 +1,124 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_rm67195_amoled_fhd_cmd: qcom,mdss_dsi_rm67195_amoled_fhd_cmd{ + qcom,mdss-dsi-panel-name = + "rm67195 amoled fhd cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <32>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 fe 0d + 15 01 00 00 00 00 02 42 00 + 15 01 00 00 00 00 02 18 08 + 15 01 00 00 00 00 02 08 41 + 15 01 00 00 00 00 02 46 02 + 15 01 00 00 00 00 02 1e 04 + 15 01 00 00 02 00 02 1e 00 + 15 01 00 00 00 00 02 fe 0a + 15 01 00 00 00 00 02 24 17 + 15 01 00 00 00 00 02 04 07 + 15 01 00 00 00 00 02 1a 0c + 15 01 00 00 02 00 02 0f 44 + 15 01 00 00 00 00 02 fe 0b + 15 01 00 00 00 00 02 28 40 + 15 01 00 00 02 00 02 29 4f + 15 01 00 00 00 00 02 fe 04 + 15 01 00 00 00 00 02 4f 1b + 15 01 00 00 02 00 02 50 2f + 15 01 00 00 00 00 02 fe 09 + 15 01 00 00 00 00 02 00 08 + 15 01 00 00 00 00 02 01 08 + 15 01 00 00 00 00 02 02 00 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 04 10 + 15 01 00 00 00 00 02 05 00 + 15 01 00 00 00 00 02 06 08 + 15 01 00 00 00 00 02 07 08 + 15 01 00 00 00 00 02 08 00 + 15 01 00 00 00 00 02 12 24 + 15 01 00 00 00 00 02 13 49 + 15 01 00 00 00 00 02 14 92 + 15 01 00 00 00 00 02 15 49 + 15 01 00 00 00 00 02 16 92 + 15 01 00 00 00 00 02 17 24 + 15 01 00 00 00 00 02 18 24 + 15 01 00 00 00 00 02 19 49 + 15 01 00 00 00 00 02 1a 92 + 15 01 00 00 00 00 02 1b 49 + 15 01 00 00 00 00 02 1c 92 + 15 01 00 00 00 00 02 1d 24 + 15 01 00 00 00 00 02 1e 24 + 15 01 00 00 00 00 02 1f 49 + 15 01 00 00 00 00 02 20 92 + 15 01 00 00 00 00 02 21 49 + 15 01 00 00 00 00 02 22 92 + 15 01 00 00 00 00 02 23 24 + 15 01 00 00 00 00 02 9b 07 + 15 01 00 00 02 00 02 9c a5 + 15 01 00 00 00 00 02 fe 00 + 15 01 00 00 00 00 02 c2 08 + 15 01 00 00 02 00 02 35 00 + 39 01 00 00 00 00 03 44 03 e8 + 05 01 00 00 82 00 02 11 00 + 05 01 00 00 14 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 82 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-pan-physical-width-dimension = <70>; + qcom,mdss-pan-physical-height-dimension = <125>; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-panel-orientation = "180"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi index 874b97a3c965..33bd86654363 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -55,7 +55,7 @@ <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clock_rpmcc RPM_AGGR2_NOC_CLK>; + clocks = <&clock_rpmcc AGGR2_NOC_SMMU_CLK>; clock-names = "smmu_aggr2_noc_clk"; #clock-cells = <1>; }; diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 9c4890a84a37..463d352f8791 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -607,6 +607,7 @@ interrupts = <0x1 0xc0 0x0 IRQ_TYPE_NONE>, <0x1 0xc0 0x1 IRQ_TYPE_NONE>; interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pm660_revid>; qcom,actuator-type = "lra"; qcom,play-mode = "direct"; qcom,vmax-mv = <3200>; @@ -619,9 +620,9 @@ qcom,brake-pattern = [03 03 00 00]; qcom,use-play-irq; qcom,use-sc-irq; - qcom,lra-high-z = "opt1"; + qcom,lra-high-z = "opt0"; qcom,lra-auto-res-mode = "qwd"; - qcom,lra-res-cal-period = <4>; + qcom,lra-calibrate-at-eop = <0>; qcom,correct-lra-drive-freq; qcom,misc-trim-error-rc19p2-clk-reg-present; }; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index 0356942cbe95..bcdbc4ed7c55 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -394,6 +394,9 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xec00 0x100>; + interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + qcom,force-module-reenable; lcdb_ldo_vreg: ldo { diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index fba0aed42146..111d0b51b6c2 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -631,6 +631,7 @@ interrupts = <0x3 0xc0 0x0 IRQ_TYPE_NONE>, <0x3 0xc0 0x1 IRQ_TYPE_NONE>; interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pmi8998_revid>; qcom,actuator-type = "lra"; qcom,play-mode = "direct"; qcom,vmax-mv = <3200>; diff --git a/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi b/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi index 3f81da7c3ebc..1396f27159df 100644 --- a/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -308,6 +308,32 @@ 23 1e 07 08 05 03 04 a0 23 1e 07 08 05 03 04 a0 23 18 07 08 04 03 04 a0]; + + qcom,mdss-dsi-on-command = [15 01 00 00 10 00 02 ff 10 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 ba 03 + 15 01 00 00 10 00 02 e5 01 + 15 01 00 00 10 00 02 35 00 + 15 01 00 00 10 00 02 bb 10 + 15 01 00 00 10 00 02 b0 03 + 15 01 00 00 10 00 02 ff e0 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 6b 3d + 15 01 00 00 10 00 02 6c 3d + 15 01 00 00 10 00 02 6d 3d + 15 01 00 00 10 00 02 6e 3d + 15 01 00 00 10 00 02 6f 3d + 15 01 00 00 10 00 02 35 02 + 15 01 00 00 10 00 02 36 72 + 15 01 00 00 10 00 02 37 10 + 15 01 00 00 10 00 02 08 c0 + 15 01 00 00 10 00 02 ff 24 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 c6 06 + 15 01 00 00 10 00 02 9d 30 /* Enable IMGSWAP */ + 15 01 00 00 10 00 02 ff 10 + 05 01 00 00 a0 00 02 11 00 + 05 01 00 00 a0 00 02 29 00]; }; &dsi_nt35597_dsc_video { diff --git a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi index 144d319d9121..cc20c57a8099 100644 --- a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi @@ -75,6 +75,8 @@ qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size + qcom,gpu-qtimer = <0x17921000 0x1000>; // base addr, size + qcom,tsens-name = "tsens_tz_sensor12"; /* Quirks */ diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi new file mode 100644 index 000000000000..7ed28e4c8813 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi @@ -0,0 +1,138 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm8998-qrd-skuk.dtsi" +#include "msm8998-camera-sensor-skuk-hdk.dtsi" + +&soc { + sound-tavil { + qcom,msm-mbhc-hphl-swh = <0>; + }; +}; + +&pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio52", "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio52", "gpio94"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio52", "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio52", "gpio94"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_s6e3ha3_amoled_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-enable-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>; + qcom,platform-bklight-en-gpio-invert; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_s6e3ha3_amoled_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-enable-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>; + qcom,platform-bklight-en-gpio-invert; +}; + +&pmi8998_wled { + qcom,disp-type-amoled; +}; + +&labibb { + status = "ok"; + qcom,qpnp-labibb-mode = "amoled"; + qcom,swire-control; +}; + +&pmi8998_gpios { + /* GPIO 1 for WLED power enable */ + gpio@c000 { + qcom,mode = <1>; + qcom,output-type = <0>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,out-strength = <1>; + qcom,src-sel = <0>; + qcom,invert = <0>; + qcom,master-en = <1>; + status = "okay"; + }; +}; + +&dsi_dual_s6e3ha3_amoled_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&i2c_5 { + status = "okay"; + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <125 0x2008>; + vdd-supply = <&pm8998_l6>; + avdd-supply = <&pm8998_l28>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 125 0x2008>; + st,reset-gpio = <&tlmm 89 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + }; +}; + +&soc { + /* HDK835 do not use improveTouch. If do not remove this node, + * legacy TOUCH could not work. + */ + /delete-node/hbtp; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts b/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts index 73debc374fda..f3ba42e4dfd9 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts +++ b/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts @@ -10,139 +10,13 @@ * GNU General Public License for more details. */ - /dts-v1/; #include "msm8998-v2.dtsi" -#include "msm8998-qrd-skuk.dtsi" -#include "msm8998-camera-sensor-skuk-hdk.dtsi" +#include "msm8998-qrd-skuk-hdk.dtsi" / { model = "Qualcomm Technologies, Inc. MSM 8998 SKUK HDK"; compatible = "qcom,msm8998-qrd", "qcom,msm8998", "qcom,qrd"; qcom,board-id = <0x06000b 0x10>; }; - -&soc { - sound-tavil { - qcom,msm-mbhc-hphl-swh = <0>; - }; -}; - -&pmx_mdss { - mdss_dsi_active: mdss_dsi_active { - mux { - pins = "gpio52", "gpio94"; - function = "gpio"; - }; - - config { - pins = "gpio52", "gpio94"; - drive-strength = <8>; /* 8 mA */ - bias-disable = <0>; /* no pull */ - }; - }; - - mdss_dsi_suspend: mdss_dsi_suspend { - mux { - pins = "gpio52", "gpio94"; - function = "gpio"; - }; - - config { - pins = "gpio52", "gpio94"; - drive-strength = <2>; /* 2 mA */ - bias-pull-down; /* pull down */ - }; - }; -}; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; -}; - -&mdss_dsi { - hw-config = "split_dsi"; -}; - -&mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_dual_s6e3ha3_amoled_cmd>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; - pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,platform-te-gpio = <&tlmm 10 0>; - qcom,platform-enable-gpio = <&tlmm 52 0>; - qcom,platform-reset-gpio = <&tlmm 94 0>; - qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>; - qcom,platform-bklight-en-gpio-invert; -}; - -&mdss_dsi1 { - qcom,dsi-pref-prim-pan = <&dsi_dual_s6e3ha3_amoled_cmd>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; - pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,platform-te-gpio = <&tlmm 10 0>; - qcom,platform-enable-gpio = <&tlmm 52 0>; - qcom,platform-reset-gpio = <&tlmm 94 0>; - qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>; - qcom,platform-bklight-en-gpio-invert; -}; - -&pmi8998_wled { - qcom,disp-type-amoled; -}; - -&labibb { - status = "ok"; - qcom,qpnp-labibb-mode = "amoled"; - qcom,swire-control; -}; - -&pmi8998_gpios { - /* GPIO 1 for WLED power enable */ - gpio@c000 { - qcom,mode = <1>; - qcom,output-type = <0>; - qcom,pull = <5>; - qcom,vin-sel = <0>; - qcom,out-strength = <1>; - qcom,src-sel = <0>; - qcom,invert = <0>; - qcom,master-en = <1>; - status = "okay"; - }; -}; - -&dsi_dual_s6e3ha3_amoled_cmd { - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; -}; - -&i2c_5 { - status = "okay"; - st_fts@49 { - compatible = "st,fts"; - reg = <0x49>; - interrupt-parent = <&tlmm>; - interrupts = <125 0x2008>; - vdd-supply = <&pm8998_l6>; - avdd-supply = <&pm8998_l28>; - pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; - pinctrl-0 = <&ts_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - st,irq-gpio = <&tlmm 125 0x2008>; - st,reset-gpio = <&tlmm 89 0x00>; - st,regulator_dvdd = "vdd"; - st,regulator_avdd = "avdd"; - }; -}; - -&soc { - /* HDK835 do not use improveTouch. If do not remove this node, - * legacy TOUCH could not work. - */ - /delete-node/hbtp; -}; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 0e014a171156..66ca39ee6ebc 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -286,16 +286,22 @@ reg = <0 0x85800000 0 0x3700000>; }; - pil_ipa_gpu_mem: pil_ipa_gpu_region@95000000 { + pil_ipa_gpu_mem: pil_ipa_gpu_region@95200000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95000000 0 0x100000>; + reg = <0 0x95200000 0 0x100000>; }; - pil_slpi_mem: pil_slpi_region@94100000 { + pil_slpi_mem: pil_slpi_region@94300000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x94100000 0 0xf00000>; + reg = <0 0x94300000 0 0xf00000>; + }; + + pil_mba_mem: pil_mba_region@94100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x94100000 0 0x200000>; }; pil_video_mem: pil_video_region@93c00000 { @@ -2109,6 +2115,10 @@ /* GPIO output to mss */ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + qcom,mba-mem@0 { + compatible = "qcom,pil-mba-mem"; + memory-region = <&pil_mba_mem>; + }; }; tsens0: tsens@10aa000 { diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi index 56210dc6892b..72f606168691 100644 --- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi @@ -501,8 +501,9 @@ cell-index = <0>; compatible = "qcom,vfe48"; reg = <0xca10000 0x4000>, - <0xca40000 0x3000>; - reg-names = "vfe", "vfe_vbif"; + <0xca40000 0x3000>, + <0x007801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; interrupts = <0 314 0>; interrupt-names = "vfe"; vdd-supply = <&gdsc_vfe0>; @@ -581,8 +582,9 @@ cell-index = <1>; compatible = "qcom,vfe48"; reg = <0xca14000 0x4000>, - <0xca40000 0x3000>; - reg-names = "vfe", "vfe_vbif"; + <0xca40000 0x3000>, + <0x007801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; interrupts = <0 315 0>; interrupt-names = "vfe"; vdd-supply = <&gdsc_vfe1>; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index 1fdfba6ddf2c..9c34a60e7aaa 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -244,6 +244,9 @@ mdss_fb0: qcom,mdss_fb_primary { cell-index = <0>; compatible = "qcom,mdss-fb"; + qcom,cont-splash-memory { + linux,contiguous-region = <&cont_splash_mem>; + }; }; mdss_fb1: qcom,mdss_fb_wfd { diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts index d535d62e521c..c2408ba7bf76 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts @@ -16,6 +16,7 @@ #include "sdm630.dtsi" #include "sdm630-qrd.dtsi" #include "msm-pm660a.dtsi" +#include "sdm660-internal-codec.dtsi" / { model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A QRD"; @@ -23,3 +24,30 @@ qcom,board-id = <0x0002000b 0x00>; qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; }; + +&int_codec { + qcom,model = "sdm660-snd-card-skush"; + /delete-property/ qcom,us-euro-gpios; + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "INT_LDO_H", "INT_MCLK0", + "MIC BIAS External2", "Headset Mic", + "AMIC2", "MIC BIAS External2", + "MIC BIAS External", "Digital Mic1", + "DMIC1", "MIC BIAS External", + "MIC BIAS External", "Digital Mic3", + "DMIC3", "MIC BIAS External", + "MIC BIAS External", "Digital Mic4", + "DMIC4", "MIC BIAS External", + "SpkrLeft IN", "SPK1 OUT", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_213_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index f21707db590a..cb083c0a8aa0 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -318,6 +318,10 @@ }; &soc { + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; + gpio_keys { compatible = "gpio-keys"; input-name = "gpio-keys"; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index ce088c372eea..623ca54de94b 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -376,13 +376,17 @@ linux,cma-default; }; + cont_splash_mem: splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x02400000>; + label = "cont_splash_mem"; + }; }; bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; - qca,bt-vdd-core-supply = <&pm660_l9_pin_ctrl>; - qca,bt-vdd-pa-supply = <&pm660_l6_pin_ctrl>; - qca,bt-vdd-ldo-supply = <&pm660_l19_pin_ctrl>; + qca,bt-vdd-core-supply = <&pm660_l9>; + qca,bt-vdd-pa-supply = <&pm660_l6>; + qca,bt-vdd-ldo-supply = <&pm660_l19>; qca,bt-chip-pwd-supply = <&pm660l_bob_pin1>; clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>; clock-names = "rf_clk1"; @@ -734,7 +738,6 @@ clock-names = "osm"; clocks = <&clock_cpu PERFCL_CLK>; - qcom,cxip-lm-enable = <0>; qcom,vdd-restriction-temp = <5>; qcom,vdd-restriction-temp-hysteresis = <10>; @@ -1205,7 +1208,7 @@ qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/ qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/ clocks = <&clock_rpmcc RPM_IPA_CLK>, - <&clock_rpmcc RPM_AGGR2_NOC_CLK>; + <&clock_rpmcc AGGR2_NOC_SMMU_CLK>; clock-names = "core_clk", "smmu_clk"; qcom,arm-smmu; qcom,smmu-disable-htw; @@ -1798,6 +1801,11 @@ reg = <0x6b0 32>; }; + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + pil@94c { compatible = "qcom,msm-imem-pil"; reg = <0x94c 200>; diff --git a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi index 0524935b9a30..d555da4cbd08 100644 --- a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi @@ -38,8 +38,8 @@ qcom,qos-off = <4096>; qcom,base-offset = <16384>; clock-names = "bus_clk", "bus_a_clk"; - clocks = <&clock_rpmcc RPM_AGGR2_NOC_CLK>, - <&clock_rpmcc RPM_AGGR2_NOC_A_CLK>; + clocks = <&clock_rpmcc AGGR2_NOC_MSMBUS_CLK>, + <&clock_rpmcc AGGR2_NOC_MSMBUS_A_CLK>; qcom,node-qos-clks { clock-names = "clk-ipa-clk", diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi index e6bd0c06e444..14b009656890 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi @@ -392,6 +392,7 @@ <106 512 0 0>, <106 512 0 0>; qcom,msm-bus-vector-dyn-vote; + qcom,cpp-cx-ipeak = <&cx_ipeak_lm 2>; resets = <&clock_mmss CAMSS_MICRO_BCR>; reset-names = "micro_iface_reset"; qcom,src-clock-rates = <120000000 256000000 384000000 @@ -577,6 +578,7 @@ <29 512 0 0>, <29 512 100000000 100000000>; qcom,msm-bus-vector-dyn-vote; + qcom,vfe-cx-ipeak = <&cx_ipeak_lm 2>; }; vfe1: qcom,vfe1@ca14000 { @@ -657,6 +659,7 @@ <29 512 0 0>, <29 512 100000000 100000000>; qcom,msm-bus-vector-dyn-vote; + qcom,vfe-cx-ipeak = <&cx_ipeak_lm 2>; }; qcom,vfe { diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi index ad30af3376c7..6ea151667abc 100644 --- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi @@ -170,7 +170,7 @@ clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, <&clock_gcc GCC_CFG_NOC_USB3_AXI_CLK>, <&clock_gcc GCC_AGGRE2_USB3_AXI_CLK>, - <&clock_rpmcc RPM_AGGR2_NOC_CLK>, + <&clock_rpmcc AGGR2_NOC_USB_CLK>, <&clock_gcc GCC_USB30_MOCK_UTMI_CLK>, <&clock_gcc GCC_USB30_SLEEP_CLK>, <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, diff --git a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi index 51903c8b028d..76023a72ed96 100644 --- a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi @@ -1133,14 +1133,6 @@ <&funnel_qatb_in_tpda>; }; }; - port@1 { - reg = <1>; - tpda_in_funnel_gpu_dl: endpoint { - slave-mode; - remote-endpoint = - <&funnel_gpu_dl_out_tpda>; - }; - }; port@2 { reg = <2>; tpda_in_funnel_dlct: endpoint { @@ -1200,60 +1192,6 @@ }; }; - funnel_gpu_dl: funnel@7140000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b908>; - - reg = <0x7140000 0x1000>; - reg-names = "funnel-base"; - - coresight-name = "coresight-funnel-gpu-dl"; - - 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_gpu_dl_out_tpda: endpoint { - remote-endpoint = - <&tpda_in_funnel_gpu_dl>; - }; - }; - port@2 { - reg = <0>; - funnel_gpu_dl_in_tpdm_gpu: endpoint { - slave-mode; - remote-endpoint = - <&tpdm_gpu_out_funnel_gpu_dl>; - }; - }; - }; - }; - - tpdm_gpu: tpdm@7111000 { - status = "disabled"; - compatible = "qcom,coresight-tpdm"; - reg = <0x7111000 0x1000>; - reg-names = "tpdm-base"; - - coresight-name = "coresight-tpdm-gpu"; - - clocks = <&clock_rpmcc RPM_QDSS_CLK>, - <&clock_rpmcc RPM_QDSS_A_CLK>; - clock-names = "core_clk", "core_a_clk"; - - port{ - tpdm_gpu_out_funnel_gpu_dl: endpoint { - remote-endpoint = <&funnel_gpu_dl_in_tpdm_gpu>; - }; - }; - }; - tpdm_vsense: tpdm@7038000 { compatible = "qcom,coresight-tpdm"; reg = <0x7038000 0x1000>; @@ -1613,14 +1551,6 @@ <&tpdm_dlct_out_funnel_dlct>; }; }; - port@3 { - reg = <3>; - funnel_dlct_in_funnel_wcss: endpoint { - slave-mode; - remote-endpoint = - <&funnel_wcss_out_funnel_dlct>; - }; - }; port@4 { reg = <1>; funnel_dlct_in_audio_etm0: endpoint { @@ -1751,94 +1681,4 @@ }; }; }; - - funnel_wcss: funnel@719e000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b908>; - - reg = <0x719e000 0x1000>; - reg-names = "funnel-base"; - - coresight-name = "coresight-funnel-wcss"; - - 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_wcss_out_funnel_dlct: endpoint { - remote-endpoint = - <&funnel_dlct_in_funnel_wcss>; - }; - }; - port@1 { - reg = <1>; - funnel_wcss_in_tpda_wcss: endpoint { - slave-mode; - remote-endpoint = - <&tpda_wcss_out_funnel_wcss>; - }; - }; - }; - }; - - tpda_wcss: tpda@719d000 { - status = "disabled"; - compatible = "qcom,coresight-tpda"; - reg = <0x719d000 0x1000>; - reg-names = "tpda-base"; - - coresight-name = "coresight-tpda-wcss"; - - qcom,tpda-atid = <70>; - qcom,dsb-elem-size = <0 32>; - - clocks = <&clock_rpmcc RPM_QDSS_CLK>, - <&clock_rpmcc RPM_QDSS_A_CLK>; - clock-names = "core_clk", "core_a_clk"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - tpda_wcss_out_funnel_wcss: endpoint { - remote-endpoint = - <&funnel_wcss_in_tpda_wcss>; - }; - }; - port@1 { - reg = <0>; - tpda_wcss_in_tpdm_wcss: endpoint { - slave-mode; - remote-endpoint = - <&tpdm_wcss_out_tpda_wcss>; - }; - }; - }; - }; - - tpdm_wcss: tpdm@719c000 { - status = "disabled"; - compatible = "qcom,coresight-tpdm"; - reg = <0x719c000 0x1000>; - reg-names = "tpdm-base"; - - coresight-name = "coresight-tpdm-wcss"; - - clocks = <&clock_rpmcc RPM_QDSS_CLK>, - <&clock_rpmcc RPM_QDSS_A_CLK>; - clock-names = "core_clk", "core_a_clk"; - - port{ - tpdm_wcss_out_tpda_wcss: endpoint { - remote-endpoint = <&tpda_wcss_in_tpdm_wcss>; - }; - }; - }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index a47a788874fa..c3c776be3209 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -118,6 +118,10 @@ vddcx-supply = <&gdsc_gpu_cx>; vdd-supply = <&gdsc_gpu_gx>; + /* Cx ipeak limit supprt */ + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 1>; + qcom,gpu-cx-ipeak-clk = <700000000>; + /* CPU latency parameter */ qcom,pm-qos-active-latency = <518>; qcom,pm-qos-wakeup-latency = <518>; @@ -137,6 +141,9 @@ qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>; + /* Enable midframe sampling */ + qcom,enable-midframe-timer; + /* GPU Mempools */ qcom,gpu-mempools { #address-cells= <1>; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index 9c3862ce6a1f..ff51db728d85 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -24,6 +24,7 @@ #include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" #include "dsi-panel-truly-1080p-cmd.dtsi" #include "dsi-panel-truly-1080p-video.dtsi" +#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -67,7 +68,7 @@ qcom,panel-supply-entry@0 { reg = <0>; qcom,supply-name = "wqhd-vddio"; - qcom,supply-min-voltage = <1880000>; + qcom,supply-min-voltage = <1800000>; qcom,supply-max-voltage = <1950000>; qcom,supply-enable-load = <32000>; qcom,supply-disable-load = <80>; @@ -117,7 +118,7 @@ qcom,panel-supply-entry@0 { reg = <0>; qcom,supply-name = "wqhd-vddio"; - qcom,supply-min-voltage = <1880000>; + qcom,supply-min-voltage = <1800000>; qcom,supply-max-voltage = <1950000>; qcom,supply-enable-load = <32000>; qcom,supply-disable-load = <80>; @@ -133,6 +134,10 @@ 23 18 07 08 04 03 04 a0]; qcom,esd-check-enabled; qcom,mdss-dsi-panel-status-check-mode = "bta_check"; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; }; &dsi_dual_nt35597_truly_cmd { @@ -256,3 +261,13 @@ qcom,esd-check-enabled; qcom,mdss-dsi-panel-status-check-mode = "bta_check"; }; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 19 07 08 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi index 6e32c1282d3e..4794e648752b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi @@ -50,6 +50,7 @@ qcom,vbif-settings = <0x00ac 0x00008040>, <0x00d0 0x00002828>; + qcom,mdss-cx-ipeak = <&cx_ipeak_lm 3>; qcom,mdss-has-panic-ctrl; qcom,mdss-per-pipe-panic-luts = <0x000f>, <0xffff>, diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 57565134788c..37a88ea0dcec 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -52,12 +52,12 @@ trigout_a: trigout_a { mux { pins = "gpio49"; - function = "qdss_cti_trig_out_a"; + function = "qdss_cti0_a"; }; config { pins = "gpio49"; - drive-strength = <2>; + drive-strength = <16>; bias-disable; output-low; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts index 48e02bbdfbfe..d9d74ea31d3d 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts @@ -23,3 +23,34 @@ qcom,board-id = <0x0012000b 0>; qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; }; + +&pm660a_oledb { + status = "okay"; + qcom,oledb-default-voltage-mv = <6400>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 417df33047f6..001ae6e4fc04 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -382,9 +382,9 @@ bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; - qca,bt-vdd-core-supply = <&pm660_l9_pin_ctrl>; - qca,bt-vdd-pa-supply = <&pm660_l6_pin_ctrl>; - qca,bt-vdd-ldo-supply = <&pm660_l19_pin_ctrl>; + qca,bt-vdd-core-supply = <&pm660_l9>; + qca,bt-vdd-pa-supply = <&pm660_l6>; + qca,bt-vdd-ldo-supply = <&pm660_l19>; qca,bt-chip-pwd-supply = <&pm660l_bob_pin1>; clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>; clock-names = "rf_clk1"; @@ -818,6 +818,11 @@ }; }; + cx_ipeak_lm: cx_ipeak@1fe5040 { + compatible = "qcom,cx-ipeak-sdm660"; + reg = <0x1fe5040 0x28>; + }; + qcom,bcl { compatible = "qcom,bcl"; qcom,bcl-enable; @@ -1430,7 +1435,7 @@ qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/ qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/ clocks = <&clock_rpmcc RPM_IPA_CLK>, - <&clock_rpmcc RPM_AGGR2_NOC_CLK>; + <&clock_rpmcc AGGR2_NOC_SMMU_CLK>; clock-names = "core_clk", "smmu_clk"; qcom,arm-smmu; qcom,smmu-disable-htw; @@ -2050,6 +2055,11 @@ reg = <0x6b0 32>; }; + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + pil@94c { compatible = "qcom,msm-imem-pil"; reg = <0x94c 200>; @@ -2515,6 +2525,11 @@ }; }; +&msm_vidc { + qcom,cx-ipeak-data = <&cx_ipeak_lm 4>; + qcom,clock-freq-threshold = <518400000>; +}; + &soc { gpio_keys { status = "okay"; diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index 309d7a802d07..21650ead5a34 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -243,6 +243,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -379,6 +380,32 @@ CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_CAMERA=y CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSMB_CAMERA_DEBUG=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CSI20_HEADER=y +CONFIG_MSM_CSI22_HEADER=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSI31_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +CONFIG_IMX134=y +CONFIG_IMX132=y +CONFIG_OV9724=y +CONFIG_OV5648=y +CONFIG_GC0339=y +CONFIG_OV8825=y +CONFIG_OV8865=y +CONFIG_s5k4e1=y +CONFIG_OV12830=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_FD=y +CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y @@ -460,8 +487,6 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y @@ -560,6 +585,7 @@ CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y # CONFIG_WCD_DSP_GLINK is not set CONFIG_QCOM_SMCINVOKE=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index ba22d7864d1c..02b15745e882 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -242,6 +242,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -378,6 +379,32 @@ CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_CAMERA=y CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSMB_CAMERA_DEBUG=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CSI20_HEADER=y +CONFIG_MSM_CSI22_HEADER=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSI31_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +CONFIG_IMX134=y +CONFIG_IMX132=y +CONFIG_OV9724=y +CONFIG_OV5648=y +CONFIG_GC0339=y +CONFIG_OV8825=y +CONFIG_OV8865=y +CONFIG_s5k4e1=y +CONFIG_OV12830=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_FD=y +CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y @@ -460,8 +487,6 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y @@ -565,6 +590,7 @@ CONFIG_MSM_RPM_STATS_LOG=y # CONFIG_WCD_DSP_GLINK is not set CONFIG_QCOM_SMCINVOKE=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 91224fc7ae68..811779ba58b2 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -240,6 +240,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index d5f30e9a8b16..d3b7ec7c4f2b 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -243,6 +243,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -643,6 +644,8 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y CONFIG_WQ_WATCHDOG=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_SCHED_BUG=y @@ -655,6 +658,7 @@ CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_LIST=y +CONFIG_RCU_STALL_WATCHDOG_BITE=y CONFIG_FAULT_INJECTION=y CONFIG_FAIL_PAGE_ALLOC=y CONFIG_UFS_FAULT_INJECTION=y diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig index 9ebe740c7d91..b6035abef7c8 100644 --- a/arch/arm64/configs/msmcortex_mediabox_defconfig +++ b/arch/arm64/configs/msmcortex_mediabox_defconfig @@ -242,6 +242,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index 740584b30c60..cf073304e0b5 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -239,6 +239,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -576,6 +577,7 @@ CONFIG_MSM_RPM_STATS_LOG=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_SMCINVOKE=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index f6c53a1e1ace..46786b90e067 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -243,6 +243,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -597,6 +598,7 @@ CONFIG_MSM_RPM_STATS_LOG=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_SMCINVOKE=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 7f4e5cba0b13..da99a728a5f9 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -411,7 +411,7 @@ ENDPROC(el1_error_invalid) */ .align 6 el1_sync: -#ifdef CONFIG_TLB_EL2_HANDLER +#ifdef CONFIG_QCOM_TLB_EL2_HANDLER smc #0xffff #endif kernel_entry 1 diff --git a/arch/arm64/kernel/perf_trace_counters.h b/arch/arm64/kernel/perf_trace_counters.h index d686e928e5df..ff3bd371791d 100644 --- a/arch/arm64/kernel/perf_trace_counters.h +++ b/arch/arm64/kernel/perf_trace_counters.h @@ -22,8 +22,10 @@ #define C1 0x2 #define C2 0x4 #define C3 0x8 -#define C_ALL (CC | C0 | C1 | C2 | C3) -#define NUM_L1_CTRS 4 +#define C4 0x10 +#define C5 0x20 +#define C_ALL (CC | C0 | C1 | C2 | C3 | C4 | C5) +#define NUM_L1_CTRS 6 #include <linux/sched.h> #include <linux/cpumask.h> @@ -46,8 +48,8 @@ TRACE_EVENT(sched_switch_with_ctrs, __field(u32, ctr1) __field(u32, ctr2) __field(u32, ctr3) - __field(u32, lctr0) - __field(u32, lctr1) + __field(u32, ctr4) + __field(u32, ctr5) ), TP_fast_assign( @@ -91,15 +93,15 @@ TRACE_EVENT(sched_switch_with_ctrs, __entry->ctr1 = delta_l1_cnts[1]; __entry->ctr2 = delta_l1_cnts[2]; __entry->ctr3 = delta_l1_cnts[3]; - __entry->lctr0 = 0; - __entry->lctr1 = 0; + __entry->ctr4 = delta_l1_cnts[4]; + __entry->ctr5 = delta_l1_cnts[5]; ), - TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, L2CTR0: %u, L2CTR1: %u", + TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u", __entry->old_pid, __entry->new_pid, __entry->cctr, __entry->ctr0, __entry->ctr1, __entry->ctr2, __entry->ctr3, - __entry->lctr0, __entry->lctr1) + __entry->ctr4, __entry->ctr5) ); #endif diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 45c365290553..2445db9bbd4f 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -1821,10 +1821,8 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, mapping->domain, iova)); int offset = handle & ~PAGE_MASK; int len = PAGE_ALIGN(size + offset); - bool iova_coherent = iommu_is_iova_coherent(mapping->domain, - handle); - if (!(iova_coherent || + if (!(is_dma_coherent(dev, attrs) || dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))) __dma_page_dev_to_cpu(page, offset, size, dir); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index c3efb77d1229..aee116e842e2 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -334,10 +334,6 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, } if (addr < USER_DS && is_permission_fault(esr, regs)) { - /* regs->orig_addr_limit may be 0 if we entered from EL0 */ - if (regs->orig_addr_limit == KERNEL_DS) - die("Accessing user space memory with fs=KERNEL_DS", regs, esr); - if (is_el1_instruction_abort(esr)) die("Attempting to execute userspace memory", regs, esr); @@ -461,7 +457,7 @@ no_context: * so that, do_mem_abort would not crash kernel thinking TLB conflict not * handled. */ -#ifdef QCOM_TLB_EL2_HANDLER +#ifdef CONFIG_QCOM_TLB_EL2_HANDLER static int do_tlb_conf_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) @@ -560,7 +556,7 @@ static const struct fault_info { { do_bad, SIGBUS, 0, "unknown 45" }, { do_bad, SIGBUS, 0, "unknown 46" }, { do_bad, SIGBUS, 0, "unknown 47" }, -#ifdef QCOM_TLB_EL2_HANDLER +#ifdef CONFIG_QCOM_TLB_EL2_HANDLER { do_tlb_conf_fault, SIGBUS, 0, "TLB conflict abort" }, #else { do_bad, SIGBUS, 0, "TLB conflict abort" }, diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 9ca46ae54ce3..7820f5625266 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -217,6 +217,7 @@ struct fastrpc_channel_ctx { int ssrcount; void *handle; int prevssrcount; + int issubsystemup; int vmid; int ramdumpenabled; void *remoteheap_ramdump_dev; @@ -230,6 +231,7 @@ struct fastrpc_apps { struct mutex smd_mutex; struct smq_phy_page range; struct hlist_head maps; + uint32_t staticpd_flags; dev_t dev_no; int compat; struct hlist_head drivers; @@ -1518,10 +1520,15 @@ static int fastrpc_init_process(struct fastrpc_file *fl, struct fastrpc_ioctl_init_attrs *uproc) { int err = 0; + struct fastrpc_apps *me = &gfa; struct fastrpc_ioctl_invoke_attrs ioctl; struct fastrpc_ioctl_init *init = &uproc->init; struct smq_phy_page pages[1]; struct fastrpc_mmap *file = 0, *mem = 0; + int srcVM[1] = {VMID_HLOS}; + int destVM[1] = {VMID_ADSP_Q6}; + int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; + int hlosVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !fastrpc_channel_open(fl)); if (err) @@ -1609,12 +1616,9 @@ static int fastrpc_init_process(struct fastrpc_file *fl, if (err) goto bail; } else if (init->flags == FASTRPC_INIT_CREATE_STATIC) { - int srcVM[1] = {VMID_HLOS}; - int destVM[1] = {VMID_ADSP_Q6}; - int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; remote_arg_t ra[3]; uint64_t phys = 0; - ssize_t size; + ssize_t size = 0; int fds[3]; char *proc_name = (unsigned char *)init->file; struct { @@ -1624,15 +1628,27 @@ static int fastrpc_init_process(struct fastrpc_file *fl, } inbuf; inbuf.pgid = current->tgid; inbuf.namelen = strlen(proc_name)+1; - inbuf.pageslen = 1; - VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem, - init->memlen, ADSP_MMAP_HEAP_ADDR, &mem)); - phys = mem->phys; - size = mem->size; - VERIFY(err, !hyp_assign_phys(phys, (uint64_t)size, - srcVM, 1, destVM, destVMperm, 1)); - if (err) - goto bail; + inbuf.pageslen = 0; + if (!me->staticpd_flags) { + inbuf.pageslen = 1; + VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem, + init->memlen, ADSP_MMAP_REMOTE_HEAP_ADDR, + &mem)); + if (err) + goto bail; + phys = mem->phys; + size = mem->size; + VERIFY(err, !hyp_assign_phys(phys, (uint64_t)size, + srcVM, 1, destVM, destVMperm, 1)); + if (err) { + pr_err("ADSPRPC: hyp_assign_phys fail err %d", + err); + pr_err("map->phys %llx, map->size %d\n", + phys, (int)size); + goto bail; + } + me->staticpd_flags = 1; + } ra[0].buf.pv = (void *)&inbuf; ra[0].buf.len = sizeof(inbuf); @@ -1662,8 +1678,14 @@ static int fastrpc_init_process(struct fastrpc_file *fl, err = -ENOTTY; } bail: - if (mem && err) + if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC)) + me->staticpd_flags = 0; + if (mem && err) { + if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + hyp_assign_phys(mem->phys, (uint64_t)mem->size, + destVM, 1, srcVM, hlosVMperm, 1); fastrpc_mmap_free(mem); + } if (file) fastrpc_mmap_free(file); return err; @@ -1790,6 +1812,8 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, ioctl.inv.pra = ra; ioctl.fds = 0; ioctl.attrs = 0; + if (fl == NULL) + goto bail; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); @@ -1824,12 +1848,6 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, uintptr_t vaddrout; ssize_t size; } inargs; - if (map->flags == ADSP_MMAP_HEAP_ADDR || - map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, map)); - if (err) - goto bail; - } inargs.pid = current->tgid; inargs.size = map->size; @@ -1847,6 +1865,14 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, ioctl.attrs = 0; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); + if (err) + goto bail; + if (map->flags == ADSP_MMAP_HEAP_ADDR || + map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, map)); + if (err) + goto bail; + } bail: return err; } @@ -1858,35 +1884,38 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl) int err = 0, ret = 0; struct fastrpc_apps *me = &gfa; struct ramdump_segment *ramdump_segments_rh = NULL; - - spin_lock(&me->hlock); - hlist_for_each_entry_safe(map, n, &me->maps, hn) { + do { + match = 0; + spin_lock(&me->hlock); + hlist_for_each_entry_safe(map, n, &me->maps, hn) { match = map; hlist_del_init(&map->hn); break; - } - spin_unlock(&me->hlock); + } + spin_unlock(&me->hlock); - if (match) { - VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, match)); - if (err) - goto bail; - if (me->channel[0].ramdumpenabled) { - ramdump_segments_rh = kcalloc(1, + if (match) { + VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, match)); + if (err) + goto bail; + if (me->channel[0].ramdumpenabled) { + ramdump_segments_rh = kcalloc(1, sizeof(struct ramdump_segment), GFP_KERNEL); - if (ramdump_segments_rh) { - ramdump_segments_rh->address = match->phys; - ramdump_segments_rh->size = match->size; - ret = do_elf_ramdump( - me->channel[0].remoteheap_ramdump_dev, - ramdump_segments_rh, 1); - if (ret < 0) - pr_err("ADSPRPC: unable to dump heap"); - kfree(ramdump_segments_rh); + if (ramdump_segments_rh) { + ramdump_segments_rh->address = + match->phys; + ramdump_segments_rh->size = match->size; + ret = do_elf_ramdump( + me->channel[0].remoteheap_ramdump_dev, + ramdump_segments_rh, 1); + if (ret < 0) + pr_err("ADSPRPC: unable to dump heap"); + kfree(ramdump_segments_rh); + } } + fastrpc_mmap_free(match); } - fastrpc_mmap_free(match); - } + } while (match); bail: if (err && match) fastrpc_mmap_add(match); @@ -2085,6 +2114,10 @@ static int fastrpc_file_free(struct fastrpc_file *fl) hlist_del_init(&fl->hn); spin_unlock(&fl->apps->hlock); + if (!fl->sctx) { + kfree(fl); + return 0; + } (void)fastrpc_release_current_dsp_process(fl); fastrpc_context_list_dtor(fl); fastrpc_buf_list_free(fl); @@ -2349,6 +2382,14 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) if (err) goto bail; cid = fl->cid; + if (me->channel[cid].ssrcount != + me->channel[cid].prevssrcount) { + if (!me->channel[cid].issubsystemup) { + VERIFY(err, 0); + if (err) + goto bail; + } + } VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); if (err) goto bail; @@ -2386,13 +2427,15 @@ bail: static int fastrpc_device_open(struct inode *inode, struct file *filp) { int err = 0; + struct dentry *debugfs_file; struct fastrpc_file *fl = 0; struct fastrpc_apps *me = &gfa; VERIFY(err, fl = kzalloc(sizeof(*fl), GFP_KERNEL)); if (err) return err; - + debugfs_file = debugfs_create_file(current->comm, 0644, debugfs_root, + fl, &debugfs_fops); context_list_ctor(&fl->clst); spin_lock_init(&fl->hlock); INIT_HLIST_HEAD(&fl->maps); @@ -2402,6 +2445,9 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->apps = me; fl->mode = FASTRPC_MODE_SERIAL; fl->cid = -1; + if (debugfs_file != NULL) + fl->debugfs_file = debugfs_file; + memset(&fl->perf, 0, sizeof(fl->perf)); filp->private_data = fl; spin_lock(&me->hlock); hlist_add_head(&fl->hn, &me->drivers); @@ -2578,6 +2624,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, if (code == SUBSYS_BEFORE_SHUTDOWN) { mutex_lock(&me->smd_mutex); ctx->ssrcount++; + ctx->issubsystemup = 0; if (ctx->chan) { fastrpc_glink_close(ctx->chan, cid); ctx->chan = 0; @@ -2585,12 +2632,16 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, gcinfo[cid].name, MAJOR(me->dev_no), cid); } mutex_unlock(&me->smd_mutex); + if (cid == 0) + me->staticpd_flags = 0; fastrpc_notify_drivers(me, cid); } else if (code == SUBSYS_RAMDUMP_NOTIFICATION) { if (me->channel[0].remoteheap_ramdump_dev && notifdata->enable_ramdump) { me->channel[0].ramdumpenabled = 1; } + } else if (code == SUBSYS_AFTER_POWERUP) { + ctx->issubsystemup = 1; } return NOTIFY_DONE; @@ -2882,6 +2933,7 @@ static int __init fastrpc_device_init(void) me->channel[i].dev = dev; me->channel[i].ssrcount = 0; me->channel[i].prevssrcount = 0; + me->channel[i].issubsystemup = 1; me->channel[i].ramdumpenabled = 0; me->channel[i].remoteheap_ramdump_dev = 0; me->channel[i].nb.notifier_call = fastrpc_restart_notifier_cb; diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index a1721a3b80cc..44e71a704e6a 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -112,10 +112,12 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) else mask_info = &log_mask; - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; mask = (struct diag_log_mask_t *)mask_info->ptr; + if (!mask->ptr) + return; buf = mask_info->update_buf; switch (mask_info->status) { @@ -224,7 +226,7 @@ static void diag_send_event_mask_update(uint8_t peripheral) else mask_info = &event_mask; - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; buf = mask_info->update_buf; @@ -305,10 +307,12 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) else mask_info = &msg_mask; - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) + return; buf = mask_info->update_buf; mutex_lock(&mask_info->lock); switch (mask_info->status) { diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index c9ba7f97eebe..632d0f4ac9c1 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -580,6 +580,9 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) rcg->curr_index = 0; else { f = qcom_find_freq(rcg->freq_tbl, rcg->current_freq); + if (!f) + return -EINVAL; + rcg->curr_index = qcom_find_src_index(hw, rcg->parent_map, f->src); diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 0d76b6b28985..5345e9086627 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -570,6 +570,10 @@ static DEFINE_CLK_VOTER(pnoc_msmbus_clk, pnoc_clk, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, pnoc_a_clk, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_pm_clk, pnoc_clk, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_sps_clk, pnoc_clk, 0); +static DEFINE_CLK_VOTER(aggre2_noc_msmbus_clk, aggre2_noc_clk, LONG_MAX); +static DEFINE_CLK_VOTER(aggre2_noc_msmbus_a_clk, aggre2_noc_a_clk, LONG_MAX); +static DEFINE_CLK_VOTER(aggre2_noc_usb_clk, aggre2_noc_clk, 19200000); +static DEFINE_CLK_VOTER(aggre2_noc_smmu_clk, aggre2_noc_clk, 1000); /* Voter Branch clocks */ static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, cxo); @@ -738,6 +742,10 @@ static struct clk_hw *sdm660_clks[] = { [CXO_PIL_LPASS_CLK] = &cxo_pil_lpass_clk.hw, [CXO_PIL_CDSP_CLK] = &cxo_pil_cdsp_clk.hw, [CNOC_PERIPH_KEEPALIVE_A_CLK] = &cnoc_periph_keepalive_a_clk.hw, + [AGGR2_NOC_MSMBUS_CLK] = &aggre2_noc_msmbus_clk.hw, + [AGGR2_NOC_MSMBUS_A_CLK] = &aggre2_noc_msmbus_a_clk.hw, + [AGGR2_NOC_SMMU_CLK] = &aggre2_noc_smmu_clk.hw, + [AGGR2_NOC_USB_CLK] = &aggre2_noc_usb_clk.hw, }; static const struct rpm_smd_clk_desc rpm_clk_sdm660 = { diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index bf3a24b3eb01..11bd3aae340b 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,6 +57,11 @@ * TZ 3.X version info */ #define QSEE_VERSION_TZ_3_X 0x800000 + +#define TZBSP_AES_256_ENCRYPTED_KEY_SIZE 256 +#define TZBSP_NONCE_LEN 12 +#define TZBSP_TAG_LEN 16 + /* * VMID Table */ @@ -125,6 +130,14 @@ struct tzdbg_int_t { uint64_t int_count[TZBSP_MAX_CPU_COUNT]; /* # of times seen per CPU */ }; +/* warm boot reason for cores */ +struct tzbsp_diag_wakeup_info_t { + /* Wake source info : APCS_GICC_HPPIR */ + uint32_t HPPIR; + /* Wake source info : APCS_GICC_AHPPIR */ + uint32_t AHPPIR; +}; + /* * Log ring buffer position */ @@ -179,6 +192,10 @@ struct tzdbg_t { * Ring Buffer Length */ uint32_t ring_len; + + /* Offset for Wakeup info */ + uint32_t wakeup_info_off; + /* * VMID to EE Mapping */ @@ -193,6 +210,16 @@ struct tzdbg_t { struct tzdbg_reset_info_t reset_info[TZBSP_MAX_CPU_COUNT]; uint32_t num_interrupts; struct tzdbg_int_t int_info[TZBSP_DIAG_INT_NUM]; + + /* Wake up info */ + struct tzbsp_diag_wakeup_info_t wakeup_info[TZBSP_MAX_CPU_COUNT]; + + uint8_t key[TZBSP_AES_256_ENCRYPTED_KEY_SIZE]; + + uint8_t nonce[TZBSP_NONCE_LEN]; + + uint8_t tag[TZBSP_TAG_LEN]; + /* * We need at least 2K for the ring buffer */ @@ -731,10 +758,16 @@ static ssize_t tzdbgfs_read(struct file *file, char __user *buf, int len = 0; int *tz_id = file->private_data; - memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, + if (*tz_id == TZDBG_BOOT || *tz_id == TZDBG_RESET || + *tz_id == TZDBG_INTERRUPT || *tz_id == TZDBG_GENERAL || + *tz_id == TZDBG_VMID || *tz_id == TZDBG_LOG) + memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, debug_rw_buf_size); - memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, + + if (*tz_id == TZDBG_HYP_GENERAL || *tz_id == TZDBG_HYP_LOG) + memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, tzdbg.hyp_debug_rw_buf_size); + switch (*tz_id) { case TZDBG_BOOT: len = _disp_tz_boot_stats(); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f821a81c53a6..532ff8677259 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1683,7 +1683,7 @@ static struct drm_driver msm_driver = { .debugfs_cleanup = msm_debugfs_cleanup, #endif .ioctls = msm_ioctls, - .num_ioctls = DRM_MSM_NUM_IOCTLS, + .num_ioctls = ARRAY_SIZE(msm_ioctls), .fops = &fops, .name = "msm_drm", .desc = "MSM Snapdragon DRM", diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 0f582cf35e6b..3faa5aaf9d03 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1720,6 +1720,30 @@ static int adreno_getproperty(struct kgsl_device *device, status = 0; } break; + case KGSL_PROP_DEVICE_QTIMER: + { + struct kgsl_qtimer_prop qtimerprop = {0}; + struct kgsl_memdesc *qtimer_desc = + kgsl_mmu_get_qtimer_global_entry(device); + + if (sizebytes != sizeof(qtimerprop)) { + status = -EINVAL; + break; + } + + if (qtimer_desc) { + qtimerprop.gpuaddr = qtimer_desc->gpuaddr; + qtimerprop.size = qtimer_desc->size; + } + + if (copy_to_user(value, &qtimerprop, + sizeof(qtimerprop))) { + status = -EFAULT; + break; + } + status = 0; + } + break; case KGSL_PROP_MMU_ENABLE: { /* Report MMU only if we can handle paged memory */ @@ -2771,6 +2795,7 @@ static const struct kgsl_functable adreno_functable = { .regulator_disable_poll = adreno_regulator_disable_poll, .clk_set_options = adreno_clk_set_options, .gpu_model = adreno_gpu_model, + .stop_fault_timer = adreno_dispatcher_stop_fault_timer, }; static struct platform_driver adreno_platform_driver = { diff --git a/drivers/gpu/msm/adreno_compat.c b/drivers/gpu/msm/adreno_compat.c index d86a0c60f0b4..5a8d587d4536 100644 --- a/drivers/gpu/msm/adreno_compat.c +++ b/drivers/gpu/msm/adreno_compat.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -113,6 +113,30 @@ int adreno_getproperty_compat(struct kgsl_device *device, status = 0; } break; + case KGSL_PROP_DEVICE_QTIMER: + { + struct kgsl_qtimer_prop qtimerprop = {0}; + struct kgsl_memdesc *qtimer_desc = + kgsl_mmu_get_qtimer_global_entry(device); + + if (sizebytes != sizeof(qtimerprop)) { + status = -EINVAL; + break; + } + + if (qtimer_desc) { + qtimerprop.gpuaddr = qtimer_desc->gpuaddr; + qtimerprop.size = qtimer_desc->size; + } + + if (copy_to_user(value, &qtimerprop, + sizeof(qtimerprop))) { + status = -EFAULT; + break; + } + status = 0; + } + break; default: /* * Call the adreno_getproperty to check if the property type diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 89218b62bb7d..f084ca9a62a1 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -208,6 +208,9 @@ static inline bool _isidle(struct adreno_device *adreno_dev) if (!kgsl_state_is_awake(KGSL_DEVICE(adreno_dev))) goto ret; + if (adreno_rb_empty(adreno_dev->cur_rb)) + goto ret; + /* only check rbbm status to determine if GPU is idle */ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS, ®_rbbm_status); @@ -2051,6 +2054,18 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) return 0; /* + * In the very unlikely case that the power is off, do nothing - the + * state will be reset on power up and everybody will be happy + */ + + if (!kgsl_state_is_awake(device) && (fault & ADRENO_SOFT_FAULT)) { + /* Clear the existing register values */ + memset(adreno_ft_regs_val, 0, + adreno_ft_regs_num * sizeof(unsigned int)); + return 0; + } + + /* * On A5xx, read RBBM_STATUS3:SMMU_STALLED_ON_FAULT (BIT 24) to * tell if this function was entered after a pagefault. If so, only * proceed if the fault handler has already run in the IRQ thread, @@ -2505,7 +2520,7 @@ static void adreno_dispatcher_fault_timer(unsigned long data) if (!fault_detect_read_compare(adreno_dev)) { adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT); adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); - } else { + } else if (dispatcher->inflight > 0) { mod_timer(&dispatcher->fault_timer, jiffies + msecs_to_jiffies(_fault_timer_interval)); } @@ -2550,6 +2565,20 @@ void adreno_dispatcher_stop(struct adreno_device *adreno_dev) } /** + * adreno_dispatcher_stop() - stop the dispatcher fault timer + * @adreno_dev: pointer to the adreno device structure + * + * Stop the dispatcher fault timer + */ +void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + del_timer_sync(&dispatcher->fault_timer); +} + +/** * adreno_dispatcher_close() - close the dispatcher * @adreno_dev: pointer to the adreno device structure * diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h index cb9106fedc82..72545db12f90 100644 --- a/drivers/gpu/msm/adreno_dispatch.h +++ b/drivers/gpu/msm/adreno_dispatch.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -108,6 +108,7 @@ void adreno_dispatcher_close(struct adreno_device *adreno_dev); int adreno_dispatcher_idle(struct adreno_device *adreno_dev); void adreno_dispatcher_irq_fault(struct adreno_device *adreno_dev); void adreno_dispatcher_stop(struct adreno_device *adreno_dev); +void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device); int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, struct kgsl_context *context, struct kgsl_drawobj *drawobj[], diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 0a2c39b82781..aca484618268 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -169,6 +169,7 @@ struct kgsl_functable { const char *name, struct clk *clk); void (*gpu_model)(struct kgsl_device *device, char *str, size_t bufsz); + void (*stop_fault_timer)(struct kgsl_device *device); }; struct kgsl_ioctl { diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 6c667cb62896..af9fc1c15236 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -106,6 +106,7 @@ static struct kgsl_memdesc *kgsl_global_secure_pt_entry; static int global_pt_count; uint64_t global_pt_alloc; static struct kgsl_memdesc gpu_qdss_desc; +static struct kgsl_memdesc gpu_qtimer_desc; void kgsl_print_global_pt_entries(struct seq_file *s) { @@ -261,6 +262,50 @@ static inline void kgsl_cleanup_qdss_desc(struct kgsl_mmu *mmu) kgsl_sharedmem_free(&gpu_qdss_desc); } +struct kgsl_memdesc *kgsl_iommu_get_qtimer_global_entry(void) +{ + return &gpu_qtimer_desc; +} + +static void kgsl_setup_qtimer_desc(struct kgsl_device *device) +{ + int result = 0; + uint32_t gpu_qtimer_entry[2]; + + if (!of_find_property(device->pdev->dev.of_node, + "qcom,gpu-qtimer", NULL)) + return; + + if (of_property_read_u32_array(device->pdev->dev.of_node, + "qcom,gpu-qtimer", gpu_qtimer_entry, 2)) { + KGSL_CORE_ERR("Failed to read gpu qtimer dts entry\n"); + return; + } + + gpu_qtimer_desc.flags = 0; + gpu_qtimer_desc.priv = 0; + gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0]; + gpu_qtimer_desc.size = gpu_qtimer_entry[1]; + gpu_qtimer_desc.pagetable = NULL; + gpu_qtimer_desc.ops = NULL; + gpu_qtimer_desc.dev = device->dev->parent; + gpu_qtimer_desc.hostptr = NULL; + + result = memdesc_sg_dma(&gpu_qtimer_desc, gpu_qtimer_desc.physaddr, + gpu_qtimer_desc.size); + if (result) { + KGSL_CORE_ERR("memdesc_sg_dma failed: %d\n", result); + return; + } + + kgsl_mmu_add_global(device, &gpu_qtimer_desc, "gpu-qtimer"); +} + +static inline void kgsl_cleanup_qtimer_desc(struct kgsl_mmu *mmu) +{ + kgsl_iommu_remove_global(mmu, &gpu_qtimer_desc); + kgsl_sharedmem_free(&gpu_qtimer_desc); +} static inline void _iommu_sync_mmu_pc(bool lock) { @@ -1403,6 +1448,7 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu) kgsl_iommu_remove_global(mmu, &iommu->setstate); kgsl_sharedmem_free(&iommu->setstate); kgsl_cleanup_qdss_desc(mmu); + kgsl_cleanup_qtimer_desc(mmu); } static int _setstate_alloc(struct kgsl_device *device, @@ -1474,6 +1520,7 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) kgsl_iommu_add_global(mmu, &iommu->setstate, "setstate"); kgsl_setup_qdss_desc(device); + kgsl_setup_qtimer_desc(device); done: if (status) @@ -2616,6 +2663,7 @@ struct kgsl_mmu_ops kgsl_iommu_ops = { .mmu_remove_global = kgsl_iommu_remove_global, .mmu_getpagetable = kgsl_iommu_getpagetable, .mmu_get_qdss_global_entry = kgsl_iommu_get_qdss_global_entry, + .mmu_get_qtimer_global_entry = kgsl_iommu_get_qtimer_global_entry, .probe = kgsl_iommu_probe, }; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 46bb6f4656fb..aa7157e882ac 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -619,6 +619,18 @@ struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device) } EXPORT_SYMBOL(kgsl_mmu_get_qdss_global_entry); +struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry( + struct kgsl_device *device) +{ + struct kgsl_mmu *mmu = &device->mmu; + + if (MMU_OP_VALID(mmu, mmu_get_qtimer_global_entry)) + return mmu->mmu_ops->mmu_get_qtimer_global_entry(); + + return NULL; +} +EXPORT_SYMBOL(kgsl_mmu_get_qtimer_global_entry); + /* * NOMMU defintions - NOMMU really just means that the MMU is kept in pass * through and the GPU directly accesses physical memory. Used in debug mode and diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index bc448d424ccb..505fe591a53e 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -81,6 +81,7 @@ struct kgsl_mmu_ops { struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu, unsigned long name); struct kgsl_memdesc* (*mmu_get_qdss_global_entry)(void); + struct kgsl_memdesc* (*mmu_get_qtimer_global_entry)(void); }; struct kgsl_mmu_pt_ops { @@ -231,6 +232,9 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device); +struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry( + struct kgsl_device *device); + int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index e639e197de93..e4c431546d2a 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -2600,6 +2600,7 @@ _nap(struct kgsl_device *device) return -EBUSY; } + device->ftbl->stop_fault_timer(device); kgsl_pwrscale_midframe_timer_cancel(device); /* diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 577183bea07c..34ea83d067af 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2011,7 +2011,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 99de4002275e..075c18e0e4ae 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1206,18 +1206,6 @@ config TOUCHSCREEN_IT7260_I2C To compile this driver as a module, choose M here: the module will be called it7258_ts_i2c. -config TOUCHSCREEN_GT9XX - bool "Goodix touchpanel GT9xx series" - depends on I2C - help - Say Y here if you have a Goodix GT9xx touchscreen. - Gt9xx controllers are multi touch controllers which can - report 5 touches at a time. - - If unsure, say N. - -source "drivers/input/touchscreen/gt9xx/Kconfig" - config TOUCHSCREEN_ST bool "STMicroelectronics Touchscreen Driver" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index a32132cffe92..2e0161cf95bc 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -98,5 +98,4 @@ obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o -obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ obj-$(CONFIG_TOUCHSCREEN_ST) += st/ diff --git a/drivers/input/touchscreen/gt9xx/Kconfig b/drivers/input/touchscreen/gt9xx/Kconfig deleted file mode 100644 index 2e1b5ba567a0..000000000000 --- a/drivers/input/touchscreen/gt9xx/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -# -# Goodix GT9xx Touchscreen driver -# - -config GT9XX_TOUCHPANEL_DRIVER - tristate "Goodix GT9xx touchpanel driver" - depends on TOUCHSCREEN_GT9XX - default n - help - This is the main file for touchpanel driver for Goodix GT9xx - touchscreens. - - Say Y here if you have a Goodix GT9xx touchscreen connected - to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called gt9xx. - -config GT9XX_TOUCHPANEL_UPDATE - tristate "Goodix GT9xx touchpanel auto update support" - depends on GT9XX_TOUCHPANEL_DRIVER - default n - help - This enables support for firmware update for Goodix GT9xx - touchscreens. - - Say Y here if you have a Goodix GT9xx touchscreen connected - to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called gt9xx_update. - -config GT9XX_TOUCHPANEL_DEBUG - tristate "Goodix GT9xx Tools for debuging" - depends on GT9XX_TOUCHPANEL_DRIVER - default n - help - This is application debug interface support for Goodix GT9xx - touchscreens. - - Say Y here if you want to have a Android app debug interface - to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called gt9xx_tool. diff --git a/drivers/input/touchscreen/gt9xx/Makefile b/drivers/input/touchscreen/gt9xx/Makefile deleted file mode 100644 index 482d869a2d37..000000000000 --- a/drivers/input/touchscreen/gt9xx/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -#gt915 touchpanel driver - - -obj-$(CONFIG_GT9XX_TOUCHPANEL_DRIVER) += gt9xx.o -#gt915 update file -obj-$(CONFIG_GT9XX_TOUCHPANEL_UPDATE) += gt9xx_update.o -#debug tool -obj-$(CONFIG_GT9XX_TOUCHPANEL_DEBUG) += goodix_tool.o diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c deleted file mode 100644 index ded8c88fdac9..000000000000 --- a/drivers/input/touchscreen/gt9xx/goodix_tool.c +++ /dev/null @@ -1,603 +0,0 @@ -/* drivers/input/touchscreen/goodix_tool.c - * - * 2010 - 2012 Goodix Technology. - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be a reference - * to you, when you are integrating the GOODiX's CTP IC into your system, - * 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. - * - * Version:1.6 - * V1.0:2012/05/01,create file. - * V1.2:2012/06/08,modify some warning. - * V1.4:2012/08/28,modified to support GT9XX - * V1.6:new proc name - */ - -#include "gt9xx.h" -#include <linux/mutex.h> -#include <linux/proc_fs.h> -#include <linux/debugfs.h> - -#define DATA_LENGTH_UINT 512 -#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *)) -static char procname[20] = {0}; - -struct st_cmd_head { - u8 wr; /* write read flag 0:R 1:W 2:PID 3: */ - u8 flag; /* 0:no need flag/int 1: need flag 2:need int */ - u8 flag_addr[2];/* flag address */ - u8 flag_val; /* flag val */ - u8 flag_relation; /* flag_val:flag 0:not equal 1:equal 2:> 3:< */ - u16 circle; /* polling cycle */ - u8 times; /* plling times */ - u8 retry; /* I2C retry times */ - u16 delay; /* delay before read or after write */ - u16 data_len; /* data length */ - u8 addr_len; /* address length */ - u8 addr[2]; /* address */ - u8 res[3]; /* reserved */ - u8 *data; /* data pointer */ -} __packed; - -static struct st_cmd_head cmd_head; - -static struct i2c_client *gt_client; - -static struct proc_dir_entry *goodix_proc_entry; - -static struct mutex lock; - -static s32 (*tool_i2c_read)(u8 *, u16); -static s32 (*tool_i2c_write)(u8 *, u16); - -s32 data_length; -s8 ic_type[16] = {0}; - -static void tool_set_proc_name(char *procname) -{ - char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", - "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - char date[20] = {0}; - char month[4] = {0}; - int i = 0, n_month = 1, n_day = 0, n_year = 0, ret; - - ret = sscanf(date, "%s %d %d", month, &n_day, &n_year); - if (!ret) - return; - for (i = 0; i < 12; ++i) { - if (!memcmp(months[i], month, 3)) { - n_month = i+1; - break; - } - } - - snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day); -} - -static s32 tool_i2c_read_no_extra(u8 *buf, u16 len) -{ - s32 ret = -1; - u8 i = 0; - struct i2c_msg msgs[2] = { - { - .flags = !I2C_M_RD, - .addr = gt_client->addr, - .len = cmd_head.addr_len, - .buf = &buf[0], - }, - { - .flags = I2C_M_RD, - .addr = gt_client->addr, - .len = len, - .buf = &buf[GTP_ADDR_LENGTH], - }, - }; - - for (i = 0; i < cmd_head.retry; i++) { - ret = i2c_transfer(gt_client->adapter, msgs, 2); - if (ret > 0) - break; - } - - if (i == cmd_head.retry) { - dev_err(>_client->dev, "I2C read retry limit over\n"); - ret = -EIO; - } - - return ret; -} - -static s32 tool_i2c_write_no_extra(u8 *buf, u16 len) -{ - s32 ret = -1; - u8 i = 0; - struct i2c_msg msg = { - .flags = !I2C_M_RD, - .addr = gt_client->addr, - .len = len, - .buf = buf, - }; - - for (i = 0; i < cmd_head.retry; i++) { - ret = i2c_transfer(gt_client->adapter, &msg, 1); - if (ret > 0) - break; - } - - if (i == cmd_head.retry) { - dev_err(>_client->dev, "I2C write retry limit over\n"); - ret = -EIO; - } - - return ret; -} - -static s32 tool_i2c_read_with_extra(u8 *buf, u16 len) -{ - s32 ret = -1; - u8 pre[2] = {0x0f, 0xff}; - u8 end[2] = {0x80, 0x00}; - - tool_i2c_write_no_extra(pre, 2); - ret = tool_i2c_read_no_extra(buf, len); - tool_i2c_write_no_extra(end, 2); - - return ret; -} - -static s32 tool_i2c_write_with_extra(u8 *buf, u16 len) -{ - s32 ret = -1; - u8 pre[2] = {0x0f, 0xff}; - u8 end[2] = {0x80, 0x00}; - - tool_i2c_write_no_extra(pre, 2); - ret = tool_i2c_write_no_extra(buf, len); - tool_i2c_write_no_extra(end, 2); - - return ret; -} - -static void register_i2c_func(void) -{ - if (strcmp(ic_type, "GT8110") && strcmp(ic_type, "GT8105") - && strcmp(ic_type, "GT801") && strcmp(ic_type, "GT800") - && strcmp(ic_type, "GT801PLUS") && strcmp(ic_type, "GT811") - && strcmp(ic_type, "GTxxx")) { - tool_i2c_read = tool_i2c_read_with_extra; - tool_i2c_write = tool_i2c_write_with_extra; - pr_debug("I2C function: with pre and end cmd\n"); - } else { - tool_i2c_read = tool_i2c_read_no_extra; - tool_i2c_write = tool_i2c_write_no_extra; - pr_info("I2C function: without pre and end cmd\n"); - } -} - -static void unregister_i2c_func(void) -{ - tool_i2c_read = NULL; - tool_i2c_write = NULL; - pr_info("I2C function: unregister i2c transfer function\n"); -} - -void uninit_wr_node(void) -{ - cmd_head.data = NULL; - unregister_i2c_func(); - proc_remove(goodix_proc_entry); -} - -static u8 relation(u8 src, u8 dst, u8 rlt) -{ - u8 ret = 0; - - switch (rlt) { - - case 0: - ret = (src != dst) ? true : false; - break; - - case 1: - ret = (src == dst) ? true : false; - pr_debug("equal:src:0x%02x dst:0x%02x ret:%d\n", - src, dst, (s32)ret); - break; - - case 2: - ret = (src > dst) ? true : false; - break; - - case 3: - ret = (src < dst) ? true : false; - break; - - case 4: - ret = (src & dst) ? true : false; - break; - - case 5: - ret = (!(src | dst)) ? true : false; - break; - - default: - ret = false; - break; - } - - return ret; -} - -/* - * Function: - * Comfirm function. - * Input: - * None. - * Output: - * Return write length. - */ -static u8 comfirm(void) -{ - s32 i = 0; - u8 buf[32]; - - memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); - - for (i = 0; i < cmd_head.times; i++) { - if (tool_i2c_read(buf, 1) <= 0) { - dev_err(>_client->dev, "Read flag data failed"); - return FAIL; - } - if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, - cmd_head.flag_relation)) { - pr_debug("value at flag addr:0x%02x\n", - buf[GTP_ADDR_LENGTH]); - pr_debug("flag value:0x%02x\n", cmd_head.flag_val); - break; - } - - msleep(cmd_head.circle); - } - - if (i >= cmd_head.times) { - dev_err(>_client->dev, "Didn't get the flag to continue"); - return FAIL; - } - - return SUCCESS; -} - -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE -static s32 fill_update_info(char __user *user_buf, - size_t count, loff_t *ppos) -{ - u8 buf[4]; - - buf[0] = show_len >> 8; - buf[1] = show_len & 0xff; - buf[2] = total_len >> 8; - buf[3] = total_len & 0xff; - return simple_read_from_buffer(user_buf, count, ppos, - buf, sizeof(buf)); -} -#else -static s32 fill_update_info(char __user *user_buf, - size_t count, loff_t *ppos) -{ - return -ENODEV; -} -#endif - -/* - * Function: - * Goodix tool write function. - * Input: - * standard proc write function param. - * Output: - * Return write length. - */ -static ssize_t goodix_tool_write(struct file *filp, const char __user *userbuf, - size_t count, loff_t *ppos) -{ - s32 ret = 0; - u8 *dataptr = NULL; - - mutex_lock(&lock); - ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH); - if (ret) { - dev_err(>_client->dev, "copy_from_user failed"); - ret = -EFAULT; - goto exit; - } - - dev_dbg(>_client->dev, - "wr: 0x%02x, flag:0x%02x, flag addr:0x%02x%02x\n", cmd_head.wr, - cmd_head.flag, cmd_head.flag_addr[0], cmd_head.flag_addr[1]); - dev_dbg(>_client->dev, - "flag val:0x%02x, flag rel:0x%02x,\n", cmd_head.flag_val, - cmd_head.flag_relation); - dev_dbg(>_client->dev, "circle:%u, times:%u, retry:%u, delay:%u\n", - (s32) cmd_head.circle, (s32) cmd_head.times, - (s32) cmd_head.retry, (s32)cmd_head.delay); - dev_dbg(>_client->dev, - "data len:%u, addr len:%u, addr:0x%02x%02x, write len: %u\n", - (s32)cmd_head.data_len, (s32)cmd_head.addr_len, - cmd_head.addr[0], cmd_head.addr[1], (s32)count); - - if (cmd_head.data_len > (data_length - GTP_ADDR_LENGTH)) { - dev_err(>_client->dev, "data len %u > data buff %d, rejected\n", - cmd_head.data_len, (data_length - GTP_ADDR_LENGTH)); - ret = -EINVAL; - goto exit; - } - - if (cmd_head.wr == GTP_RW_WRITE) { - ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], - &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); - if (ret) { - dev_err(>_client->dev, "copy_from_user failed"); - ret = -EFAULT; - goto exit; - } - - memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], - cmd_head.addr, cmd_head.addr_len); - - if (cmd_head.flag == GTP_NEED_FLAG) { - if (comfirm() == FAIL) { - dev_err(>_client->dev, "Confirm fail"); - ret = -EINVAL; - goto exit; - } - } else if (cmd_head.flag == GTP_NEED_INTERRUPT) { - /* Need interrupt! */ - } - if (tool_i2c_write( - &cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], - cmd_head.data_len + cmd_head.addr_len) <= 0) { - dev_err(>_client->dev, "Write data failed"); - ret = -EIO; - goto exit; - } - - if (cmd_head.delay) - msleep(cmd_head.delay); - - ret = cmd_head.data_len + CMD_HEAD_LENGTH; - goto exit; - } else if (cmd_head.wr == GTP_RW_WRITE_IC_TYPE) { /* Write ic type */ - ret = copy_from_user(&cmd_head.data[0], - &userbuf[CMD_HEAD_LENGTH], - cmd_head.data_len); - if (ret) { - dev_err(>_client->dev, "copy_from_user failed"); - ret = -EFAULT; - goto exit; - } - - if (cmd_head.data_len > sizeof(ic_type)) { - dev_err(>_client->dev, - "data len %u > data buff %zu, rejected\n", - cmd_head.data_len, sizeof(ic_type)); - ret = -EINVAL; - goto exit; - } - memcpy(ic_type, cmd_head.data, cmd_head.data_len); - - register_i2c_func(); - - ret = cmd_head.data_len + CMD_HEAD_LENGTH; - goto exit; - } else if (cmd_head.wr == GTP_RW_NO_WRITE) { - ret = cmd_head.data_len + CMD_HEAD_LENGTH; - goto exit; - } else if (cmd_head.wr == GTP_RW_DISABLE_IRQ) { /* disable irq! */ - gtp_irq_disable(i2c_get_clientdata(gt_client)); - - #if GTP_ESD_PROTECT - gtp_esd_switch(gt_client, SWITCH_OFF); - #endif - ret = CMD_HEAD_LENGTH; - goto exit; - } else if (cmd_head.wr == GTP_RW_ENABLE_IRQ) { /* enable irq! */ - gtp_irq_enable(i2c_get_clientdata(gt_client)); - - #if GTP_ESD_PROTECT - gtp_esd_switch(gt_client, SWITCH_ON); - #endif - ret = CMD_HEAD_LENGTH; - goto exit; - } else if (cmd_head.wr == GTP_RW_CHECK_RAWDIFF_MODE) { - struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); - - ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], - &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); - if (ret) { - dev_err(>_client->dev, "copy_from_user failed"); - goto exit; - } - if (cmd_head.data[GTP_ADDR_LENGTH]) { - pr_debug("gtp enter rawdiff\n"); - ts->gtp_rawdiff_mode = true; - } else { - ts->gtp_rawdiff_mode = false; - pr_debug("gtp leave rawdiff\n"); - } - ret = CMD_HEAD_LENGTH; - goto exit; - } else if (cmd_head.wr == GTP_RW_ENTER_UPDATE_MODE) { - /* Enter update mode! */ - if (gup_enter_update_mode(gt_client) == FAIL) { - ret = -EBUSY; - goto exit; - } - } else if (cmd_head.wr == GTP_RW_LEAVE_UPDATE_MODE) { - /* Leave update mode! */ - gup_leave_update_mode(gt_client); - } else if (cmd_head.wr == GTP_RW_UPDATE_FW) { - /* Update firmware! */ - show_len = 0; - total_len = 0; - if (cmd_head.data_len + 1 > data_length) { - dev_err(>_client->dev, "data len %u > data buff %d, rejected\n", - cmd_head.data_len + 1, data_length); - ret = -EINVAL; - goto exit; - } - memset(cmd_head.data, 0, cmd_head.data_len + 1); - memcpy(cmd_head.data, &userbuf[CMD_HEAD_LENGTH], - cmd_head.data_len); - - if (gup_update_proc((void *)cmd_head.data) == FAIL) { - ret = -EBUSY; - goto exit; - } - } - ret = CMD_HEAD_LENGTH; - -exit: - dataptr = cmd_head.data; - memset(&cmd_head, 0, sizeof(cmd_head)); - cmd_head.wr = 0xFF; - cmd_head.data = dataptr; - - mutex_unlock(&lock); - return ret; -} - -/* - * Function: - * Goodix tool read function. - * Input: - * standard proc read function param. - * Output: - * Return read length. - */ -static ssize_t goodix_tool_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - u16 data_len = 0; - s32 ret; - u8 buf[32]; - - mutex_lock(&lock); - if (cmd_head.wr & 0x1) { - dev_err(>_client->dev, "command head wrong\n"); - ret = -EINVAL; - goto exit; - } - - switch (cmd_head.wr) { - case GTP_RW_READ: - if (cmd_head.flag == GTP_NEED_FLAG) { - if (comfirm() == FAIL) { - dev_err(>_client->dev, "Confirm fail"); - ret = -EINVAL; - goto exit; - } - } else if (cmd_head.flag == GTP_NEED_INTERRUPT) { - /* Need interrupt! */ - } - - memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len); - - pr_debug("[CMD HEAD DATA] ADDR:0x%02x%02x.\n", cmd_head.data[0], - cmd_head.data[1]); - pr_debug("[CMD HEAD ADDR] ADDR:0x%02x%02x.\n", cmd_head.addr[0], - cmd_head.addr[1]); - - if (cmd_head.delay) - msleep(cmd_head.delay); - - data_len = cmd_head.data_len; - if (data_len <= 0 || (data_len > data_length)) { - dev_err(>_client->dev, "Invalid data length %d\n", - data_len); - ret = -EINVAL; - goto exit; - } - if (data_len > count) - data_len = count; - - if (tool_i2c_read(cmd_head.data, data_len) <= 0) { - dev_err(>_client->dev, "Read data failed\n"); - ret = -EIO; - goto exit; - } - ret = simple_read_from_buffer(user_buf, count, ppos, - &cmd_head.data[GTP_ADDR_LENGTH], data_len); - break; - case GTP_RW_FILL_INFO: - ret = fill_update_info(user_buf, count, ppos); - break; - case GTP_RW_READ_VERSION: - /* Read driver version */ - data_len = scnprintf(buf, sizeof(buf), "%s\n", - GTP_DRIVER_VERSION); - ret = simple_read_from_buffer(user_buf, count, ppos, - buf, data_len); - break; - default: - ret = -EINVAL; - break; - } - -exit: - mutex_unlock(&lock); - return ret; -} - -static const struct file_operations goodix_proc_fops = { - .write = goodix_tool_write, - .read = goodix_tool_read, - .open = simple_open, - .owner = THIS_MODULE, -}; - -s32 init_wr_node(struct i2c_client *client) -{ - u8 i; - - gt_client = client; - memset(&cmd_head, 0, sizeof(cmd_head)); - cmd_head.data = NULL; - - i = GTP_I2C_RETRY_5; - while ((!cmd_head.data) && i) { - cmd_head.data = devm_kzalloc(&client->dev, - i * DATA_LENGTH_UINT, GFP_KERNEL); - if (cmd_head.data) - break; - i--; - } - if (i) { - data_length = i * DATA_LENGTH_UINT; - dev_dbg(&client->dev, "Applied memory size:%d", data_length); - } - - cmd_head.addr_len = 2; - cmd_head.retry = GTP_I2C_RETRY_5; - - register_i2c_func(); - - mutex_init(&lock); - tool_set_proc_name(procname); - goodix_proc_entry = proc_create(procname, - S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, - goodix_proc_entry, - &goodix_proc_fops); - if (goodix_proc_entry == NULL) { - dev_err(&client->dev, "Couldn't create proc entry"); - return FAIL; - } - - return SUCCESS; -} diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c deleted file mode 100644 index ead935120624..000000000000 --- a/drivers/input/touchscreen/gt9xx/gt9xx.c +++ /dev/null @@ -1,2564 +0,0 @@ -/* drivers/input/touchscreen/gt9xx.c - * - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. - * - * 2010 - 2013 Goodix Technology. - * - * 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. - * - * This program is distributed in the hope that it will be a reference - * to you, when you are integrating the GOODiX's CTP IC into your system, - * 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. - * - * Version: 1.8 - * Authors: andrew@goodix.com, meta@goodix.com - * Release Date: 2013/04/25 - * Revision record: - * V1.0: - * first Release. By Andrew, 2012/08/31 - * V1.2: - * modify gtp_reset_guitar,slot report,tracking_id & 0x0F. - * By Andrew, 2012/10/15 - * V1.4: - * modify gt9xx_update.c. By Andrew, 2012/12/12 - * V1.6: - * 1. new heartbeat/esd_protect mechanism(add external watchdog) - * 2. doze mode, sliding wakeup - * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5) - * 3. config length verification - * 4. names & comments - * By Meta, 2013/03/11 - * V1.8: - * 1. pen/stylus identification - * 2. read double check & fixed config support - * 2. new esd & slide wakeup optimization - * By Meta, 2013/06/08 - */ - -#include <linux/regulator/consumer.h> -#include "gt9xx.h" - -#include <linux/of_gpio.h> -#include <linux/irq.h> -#include <linux/module.h> -#include <linux/input/mt.h> -#include <linux/debugfs.h> -#include <linux/interrupt.h> - -#define GOODIX_DEV_NAME "Goodix-CTP" -#define CFG_MAX_TOUCH_POINTS 5 -#define GOODIX_COORDS_ARR_SIZE 4 -#define MAX_BUTTONS 4 - -#define GOODIX_VTG_MIN_UV 2600000 -#define GOODIX_VTG_MAX_UV 3300000 -#define GOODIX_I2C_VTG_MIN_UV 1800000 -#define GOODIX_I2C_VTG_MAX_UV 1800000 -#define GOODIX_VDD_LOAD_MIN_UA 0 -#define GOODIX_VDD_LOAD_MAX_UA 10000 -#define GOODIX_VIO_LOAD_MIN_UA 0 -#define GOODIX_VIO_LOAD_MAX_UA 10000 - -#define RESET_DELAY_T3_US 200 /* T3: > 100us */ -#define RESET_DELAY_T4 20 /* T4: > 5ms */ -#define SLEEP_DELAY_US 5000 -#define WAKE_UP_DELAY_US 5000 - -#define PHY_BUF_SIZE 32 -#define PROP_NAME_SIZE 24 - -#define GTP_MAX_TOUCH 5 -#define GTP_ESD_CHECK_CIRCLE_MS 2000 - -static void gtp_int_sync(struct goodix_ts_data *ts, int ms); -static int gtp_i2c_test(struct i2c_client *client); -static int goodix_power_off(struct goodix_ts_data *ts); -static int goodix_power_on(struct goodix_ts_data *ts); - -#if defined(CONFIG_FB) -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data); -static int goodix_ts_suspend(struct device *dev); -static int goodix_ts_resume(struct device *dev); -#elif defined(CONFIG_HAS_EARLYSUSPEND) -static void goodix_ts_early_suspend(struct early_suspend *h); -static void goodix_ts_late_resume(struct early_suspend *h); -#endif - -#if GTP_ESD_PROTECT -static struct delayed_work gtp_esd_check_work; -static struct workqueue_struct *gtp_esd_check_workqueue; -static void gtp_esd_check_func(struct work_struct *work); -static int gtp_init_ext_watchdog(struct i2c_client *client); -#endif - -enum doze { - DOZE_DISABLED = 0, - DOZE_ENABLED = 1, - DOZE_WAKEUP = 2, -}; -static enum doze doze_status = DOZE_DISABLED; -static s8 gtp_enter_doze(struct goodix_ts_data *ts); - -bool init_done; -static u8 chip_gt9xxs; /* true if ic is gt9xxs, like gt915s */ -u8 grp_cfg_version; -struct i2c_client *i2c_connect_client; - -#define GTP_DEBUGFS_DIR "ts_debug" -#define GTP_DEBUGFS_FILE_SUSPEND "suspend" -#define GTP_DEBUGFS_FILE_DATA "data" -#define GTP_DEBUGFS_FILE_ADDR "addr" - -/******************************************************* -Function: - Read data from the i2c slave device. -Input: - client: i2c device. - buf[0~1]: read start address. - buf[2~len-1]: read data buffer. - len: GTP_ADDR_LENGTH + read bytes count -Output: - numbers of i2c_msgs to transfer: - 2: succeed, otherwise: failed -*********************************************************/ -int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len) -{ - struct goodix_ts_data *ts = i2c_get_clientdata(client); - int ret = -EIO; - u8 retries; - struct i2c_msg msgs[2] = { - { - .flags = !I2C_M_RD, - .addr = client->addr, - .len = GTP_ADDR_LENGTH, - .buf = &buf[0], - }, - { - .flags = I2C_M_RD, - .addr = client->addr, - .len = len - GTP_ADDR_LENGTH, - .buf = &buf[GTP_ADDR_LENGTH], - }, - }; - - for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) { - ret = i2c_transfer(client->adapter, msgs, 2); - if (ret == 2) - break; - dev_err(&client->dev, "I2C retry: %d\n", retries + 1); - } - if (retries == GTP_I2C_RETRY_5) { - if (ts->pdata->slide_wakeup) - /* reset chip would quit doze mode */ - if (doze_status == DOZE_ENABLED) - return ret; - - if (init_done) - gtp_reset_guitar(ts, 10); - else - dev_warn(&client->dev, - "gtp_reset_guitar exit init_done=%d:\n", - init_done); - } - return ret; -} - -/******************************************************* -Function: - Write data to the i2c slave device. -Input: - client: i2c device. - buf[0~1]: write start address. - buf[2~len-1]: data buffer - len: GTP_ADDR_LENGTH + write bytes count -Output: - numbers of i2c_msgs to transfer: - 1: succeed, otherwise: failed -*********************************************************/ -int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) -{ - struct goodix_ts_data *ts = i2c_get_clientdata(client); - int ret = -EIO; - u8 retries; - struct i2c_msg msg = { - .flags = !I2C_M_RD, - .addr = client->addr, - .len = len, - .buf = buf, - }; - - for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) { - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret == 1) - break; - dev_err(&client->dev, "I2C retry: %d\n", retries + 1); - } - if (retries == GTP_I2C_RETRY_5) { - if (ts->pdata->slide_wakeup) - if (doze_status == DOZE_ENABLED) - return ret; - - if (init_done) - gtp_reset_guitar(ts, 10); - else - dev_warn(&client->dev, - "gtp_reset_guitar exit init_done=%d:\n", - init_done); - } - return ret; -} - -/******************************************************* -Function: - i2c read twice, compare the results -Input: - client: i2c device - addr: operate address - rxbuf: read data to store, if compare successful - len: bytes to read -Output: - FAIL: read failed - SUCCESS: read successful -*********************************************************/ -int gtp_i2c_read_dbl_check(struct i2c_client *client, - u16 addr, u8 *rxbuf, int len) -{ - u8 buf[16] = {0}; - u8 confirm_buf[16] = {0}; - u8 retry = 0; - - while (retry++ < GTP_I2C_RETRY_3) { - memset(buf, 0xAA, 16); - buf[0] = (u8)(addr >> 8); - buf[1] = (u8)(addr & 0xFF); - gtp_i2c_read(client, buf, len + 2); - - memset(confirm_buf, 0xAB, 16); - confirm_buf[0] = (u8)(addr >> 8); - confirm_buf[1] = (u8)(addr & 0xFF); - gtp_i2c_read(client, confirm_buf, len + 2); - - if (!memcmp(buf, confirm_buf, len + 2)) - break; - } - if (retry < GTP_I2C_RETRY_3) { - memcpy(rxbuf, confirm_buf + 2, len); - return SUCCESS; - } - dev_err(&client->dev, - "i2c read 0x%04X, %d bytes, double check failed!", addr, len); - return FAIL; -} - -/******************************************************* -Function: - Send config data. -Input: - client: i2c device. -Output: - result of i2c write operation. - > 0: succeed, otherwise: failed -*********************************************************/ -int gtp_send_cfg(struct goodix_ts_data *ts) -{ - int ret = 0; - int retry; - - if (ts->pdata->driver_send_cfg) { - if (ts->fixed_cfg) { - dev_dbg(&ts->client->dev, - "Ic fixed config, no config sent!"); - ret = 2; - } else { - for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) { - ret = gtp_i2c_write(ts->client, - ts->config_data, - GTP_CONFIG_MAX_LENGTH + - GTP_ADDR_LENGTH); - if (ret > 0) - break; - } - } - } - - return ret; -} - -/******************************************************* -Function: - Disable irq function -Input: - ts: goodix i2c_client private data -Output: - None. -*********************************************************/ -void gtp_irq_disable(struct goodix_ts_data *ts) -{ - unsigned long irqflags; - - spin_lock_irqsave(&ts->irq_lock, irqflags); - if (!ts->irq_is_disabled) { - ts->irq_is_disabled = true; - disable_irq_nosync(ts->client->irq); - } - spin_unlock_irqrestore(&ts->irq_lock, irqflags); -} - -/******************************************************* -Function: - Enable irq function -Input: - ts: goodix i2c_client private data -Output: - None. -*********************************************************/ -void gtp_irq_enable(struct goodix_ts_data *ts) -{ - unsigned long irqflags = 0; - - spin_lock_irqsave(&ts->irq_lock, irqflags); - if (ts->irq_is_disabled) { - enable_irq(ts->client->irq); - ts->irq_is_disabled = false; - } - spin_unlock_irqrestore(&ts->irq_lock, irqflags); -} - -/******************************************************* -Function: - Report touch point event -Input: - ts: goodix i2c_client private data - id: trackId - x: input x coordinate - y: input y coordinate - w: input pressure -Output: - None. -*********************************************************/ -static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y, - int w) -{ - if (ts->pdata->change_x2y) - swap(x, y); - - input_mt_slot(ts->input_dev, id); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); -} - -/******************************************************* -Function: - Report touch release event -Input: - ts: goodix i2c_client private data -Output: - None. -*********************************************************/ -static void gtp_touch_up(struct goodix_ts_data *ts, int id) -{ - input_mt_slot(ts->input_dev, id); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); -} - - - -/******************************************************* -Function: - Goodix touchscreen work function -Input: - work: work struct of goodix_workqueue -Output: - None. -*********************************************************/ -static void goodix_ts_work_func(struct work_struct *work) -{ - u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, - GTP_READ_COOR_ADDR & 0xFF, 0}; - u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = { - GTP_READ_COOR_ADDR >> 8, - GTP_READ_COOR_ADDR & 0xFF}; - u8 touch_num = 0; - u8 finger = 0; - static u16 pre_touch; - static u8 pre_key; - static u8 pre_pen; - u8 key_value = 0; - u8 *coor_data = NULL; - s32 input_x = 0; - s32 input_y = 0; - s32 input_w = 0; - s32 id = 0; - s32 i = 0; - int ret = -1; - struct goodix_ts_data *ts = NULL; - u8 doze_buf[3] = {0x81, 0x4B}; - - ts = container_of(work, struct goodix_ts_data, work); -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE - if (ts->enter_update) - return; -#endif - - if (ts->pdata->slide_wakeup) { - if (doze_status == DOZE_ENABLED) { - ret = gtp_i2c_read(ts->client, doze_buf, 3); - if (ret > 0) { - if (doze_buf[2] == 0xAA) { - dev_dbg(&ts->client->dev, - "Slide(0xAA) To Light up the screen!"); - doze_status = DOZE_WAKEUP; - input_report_key( - ts->input_dev, KEY_POWER, 1); - input_sync(ts->input_dev); - input_report_key( - ts->input_dev, KEY_POWER, 0); - input_sync(ts->input_dev); - /* clear 0x814B */ - doze_buf[2] = 0x00; - gtp_i2c_write(ts->client, doze_buf, 3); - } else if (doze_buf[2] == 0xBB) { - dev_dbg(&ts->client->dev, - "Slide(0xBB) To Light up the screen!"); - doze_status = DOZE_WAKEUP; - input_report_key(ts->input_dev, - KEY_POWER, 1); - input_sync(ts->input_dev); - input_report_key(ts->input_dev, - KEY_POWER, 0); - input_sync(ts->input_dev); - /* clear 0x814B*/ - doze_buf[2] = 0x00; - gtp_i2c_write(ts->client, doze_buf, 3); - } else if (0xC0 == (doze_buf[2] & 0xC0)) { - dev_dbg(&ts->client->dev, - "double click to light up the screen!"); - doze_status = DOZE_WAKEUP; - input_report_key(ts->input_dev, - KEY_POWER, 1); - input_sync(ts->input_dev); - input_report_key(ts->input_dev, - KEY_POWER, 0); - input_sync(ts->input_dev); - /* clear 0x814B */ - doze_buf[2] = 0x00; - gtp_i2c_write(ts->client, doze_buf, 3); - } else { - gtp_enter_doze(ts); - } - } - if (ts->use_irq) - gtp_irq_enable(ts); - - return; - } - } - - ret = gtp_i2c_read(ts->client, point_data, 12); - if (ret < 0) { - dev_err(&ts->client->dev, - "I2C transfer error. errno:%d\n ", ret); - goto exit_work_func; - } - - finger = point_data[GTP_ADDR_LENGTH]; - if ((finger & 0x80) == 0) - goto exit_work_func; - - touch_num = finger & 0x0f; - if (touch_num > GTP_MAX_TOUCH) - goto exit_work_func; - - if (touch_num > 1) { - u8 buf[8 * GTP_MAX_TOUCH] = { (GTP_READ_COOR_ADDR + 10) >> 8, - (GTP_READ_COOR_ADDR + 10) & 0xff }; - - ret = gtp_i2c_read(ts->client, buf, - 2 + 8 * (touch_num - 1)); - memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); - } - - - key_value = point_data[3 + 8 * touch_num]; - - if (key_value || pre_key) { - for (i = 0; i < ts->pdata->num_button; i++) { - input_report_key(ts->input_dev, - ts->pdata->button_map[i], - key_value & (0x01<<i)); - } - touch_num = 0; - pre_touch = 0; - } - - pre_key = key_value; - - if (ts->pdata->with_pen) { - if (pre_pen && (touch_num == 0)) { - dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!"); - input_report_key(ts->input_dev, BTN_TOOL_PEN, 0); - input_mt_slot(ts->input_dev, 5); - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); - pre_pen = 0; - } - } - - if (pre_touch || touch_num) { - s32 pos = 0; - u16 touch_index = 0; - - coor_data = &point_data[3]; - if (touch_num) { - id = coor_data[pos] & 0x0F; - if (ts->pdata->with_pen) { - id = coor_data[pos]; - if (id == 128) { - dev_dbg(&ts->client->dev, - "Pen touch DOWN(Slot)!"); - input_x = coor_data[pos + 1] - | (coor_data[pos + 2] << 8); - input_y = coor_data[pos + 3] - | (coor_data[pos + 4] << 8); - input_w = coor_data[pos + 5] - | (coor_data[pos + 6] << 8); - - input_report_key(ts->input_dev, - BTN_TOOL_PEN, 1); - input_mt_slot(ts->input_dev, 5); - input_report_abs(ts->input_dev, - ABS_MT_TRACKING_ID, 5); - input_report_abs(ts->input_dev, - ABS_MT_POSITION_X, input_x); - input_report_abs(ts->input_dev, - ABS_MT_POSITION_Y, input_y); - input_report_abs(ts->input_dev, - ABS_MT_TOUCH_MAJOR, input_w); - dev_dbg(&ts->client->dev, - "Pen/Stylus: (%d, %d)[%d]", - input_x, input_y, input_w); - pre_pen = 1; - pre_touch = 0; - } - } - - touch_index |= (0x01<<id); - } - - for (i = 0; i < GTP_MAX_TOUCH; i++) { - if (ts->pdata->with_pen) - if (pre_pen == 1) - break; - - if (touch_index & (0x01<<i)) { - input_x = coor_data[pos + 1] | - coor_data[pos + 2] << 8; - input_y = coor_data[pos + 3] | - coor_data[pos + 4] << 8; - input_w = coor_data[pos + 5] | - coor_data[pos + 6] << 8; - - gtp_touch_down(ts, id, - input_x, input_y, input_w); - pre_touch |= 0x01 << i; - - pos += 8; - id = coor_data[pos] & 0x0F; - touch_index |= (0x01<<id); - } else { - gtp_touch_up(ts, i); - pre_touch &= ~(0x01 << i); - } - } - } - input_sync(ts->input_dev); - -exit_work_func: - if (!ts->gtp_rawdiff_mode) { - ret = gtp_i2c_write(ts->client, end_cmd, 3); - if (ret < 0) - dev_warn(&ts->client->dev, "I2C write end_cmd error!\n"); - - } - if (ts->use_irq) - gtp_irq_enable(ts); - - return; -} - -/******************************************************* -Function: - External interrupt service routine for interrupt mode. -Input: - irq: interrupt number. - dev_id: private data pointer -Output: - Handle Result. - IRQ_HANDLED: interrupt handled successfully -*********************************************************/ -static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) -{ - struct goodix_ts_data *ts = dev_id; - - gtp_irq_disable(ts); - - queue_work(ts->goodix_wq, &ts->work); - - return IRQ_HANDLED; -} -/******************************************************* -Function: - Synchronization. -Input: - ms: synchronization time in millisecond. -Output: - None. -*******************************************************/ -void gtp_int_sync(struct goodix_ts_data *ts, int ms) -{ - gpio_direction_output(ts->pdata->irq_gpio, 0); - msleep(ms); - gpio_direction_input(ts->pdata->irq_gpio); -} - -/******************************************************* -Function: - Reset chip. -Input: - ms: reset time in millisecond, must >10ms -Output: - None. -*******************************************************/ -void gtp_reset_guitar(struct goodix_ts_data *ts, int ms) -{ - /* This reset sequence will selcet I2C slave address */ - gpio_direction_output(ts->pdata->reset_gpio, 0); - msleep(ms); - - if (ts->client->addr == GTP_I2C_ADDRESS_HIGH) - gpio_direction_output(ts->pdata->irq_gpio, 1); - else - gpio_direction_output(ts->pdata->irq_gpio, 0); - - usleep_range(RESET_DELAY_T3_US, RESET_DELAY_T3_US + 1); - gpio_direction_output(ts->pdata->reset_gpio, 1); - msleep(RESET_DELAY_T4); - - gpio_direction_input(ts->pdata->reset_gpio); - - gtp_int_sync(ts, 50); - -#if GTP_ESD_PROTECT - gtp_init_ext_watchdog(ts->client); -#endif -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB) -/******************************************************* -Function: - Enter doze mode for sliding wakeup. -Input: - ts: goodix tp private data -Output: - 1: succeed, otherwise failed -*******************************************************/ -static s8 gtp_enter_doze(struct goodix_ts_data *ts) -{ - int ret = -1; - s8 retry = 0; - u8 i2c_control_buf[3] = { - (u8)(GTP_REG_SLEEP >> 8), - (u8)GTP_REG_SLEEP, 8}; - - if (ts->pdata->dbl_clk_wakeup) - i2c_control_buf[2] = 0x09; - - gtp_irq_disable(ts); - - while (retry++ < GTP_I2C_RETRY_3) { - i2c_control_buf[0] = 0x80; - i2c_control_buf[1] = 0x46; - ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); - if (ret < 0) { - dev_err(&ts->client->dev, - "failed to set doze flag into 0x8046, %d", - retry); - continue; - } - i2c_control_buf[0] = 0x80; - i2c_control_buf[1] = 0x40; - ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); - if (ret > 0) { - doze_status = DOZE_ENABLED; - dev_dbg(&ts->client->dev, - "GTP has been working in doze mode!"); - gtp_irq_enable(ts); - return ret; - } - msleep(20); - } - dev_err(&ts->client->dev, "GTP send doze cmd failed.\n"); - gtp_irq_enable(ts); - return ret; -} -/** - * gtp_enter_sleep - Enter sleep mode - * @ts: driver private data - * - * Returns zero on success, else an error. - */ -static u8 gtp_enter_sleep(struct goodix_ts_data *ts) -{ - int ret = -1; - s8 retry = 0; - u8 i2c_control_buf[3] = { - (u8)(GTP_REG_SLEEP >> 8), - (u8)GTP_REG_SLEEP, 5}; - - ret = gpio_direction_output(ts->pdata->irq_gpio, 0); - if (ret) - dev_err(&ts->client->dev, - "GTP sleep: Cannot reconfig gpio %d.\n", - ts->pdata->irq_gpio); - if (ts->pdata->enable_power_off) { - ret = gpio_direction_output(ts->pdata->reset_gpio, 0); - if (ret) - dev_err(&ts->client->dev, - "GTP sleep: Cannot reconfig gpio %d.\n", - ts->pdata->reset_gpio); - ret = goodix_power_off(ts); - if (ret) { - dev_err(&ts->client->dev, "GTP power off failed.\n"); - return ret; - } - return 0; - } - usleep_range(SLEEP_DELAY_US, SLEEP_DELAY_US + 1); - while (retry++ < GTP_I2C_RETRY_5) { - ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); - if (ret == 1) { - dev_dbg(&ts->client->dev, "GTP enter sleep!"); - return 0; - } - msleep(20); - } - dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n"); - return ret; -} - -/******************************************************* -Function: - Wakeup from sleep. -Input: - ts: private data. -Output: - Executive outcomes. - >0: succeed, otherwise: failed. -*******************************************************/ -static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts) -{ - u8 retry = 0; - s8 ret = -1; - - if (ts->pdata->enable_power_off) { - ret = gpio_direction_output(ts->pdata->irq_gpio, 0); - if (ret) - dev_err(&ts->client->dev, - "GTP wakeup: Cannot reconfig gpio %d.\n", - ts->pdata->irq_gpio); - ret = gpio_direction_output(ts->pdata->reset_gpio, 0); - if (ret) - dev_err(&ts->client->dev, - "GTP wakeup: Cannot reconfig gpio %d.\n", - ts->pdata->reset_gpio); - ret = goodix_power_on(ts); - if (ret) { - dev_err(&ts->client->dev, "GTP power on failed.\n"); - return 0; - } - - gtp_reset_guitar(ts, 20); - - ret = gtp_send_cfg(ts); - if (ret <= 0) { - dev_err(&ts->client->dev, - "GTP wakeup sleep failed.\n"); - return ret; - } - - dev_dbg(&ts->client->dev, - "Wakeup sleep send config success."); - } else { -err_retry: - if (ts->pdata->slide_wakeup) { /* wakeup not by slide */ - if (doze_status != DOZE_WAKEUP) - gtp_reset_guitar(ts, 10); - else - /* wakeup by slide */ - doze_status = DOZE_DISABLED; - } else { - if (chip_gt9xxs == 1) { - gtp_reset_guitar(ts, 10); - } else { - ret = gpio_direction_output( - ts->pdata->irq_gpio, 1); - usleep_range(WAKE_UP_DELAY_US, - WAKE_UP_DELAY_US + 1); - } - } - ret = gtp_i2c_test(ts->client); - if (ret == 2) { - dev_dbg(&ts->client->dev, "GTP wakeup sleep."); - if (!ts->pdata->slide_wakeup) { - if (chip_gt9xxs == 0) { - gtp_int_sync(ts, 25); - msleep(20); -#if GTP_ESD_PROTECT - gtp_init_ext_watchdog(ts->client); -#endif - } - } - return ret; - } - gtp_reset_guitar(ts, 20); - if (retry++ < GTP_I2C_RETRY_10) - goto err_retry; - dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n"); - } - return ret; -} -#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/ - -/******************************************************* -Function: - Initialize gtp. -Input: - ts: goodix private data -Output: - Executive outcomes. - > =0: succeed, otherwise: failed -*******************************************************/ -static int gtp_init_panel(struct goodix_ts_data *ts) -{ - struct i2c_client *client = ts->client; - unsigned char *config_data = NULL; - int ret = -EIO; - int i; - u8 check_sum = 0; - u8 opr_buf[16]; - u8 sensor_id = 0; - - if (ts->pdata->driver_send_cfg) { - for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) - dev_dbg(&client->dev, "Config Groups(%d) Lengths: %zu", - i, ts->pdata->config_data_len[i]); - - ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); - if (ret == SUCCESS) { - if (opr_buf[0] != 0xBE) { - ts->fw_error = 1; - dev_err(&client->dev, - "Firmware error, no config sent!"); - return -EINVAL; - } - } - - for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) { - if (ts->pdata->config_data_len[i]) - break; - } - - if (i == GOODIX_MAX_CFG_GROUP) { - sensor_id = 0; - } else { - ret = gtp_i2c_read_dbl_check(ts->client, - GTP_REG_SENSOR_ID, &sensor_id, 1); - if (ret == SUCCESS) { - if (sensor_id >= GOODIX_MAX_CFG_GROUP) { - dev_err(&client->dev, - "Invalid sensor_id(0x%02X), No Config Sent!", - sensor_id); - return -EINVAL; - } - } else { - dev_err(&client->dev, - "Failed to get sensor_id, No config sent!"); - return -EINVAL; - } - } - - dev_info(&client->dev, "Sensor ID selected: %d", sensor_id); - - if (ts->pdata->config_data_len[sensor_id] < - GTP_CONFIG_MIN_LENGTH || - !ts->pdata->config_data[sensor_id]) { - dev_err(&client->dev, - "Sensor_ID(%d) matches with NULL or invalid config group!\n", - sensor_id); - return -EINVAL; - } - - ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, - &opr_buf[0], 1); - if (ret == SUCCESS) { - if (opr_buf[0] < 90) { - /* backup group config version */ - grp_cfg_version = - ts->pdata-> - config_data[sensor_id][GTP_ADDR_LENGTH]; - ts->pdata-> - config_data[sensor_id][GTP_ADDR_LENGTH] - = 0x00; - ts->fixed_cfg = 0; - } else { - /* treated as fixed config, not send config */ - dev_warn(&client->dev, - "Ic fixed config with config version(%d, 0x%02X)", - opr_buf[0], opr_buf[0]); - ts->fixed_cfg = 1; - } - } else { - dev_err(&client->dev, - "Failed to get ic config version!No config sent!"); - return -EINVAL; - } - - config_data = ts->pdata->config_data[sensor_id]; - ts->config_data = ts->pdata->config_data[sensor_id]; - ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id]; - -#if GTP_CUSTOM_CFG - config_data[RESOLUTION_LOC] = - (unsigned char)(GTP_MAX_WIDTH && 0xFF); - config_data[RESOLUTION_LOC + 1] = - (unsigned char)(GTP_MAX_WIDTH >> 8); - config_data[RESOLUTION_LOC + 2] = - (unsigned char)(GTP_MAX_HEIGHT && 0xFF); - config_data[RESOLUTION_LOC + 3] = - (unsigned char)(GTP_MAX_HEIGHT >> 8); - - if (GTP_INT_TRIGGER == 0) - config_data[TRIGGER_LOC] &= 0xfe; - else if (GTP_INT_TRIGGER == 1) - config_data[TRIGGER_LOC] |= 0x01; -#endif /* !GTP_CUSTOM_CFG */ - - check_sum = 0; - for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) - check_sum += config_data[i]; - - config_data[ts->gtp_cfg_len] = (~check_sum) + 1; - - } else { /* DRIVER NOT SEND CONFIG */ - ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH; - ret = gtp_i2c_read(ts->client, config_data, - ts->gtp_cfg_len + GTP_ADDR_LENGTH); - if (ret < 0) { - dev_err(&client->dev, - "Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n"); - ts->abs_x_max = GTP_MAX_WIDTH; - ts->abs_y_max = GTP_MAX_HEIGHT; - ts->int_trigger_type = GTP_INT_TRIGGER; - } - } /* !DRIVER NOT SEND CONFIG */ - - if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) { - ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8) - + config_data[RESOLUTION_LOC]; - ts->abs_y_max = (config_data[RESOLUTION_LOC + 3] << 8) - + config_data[RESOLUTION_LOC + 2]; - ts->int_trigger_type = (config_data[TRIGGER_LOC]) & 0x03; - } - ret = gtp_send_cfg(ts); - if (ret < 0) - dev_err(&client->dev, "%s: Send config error.\n", __func__); - - msleep(20); - return ret; -} - -/******************************************************* -Function: - Read firmware version -Input: - client: i2c device - version: buffer to keep ic firmware version -Output: - read operation return. - 0: succeed, otherwise: failed -*******************************************************/ -static int gtp_read_fw_version(struct i2c_client *client, u16 *version) -{ - int ret = 0; - u8 buf[GTP_FW_VERSION_BUFFER_MAXSIZE] = { - GTP_REG_FW_VERSION >> 8, GTP_REG_FW_VERSION & 0xff }; - - ret = gtp_i2c_read(client, buf, sizeof(buf)); - if (ret < 0) { - dev_err(&client->dev, "GTP read version failed.\n"); - return -EIO; - } - - if (version) - *version = (buf[3] << 8) | buf[2]; - - return ret; -} -/* - * Function: - * Read and check chip id. - * Input: - * client: i2c device - * Output: - * read operation return. - * 0: succeed, otherwise: failed - */ -static int gtp_check_product_id(struct i2c_client *client) -{ - int ret = 0; - char product_id[GTP_PRODUCT_ID_MAXSIZE]; - struct goodix_ts_data *ts = i2c_get_clientdata(client); - /* 04 bytes are used for the Product-id in the register space.*/ - u8 buf[GTP_PRODUCT_ID_BUFFER_MAXSIZE] = { - GTP_REG_PRODUCT_ID >> 8, GTP_REG_PRODUCT_ID & 0xff }; - - ret = gtp_i2c_read(client, buf, sizeof(buf)); - if (ret < 0) { - dev_err(&client->dev, "GTP read product_id failed.\n"); - return -EIO; - } - - if (buf[5] == 0x00) { - /* copy (GTP_PRODUCT_ID_MAXSIZE - 1) from buffer. Ex: 915 */ - strlcpy(product_id, &buf[2], GTP_PRODUCT_ID_MAXSIZE - 1); - } else { - if (buf[5] == 'S' || buf[5] == 's') - chip_gt9xxs = 1; - /* copy GTP_PRODUCT_ID_MAXSIZE from buffer. Ex: 915s */ - strlcpy(product_id, &buf[2], GTP_PRODUCT_ID_MAXSIZE); - } - - dev_info(&client->dev, "Goodix Product ID = %s\n", product_id); - - ret = strcmp(product_id, ts->pdata->product_id); - if (ret != 0) - return -EINVAL; - - return ret; -} - -/******************************************************* -Function: - I2c test Function. -Input: - client:i2c client. -Output: - Executive outcomes. - 2: succeed, otherwise failed. -*******************************************************/ -static int gtp_i2c_test(struct i2c_client *client) -{ - u8 buf[3] = { GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff }; - int retry = GTP_I2C_RETRY_5; - int ret = -EIO; - - while (retry--) { - ret = gtp_i2c_read(client, buf, 3); - if (ret > 0) - return ret; - dev_err(&client->dev, "GTP i2c test failed time %d.\n", retry); - msleep(20); - } - return ret; -} - -/******************************************************* -Function: - Request gpio(INT & RST) ports. -Input: - ts: private data. -Output: - Executive outcomes. - = 0: succeed, != 0: failed -*******************************************************/ -static int gtp_request_io_port(struct goodix_ts_data *ts) -{ - struct i2c_client *client = ts->client; - struct goodix_ts_platform_data *pdata = ts->pdata; - int ret; - - if (gpio_is_valid(pdata->irq_gpio)) { - ret = gpio_request(pdata->irq_gpio, "goodix_ts_irq_gpio"); - if (ret) { - dev_err(&client->dev, "Unable to request irq gpio [%d]\n", - pdata->irq_gpio); - goto err_pwr_off; - } - ret = gpio_direction_input(pdata->irq_gpio); - if (ret) { - dev_err(&client->dev, "Unable to set direction for irq gpio [%d]\n", - pdata->irq_gpio); - goto err_free_irq_gpio; - } - } else { - dev_err(&client->dev, "Invalid irq gpio [%d]!\n", - pdata->irq_gpio); - ret = -EINVAL; - goto err_pwr_off; - } - - if (gpio_is_valid(pdata->reset_gpio)) { - ret = gpio_request(pdata->reset_gpio, "goodix_ts_reset_gpio"); - if (ret) { - dev_err(&client->dev, "Unable to request reset gpio [%d]\n", - pdata->reset_gpio); - goto err_free_irq_gpio; - } - - ret = gpio_direction_output(pdata->reset_gpio, 0); - if (ret) { - dev_err(&client->dev, "Unable to set direction for reset gpio [%d]\n", - pdata->reset_gpio); - goto err_free_reset_gpio; - } - } else { - dev_err(&client->dev, "Invalid irq gpio [%d]!\n", - pdata->reset_gpio); - ret = -EINVAL; - goto err_free_irq_gpio; - } - /* IRQ GPIO is an input signal, but we are setting it to output - * direction and pulling it down, to comply with power up timing - * requirements, mentioned in power up timing section of device - * datasheet. - */ - ret = gpio_direction_output(pdata->irq_gpio, 0); - if (ret) - dev_warn(&client->dev, - "pull down interrupt gpio failed\n"); - ret = gpio_direction_output(pdata->reset_gpio, 0); - if (ret) - dev_warn(&client->dev, - "pull down reset gpio failed\n"); - - return ret; - -err_free_reset_gpio: - if (gpio_is_valid(pdata->reset_gpio)) - gpio_free(pdata->reset_gpio); -err_free_irq_gpio: - if (gpio_is_valid(pdata->irq_gpio)) - gpio_free(pdata->irq_gpio); -err_pwr_off: - return ret; -} - -/******************************************************* -Function: - Request interrupt. -Input: - ts: private data. -Output: - Executive outcomes. - 0: succeed, -1: failed. -*******************************************************/ -static int gtp_request_irq(struct goodix_ts_data *ts) -{ - int ret; - const u8 irq_table[] = GTP_IRQ_TAB; - - dev_dbg(&ts->client->dev, "INT trigger type:%x, irq=%d", - ts->int_trigger_type, - ts->client->irq); - - ret = request_threaded_irq(ts->client->irq, NULL, - goodix_ts_irq_handler, - irq_table[ts->int_trigger_type], - ts->client->name, ts); - if (ret) { - ts->use_irq = false; - return ret; - } - gtp_irq_disable(ts); - ts->use_irq = true; - return 0; -} - -/******************************************************* -Function: - Request input device Function. -Input: - ts:private data. -Output: - Executive outcomes. - 0: succeed, otherwise: failed. -*******************************************************/ -static int gtp_request_input_dev(struct goodix_ts_data *ts) -{ - int ret; - char phys[PHY_BUF_SIZE]; - int index = 0; - - ts->input_dev = input_allocate_device(); - if (ts->input_dev == NULL) { - dev_err(&ts->client->dev, - "Failed to allocate input device.\n"); - return -ENOMEM; - } - - ts->input_dev->evbit[0] = - BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); - __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); - /* in case of "out of memory" */ - input_mt_init_slots(ts->input_dev, 10, 0); - - if (ts->pdata->have_touch_key) { - for (index = 0; index < ts->pdata->num_button; index++) { - input_set_capability(ts->input_dev, - EV_KEY, ts->pdata->button_map[index]); - } - } - - if (ts->pdata->slide_wakeup) - input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); - - if (ts->pdata->with_pen) { /* pen support */ - __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); - __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); - __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit); - } - - if (ts->pdata->change_x2y) - swap(ts->abs_x_max, ts->abs_y_max); - - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, - 0, ts->abs_x_max, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, - 0, ts->abs_y_max, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 0, 255, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 0, 255, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, - 0, 255, 0, 0); - - snprintf(phys, PHY_BUF_SIZE, "input/ts"); - ts->input_dev->name = GOODIX_DEV_NAME; - ts->input_dev->phys = phys; - ts->input_dev->id.bustype = BUS_I2C; - ts->input_dev->id.vendor = 0xDEAD; - ts->input_dev->id.product = 0xBEEF; - ts->input_dev->id.version = 10427; - - ret = input_register_device(ts->input_dev); - if (ret) { - dev_err(&ts->client->dev, - "Register %s input device failed.\n", - ts->input_dev->name); - goto exit_free_inputdev; - } - - return 0; - -exit_free_inputdev: - input_free_device(ts->input_dev); - ts->input_dev = NULL; - return ret; -} - -static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) -{ - return (regulator_count_voltages(reg) > 0) ? - regulator_set_load(reg, load_uA) : 0; -} - -/** - * goodix_power_on - Turn device power ON - * @ts: driver private data - * - * Returns zero on success, else an error. - */ -static int goodix_power_on(struct goodix_ts_data *ts) -{ - int ret; - - if (ts->power_on) { - dev_info(&ts->client->dev, - "Device already power on\n"); - return 0; - } - - if (!IS_ERR(ts->avdd)) { - ret = reg_set_optimum_mode_check(ts->avdd, - GOODIX_VDD_LOAD_MAX_UA); - if (ret < 0) { - dev_err(&ts->client->dev, - "Regulator avdd set_opt failed rc=%d\n", ret); - goto err_set_opt_avdd; - } - ret = regulator_enable(ts->avdd); - if (ret) { - dev_err(&ts->client->dev, - "Regulator avdd enable failed ret=%d\n", ret); - goto err_enable_avdd; - } - } - - if (!IS_ERR(ts->vdd)) { - ret = regulator_set_voltage(ts->vdd, GOODIX_VTG_MIN_UV, - GOODIX_VTG_MAX_UV); - if (ret) { - dev_err(&ts->client->dev, - "Regulator set_vtg failed vdd ret=%d\n", ret); - goto err_set_vtg_vdd; - } - ret = reg_set_optimum_mode_check(ts->vdd, - GOODIX_VDD_LOAD_MAX_UA); - if (ret < 0) { - dev_err(&ts->client->dev, - "Regulator vdd set_opt failed rc=%d\n", ret); - goto err_set_opt_vdd; - } - ret = regulator_enable(ts->vdd); - if (ret) { - dev_err(&ts->client->dev, - "Regulator vdd enable failed ret=%d\n", ret); - goto err_enable_vdd; - } - } - - if (!IS_ERR(ts->vcc_i2c)) { - ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV, - GOODIX_I2C_VTG_MAX_UV); - if (ret) { - dev_err(&ts->client->dev, - "Regulator set_vtg failed vcc_i2c ret=%d\n", - ret); - goto err_set_vtg_vcc_i2c; - } - ret = reg_set_optimum_mode_check(ts->vcc_i2c, - GOODIX_VIO_LOAD_MAX_UA); - if (ret < 0) { - dev_err(&ts->client->dev, - "Regulator vcc_i2c set_opt failed rc=%d\n", - ret); - goto err_set_opt_vcc_i2c; - } - ret = regulator_enable(ts->vcc_i2c); - if (ret) { - dev_err(&ts->client->dev, - "Regulator vcc_i2c enable failed ret=%d\n", - ret); - regulator_disable(ts->vdd); - goto err_enable_vcc_i2c; - } - } - - ts->power_on = true; - return 0; - -err_enable_vcc_i2c: -err_set_opt_vcc_i2c: - if (!IS_ERR(ts->vcc_i2c)) - regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV); -err_set_vtg_vcc_i2c: - if (!IS_ERR(ts->vdd)) - regulator_disable(ts->vdd); -err_enable_vdd: -err_set_opt_vdd: - if (!IS_ERR(ts->vdd)) - regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV); -err_set_vtg_vdd: - if (!IS_ERR(ts->avdd)) - regulator_disable(ts->avdd); -err_enable_avdd: -err_set_opt_avdd: - ts->power_on = false; - return ret; -} - -/** - * goodix_power_off - Turn device power OFF - * @ts: driver private data - * - * Returns zero on success, else an error. - */ -static int goodix_power_off(struct goodix_ts_data *ts) -{ - int ret; - - if (!ts->power_on) { - dev_info(&ts->client->dev, - "Device already power off\n"); - return 0; - } - - if (!IS_ERR(ts->vcc_i2c)) { - ret = regulator_set_voltage(ts->vcc_i2c, 0, - GOODIX_I2C_VTG_MAX_UV); - if (ret < 0) - dev_err(&ts->client->dev, - "Regulator vcc_i2c set_vtg failed ret=%d\n", - ret); - ret = regulator_disable(ts->vcc_i2c); - if (ret) - dev_err(&ts->client->dev, - "Regulator vcc_i2c disable failed ret=%d\n", - ret); - } - - if (!IS_ERR(ts->vdd)) { - ret = regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV); - if (ret < 0) - dev_err(&ts->client->dev, - "Regulator vdd set_vtg failed ret=%d\n", ret); - ret = regulator_disable(ts->vdd); - if (ret) - dev_err(&ts->client->dev, - "Regulator vdd disable failed ret=%d\n", ret); - } - - if (!IS_ERR(ts->avdd)) { - ret = regulator_disable(ts->avdd); - if (ret) - dev_err(&ts->client->dev, - "Regulator avdd disable failed ret=%d\n", ret); - } - - ts->power_on = false; - return 0; -} - -/** - * goodix_power_init - Initialize device power - * @ts: driver private data - * - * Returns zero on success, else an error. - */ -static int goodix_power_init(struct goodix_ts_data *ts) -{ - int ret; - - ts->avdd = regulator_get(&ts->client->dev, "avdd"); - if (IS_ERR(ts->avdd)) { - ret = PTR_ERR(ts->avdd); - dev_info(&ts->client->dev, - "Regulator get failed avdd ret=%d\n", ret); - } - - ts->vdd = regulator_get(&ts->client->dev, "vdd"); - if (IS_ERR(ts->vdd)) { - ret = PTR_ERR(ts->vdd); - dev_info(&ts->client->dev, - "Regulator get failed vdd ret=%d\n", ret); - } - - ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc-i2c"); - if (IS_ERR(ts->vcc_i2c)) { - ret = PTR_ERR(ts->vcc_i2c); - dev_info(&ts->client->dev, - "Regulator get failed vcc_i2c ret=%d\n", ret); - } - - return 0; -} - -/** - * goodix_power_deinit - Deinitialize device power - * @ts: driver private data - * - * Returns zero on success, else an error. - */ -static int goodix_power_deinit(struct goodix_ts_data *ts) -{ - regulator_put(ts->vdd); - regulator_put(ts->vcc_i2c); - regulator_put(ts->avdd); - - return 0; -} - -static ssize_t gtp_fw_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - - if (!strlen(ts->fw_name)) - return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1, - "No fw name has been given."); - else - return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1, - "%s\n", ts->fw_name); -} - -static ssize_t gtp_fw_name_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - - if (size > GTP_FW_NAME_MAXSIZE - 1) { - dev_err(dev, "FW name size exceeds the limit."); - return -EINVAL; - } - - strlcpy(ts->fw_name, buf, size); - if (ts->fw_name[size-1] == '\n') - ts->fw_name[size-1] = '\0'; - - return size; -} - -static ssize_t gtp_fw_upgrade_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - - return snprintf(buf, 2, "%d\n", ts->fw_loading); -} - -static ssize_t gtp_fw_upgrade_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - unsigned int val; - int ret; - - if (size > 2) - return -EINVAL; - - ret = kstrtouint(buf, 10, &val); - if (ret) - return ret; - - if (ts->gtp_is_suspend) { - dev_err(&ts->client->dev, - "Can't start fw upgrade. Device is in suspend state"); - return -EBUSY; - } - - mutex_lock(&ts->input_dev->mutex); - if (!ts->fw_loading && val) { - disable_irq(ts->client->irq); - ts->fw_loading = true; - if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { - ret = gup_update_proc(NULL); - if (ret == FAIL) - dev_err(&ts->client->dev, - "Fail to update GTP firmware\n"); - } - ts->fw_loading = false; - enable_irq(ts->client->irq); - } - mutex_unlock(&ts->input_dev->mutex); - - return size; -} - -static ssize_t gtp_force_fw_upgrade_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - unsigned int val; - int ret; - - if (size > 2) - return -EINVAL; - - ret = kstrtouint(buf, 10, &val); - if (ret) - return ret; - - if (ts->gtp_is_suspend) { - dev_err(&ts->client->dev, - "Can't start fw upgrade. Device is in suspend state."); - return -EBUSY; - } - - mutex_lock(&ts->input_dev->mutex); - if (!ts->fw_loading && val) { - disable_irq(ts->client->irq); - ts->fw_loading = true; - ts->force_update = true; - if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { - ret = gup_update_proc(NULL); - if (ret == FAIL) - dev_err(&ts->client->dev, - "Fail to force update GTP firmware.\n"); - } - ts->force_update = false; - ts->fw_loading = false; - enable_irq(ts->client->irq); - } - mutex_unlock(&ts->input_dev->mutex); - - return size; -} - -static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP), - gtp_fw_name_show, - gtp_fw_name_store); -static DEVICE_ATTR(fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), - gtp_fw_upgrade_show, - gtp_fw_upgrade_store); -static DEVICE_ATTR(force_fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), - gtp_fw_upgrade_show, - gtp_force_fw_upgrade_store); - -static struct attribute *gtp_attrs[] = { - &dev_attr_fw_name.attr, - &dev_attr_fw_upgrade.attr, - &dev_attr_force_fw_upgrade.attr, - NULL -}; - -static const struct attribute_group gtp_attr_grp = { - .attrs = gtp_attrs, -}; - -static int gtp_debug_addr_is_valid(u16 addr) -{ - if (addr < GTP_VALID_ADDR_START || addr > GTP_VALID_ADDR_END) { - pr_err("GTP reg address is invalid: 0x%x\n", addr); - return false; - } - - return true; -} - -static int gtp_debug_data_set(void *_data, u64 val) -{ - struct goodix_ts_data *ts = _data; - - mutex_lock(&ts->input_dev->mutex); - if (gtp_debug_addr_is_valid(ts->addr)) - dev_err(&ts->client->dev, - "Writing to GTP registers not supported\n"); - mutex_unlock(&ts->input_dev->mutex); - - return 0; -} - -static int gtp_debug_data_get(void *_data, u64 *val) -{ - struct goodix_ts_data *ts = _data; - int ret; - u8 buf[3] = {0}; - - mutex_lock(&ts->input_dev->mutex); - buf[0] = ts->addr >> 8; - buf[1] = ts->addr & 0x00ff; - - if (gtp_debug_addr_is_valid(ts->addr)) { - ret = gtp_i2c_read(ts->client, buf, 3); - if (ret < 0) - dev_err(&ts->client->dev, - "GTP read register 0x%x failed (%d)\n", - ts->addr, ret); - else - *val = buf[2]; - } - mutex_unlock(&ts->input_dev->mutex); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, gtp_debug_data_get, - gtp_debug_data_set, "%llx\n"); - -static int gtp_debug_addr_set(void *_data, u64 val) -{ - struct goodix_ts_data *ts = _data; - - if (gtp_debug_addr_is_valid(val)) { - mutex_lock(&ts->input_dev->mutex); - ts->addr = val; - mutex_unlock(&ts->input_dev->mutex); - } - - return 0; -} - -static int gtp_debug_addr_get(void *_data, u64 *val) -{ - struct goodix_ts_data *ts = _data; - - mutex_lock(&ts->input_dev->mutex); - if (gtp_debug_addr_is_valid(ts->addr)) - *val = ts->addr; - mutex_unlock(&ts->input_dev->mutex); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, gtp_debug_addr_get, - gtp_debug_addr_set, "%llx\n"); - -static int gtp_debug_suspend_set(void *_data, u64 val) -{ - struct goodix_ts_data *ts = _data; - - mutex_lock(&ts->input_dev->mutex); - if (val) - goodix_ts_suspend(&ts->client->dev); - else - goodix_ts_resume(&ts->client->dev); - mutex_unlock(&ts->input_dev->mutex); - - return 0; -} - -static int gtp_debug_suspend_get(void *_data, u64 *val) -{ - struct goodix_ts_data *ts = _data; - - mutex_lock(&ts->input_dev->mutex); - *val = ts->gtp_is_suspend; - mutex_unlock(&ts->input_dev->mutex); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, gtp_debug_suspend_get, - gtp_debug_suspend_set, "%lld\n"); - -static int gtp_debugfs_init(struct goodix_ts_data *data) -{ - data->debug_base = debugfs_create_dir(GTP_DEBUGFS_DIR, NULL); - - if (IS_ERR_OR_NULL(data->debug_base)) { - dev_err(&data->client->dev, "Failed to create debugfs dir\n"); - return -EINVAL; - } - - if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_SUSPEND, - S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, - data->debug_base, - data, - &debug_suspend_fops)))) { - dev_err(&data->client->dev, "Failed to create suspend file\n"); - debugfs_remove_recursive(data->debug_base); - return -EINVAL; - } - - if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_DATA, - S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, - data->debug_base, - data, - &debug_data_fops)))) { - dev_err(&data->client->dev, "Failed to create data file\n"); - debugfs_remove_recursive(data->debug_base); - return -EINVAL; - } - - if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_ADDR, - S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, - data->debug_base, - data, - &debug_addr_fops)))) { - dev_err(&data->client->dev, "Failed to create addr file\n"); - debugfs_remove_recursive(data->debug_base); - return -EINVAL; - } - - return 0; -} - -static int goodix_ts_get_dt_coords(struct device *dev, char *name, - struct goodix_ts_platform_data *pdata) -{ - struct property *prop; - struct device_node *np = dev->of_node; - int rc; - u32 coords[GOODIX_COORDS_ARR_SIZE]; - - prop = of_find_property(np, name, NULL); - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - - rc = of_property_read_u32_array(np, name, coords, - GOODIX_COORDS_ARR_SIZE); - if (rc && (rc != -EINVAL)) { - dev_err(dev, "Unable to read %s\n", name); - return rc; - } - - if (!strcmp(name, "goodix,panel-coords")) { - pdata->panel_minx = coords[0]; - pdata->panel_miny = coords[1]; - pdata->panel_maxx = coords[2]; - pdata->panel_maxy = coords[3]; - } else if (!strcmp(name, "goodix,display-coords")) { - pdata->x_min = coords[0]; - pdata->y_min = coords[1]; - pdata->x_max = coords[2]; - pdata->y_max = coords[3]; - } else { - dev_err(dev, "unsupported property %s\n", name); - return -EINVAL; - } - - return 0; -} - -static int goodix_parse_dt(struct device *dev, - struct goodix_ts_platform_data *pdata) -{ - int rc; - struct device_node *np = dev->of_node; - struct property *prop; - u32 temp_val, num_buttons; - u32 button_map[MAX_BUTTONS]; - char prop_name[PROP_NAME_SIZE]; - int i, read_cfg_num, temp; - - rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata); - if (rc && (rc != -EINVAL)) - return rc; - - rc = goodix_ts_get_dt_coords(dev, "goodix,display-coords", pdata); - if (rc) - return rc; - - pdata->i2c_pull_up = of_property_read_bool(np, - "goodix,i2c-pull-up"); - - pdata->force_update = of_property_read_bool(np, - "goodix,force-update"); - - pdata->enable_power_off = of_property_read_bool(np, - "goodix,enable-power-off"); - - pdata->have_touch_key = of_property_read_bool(np, - "goodix,have-touch-key"); - - pdata->driver_send_cfg = of_property_read_bool(np, - "goodix,driver-send-cfg"); - - pdata->change_x2y = of_property_read_bool(np, - "goodix,change-x2y"); - - pdata->with_pen = of_property_read_bool(np, - "goodix,with-pen"); - - pdata->slide_wakeup = of_property_read_bool(np, - "goodix,slide-wakeup"); - - pdata->dbl_clk_wakeup = of_property_read_bool(np, - "goodix,dbl_clk_wakeup"); - - /* reset, irq gpio info */ - pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", - 0, &pdata->reset_gpio_flags); - if (pdata->reset_gpio < 0) - return pdata->reset_gpio; - - pdata->irq_gpio = of_get_named_gpio_flags(np, "interrupt-gpios", - 0, &pdata->irq_gpio_flags); - if (pdata->irq_gpio < 0) - return pdata->irq_gpio; - - rc = of_property_read_string(np, "goodix,product-id", - &pdata->product_id); - if (rc && (rc != -EINVAL)) { - dev_err(dev, "Failed to parse product_id."); - return -EINVAL; - } - - rc = of_property_read_string(np, "goodix,fw_name", - &pdata->fw_name); - if (rc && (rc != -EINVAL)) { - dev_err(dev, "Failed to parse firmware name.\n"); - return -EINVAL; - } - - prop = of_find_property(np, "goodix,button-map", NULL); - if (prop) { - num_buttons = prop->length / sizeof(temp_val); - if (num_buttons > MAX_BUTTONS) - return -EINVAL; - - rc = of_property_read_u32_array(np, - "goodix,button-map", button_map, - num_buttons); - if (rc) { - dev_err(dev, "Unable to read key codes\n"); - return rc; - } - pdata->num_button = num_buttons; - memcpy(pdata->button_map, button_map, - pdata->num_button * sizeof(u32)); - } - - read_cfg_num = 0; - for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) { - temp = 0; - snprintf(prop_name, sizeof(prop_name), "goodix,cfg-data%d", i); - prop = of_find_property(np, prop_name, &temp); - if (!prop || !prop->value) { - pdata->config_data_len[i] = 0; - pdata->config_data[i] = NULL; - continue; - } - pdata->config_data_len[i] = temp; - pdata->config_data[i] = devm_kzalloc(dev, - GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, - GFP_KERNEL); - if (!pdata->config_data[i]) { - dev_err(dev, - "Not enough memory for panel config data %d\n", - i); - return -ENOMEM; - } - pdata->config_data[i][0] = GTP_REG_CONFIG_DATA >> 8; - pdata->config_data[i][1] = GTP_REG_CONFIG_DATA & 0xff; - memcpy(&pdata->config_data[i][GTP_ADDR_LENGTH], - prop->value, pdata->config_data_len[i]); - read_cfg_num++; - } - dev_dbg(dev, "%d config data read from device tree\n", read_cfg_num); - - return 0; -} - -/******************************************************* -Function: - I2c probe. -Input: - client: i2c device struct. - id: device id. -Output: - Executive outcomes. - 0: succeed. -*******************************************************/ - -static int goodix_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct goodix_ts_platform_data *pdata; - struct goodix_ts_data *ts; - u16 version_info; - int ret; - - dev_dbg(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); - if (client->dev.of_node) { - pdata = devm_kzalloc(&client->dev, - sizeof(struct goodix_ts_platform_data), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - ret = goodix_parse_dt(&client->dev, pdata); - if (ret) - return ret; - } else { - pdata = client->dev.platform_data; - } - - if (!pdata) { - dev_err(&client->dev, "GTP invalid pdata\n"); - return -EINVAL; - } - - i2c_connect_client = client; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "GTP I2C not supported\n"); - return -ENODEV; - } - - ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); - if (!ts) - return -ENOMEM; - - memset(ts, 0, sizeof(*ts)); - ts->client = client; - ts->pdata = pdata; - /* For 2.6.39 & later use spin_lock_init(&ts->irq_lock) - * For 2.6.39 & before, use ts->irq_lock = SPIN_LOCK_UNLOCKED - */ - spin_lock_init(&ts->irq_lock); - i2c_set_clientdata(client, ts); - ts->gtp_rawdiff_mode = 0; - ts->power_on = false; - - ret = gtp_request_io_port(ts); - if (ret) { - dev_err(&client->dev, "GTP request IO port failed.\n"); - goto exit_free_client_data; - } - - ret = goodix_power_init(ts); - if (ret) { - dev_err(&client->dev, "GTP power init failed\n"); - goto exit_free_io_port; - } - - ret = goodix_power_on(ts); - if (ret) { - dev_err(&client->dev, "GTP power on failed\n"); - goto exit_deinit_power; - } - - gtp_reset_guitar(ts, 20); - - ret = gtp_i2c_test(client); - if (ret != 2) { - dev_err(&client->dev, "I2C communication ERROR\n"); - goto exit_power_off; - } - - if (pdata->force_update) - ts->force_update = true; - - if (pdata->fw_name) - strlcpy(ts->fw_name, pdata->fw_name, - strlen(pdata->fw_name) + 1); - - if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { - ret = gup_init_update_proc(ts); - if (ret < 0) { - dev_err(&client->dev, - "GTP Create firmware update thread error\n"); - goto exit_power_off; - } - } - ret = gtp_init_panel(ts); - if (ret < 0) { - dev_err(&client->dev, "GTP init panel failed\n"); - ts->abs_x_max = GTP_MAX_WIDTH; - ts->abs_y_max = GTP_MAX_HEIGHT; - ts->int_trigger_type = GTP_INT_TRIGGER; - } - - ret = gtp_request_input_dev(ts); - if (ret) { - dev_err(&client->dev, "GTP request input dev failed\n"); - goto exit_free_inputdev; - } - input_set_drvdata(ts->input_dev, ts); - - mutex_init(&ts->lock); -#if defined(CONFIG_FB) - ts->fb_notif.notifier_call = fb_notifier_callback; - ret = fb_register_client(&ts->fb_notif); - if (ret) - dev_err(&ts->client->dev, - "Unable to register fb_notifier: %d\n", - ret); -#elif defined(CONFIG_HAS_EARLYSUSPEND) - ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; - ts->early_suspend.suspend = goodix_ts_early_suspend; - ts->early_suspend.resume = goodix_ts_late_resume; - register_early_suspend(&ts->early_suspend); -#endif - - ts->goodix_wq = create_singlethread_workqueue("goodix_wq"); - INIT_WORK(&ts->work, goodix_ts_work_func); - - ret = gtp_request_irq(ts); - if (ret) - dev_info(&client->dev, "GTP request irq failed %d\n", ret); - else - dev_info(&client->dev, "GTP works in interrupt mode\n"); - - ret = gtp_read_fw_version(client, &version_info); - if (ret != 2) - dev_err(&client->dev, "GTP firmware version read failed\n"); - - ret = gtp_check_product_id(client); - if (ret != 0) { - dev_err(&client->dev, "GTP Product id doesn't match\n"); - goto exit_free_irq; - } - if (ts->use_irq) - gtp_irq_enable(ts); - -#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG - init_wr_node(client); -#endif - -#if GTP_ESD_PROTECT - gtp_esd_switch(client, SWITCH_ON); -#endif - ret = sysfs_create_group(&client->dev.kobj, >p_attr_grp); - if (ret < 0) { - dev_err(&client->dev, "sys file creation failed\n"); - goto exit_free_irq; - } - - ret = gtp_debugfs_init(ts); - if (ret != 0) - goto exit_remove_sysfs; - - init_done = true; - return 0; -exit_free_irq: - mutex_destroy(&ts->lock); -#if defined(CONFIG_FB) - if (fb_unregister_client(&ts->fb_notif)) - dev_err(&client->dev, - "Error occurred while unregistering fb_notifier\n"); -#elif defined(CONFIG_HAS_EARLYSUSPEND) - unregister_early_suspend(&ts->early_suspend); -#endif - if (ts->use_irq) - free_irq(client->irq, ts); - cancel_work_sync(&ts->work); - flush_workqueue(ts->goodix_wq); - destroy_workqueue(ts->goodix_wq); - - input_unregister_device(ts->input_dev); - if (ts->input_dev) { - input_free_device(ts->input_dev); - ts->input_dev = NULL; - } -exit_remove_sysfs: - sysfs_remove_group(&ts->input_dev->dev.kobj, >p_attr_grp); -exit_free_inputdev: - kfree(ts->config_data); -exit_power_off: - goodix_power_off(ts); -exit_deinit_power: - goodix_power_deinit(ts); -exit_free_io_port: - if (gpio_is_valid(pdata->reset_gpio)) - gpio_free(pdata->reset_gpio); - if (gpio_is_valid(pdata->irq_gpio)) - gpio_free(pdata->irq_gpio); -exit_free_client_data: - i2c_set_clientdata(client, NULL); - return ret; -} - -/******************************************************* -Function: - Goodix touchscreen driver release function. -Input: - client: i2c device struct. -Output: - Executive outcomes. 0---succeed. -*******************************************************/ -static int goodix_ts_remove(struct i2c_client *client) -{ - struct goodix_ts_data *ts = i2c_get_clientdata(client); - - sysfs_remove_group(&ts->input_dev->dev.kobj, >p_attr_grp); - -#if defined(CONFIG_FB) - if (fb_unregister_client(&ts->fb_notif)) - dev_err(&client->dev, - "Error occurred while unregistering fb_notifier\n"); -#elif defined(CONFIG_HAS_EARLYSUSPEND) - unregister_early_suspend(&ts->early_suspend); -#endif - mutex_destroy(&ts->lock); - -#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG - uninit_wr_node(); -#endif - -#if GTP_ESD_PROTECT - cancel_work_sync(gtp_esd_check_workqueue); - flush_workqueue(gtp_esd_check_workqueue); - destroy_workqueue(gtp_esd_check_workqueue); -#endif - - if (ts) { - if (ts->use_irq) - free_irq(client->irq, ts); - - cancel_work_sync(&ts->work); - flush_workqueue(ts->goodix_wq); - destroy_workqueue(ts->goodix_wq); - - input_unregister_device(ts->input_dev); - if (ts->input_dev) { - input_free_device(ts->input_dev); - ts->input_dev = NULL; - } - - if (gpio_is_valid(ts->pdata->reset_gpio)) - gpio_free(ts->pdata->reset_gpio); - if (gpio_is_valid(ts->pdata->irq_gpio)) - gpio_free(ts->pdata->irq_gpio); - - goodix_power_off(ts); - goodix_power_deinit(ts); - i2c_set_clientdata(client, NULL); - } - debugfs_remove_recursive(ts->debug_base); - - return 0; -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB) -/******************************************************* -Function: - Early suspend function. -Input: - h: early_suspend struct. -Output: - None. -*******************************************************/ -static int goodix_ts_suspend(struct device *dev) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - int ret = 0, i; - - if (ts->gtp_is_suspend) { - dev_dbg(&ts->client->dev, "Already in suspend state\n"); - return 0; - } - - mutex_lock(&ts->lock); - - if (ts->fw_loading) { - dev_info(&ts->client->dev, - "Fw upgrade in progress, can't go to suspend."); - mutex_unlock(&ts->lock); - return 0; - } - -#if GTP_ESD_PROTECT - gtp_esd_switch(ts->client, SWITCH_OFF); -#endif - - if (ts->pdata->slide_wakeup) { - ret = gtp_enter_doze(ts); - } else { - if (ts->use_irq) - gtp_irq_disable(ts); - - for (i = 0; i < GTP_MAX_TOUCH; i++) - gtp_touch_up(ts, i); - - input_sync(ts->input_dev); - - ret = gtp_enter_sleep(ts); - if (ret < 0) - dev_err(&ts->client->dev, "GTP early suspend failed.\n"); - } - /* to avoid waking up while not sleeping, - * delay 48 + 10ms to ensure reliability - */ - msleep(58); - mutex_unlock(&ts->lock); - ts->gtp_is_suspend = 1; - - return ret; -} - -/******************************************************* -Function: - Late resume function. -Input: - h: early_suspend struct. -Output: - None. -*******************************************************/ -static int goodix_ts_resume(struct device *dev) -{ - struct goodix_ts_data *ts = dev_get_drvdata(dev); - int ret = 0; - - if (!ts->gtp_is_suspend) { - dev_dbg(&ts->client->dev, "Already in awake state\n"); - return 0; - } - - mutex_lock(&ts->lock); - ret = gtp_wakeup_sleep(ts); - - if (ts->pdata->slide_wakeup) - doze_status = DOZE_DISABLED; - - if (ret <= 0) - dev_err(&ts->client->dev, "GTP resume failed\n"); - - if (ts->use_irq) - gtp_irq_enable(ts); - -#if GTP_ESD_PROTECT - gtp_esd_switch(ts->client, SWITCH_ON); -#endif - mutex_unlock(&ts->lock); - ts->gtp_is_suspend = 0; - - return ret; -} - -#if defined(CONFIG_FB) -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) -{ - struct fb_event *evdata = data; - int *blank; - struct goodix_ts_data *ts = - container_of(self, struct goodix_ts_data, fb_notif); - - if (evdata && evdata->data && event == FB_EVENT_BLANK && - ts && ts->client) { - blank = evdata->data; - if (*blank == FB_BLANK_UNBLANK) - goodix_ts_resume(&ts->client->dev); - else if (*blank == FB_BLANK_POWERDOWN) - goodix_ts_suspend(&ts->client->dev); - } - - return 0; -} -#elif defined(CONFIG_HAS_EARLYSUSPEND) -/* - * Function: - * Early suspend function. - * Input: - * h: early_suspend struct. - * Output: - * None. - */ -static void goodix_ts_early_suspend(struct early_suspend *h) -{ - struct goodix_ts_data *ts; - - ts = container_of(h, struct goodix_ts_data, early_suspend); - goodix_ts_suspend(&ts->client->dev); - return; -} - -/* - * Function: - * Late resume function. - * Input: - * h: early_suspend struct. - * Output: - * None. - */ -static void goodix_ts_late_resume(struct early_suspend *h) -{ - struct goodix_ts_data *ts; - - ts = container_of(h, struct goodix_ts_data, early_suspend); - goodix_ts_late_resume(ts); -} -#endif -#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/ - -#if GTP_ESD_PROTECT -/* - * Function: - * switch on & off esd delayed work - * Input: - * client: i2c device - * on: SWITCH_ON / SWITCH_OFF - * Output: - * void - */ -void gtp_esd_switch(struct i2c_client *client, int on) -{ - struct goodix_ts_data *ts; - - ts = i2c_get_clientdata(client); - if (on == SWITCH_ON) { - /* switch on esd */ - if (!ts->esd_running) { - ts->esd_running = 1; - dev_dbg(&client->dev, "Esd started\n"); - queue_delayed_work(gtp_esd_check_workqueue, - >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); - } - } else { - /* switch off esd */ - if (ts->esd_running) { - ts->esd_running = 0; - dev_dbg(&client->dev, "Esd cancelled\n"); - cancel_delayed_work_sync(>p_esd_check_work); - } - } -} - -/******************************************************* -Function: - Initialize external watchdog for esd protect -Input: - client: i2c device. -Output: - result of i2c write operation. - 1: succeed, otherwise: failed -*********************************************************/ -static int gtp_init_ext_watchdog(struct i2c_client *client) -{ - /* in case of recursively reset by calling gtp_i2c_write*/ - struct i2c_msg msg; - u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA}; - int ret; - int retries = 0; - - msg.flags = !I2C_M_RD; - msg.addr = client->addr; - msg.len = 4; - msg.buf = opr_buffer; - - while (retries < GTP_I2C_RETRY_5) { - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret == 1) - return 1; - retries++; - } - if (retries == GTP_I2C_RETRY_5) - dev_err(&client->dev, "init external watchdog failed!"); - return 0; -} - -/******************************************************* -Function: - Esd protect function. - Added external watchdog by meta, 2013/03/07 -Input: - work: delayed work -Output: - None. -*******************************************************/ -static void gtp_esd_check_func(struct work_struct *work) -{ - s32 retry; - s32 ret = -1; - struct goodix_ts_data *ts = NULL; - u8 test[4] = {0x80, 0x40}; - - ts = i2c_get_clientdata(i2c_connect_client); - - if (ts->gtp_is_suspend) { - dev_dbg(&ts->client->dev, "Esd terminated!\n"); - ts->esd_running = 0; - return; - } -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE - if (ts->enter_update) - return; -#endif - - for (retry = 0; retry < GTP_I2C_RETRY_3; retry++) { - ret = gtp_i2c_read(ts->client, test, 4); - - if ((ret < 0)) { - /* IC works abnormally..*/ - continue; - } else { - if ((test[2] == 0xAA) || (test[3] != 0xAA)) { - /* IC works abnormally..*/ - retry = GTP_I2C_RETRY_3; - break; - } - /* IC works normally, Write 0x8040 0xAA*/ - test[2] = 0xAA; - gtp_i2c_write(ts->client, test, 3); - break; - } - } - if (retry == GTP_I2C_RETRY_3) { - dev_err(&ts->client->dev, - "IC Working ABNORMALLY, Resetting Guitar...\n"); - gtp_reset_guitar(ts, 50); - } - - if (!ts->gtp_is_suspend) - queue_delayed_work(gtp_esd_check_workqueue, - >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); - else { - dev_dbg(&ts->client->dev, "Esd terminated!\n"); - ts->esd_running = 0; - } - - return; -} -#endif - -#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND)) -static const struct dev_pm_ops goodix_ts_dev_pm_ops = { - .suspend = goodix_ts_suspend, - .resume = goodix_ts_resume, -}; -#else -static const struct dev_pm_ops goodix_ts_dev_pm_ops = { -}; -#endif - -static const struct i2c_device_id goodix_ts_id[] = { - { GTP_I2C_NAME, 0 }, - { } -}; - -static const struct of_device_id goodix_match_table[] = { - { .compatible = "goodix,gt9xx", }, - { }, -}; - -static struct i2c_driver goodix_ts_driver = { - .probe = goodix_ts_probe, - .remove = goodix_ts_remove, -#ifdef CONFIG_HAS_EARLYSUSPEND - .suspend = goodix_ts_early_suspend, - .resume = goodix_ts_late_resume, -#endif - .id_table = goodix_ts_id, - .driver = { - .name = GTP_I2C_NAME, - .owner = THIS_MODULE, - .of_match_table = goodix_match_table, -#if CONFIG_PM - .pm = &goodix_ts_dev_pm_ops, -#endif - }, -}; - -/******************************************************* -Function: - Driver Install function. -Input: - None. -Output: - Executive Outcomes. 0---succeed. -********************************************************/ -static int __init goodix_ts_init(void) -{ - int ret; - -#if GTP_ESD_PROTECT - INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func); - gtp_esd_check_workqueue = create_workqueue("gtp_esd_check"); -#endif - ret = i2c_add_driver(&goodix_ts_driver); - return ret; -} - -/******************************************************* -Function: - Driver uninstall function. -Input: - None. -Output: - Executive Outcomes. 0---succeed. -********************************************************/ -static void __exit goodix_ts_exit(void) -{ - i2c_del_driver(&goodix_ts_driver); -} - -module_init(goodix_ts_init); -module_exit(goodix_ts_exit); - -MODULE_DESCRIPTION("GTP Series Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h deleted file mode 100644 index 1e85e2fce276..000000000000 --- a/drivers/input/touchscreen/gt9xx/gt9xx.h +++ /dev/null @@ -1,220 +0,0 @@ -/* drivers/input/touchscreen/gt9xx.h - * - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. - * - * 2010 - 2013 Goodix Technology. - * - * 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. - * - * This program is distributed in the hope that it will be a reference - * to you, when you are integrating the GOODiX's CTP IC into your system, - * 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 _GOODIX_GT9XX_H_ -#define _GOODIX_GT9XX_H_ - -#include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/uaccess.h> - -#if defined(CONFIG_FB) -#include <linux/notifier.h> -#include <linux/fb.h> -#elif defined(CONFIG_HAS_EARLYSUSPEND) -#include <linux/earlysuspend.h> -#define GOODIX_SUSPEND_LEVEL 1 -#endif - -#define MAX_BUTTONS 4 -#define GOODIX_MAX_CFG_GROUP 6 -#define GTP_FW_NAME_MAXSIZE 50 - -struct goodix_ts_platform_data { - int irq_gpio; - u32 irq_gpio_flags; - int reset_gpio; - u32 reset_gpio_flags; - const char *product_id; - const char *fw_name; - u32 x_max; - u32 y_max; - u32 x_min; - u32 y_min; - u32 panel_minx; - u32 panel_miny; - u32 panel_maxx; - u32 panel_maxy; - bool force_update; - bool i2c_pull_up; - bool enable_power_off; - size_t config_data_len[GOODIX_MAX_CFG_GROUP]; - u8 *config_data[GOODIX_MAX_CFG_GROUP]; - u32 button_map[MAX_BUTTONS]; - u8 num_button; - bool have_touch_key; - bool driver_send_cfg; - bool change_x2y; - bool with_pen; - bool slide_wakeup; - bool dbl_clk_wakeup; -}; -struct goodix_ts_data { - spinlock_t irq_lock; - struct i2c_client *client; - struct input_dev *input_dev; - struct goodix_ts_platform_data *pdata; - struct hrtimer timer; - struct workqueue_struct *goodix_wq; - struct work_struct work; - char fw_name[GTP_FW_NAME_MAXSIZE]; - struct delayed_work goodix_update_work; - s32 irq_is_disabled; - s32 use_irq; - u16 abs_x_max; - u16 abs_y_max; - u16 addr; - u8 max_touch_num; - u8 int_trigger_type; - u8 green_wake_mode; - u8 chip_type; - u8 *config_data; - u8 enter_update; - u8 gtp_is_suspend; - u8 gtp_rawdiff_mode; - u8 gtp_cfg_len; - u8 fixed_cfg; - u8 esd_running; - u8 fw_error; - bool power_on; - struct mutex lock; - bool fw_loading; - bool force_update; - struct regulator *avdd; - struct regulator *vdd; - struct regulator *vcc_i2c; -#if defined(CONFIG_FB) - struct notifier_block fb_notif; -#elif defined(CONFIG_HAS_EARLYSUSPEND) - struct early_suspend early_suspend; -#endif - struct dentry *debug_base; -}; - -extern u16 show_len; -extern u16 total_len; - -/***************************PART1:ON/OFF define*******************************/ -#define GTP_CUSTOM_CFG 0 -#define GTP_ESD_PROTECT 0 - -#define GTP_IRQ_TAB {\ - IRQ_TYPE_EDGE_RISING,\ - IRQ_TYPE_EDGE_FALLING,\ - IRQ_TYPE_LEVEL_LOW,\ - IRQ_TYPE_LEVEL_HIGH\ - } - - -#define GTP_IRQ_TAB_RISING 0 -#define GTP_IRQ_TAB_FALLING 1 -#if GTP_CUSTOM_CFG -#define GTP_MAX_HEIGHT 800 -#define GTP_MAX_WIDTH 480 -#define GTP_INT_TRIGGER GTP_IRQ_TAB_RISING -#else -#define GTP_MAX_HEIGHT 4096 -#define GTP_MAX_WIDTH 4096 -#define GTP_INT_TRIGGER GTP_IRQ_TAB_FALLING -#endif - -#define GTP_PRODUCT_ID_MAXSIZE 5 -#define GTP_PRODUCT_ID_BUFFER_MAXSIZE 6 -#define GTP_FW_VERSION_BUFFER_MAXSIZE 4 -#define GTP_MAX_TOUCH 5 -#define GTP_ESD_CHECK_CIRCLE 2000 /* jiffy: ms */ - -/***************************PART3:OTHER define*********************************/ -#define GTP_DRIVER_VERSION "V1.8.1<2013/09/01>" -#define GTP_I2C_NAME "Goodix-TS" -#define GTP_POLL_TIME 10 /* jiffy: ms*/ -#define GTP_ADDR_LENGTH 2 -#define GTP_CONFIG_MIN_LENGTH 186 -#define GTP_CONFIG_MAX_LENGTH 240 -#define FAIL 0 -#define SUCCESS 1 -#define SWITCH_OFF 0 -#define SWITCH_ON 1 - -/* Registers define */ -#define GTP_READ_COOR_ADDR 0x814E -#define GTP_REG_SLEEP 0x8040 -#define GTP_REG_SENSOR_ID 0x814A -#define GTP_REG_CONFIG_DATA 0x8047 -#define GTP_REG_FW_VERSION 0x8144 -#define GTP_REG_PRODUCT_ID 0x8140 - -#define GTP_I2C_RETRY_3 3 -#define GTP_I2C_RETRY_5 5 -#define GTP_I2C_RETRY_10 10 - -#define RESOLUTION_LOC 3 -#define TRIGGER_LOC 8 - -/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ -#define GTP_I2C_ADDRESS_HIGH 0x14 -#define GTP_I2C_ADDRESS_LOW 0x5D -#define GTP_VALID_ADDR_START 0x8040 -#define GTP_VALID_ADDR_END 0x8177 - -/* GTP CM_HEAD RW flags */ -#define GTP_RW_READ 0 -#define GTP_RW_WRITE 1 -#define GTP_RW_READ_IC_TYPE 2 -#define GTP_RW_WRITE_IC_TYPE 3 -#define GTP_RW_FILL_INFO 4 -#define GTP_RW_NO_WRITE 5 -#define GTP_RW_READ_ERROR 6 -#define GTP_RW_DISABLE_IRQ 7 -#define GTP_RW_READ_VERSION 8 -#define GTP_RW_ENABLE_IRQ 9 -#define GTP_RW_ENTER_UPDATE_MODE 11 -#define GTP_RW_LEAVE_UPDATE_MODE 13 -#define GTP_RW_UPDATE_FW 15 -#define GTP_RW_CHECK_RAWDIFF_MODE 17 - -/* GTP need flag or interrupt */ -#define GTP_NO_NEED 0 -#define GTP_NEED_FLAG 1 -#define GTP_NEED_INTERRUPT 2 - -/*****************************End of Part III********************************/ - -void gtp_esd_switch(struct i2c_client *client, int on); - -int gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, - u8 *rxbuf, int len); -int gtp_send_cfg(struct goodix_ts_data *ts); -void gtp_reset_guitar(struct goodix_ts_data *ts, int ms); -void gtp_irq_disable(struct goodix_ts_data *ts); -void gtp_irq_enable(struct goodix_ts_data *ts); - -#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG -s32 init_wr_node(struct i2c_client *client); -void uninit_wr_node(void); -#endif - -u8 gup_init_update_proc(struct goodix_ts_data *ts); -s32 gup_enter_update_mode(struct i2c_client *client); -void gup_leave_update_mode(struct i2c_client *client); -s32 gup_update_proc(void *dir); -extern struct i2c_client *i2c_connect_client; -#endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c deleted file mode 100644 index 6bc243492272..000000000000 --- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c +++ /dev/null @@ -1,1530 +0,0 @@ -/* drivers/input/touchscreen/gt9xx_update.c - * - * 2010 - 2012 Goodix Technology. - * Copyright (c) 2013-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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be a reference - * to you, when you are integrating the GOODiX's CTP IC into your system, - * 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. - * - * Latest Version:1.6 - * Author: andrew@goodix.com - * Revision Record: - * V1.0: - * first release. By Andrew, 2012/08/31 - * V1.2: - * add force update,GT9110P pid map. By Andrew, 2012/10/15 - * V1.4: - * 1. add config auto update function; - * 2. modify enter_update_mode; - * 3. add update file cal checksum. - * By Andrew, 2012/12/12 - * V1.6: - * 1. replace guitar_client with i2c_connect_client; - * 2. support firmware header array update. - * By Meta, 2013/03/11 - */ -#include "gt9xx.h" -#include <linux/firmware.h> -#include <linux/workqueue.h> -#include <linux/kernel.h> - -#define FIRMWARE_NAME_LEN_MAX 256 - -#define GUP_REG_HW_INFO 0x4220 -#define GUP_REG_FW_MSG 0x41E4 -#define GUP_REG_PID_VID 0x8140 - -#define GOODIX_FIRMWARE_FILE_NAME "_goodix_update_.bin" -#define GOODIX_CONFIG_FILE_NAME "_goodix_config_.cfg" - -#define FW_HEAD_LENGTH 14 -#define FW_SECTION_LENGTH 0x2000 -#define FW_DSP_ISP_LENGTH 0x1000 -#define FW_DSP_LENGTH 0x1000 -#define FW_BOOT_LENGTH 0x800 - -#define PACK_SIZE 256 -#define MAX_FRAME_CHECK_TIME 5 - -#define _bRW_MISCTL__SRAM_BANK 0x4048 -#define _bRW_MISCTL__MEM_CD_EN 0x4049 -#define _bRW_MISCTL__CACHE_EN 0x404B -#define _bRW_MISCTL__TMR0_EN 0x40B0 -#define _rRW_MISCTL__SWRST_B0_ 0x4180 -#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 -#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 -#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 -#define _rRW_MISCTL__BOOT_CTL_ 0x5094 - -#define FAIL 0 -#define SUCCESS 1 - -#define RESET_DELAY_US 20000 - -struct st_fw_head { - u8 hw_info[4]; /* hardware info */ - u8 pid[8]; /* product id */ - u16 vid; /* version id */ -} __packed; - -struct st_update_msg { - u8 force_update; - u8 fw_flag; - bool need_free; - u8 *fw_data; - u32 fw_len; - struct st_fw_head ic_fw_msg; -}; - -static struct st_update_msg update_msg; -u16 show_len; -u16 total_len; -u8 got_file_flag; -u8 searching_file; -/******************************************************* -Function: - Read data from the i2c slave device. -Input: - client: i2c device. - buf[0~1]: read start address. - buf[2~len-1]: read data buffer. - len: GTP_ADDR_LENGTH + read bytes count -Output: - numbers of i2c_msgs to transfer: - 2: succeed, otherwise: failed -*********************************************************/ -static s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len) -{ - s32 ret = -1; - u8 retries = 0; - struct i2c_msg msgs[2] = { - { - .flags = !I2C_M_RD, - .addr = client->addr, - .len = GTP_ADDR_LENGTH, - .buf = &buf[0], - }, - { - .flags = I2C_M_RD, - .addr = client->addr, - .len = len - GTP_ADDR_LENGTH, - .buf = &buf[GTP_ADDR_LENGTH], - }, - }; - - while (retries < 5) { - ret = i2c_transfer(client->adapter, msgs, 2); - if (ret == 2) - break; - retries++; - } - - if (retries == 5) { - dev_err(&client->dev, "I2C read retry limit over.\n"); - ret = -EIO; - } - - return ret; -} - -/******************************************************* -Function: - Write data to the i2c slave device. -Input: - client: i2c device. - buf[0~1]: write start address. - buf[2~len-1]: data buffer - len: GTP_ADDR_LENGTH + write bytes count -Output: - numbers of i2c_msgs to transfer: - 1: succeed, otherwise: failed -*********************************************************/ -s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len) -{ - s32 ret = -1; - u8 retries = 0; - struct i2c_msg msg = { - .flags = !I2C_M_RD, - .addr = client->addr, - .len = len, - .buf = buf, - }; - - while (retries < 5) { - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret == 1) - break; - retries++; - } - - if (retries == 5) { - dev_err(&client->dev, "I2C write retry limit over\n"); - ret = -EIO; - } - - return ret; -} - -static s32 gup_init_panel(struct goodix_ts_data *ts) -{ - struct i2c_client *client = ts->client; - u8 *config_data; - s32 ret = 0; - s32 i = 0; - u8 check_sum = 0; - u8 opr_buf[16]; - u8 sensor_id = 0; - - for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) - if (ts->pdata->config_data_len[i]) - break; - - if (i == GOODIX_MAX_CFG_GROUP) { - sensor_id = 0; - } else { - ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID, - &sensor_id, 1); - if (ret == SUCCESS) { - if (sensor_id >= GOODIX_MAX_CFG_GROUP) { - pr_err("Invalid sensor_id(0x%02X), No Config Sent", - sensor_id); - return -EINVAL; - } - } else { - pr_err("Failed to get sensor_id, No config sent\n"); - return -EINVAL; - } - } - - pr_debug("Sensor ID selected: %d", sensor_id); - - if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH || - !ts->pdata->config_data_len[sensor_id]) { - pr_err("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP", - sensor_id); - return -EINVAL; - } - - ret = gtp_i2c_read_dbl_check(client, GTP_REG_CONFIG_DATA, - &opr_buf[0], 1); - if (ret == SUCCESS) { - pr_debug("CFG_GROUP%d Config Version: %d, IC Config Version: %d", - sensor_id + 1, - ts->pdata->config_data[sensor_id][0], - opr_buf[0]); - - ts->pdata->config_data[sensor_id][0] = opr_buf[0]; - ts->fixed_cfg = 0; - } else { - pr_err("Failed to get ic config version. No config sent"); - return -EINVAL; - } - - config_data = ts->pdata->config_data[sensor_id]; - ts->config_data = ts->pdata->config_data[sensor_id]; - ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id]; - - pr_debug("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x\n", - ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type); - - config_data[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; - config_data[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); - config_data[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; - config_data[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); - - if (GTP_INT_TRIGGER == 0) /* RISING */ - config_data[TRIGGER_LOC] &= 0xfe; - else if (GTP_INT_TRIGGER == 1) /* FALLING */ - config_data[TRIGGER_LOC] |= 0x01; - - check_sum = 0; - for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) - check_sum += config_data[i]; - - config_data[ts->gtp_cfg_len] = (~check_sum) + 1; - - ret = gtp_send_cfg(ts); - if (ret < 0) - pr_err("Send config error\n"); - - ts->config_data = NULL; - ts->gtp_cfg_len = 0; - msleep(20); - return 0; -} - -static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len) -{ - u8 i = 0; - - msg[0] = (addr >> 8) & 0xff; - msg[1] = addr & 0xff; - - for (i = 0; i < 5; i++) - if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) - break; - - if (i >= 5) { - pr_err("Read data from 0x%02x%02x failed\n", msg[0], msg[1]); - return FAIL; - } - - return SUCCESS; -} - -static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) -{ - u8 i = 0; - u8 msg[3] = { - (addr >> 8) & 0xff, - addr & 0xff, - val, - }; - - for (i = 0; i < 5; i++) - if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) - break; - - if (i >= 5) { - pr_err("Set data to 0x%02x%02x failed\n", msg[0], msg[1]); - return FAIL; - } - - return SUCCESS; -} - -static u8 gup_get_ic_fw_msg(struct i2c_client *client) -{ - s32 ret = -1; - u8 retry = 0; - u8 buf[16]; - u8 i; - - /* step1:get hardware info */ - ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, - &buf[GTP_ADDR_LENGTH], 4); - if (ret == FAIL) { - pr_err("get hw_info failed,exit"); - return FAIL; - } - - /* buf[2~5]: 00 06 90 00 */ - /* hw_info: 00 90 06 00 */ - for (i = 0; i < 4; i++) - update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; - - pr_debug("IC Hardware info:%02x%02x%02x%02x\n", - update_msg.ic_fw_msg.hw_info[0], - update_msg.ic_fw_msg.hw_info[1], - update_msg.ic_fw_msg.hw_info[2], - update_msg.ic_fw_msg.hw_info[3]); - - /* step2:get firmware message */ - for (retry = 0; retry < 2; retry++) { - ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); - if (ret == FAIL) { - pr_err("Read firmware message fail\n"); - return ret; - } - - update_msg.force_update = buf[GTP_ADDR_LENGTH]; - if ((update_msg.force_update != 0xBE) && (!retry)) { - pr_info("The check sum in ic is error\n"); - pr_info("The IC will be updated by force\n"); - continue; - } - break; - } - pr_debug("IC force update flag:0x%x\n", update_msg.force_update); - - /* step3:get pid & vid */ - ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, - &buf[GTP_ADDR_LENGTH], 6); - if (ret == FAIL) { - pr_err("get pid & vid failed,exit"); - return FAIL; - } - - memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); - memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); - pr_debug("IC Product id:%s\n", update_msg.ic_fw_msg.pid); - - /* GT9XX PID MAPPING - * |-----FLASH-----RAM-----| - * |------918------918-----| - * |------968------968-----| - * |------913------913-----| - * |------913P-----913P----| - * |------927------927-----| - * |------927P-----927P----| - * |------9110-----9110----| - * |------9110P----9111----| - */ - if (update_msg.ic_fw_msg.pid[0] != 0) { - if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) { - pr_debug("IC Mapping Product id:%s\n", - update_msg.ic_fw_msg.pid); - memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); - } - } - - update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] + - (buf[GTP_ADDR_LENGTH + 5] << 8); - pr_debug("IC version id:%04x\n", update_msg.ic_fw_msg.vid); - - return SUCCESS; -} - -s32 gup_enter_update_mode(struct i2c_client *client) -{ - s32 ret = -1; - u8 retry = 0; - u8 rd_buf[3]; - struct goodix_ts_data *ts = i2c_get_clientdata(client); - - /* step1:RST output low last at least 2ms */ - gpio_direction_output(ts->pdata->reset_gpio, 0); - usleep_range(RESET_DELAY_US, RESET_DELAY_US + 1); - - /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */ - gpio_direction_output(ts->pdata->irq_gpio, - (client->addr == GTP_I2C_ADDRESS_HIGH)); - msleep(20); - - /* step3:RST output high reset guitar */ - gpio_direction_output(ts->pdata->reset_gpio, 1); - - /* 20121211 modify start */ - msleep(20); - while (retry++ < 200) { - /* step4:Hold ss51 & dsp */ - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); - if (ret <= 0) { - pr_debug("Hold ss51 & dsp I2C error,retry:%d\n", retry); - continue; - } - - /* step5:Confirm hold */ - ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); - if (ret <= 0) { - pr_debug("Hold ss51 & dsp I2C error,retry:%d\n", retry); - continue; - } - if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) { - pr_debug("Hold ss51 & dsp confirm SUCCESS\n"); - break; - } - pr_debug("Hold ss51 & dsp confirm 0x4180 failed,value:%d\n", - rd_buf[GTP_ADDR_LENGTH]); - } - if (retry >= 200) { - pr_err("Enter update Hold ss51 failed\n"); - return FAIL; - } - - /* step6:DSP_CK and DSP_ALU_CK PowerOn */ - ret = gup_set_ic_msg(client, 0x4010, 0x00); - - /* 20121211 modify end */ - return ret; -} - -void gup_leave_update_mode(struct i2c_client *client) -{ - struct goodix_ts_data *ts = i2c_get_clientdata(client); - - gpio_direction_input(ts->pdata->irq_gpio); - pr_debug("reset chip"); - gtp_reset_guitar(ts, 20); -} - -/* Get the correct nvram data - * The correct conditions: - * 1. the hardware info is the same - * 2. the product id is the same - * 3. the firmware version in update file is greater than the firmware - * version in ic or the check sum in ic is wrong - - * Update Conditions: - * 1. Same hardware info - * 2. Same PID - * 3. File PID > IC PID - - * Force Update Conditions: - * 1. Wrong ic firmware checksum - * 2. INVALID IC PID or VID - * 3. IC PID == 91XX || File PID == 91XX - */ - -static u8 gup_enter_update_judge(struct i2c_client *client, - struct st_fw_head *fw_head) -{ - u16 u16_tmp; - s32 i = 0; - - u16_tmp = fw_head->vid; - fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); - - pr_debug("FILE HARDWARE INFO:%02x%02x%02x%02x\n", fw_head->hw_info[0], - fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]); - pr_debug("FILE PID:%s\n", fw_head->pid); - pr_debug("FILE VID:%04x\n", fw_head->vid); - - pr_debug("IC HARDWARE INFO:%02x%02x%02x%02x\n", - update_msg.ic_fw_msg.hw_info[0], - update_msg.ic_fw_msg.hw_info[1], - update_msg.ic_fw_msg.hw_info[2], - update_msg.ic_fw_msg.hw_info[3]); - pr_debug("IC PID:%s\n", update_msg.ic_fw_msg.pid); - pr_debug("IC VID:%04x\n", update_msg.ic_fw_msg.vid); - - /* First two conditions */ - if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, - sizeof(update_msg.ic_fw_msg.hw_info))) { - pr_debug("Get the same hardware info\n"); - if (update_msg.force_update != 0xBE) { - pr_info("FW chksum error,need enter update\n"); - return SUCCESS; - } - - /* 20130523 start */ - if (strlen(update_msg.ic_fw_msg.pid) < 3) { - pr_info("Illegal IC pid, need enter update\n"); - return SUCCESS; - } - for (i = 0; i < 3; i++) { - if ((update_msg.ic_fw_msg.pid[i] < 0x30) || - (update_msg.ic_fw_msg.pid[i] > 0x39)) { - pr_info("Illegal IC pid, out of bound, need enter update\n"); - return SUCCESS; - } - } - /* 20130523 end */ - - if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, - (strlen(fw_head->pid) < 3 ? 3 : strlen(fw_head->pid)))) || - (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) || - (!memcmp(fw_head->pid, "91XX", 4))) { - if (!memcmp(fw_head->pid, "91XX", 4)) - pr_debug("Force none same pid update mode\n"); - else - pr_debug("Get the same pid\n"); - - /* The third condition */ - if (fw_head->vid > update_msg.ic_fw_msg.vid) { - pr_info("Need enter update"); - return SUCCESS; - } - pr_err("Don't meet the third condition\n"); - pr_err("File VID <= Ic VID, update aborted\n"); - } else { - pr_err("File PID != Ic PID, update aborted\n"); - } - } else { - pr_err("Different Hardware, update aborted\n"); - } - - return FAIL; -} - -static s8 gup_update_config(struct i2c_client *client, - const struct firmware *cfg) -{ - s32 ret = 0; - s32 i = 0; - s32 file_cfg_len = 0; - u32 chip_cfg_len = 0; - s32 count = 0; - u8 *buf; - u8 *file_config; - u8 pid[8]; - u8 high, low; - - if (!cfg || !cfg->data) { - pr_err("No need to upgrade config"); - return FAIL; - } - - ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6); - if (ret == FAIL) { - pr_err("Read product id & version id fail"); - return FAIL; - } - pid[5] = '\0'; - pr_debug("update cfg get pid:%s\n", &pid[GTP_ADDR_LENGTH]); - - chip_cfg_len = 186; - if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) || - !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) || - !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) { - chip_cfg_len = 228; - } - pr_debug("config file ASCII len: %zu", cfg->size); - pr_debug("need config binary len: %u", chip_cfg_len); - if ((cfg->size + 5) < chip_cfg_len * 5) { - pr_err("Config length error"); - return -EINVAL; - } - - buf = devm_kzalloc(&client->dev, cfg->size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - file_config = devm_kzalloc(&client->dev, chip_cfg_len + GTP_ADDR_LENGTH, - GFP_KERNEL); - if (!file_config) - return -ENOMEM; - - pr_debug("Delete illegal character"); - for (i = 0, count = 0; i < cfg->size; i++) { - if (cfg->data[i] == ' ' || cfg->data[i] == '\r' - || cfg->data[i] == '\n') - continue; - buf[count++] = cfg->data[i]; - } - - pr_debug("Ascii to hex"); - file_config[0] = GTP_REG_CONFIG_DATA >> 8; - file_config[1] = GTP_REG_CONFIG_DATA & 0xff; - for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i = i + 5) { - if ((buf[i] == '0') && ((buf[i + 1] == 'x') || - (buf[i + 1] == 'X'))) { - ret = hex2bin(&high, &buf[i + 2], 1); - if (ret) { - pr_err("Failed to convert high address from hex2bin"); - return ret; - } - ret = hex2bin(&low, &buf[i + 3], 1); - if (ret) { - pr_err("Failed to convert low address from hex2bin"); - return ret; - } - - if ((high == 0xFF) || (low == 0xFF)) { - ret = 0; - pr_err("Illegal config file"); - return ret; - } - file_config[file_cfg_len++] = (high<<4) + low; - } else { - ret = 0; - pr_err("Illegal config file"); - return ret; - } - } - - i = 0; - while (i++ < 5) { - ret = gup_i2c_write(client, file_config, file_cfg_len); - if (ret > 0) - break; - pr_err("Send config i2c error"); - } - - return ret; -} - -static s32 gup_get_firmware_file(struct i2c_client *client, - struct st_update_msg *msg, u8 *path) -{ - s32 ret; - const struct firmware *fw = NULL; - - ret = request_firmware(&fw, path, &client->dev); - if (ret < 0) { - dev_info(&client->dev, "Cannot get firmware - %s (%d)\n", - path, ret); - return -EEXIST; - } - - dev_dbg(&client->dev, "Config File: %s size: %zu", path, fw->size); - msg->fw_data = - devm_kzalloc(&client->dev, fw->size, GFP_KERNEL); - if (!msg->fw_data) { - release_firmware(fw); - return -ENOMEM; - } - - memcpy(msg->fw_data, fw->data, fw->size); - msg->fw_len = fw->size; - msg->need_free = true; - release_firmware(fw); - return 0; -} - -static u8 gup_check_firmware_name(struct i2c_client *client, - u8 **path_p) -{ - u8 len; - u8 *fname; - - if (!(*path_p)) { - *path_p = GOODIX_FIRMWARE_FILE_NAME; - return 0; - } - - len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX); - if (len >= FIRMWARE_NAME_LEN_MAX) { - dev_err(&client->dev, "firmware name too long"); - return -EINVAL; - } - - fname = strrchr(*path_p, '/'); - if (fname) { - fname = fname + 1; - *path_p = fname; - } - return 0; -} - -static u8 gup_check_update_file(struct i2c_client *client, - struct st_fw_head *fw_head, u8 *path) -{ - s32 ret = 0; - s32 i = 0; - s32 fw_checksum = 0; - u16 temp; - const struct firmware *fw = NULL; - - ret = request_firmware(&fw, GOODIX_CONFIG_FILE_NAME, &client->dev); - if (ret < 0) { - dev_info(&client->dev, "Cannot get config file - %s (%d)\n", - GOODIX_CONFIG_FILE_NAME, ret); - } else { - dev_dbg(&client->dev, - "Update config File: %s", GOODIX_CONFIG_FILE_NAME); - ret = gup_update_config(client, fw); - if (ret <= 0) - dev_err(&client->dev, "Update config failed"); - release_firmware(fw); - } - - update_msg.need_free = false; - update_msg.fw_len = 0; - - if (gup_check_firmware_name(client, &path)) - goto load_failed; - - if (gup_get_firmware_file(client, &update_msg, path)) - goto load_failed; - - memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH); - - /* check firmware legality */ - fw_checksum = 0; - for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH + - FW_DSP_LENGTH + FW_BOOT_LENGTH; i += 2) { - temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) + - update_msg.fw_data[FW_HEAD_LENGTH + i + 1]; - fw_checksum += temp; - } - - pr_debug("firmware checksum:%x", fw_checksum & 0xFFFF); - if (fw_checksum & 0xFFFF) { - dev_err(&client->dev, "Illegal firmware file"); - goto load_failed; - } - - return SUCCESS; - -load_failed: - if (update_msg.need_free) { - devm_kfree(&client->dev, update_msg.fw_data); - update_msg.need_free = false; - } - return FAIL; -} - -static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, - u16 total_length) -{ - s32 ret = 0; - u16 burn_addr = start_addr; - u16 frame_length = 0; - u16 burn_length = 0; - u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; - u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; - u8 retry = 0; - - pr_debug("Begin burn %dk data to addr 0x%x", (total_length / 1024), - start_addr); - while (burn_length < total_length) { - pr_debug("B/T:%04d/%04d", burn_length, total_length); - frame_length = ((total_length - burn_length) > PACK_SIZE) - ? PACK_SIZE : (total_length - burn_length); - wr_buf[0] = (u8)(burn_addr>>8); - rd_buf[0] = wr_buf[0]; - wr_buf[1] = (u8)burn_addr; - rd_buf[1] = wr_buf[1]; - memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], - frame_length); - - for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) { - ret = gup_i2c_write(client, wr_buf, - GTP_ADDR_LENGTH + frame_length); - if (ret <= 0) { - pr_err("Write frame data i2c error\n"); - continue; - } - ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + - frame_length); - if (ret <= 0) { - pr_err("Read back frame data i2c error\n"); - continue; - } - - if (memcmp(&wr_buf[GTP_ADDR_LENGTH], - &rd_buf[GTP_ADDR_LENGTH], frame_length)) { - pr_err("Check frame data fail,not equal\n"); - continue; - } else { - break; - } - } - if (retry >= MAX_FRAME_CHECK_TIME) { - pr_err("Burn frame data time out,exit\n"); - return FAIL; - } - burn_length += frame_length; - burn_addr += frame_length; - } - return SUCCESS; -} - -static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length) -{ - if (!update_msg.fw_data || - update_msg.fw_len < FW_HEAD_LENGTH + offset + length) { - pr_err( - "<<-GTP->> cannot load section data. fw_len=%d read end=%d\n", - update_msg.fw_len, - FW_HEAD_LENGTH + offset + length); - return FAIL; - } - memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], length); - - return SUCCESS; -} - -static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src, - u16 start_rd_addr, u16 chk_length) -{ - u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; - s32 ret = 0; - u16 recall_addr = start_rd_addr; - u16 recall_length = 0; - u16 frame_length = 0; - - while (recall_length < chk_length) { - frame_length = ((chk_length - recall_length) > PACK_SIZE) - ? PACK_SIZE : (chk_length - recall_length); - ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); - if (ret <= 0) { - pr_err("recall i2c error,exit\n"); - return FAIL; - } - - if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], - frame_length)) { - pr_err("Recall frame data fail,not equal\n"); - return FAIL; - } - - recall_length += frame_length; - recall_addr += frame_length; - } - pr_debug("Recall check %dk firmware success\n", (chk_length/1024)); - - return SUCCESS; -} - -static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, - u16 start_addr, u8 bank_cmd) -{ - s32 ret = 0; - u8 rd_buf[5]; - - /* step1:hold ss51 & dsp */ - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); - if (ret <= 0) { - pr_err("hold ss51 & dsp fail"); - return FAIL; - } - - /* step2:set scramble */ - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); - if (ret <= 0) { - pr_err("set scramble fail"); - return FAIL; - } - - /* step3:select bank */ - ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, - (bank_cmd >> 4)&0x0F); - if (ret <= 0) { - pr_err("select bank %d fail", - (bank_cmd >> 4)&0x0F); - return FAIL; - } - - /* step4:enable accessing code */ - ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); - if (ret <= 0) { - pr_err("enable accessing code fail"); - return FAIL; - } - - /* step5:burn 8k fw section */ - ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); - if (ret == FAIL) { - pr_err("burn fw_section fail"); - return FAIL; - } - - /* step6:hold ss51 & release dsp */ - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); - if (ret <= 0) { - pr_err("hold ss51 & release dsp fail"); - return FAIL; - } - /* must delay */ - msleep(20); - - /* step7:send burn cmd to move data to flash from sram */ - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); - if (ret <= 0) { - pr_err("send burn cmd fail"); - return FAIL; - } - pr_debug("Wait for the burn is complete"); - do { - ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); - if (ret <= 0) { - pr_err("Get burn state fail"); - return FAIL; - } - msleep(20); - } while (rd_buf[GTP_ADDR_LENGTH]); - - /* step8:select bank */ - ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, - (bank_cmd >> 4)&0x0F); - if (ret <= 0) { - pr_err("select bank %d fail", - (bank_cmd >> 4)&0x0F); - return FAIL; - } - - /* step9:enable accessing code */ - ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); - if (ret <= 0) { - pr_err("enable accessing code fail"); - return FAIL; - } - - /* step10:recall 8k fw section */ - ret = gup_recall_check(client, fw_section, start_addr, - FW_SECTION_LENGTH); - if (ret == FAIL) { - pr_err("recall check 8k firmware fail"); - return FAIL; - } - - /* step11:disable accessing code */ - ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); - if (ret <= 0) { - pr_err("disable accessing code fail"); - return FAIL; - } - - return SUCCESS; -} - -static u8 gup_burn_dsp_isp(struct i2c_client *client) -{ - s32 ret = 0; - u8 *fw_dsp_isp = NULL; - u8 retry = 0; - - pr_debug("Begin burn dsp isp"); - - /* step1:alloc memory */ - pr_debug("step1:alloc memory"); - while (retry++ < 5) { - fw_dsp_isp = devm_kzalloc(&client->dev, FW_DSP_ISP_LENGTH, - GFP_KERNEL); - if (fw_dsp_isp == NULL) { - continue; - } else { - break; - } - } - if (retry == 5) - return FAIL; - - /* step2:load dsp isp file data */ - pr_debug("step2:load dsp isp file data"); - ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH + - FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH); - if (ret == FAIL) { - pr_err("load firmware dsp_isp fail"); - return FAIL; - } - - /* step3:disable wdt,clear cache enable */ - pr_debug("step3:disable wdt,clear cache enable"); - ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); - if (ret <= 0) { - pr_err("disable wdt fail"); - return FAIL; - } - ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); - if (ret <= 0) { - pr_err("clear cache enable fail"); - return FAIL; - } - - /* step4:hold ss51 & dsp */ - pr_debug("step4:hold ss51 & dsp"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); - if (ret <= 0) { - pr_err("hold ss51 & dsp fail"); - return FAIL; - } - - /* step5:set boot from sram */ - pr_debug("step5:set boot from sram"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); - if (ret <= 0) { - pr_err("set boot from sram fail"); - return FAIL; - } - - /* step6:software reboot */ - pr_debug("step6:software reboot"); - ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); - if (ret <= 0) { - pr_err("software reboot fail"); - return FAIL; - } - - /* step7:select bank2 */ - pr_debug("step7:select bank2"); - ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); - if (ret <= 0) { - pr_err("select bank2 fail"); - return FAIL; - } - - /* step8:enable accessing code */ - pr_debug("step8:enable accessing code"); - ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); - if (ret <= 0) { - pr_err("enable accessing code fail"); - return FAIL; - } - - /* step9:burn 4k dsp_isp */ - pr_debug("step9:burn 4k dsp_isp"); - ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); - if (ret == FAIL) { - pr_err("burn dsp_isp fail"); - return FAIL; - } - - /* step10:set scramble */ - pr_debug("step10:set scramble"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); - if (ret <= 0) { - pr_err("set scramble fail"); - return FAIL; - } - - return SUCCESS; -} - -static u8 gup_burn_fw_ss51(struct i2c_client *client) -{ - u8 *fw_ss51 = NULL; - u8 retry = 0; - s32 ret = 0; - - pr_debug("Begin burn ss51 firmware"); - - /* step1:alloc memory */ - pr_debug("step1:alloc memory"); - while (retry++ < 5) { - fw_ss51 = devm_kzalloc(&client->dev, FW_SECTION_LENGTH, - GFP_KERNEL); - if (fw_ss51 == NULL) { - continue; - } else { - break; - } - } - if (retry == 5) - return FAIL; - - /* step2:load ss51 firmware section 1 file data */ - pr_debug("step2:load ss51 firmware section 1 file data"); - ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH); - if (ret == FAIL) { - pr_err("load ss51 firmware section 1 fail"); - return FAIL; - } - - /* step3:clear control flag */ - pr_debug("step3:clear control flag"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); - if (ret <= 0) { - pr_err("clear control flag fail"); - return FAIL; - } - - /* step4:burn ss51 firmware section 1 */ - pr_debug("step4:burn ss51 firmware section 1"); - ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); - if (ret == FAIL) { - pr_err("burn ss51 firmware section 1 fail"); - return FAIL; - } - - /* step5:load ss51 firmware section 2 file data */ - pr_debug("step5:load ss51 firmware section 2 file data"); - ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, - FW_SECTION_LENGTH); - if (ret == FAIL) { - pr_err("[burn_fw_ss51]load ss51 firmware section 2 fail\n"); - return FAIL; - } - - /* step6:burn ss51 firmware section 2 */ - pr_debug("step6:burn ss51 firmware section 2"); - ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); - if (ret == FAIL) { - pr_err("burn ss51 firmware section 2 fail"); - return FAIL; - } - - /* step7:load ss51 firmware section 3 file data */ - pr_debug("step7:load ss51 firmware section 3 file data"); - ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, - FW_SECTION_LENGTH); - if (ret == FAIL) { - pr_err("load ss51 firmware section 3 fail"); - return FAIL; - } - - /* step8:burn ss51 firmware section 3 */ - pr_debug("step8:burn ss51 firmware section 3"); - ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); - if (ret == FAIL) { - pr_err("burn ss51 firmware section 3 fail"); - return FAIL; - } - - /* step9:load ss51 firmware section 4 file data */ - pr_debug("step9:load ss51 firmware section 4 file data"); - ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, - FW_SECTION_LENGTH); - if (ret == FAIL) { - pr_err("load ss51 firmware section 4 fail"); - return FAIL; - } - - /* step10:burn ss51 firmware section 4 */ - pr_debug("step10:burn ss51 firmware section 4"); - ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); - if (ret == FAIL) { - pr_err("burn ss51 firmware section 4 fail"); - return FAIL; - } - - return SUCCESS; -} - -static u8 gup_burn_fw_dsp(struct i2c_client *client) -{ - s32 ret = 0; - u8 *fw_dsp = NULL; - u8 retry = 0; - u8 rd_buf[5]; - - pr_debug("Begin burn dsp firmware"); - /* step1:alloc memory */ - pr_debug("step1:alloc memory"); - while (retry++ < 5) { - fw_dsp = devm_kzalloc(&client->dev, FW_DSP_LENGTH, - GFP_KERNEL); - if (fw_dsp == NULL) { - continue; - } else { - break; - } - } - if (retry == 5) - return FAIL; - - /* step2:load firmware dsp */ - pr_debug("step2:load firmware dsp"); - ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH); - if (ret == FAIL) { - pr_err("load firmware dsp fail"); - return ret; - } - - /* step3:select bank3 */ - pr_debug("step3:select bank3"); - ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); - if (ret <= 0) { - pr_err("select bank3 fail"); - return FAIL; - } - - /* Step4:hold ss51 & dsp */ - pr_debug("step4:hold ss51 & dsp"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); - if (ret <= 0) { - pr_err("hold ss51 & dsp fail"); - return FAIL; - } - - /* step5:set scramble */ - pr_debug("step5:set scramble"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); - if (ret <= 0) { - pr_err("set scramble fail"); - return FAIL; - } - - /* step6:release ss51 & dsp */ - pr_debug("step6:release ss51 & dsp"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); - if (ret <= 0) { - pr_err("release ss51 & dsp fail"); - return FAIL; - } - /* must delay */ - msleep(20); - - /* step7:burn 4k dsp firmware */ - pr_debug("step7:burn 4k dsp firmware"); - ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); - if (ret == FAIL) { - pr_err("[burn_fw_dsp]burn fw_section fail\n"); - return ret; - } - - /* step8:send burn cmd to move data to flash from sram */ - pr_debug("step8:send burn cmd to move data to flash from sram"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); - if (ret <= 0) { - pr_err("send burn cmd fail"); - return ret; - } - pr_debug("Wait for the burn is complete"); - do { - ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); - if (ret <= 0) { - pr_err("Get burn state fail"); - return ret; - } - msleep(20); - } while (rd_buf[GTP_ADDR_LENGTH]); - - /* step9:recall check 4k dsp firmware */ - pr_debug("step9:recall check 4k dsp firmware"); - ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); - if (ret == FAIL) { - pr_err("recall check 4k dsp firmware fail"); - return ret; - } - - return SUCCESS; -} - -static u8 gup_burn_fw_boot(struct i2c_client *client) -{ - s32 ret = 0; - u8 *fw_boot = NULL; - u8 retry = 0; - u8 rd_buf[5]; - - pr_debug("Begin burn bootloader firmware"); - - /* step1:Alloc memory */ - pr_debug("step1:Alloc memory"); - while (retry++ < 5) { - fw_boot = devm_kzalloc(&client->dev, FW_BOOT_LENGTH, - GFP_KERNEL); - if (fw_boot == NULL) { - continue; - } else { - break; - } - } - if (retry == 5) - return FAIL; - - /* step2:load firmware bootloader */ - pr_debug("step2:load firmware bootloader"); - ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH + - FW_DSP_LENGTH), FW_BOOT_LENGTH); - if (ret == FAIL) { - pr_err("load firmware dsp fail"); - return ret; - } - - /* step3:hold ss51 & dsp */ - pr_debug("step3:hold ss51 & dsp"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); - if (ret <= 0) { - pr_err("hold ss51 & dsp fail"); - return FAIL; - } - - /* step4:set scramble */ - pr_debug("step4:set scramble"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); - if (ret <= 0) { - pr_err("set scramble fail"); - return FAIL; - } - - /* step5:release ss51 & dsp */ - pr_debug("step5:release ss51 & dsp"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); - if (ret <= 0) { - pr_err("release ss51 & dsp fail"); - return FAIL; - } - /* must delay */ - msleep(20); - - /* step6:select bank3 */ - pr_debug("step6:select bank3"); - ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); - if (ret <= 0) { - pr_err("select bank3 fail"); - return FAIL; - } - - /* step7:burn 2k bootloader firmware */ - pr_debug("step7:burn 2k bootloader firmware"); - ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); - if (ret == FAIL) { - pr_err("burn fw_section fail"); - return ret; - } - - /* step7:send burn cmd to move data to flash from sram */ - pr_debug("step7:send burn cmd to flash data from sram"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); - if (ret <= 0) { - pr_err("send burn cmd fail"); - return ret; - } - pr_debug("Wait for the burn is complete"); - do { - ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); - if (ret <= 0) { - pr_err("Get burn state fail"); - return ret; - } - msleep(20); - } while (rd_buf[GTP_ADDR_LENGTH]); - - /* step8:recall check 2k bootloader firmware */ - pr_debug("step8:recall check 2k bootloader firmware"); - ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); - if (ret == FAIL) { - pr_err("recall check 4k dsp firmware fail"); - return ret; - } - - /* step9:enable download DSP code */ - pr_debug("step9:enable download DSP code "); - ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); - if (ret <= 0) { - pr_err("enable download DSP code fail"); - return FAIL; - } - - /* step10:release ss51 & hold dsp */ - pr_debug("step10:release ss51 & hold dsp"); - ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); - if (ret <= 0) { - pr_err("release ss51 & hold dsp fail"); - return FAIL; - } - - return SUCCESS; -} - -s32 gup_update_proc(void *dir) -{ - s32 ret = 0; - u8 retry = 0; - struct st_fw_head fw_head; - struct goodix_ts_data *ts = NULL; - - pr_debug("Begin update."); - - if (!i2c_connect_client) { - pr_err("No i2c connect client for %s\n", __func__); - return -EIO; - } - - show_len = 1; - total_len = 100; - - ts = i2c_get_clientdata(i2c_connect_client); - - if (searching_file) { - /* exit .bin update file searching */ - searching_file = 0; - pr_info("Exiting searching .bin update file."); - /* wait for auto update quitted completely */ - while ((show_len != 200) && (show_len != 100)) - msleep(100); - } - - ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir); - if (ret == FAIL) { - pr_err("check update file fail"); - goto file_fail; - } - - /* gtp_reset_guitar(i2c_connect_client, 20); */ - ret = gup_get_ic_fw_msg(i2c_connect_client); - if (ret == FAIL) { - pr_err("get ic message fail"); - goto file_fail; - } - - if (ts->force_update) { - dev_dbg(&ts->client->dev, "Enter force update."); - } else { - ret = gup_enter_update_judge(ts->client, &fw_head); - if (ret == FAIL) { - dev_err(&ts->client->dev, - "Check *.bin file fail."); - goto file_fail; - } - } - - ts->enter_update = 1; - gtp_irq_disable(ts); -#if GTP_ESD_PROTECT - gtp_esd_switch(ts->client, SWITCH_OFF); -#endif - ret = gup_enter_update_mode(i2c_connect_client); - if (ret == FAIL) { - pr_err("enter update mode fail"); - goto update_fail; - } - - while (retry++ < 5) { - show_len = 10; - total_len = 100; - ret = gup_burn_dsp_isp(i2c_connect_client); - if (ret == FAIL) { - pr_err("burn dsp isp fail"); - continue; - } - - show_len += 10; - ret = gup_burn_fw_ss51(i2c_connect_client); - if (ret == FAIL) { - pr_err("burn ss51 firmware fail"); - continue; - } - - show_len += 40; - ret = gup_burn_fw_dsp(i2c_connect_client); - if (ret == FAIL) { - pr_err("burn dsp firmware fail"); - continue; - } - - show_len += 20; - ret = gup_burn_fw_boot(i2c_connect_client); - if (ret == FAIL) { - pr_err("burn bootloader fw fail"); - continue; - } - show_len += 10; - pr_info("UPDATE SUCCESS"); - break; - } - if (retry >= 5) { - pr_err("retry timeout,UPDATE FAIL"); - goto update_fail; - } - - pr_debug("leave update mode"); - gup_leave_update_mode(i2c_connect_client); - - msleep(100); - - if (ts->fw_error) { - pr_info("firmware error auto update, resent config\n"); - gup_init_panel(ts); - } - show_len = 100; - total_len = 100; - ts->enter_update = 0; - gtp_irq_enable(ts); - -#if GTP_ESD_PROTECT - gtp_esd_switch(ts->client, SWITCH_ON); -#endif - if (update_msg.need_free) { - devm_kfree(&ts->client->dev, update_msg.fw_data); - update_msg.need_free = false; - } - - return SUCCESS; - -update_fail: - ts->enter_update = 0; - gtp_irq_enable(ts); - -#if GTP_ESD_PROTECT - gtp_esd_switch(ts->client, SWITCH_ON); -#endif - -file_fail: - show_len = 200; - total_len = 100; - if (update_msg.need_free) { - devm_kfree(&ts->client->dev, update_msg.fw_data); - update_msg.need_free = false; - } - return FAIL; -} - -static void gup_update_work(struct work_struct *work) -{ - if (gup_update_proc(NULL) == FAIL) - pr_err("Goodix update work fail\n"); -} - -u8 gup_init_update_proc(struct goodix_ts_data *ts) -{ - dev_dbg(&ts->client->dev, "Ready to run update work\n"); - - INIT_DELAYED_WORK(&ts->goodix_update_work, gup_update_work); - schedule_delayed_work(&ts->goodix_update_work, - msecs_to_jiffies(3000)); - - return 0; -} diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c index 52bd5cfc37c8..168318f85e53 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c @@ -2218,10 +2218,12 @@ static int fwu_get_image_firmware_id(unsigned int *fw_id) __func__); return -ENOMEM; } - while (strptr[index] >= '0' && strptr[index] <= '9') { + while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0' + && strptr[index] <= '9') { firmware_id[index] = strptr[index]; index++; } + firmware_id[index] = '\0'; retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id); kfree(firmware_id); diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c index a0f1d5148c94..01b8e0878ea9 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c @@ -894,8 +894,13 @@ static int cam_smmu_attach_sec_cpp(int idx) rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_SECURE, MSM_CAMERA_TZ_HW_BLOCK_CPP); if (rc != 0) { - pr_err("fail to set secure mode for cpp, rc %d", rc); - return rc; + pr_err("secure mode TA notification for cpp unsuccessful, rc %d\n", + rc); + /* + * Although the TA notification failed, the flow should proceed + * without returning an error as at this point cpp had already + * entered the secure mode. + */ } iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH; @@ -910,8 +915,13 @@ static int cam_smmu_detach_sec_cpp(int idx) rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_NON_SECURE, MSM_CAMERA_TZ_HW_BLOCK_CPP); if (rc != 0) { - pr_err("fail to switch to non secure mode for cpp, rc %d", rc); - return rc; + pr_err("secure mode TA notification for cpp unsuccessful, rc %d\n", + rc); + /* + * Although the TA notification failed, the flow should proceed + * without returning an error, as at this point cpp is in secure + * mode and should be switched to non-secure regardless + */ } iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; @@ -950,8 +960,13 @@ static int cam_smmu_attach_sec_vfe_ns_stats(int idx) rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_SECURE, MSM_CAMERA_TZ_HW_BLOCK_ISP); if (rc != 0) { - pr_err("fail to set secure mode for vfe, rc %d", rc); - return rc; + pr_err("secure mode TA notification for vfe unsuccessful, rc %d\n", + rc); + /* + * Although the TA notification failed, the flow should proceed + * without returning an error as at this point vfe had already + * entered the secure mode + */ } return 0; @@ -964,8 +979,13 @@ static int cam_smmu_detach_sec_vfe_ns_stats(int idx) rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_NON_SECURE, MSM_CAMERA_TZ_HW_BLOCK_ISP); if (rc != 0) { - pr_err("fail to switch to non secure mode for vfe, rc %d", rc); - return rc; + pr_err("secure mode TA notification for vfe unsuccessful, rc %d\n", + rc); + /* + * Although the TA notification failed, the flow should proceed + * without returning an error, as at this point vfe is in secure + * mode and should be switched to non-secure regardless + */ } /* diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index 8d66232dbda1..5dbed80f5b85 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -229,8 +229,8 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, mapped_info->paddr += accu_length; accu_length += qbuf_buf->planes[i].length; - CDBG("%s: plane: %d addr:%lu\n", - __func__, i, (unsigned long)mapped_info->paddr); + CDBG("%s: plane: %d addr:%pK\n", + __func__, i, (void *)mapped_info->paddr); } buf_info->num_planes = qbuf_buf->num_planes; @@ -312,8 +312,8 @@ static int msm_isp_map_buf(struct msm_isp_buf_mgr *buf_mgr, pr_err_ratelimited("%s: cannot map address", __func__); goto smmu_map_error; } - CDBG("%s: addr:%lu\n", - __func__, (unsigned long)mapped_info->paddr); + CDBG("%s: addr:%pK\n", + __func__, (void *)mapped_info->paddr); return rc; smmu_map_error: @@ -1282,6 +1282,7 @@ static int msm_isp_deinit_isp_buf_mgr( int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, unsigned int cmd, void *arg) { + int rc = -EINVAL; switch (cmd) { case VIDIOC_MSM_ISP_REQUEST_BUF: { struct msm_isp_buf_request *buf_req = arg; @@ -1290,7 +1291,7 @@ int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, memcpy(&buf_req_ver2, buf_req, sizeof(struct msm_isp_buf_request)); buf_req_ver2.security_mode = NON_SECURE_MODE; - buf_mgr->ops->request_buf(buf_mgr, &buf_req_ver2); + rc = buf_mgr->ops->request_buf(buf_mgr, &buf_req_ver2); memcpy(buf_req, &buf_req_ver2, sizeof(struct msm_isp_buf_request)); break; @@ -1298,35 +1299,35 @@ int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, case VIDIOC_MSM_ISP_REQUEST_BUF_VER2: { struct msm_isp_buf_request_ver2 *buf_req_ver2 = arg; - buf_mgr->ops->request_buf(buf_mgr, buf_req_ver2); + rc = buf_mgr->ops->request_buf(buf_mgr, buf_req_ver2); break; } case VIDIOC_MSM_ISP_ENQUEUE_BUF: { struct msm_isp_qbuf_info *qbuf_info = arg; - buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info); + rc = buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info); break; } case VIDIOC_MSM_ISP_DEQUEUE_BUF: { struct msm_isp_qbuf_info *qbuf_info = arg; - buf_mgr->ops->dequeue_buf(buf_mgr, qbuf_info); + rc = buf_mgr->ops->dequeue_buf(buf_mgr, qbuf_info); break; } case VIDIOC_MSM_ISP_RELEASE_BUF: { struct msm_isp_buf_request *buf_req = arg; - buf_mgr->ops->release_buf(buf_mgr, buf_req->handle); + rc = buf_mgr->ops->release_buf(buf_mgr, buf_req->handle); break; } case VIDIOC_MSM_ISP_UNMAP_BUF: { struct msm_isp_unmap_buf_req *unmap_req = arg; - buf_mgr->ops->unmap_buf(buf_mgr, unmap_req->fd); + rc = buf_mgr->ops->unmap_buf(buf_mgr, unmap_req->fd); break; } } - return 0; + return rc; } static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr, @@ -1335,14 +1336,15 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr, struct msm_isp_buffer *bufs = NULL; uint32_t i = 0, j = 0, k = 0, rc = 0; char *print_buf = NULL, temp_buf[100]; - uint32_t start_addr = 0, end_addr = 0, print_buf_size = 2000; + uint32_t print_buf_size = 2000; + unsigned long start_addr = 0, end_addr = 0; int buf_addr_delta = -1; int temp_delta = 0; uint32_t debug_stream_id = 0; uint32_t debug_buf_idx = 0; uint32_t debug_buf_plane = 0; - uint32_t debug_start_addr = 0; - uint32_t debug_end_addr = 0; + unsigned long debug_start_addr = 0; + unsigned long debug_end_addr = 0; uint32_t debug_frame_id = 0; enum msm_isp_buffer_state debug_state = MSM_ISP_BUFFER_STATE_UNUSED; unsigned long flags; @@ -1401,8 +1403,8 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr, debug_stream_id, debug_frame_id); pr_err("%s: nearby buf index %d, plane %d, state %d\n", __func__, debug_buf_idx, debug_buf_plane, debug_state); - pr_err("%s: buf address 0x%x -- 0x%x\n", __func__, - debug_start_addr, debug_end_addr); + pr_err("%s: buf address %pK -- %pK\n", __func__, + (void *)debug_start_addr, (void *)debug_end_addr); if (BUF_DEBUG_FULL) { print_buf = kzalloc(print_buf_size, GFP_ATOMIC); @@ -1437,9 +1439,10 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr, mapped_info[k].len; snprintf(temp_buf, sizeof(temp_buf), - " buf %d plane %d start_addr %x end_addr %x\n", - j, k, start_addr, - end_addr); + " buf %d plane %d start_addr %pK end_addr %pK\n", + j, k, + (void *)start_addr, + (void *)end_addr); strlcat(print_buf, temp_buf, print_buf_size); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index bb3f0dca9d92..f2f3388b41c1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -590,9 +590,9 @@ int vfe_hw_probe(struct platform_device *pdev) (struct msm_vfe_hardware_info *) match_dev->data; /* Cx ipeak support */ if (of_find_property(pdev->dev.of_node, - "qcom,vfe_cx_ipeak", NULL)) { + "qcom,vfe-cx-ipeak", NULL)) { vfe_dev->vfe_cx_ipeak = cx_ipeak_register( - pdev->dev.of_node, "qcom,vfe_cx_ipeak"); + pdev->dev.of_node, "qcom,vfe-cx-ipeak"); } } else { vfe_dev->hw_info = (struct msm_vfe_hardware_info *) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index e54342e3935a..0325c5ded3cf 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -768,7 +768,6 @@ struct vfe_device { size_t num_hvx_clk; size_t num_norm_clk; enum cam_ahb_clk_vote ahb_vote; - bool turbo_vote; struct cx_ipeak_client *vfe_cx_ipeak; /* Sync variables*/ @@ -809,6 +808,7 @@ struct vfe_device { uint32_t is_split; uint32_t dual_vfe_enable; unsigned long page_fault_addr; + uint32_t vfe_hw_limit; /* Debug variables */ int dump_reg; @@ -830,6 +830,8 @@ struct vfe_device { uint32_t recovery_irq1_mask; /* Store the buf_idx for pd stats RDI stream */ uint8_t pd_buf_idx; + /* total bandwidth per vfe */ + uint64_t total_bandwidth; }; struct vfe_parent_device { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index d829aefe6c98..b704e84cc140 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -331,7 +331,6 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) goto ahb_vote_fail; } vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE; - vfe_dev->turbo_vote = 0; vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = vfe_dev->vfe_base; @@ -2563,31 +2562,53 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate) int rc = 0; int clk_idx = vfe_dev->hw_info->vfe_clk_idx; int ret; + long clk_rate, prev_clk_rate; + clk_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); + if (vfe_dev->msm_isp_vfe_clk_rate == clk_rate) + return rc; + + prev_clk_rate = vfe_dev->msm_isp_vfe_clk_rate; + vfe_dev->msm_isp_vfe_clk_rate = clk_rate; + /* + * if cx_ipeak is supported vote first so that dsp throttling is + * reduced before we go to turbo + */ + if ((vfe_dev->vfe_cx_ipeak) && + (vfe_dev->msm_isp_vfe_clk_rate >= + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) && + prev_clk_rate < + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) { + ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, true); + if (ret) { + pr_err("%s: cx_ipeak_update failed %d\n", + __func__, ret); + return ret; + } + } + /*set vfe clock*/ rc = msm_camera_clk_set_rate(&vfe_dev->pdev->dev, vfe_dev->vfe_clk[clk_idx], *rate); if (rc < 0) return rc; - *rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); - vfe_dev->msm_isp_vfe_clk_rate = *rate; - if (vfe_dev->vfe_cx_ipeak) { - if (vfe_dev->msm_isp_vfe_clk_rate >= - vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] - [vfe_dev->hw_info->vfe_clk_idx] && - vfe_dev->turbo_vote == 0) { - ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, true); - if (ret) - pr_debug("%s: cx_ipeak_update failed %d\n", - __func__, ret); - else - vfe_dev->turbo_vote = 1; - } else if (vfe_dev->turbo_vote == 1) { - ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, false); - if (ret) - pr_debug("%s: cx_ipeak_update failed %d\n", - __func__, ret); - else - vfe_dev->turbo_vote = 0; + /* + * if cx_ipeak is supported remove the vote for non-turbo clock and + * if voting done earlier + */ + if ((vfe_dev->vfe_cx_ipeak) && + (vfe_dev->msm_isp_vfe_clk_rate < + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) && + prev_clk_rate >= + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) { + ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, false); + if (ret) { + pr_err("%s: cx_ipeak_update failed %d\n", + __func__, ret); + return ret; } } if (vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg) @@ -2742,6 +2763,8 @@ int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable) int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev) { int rc = 0; + void __iomem *vfe_fuse_base; + uint32_t vfe_fuse_base_size; vfe_dev->vfe_base = msm_camera_get_reg_base(vfe_dev->pdev, "vfe", 0); if (!vfe_dev->vfe_base) @@ -2766,7 +2789,18 @@ int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev) rc = -ENOMEM; goto get_res_fail; } - + vfe_dev->vfe_hw_limit = 0; + vfe_fuse_base = msm_camera_get_reg_base(vfe_dev->pdev, + "vfe_fuse", 0); + vfe_fuse_base_size = msm_camera_get_res_size(vfe_dev->pdev, + "vfe_fuse"); + if (vfe_fuse_base) { + if (vfe_fuse_base_size) + vfe_dev->vfe_hw_limit = + (msm_camera_io_r(vfe_fuse_base) >> 5) & 0x1; + msm_camera_put_reg_base(vfe_dev->pdev, vfe_fuse_base, + "vfe_fuse", 0); + } rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_regulators(vfe_dev); if (rc) goto get_regulator_fail; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 4e74851dc67d..8488405b561a 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1734,7 +1734,7 @@ int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev, } temp = buf->mapped_info[0].paddr + buf->mapped_info[0].len; - pr_err("%s: stream %x ping bit %d uses buffer %pa-%pa, num_isp %d\n", + pr_err("%s: stream %x ping bit %d uses buffer %pK-%pK, num_isp %d\n", __func__, stream_info->stream_src, pingpong_bit, &buf->mapped_info[0].paddr, &temp, @@ -1743,10 +1743,10 @@ int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev, for (i = 0; i < stream_info->num_planes; i++) { for (k = 0; k < stream_info->num_isp; k++) { pr_debug( - "%s: stream_id %x ping-pong %d plane %d start_addr %lu addr_offset %x len %zx stride %d scanline %d\n" + "%s: stream_id %x ping-pong %d plane %d start_addr %pK addr_offset %x len %zx stride %d scanline %d\n" , __func__, stream_info->stream_id, - pingpong_bit, i, (unsigned long) - buf->mapped_info[i].paddr, + pingpong_bit, i, + (void *)buf->mapped_info[i].paddr, stream_info-> plane_cfg[k][i].plane_addr_offset, buf->mapped_info[i].len, @@ -2382,7 +2382,6 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) struct msm_vfe_axi_stream *stream_info; uint64_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; uint32_t num_pix_streams = 0; - uint64_t total_bandwidth = 0; int vfe_idx; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { @@ -2401,10 +2400,10 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) } } } - total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; + vfe_dev->total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (total_bandwidth + vfe_dev->hw_info->min_ab), - (total_bandwidth + vfe_dev->hw_info->min_ib)); + (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ab), + (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ib)); if (rc < 0) pr_err("%s: update failed\n", __func__); @@ -2412,6 +2411,66 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) return rc; } +int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) +{ + int i, rc = 0; + uint64_t total_bandwidth = 0; + int vfe_idx; + unsigned long flags; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_dual_lpm_mode *ab_ib_vote = NULL; + + ab_ib_vote = (struct msm_vfe_dual_lpm_mode *)arg; + if (!ab_ib_vote) { + pr_err("%s: ab_ib_vote is NULL !!!\n", __func__); + rc = -1; + return rc; + } + if (ab_ib_vote->lpm_mode) { + for (i = 0; i < ab_ib_vote->num_src; i++) { + stream_info = + msm_isp_get_stream_common_data(vfe_dev, + ab_ib_vote->stream_src[i]); + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == ACTIVE) { + vfe_idx = + msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); + total_bandwidth += + stream_info->bandwidth[ + vfe_idx]; + stream_info->state = PAUSING; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + } + vfe_dev->total_bandwidth -= total_bandwidth; + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (vfe_dev->total_bandwidth - vfe_dev->hw_info->min_ab), + (vfe_dev->total_bandwidth - vfe_dev->hw_info->min_ib)); + } else { + for (i = 0; i < ab_ib_vote->num_src; i++) { + stream_info = + msm_isp_get_stream_common_data(vfe_dev, + ab_ib_vote->stream_src[i]); + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == PAUSING) { + vfe_idx = + msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); + total_bandwidth += + stream_info->bandwidth[ + vfe_idx]; + stream_info->state = ACTIVE; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + } + vfe_dev->total_bandwidth += total_bandwidth; + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ab), + (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ib)); + } + return rc; +} static int msm_isp_init_stream_ping_pong_reg( struct msm_vfe_axi_stream *stream_info) { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index f9ae5fb74281..65009cb22286 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -160,4 +160,6 @@ static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream( int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, uint32_t buf_idx); +int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, + void *arg); #endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index f40af6e95272..9ce2218d5e0d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -1231,6 +1231,12 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) int vfe_idx; int k; + if (update_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s: Invalid num_streams %d\n", + __func__, update_cmd->num_streams); + return -EINVAL; + } + /*validate request*/ for (i = 0; i < update_cmd->num_streams; i++) { update_info = (struct msm_vfe_axi_stream_cfg_update_info *) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 86b500973538..507198721ccc 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -951,6 +951,11 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, rc = msm_isp_dual_hw_master_slave_sync(vfe_dev, arg); mutex_unlock(&vfe_dev->core_mutex); break; + case VIDIOC_MSM_ISP_DUAL_HW_LPM_MODE: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_ab_ib_update_lpm_mode(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; case VIDIOC_MSM_ISP_FETCH_ENG_START: case VIDIOC_MSM_ISP_MAP_BUF_START_FE: mutex_lock(&vfe_dev->core_mutex); @@ -1423,6 +1428,20 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, vfe_dev->vfe_ub_policy = *cfg_data; break; } + case GET_VFE_HW_LIMIT: { + uint32_t *hw_limit = NULL; + + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + + hw_limit = (uint32_t *)cfg_data; + *hw_limit = vfe_dev->vfe_hw_limit; + break; + } } return 0; } diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 064c1e8c5bab..8402e31364b9 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -980,6 +980,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) { int rc = 0; uint32_t vbif_version; + cpp_dev->turbo_vote = 0; rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, true); @@ -1432,6 +1433,14 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return -ENODEV; } + if (cpp_dev->turbo_vote == 1) { + rc = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, false); + if (rc) + pr_err("cx_ipeak_update failed"); + else + cpp_dev->turbo_vote = 0; + } + cpp_dev->cpp_open_cnt--; if (cpp_dev->cpp_open_cnt == 0) { pr_debug("irq_status: 0x%x\n", @@ -2116,6 +2125,8 @@ static int msm_cpp_check_buf_type(struct msm_buf_mngr_info *buff_mgr_info, /* More or equal bufs as Input buffer */ num_output_bufs = new_frame->batch_info.batch_size; } + if (num_output_bufs > MSM_OUTPUT_BUF_CNT) + return 0; for (i = 0; i < num_output_bufs; i++) { new_frame->output_buffer_info[i].index = buff_mgr_info->user_buf.buf_idx[i]; @@ -2953,6 +2964,38 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, return 0; } +unsigned long cpp_cx_ipeak_update(struct cpp_device *cpp_dev, + unsigned long clock, int idx) +{ + unsigned long clock_rate = 0; + int ret = 0; + + if ((clock >= cpp_dev->hw_info.freq_tbl + [(cpp_dev->hw_info.freq_tbl_count) - 1]) && + (cpp_dev->turbo_vote == 0)) { + ret = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, true); + if (ret) { + pr_err("cx_ipeak voting failed setting clock below turbo"); + clock = cpp_dev->hw_info.freq_tbl + [(cpp_dev->hw_info.freq_tbl_count) - 2]; + } else { + cpp_dev->turbo_vote = 1; + } + clock_rate = msm_cpp_set_core_clk(cpp_dev, clock, idx); + } else if (clock < cpp_dev->hw_info.freq_tbl + [(cpp_dev->hw_info.freq_tbl_count) - 1]) { + clock_rate = msm_cpp_set_core_clk(cpp_dev, clock, idx); + if (cpp_dev->turbo_vote == 1) { + ret = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, false); + if (ret) + pr_err("cx_ipeak unvoting failed"); + else + cpp_dev->turbo_vote = 0; + } + } + return clock_rate; +} + long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -3335,9 +3378,15 @@ STREAM_BUFF_END: mutex_unlock(&cpp_dev->mutex); return -EINVAL; } - clock_rate = msm_cpp_set_core_clk(cpp_dev, - clock_settings.clock_rate, - msm_cpp_core_clk_idx); + if (cpp_dev->cpp_cx_ipeak) { + clock_rate = cpp_cx_ipeak_update(cpp_dev, + clock_settings.clock_rate, + msm_cpp_core_clk_idx); + } else { + clock_rate = msm_cpp_set_core_clk(cpp_dev, + clock_settings.clock_rate, + msm_cpp_core_clk_idx); + } if (rc < 0) { pr_err("Fail to set core clk\n"); mutex_unlock(&cpp_dev->mutex); @@ -4389,6 +4438,15 @@ static int cpp_probe(struct platform_device *pdev) } } + if (of_find_property(pdev->dev.of_node, "qcom,cpp-cx-ipeak", NULL)) { + cpp_dev->cpp_cx_ipeak = cx_ipeak_register( + pdev->dev.of_node, "qcom,cpp-cx-ipeak"); + if (cpp_dev->cpp_cx_ipeak) + CPP_DBG("Cx ipeak Registration Successful "); + else + pr_err("Cx ipeak Registration Unsuccessful"); + } + rc = msm_camera_get_reset_info(pdev, &cpp_dev->micro_iface_reset); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index e69b9d633a1f..a05448091e42 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ #include "cam_soc_api.h" #include "cam_hw_ops.h" #include <media/msmb_pproc.h> +#include <soc/qcom/cx_ipeak.h> /* hw version info: 31:28 Major version @@ -284,6 +285,8 @@ struct cpp_device { uint32_t micro_reset; struct msm_cpp_payload_params payload_params; struct msm_cpp_vbif_data *vbif_data; + bool turbo_vote; + struct cx_ipeak_client *cpp_cx_ipeak; }; int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev); diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index 48872334cd83..b067c4916341 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -291,7 +291,6 @@ static uint32_t msm_cci_wait(struct cci_device *cci_dev, __func__, __LINE__); if (rc <= 0) { - msm_cci_dump_registers(cci_dev, master, queue); pr_err("%s: %d wait for queue: %d\n", __func__, __LINE__, queue); if (rc == 0) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index c3ed1f39c2be..1e85923c20b1 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -1975,7 +1975,7 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr, devm_kfree(&mgr->pdev->dev, req); } -static void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr, +void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr, struct sde_rot_file_private *private) { struct sde_rot_entry_container *req, *req_next; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index 7b27497ac6ef..2073c6d9f115 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -428,6 +428,9 @@ int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev, int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable); +void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private); + static inline void sde_rot_mgr_lock(struct sde_rot_mgr *mgr) { mutex_lock(&mgr->lock); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index 63c53c188637..5c7b4df40d5d 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -457,11 +457,15 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q) (atomic_read(&ctx->command_pending) == 0), msecs_to_jiffies(rot_dev->streamoff_timeout)); mutex_lock(q->lock); - if (!ret) + if (!ret) { SDEDEV_ERR(rot_dev->dev, "timeout to stream off s:%d t:%d p:%d\n", ctx->session_id, q->type, atomic_read(&ctx->command_pending)); + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private); + sde_rot_mgr_unlock(rot_dev->mgr); + } sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index ce6736509d61..ca9d7fba4ee3 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -468,7 +468,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { }, { .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, - .name = "I Frame Quantization", + .name = "H264 I Frame Quantization", .type = V4L2_CTRL_TYPE_INTEGER, .minimum = 1, .maximum = 51, @@ -479,7 +479,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { }, { .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, - .name = "P Frame Quantization", + .name = "H264 P Frame Quantization", .type = V4L2_CTRL_TYPE_INTEGER, .minimum = 1, .maximum = 51, @@ -490,7 +490,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { }, { .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, - .name = "B Frame Quantization", + .name = "H264 B Frame Quantization", .type = V4L2_CTRL_TYPE_INTEGER, .minimum = 1, .maximum = 51, @@ -500,6 +500,61 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .qmenu = NULL, }, { + .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP, + .name = "H263 I Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 31, + .default_value = I_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP, + .name = "H263 P Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 31, + .default_value = P_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP, + .name = "H263 B Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 31, + .default_value = B_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, + .name = "VPX I Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = I_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, + .name = "VPX P Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = P_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, .name = "H264 Minimum QP", .type = V4L2_CTRL_TYPE_INTEGER, @@ -522,6 +577,24 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .qmenu = NULL, }, { + .id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, + .name = "VPX Minimum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, + .name = "VPX Maximum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = 127, + .step = 1, + }, + { .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP, .name = "VP8 Minimum QP", .type = V4L2_CTRL_TYPE_INTEGER, @@ -540,6 +613,24 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .step = 1, }, { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP, + .name = "MPEG4 Minimum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 31, + .default_value = 1, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP, + .name = "MPEG4 Maximum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 31, + .default_value = 31, + .step = 1, + }, + { .id = V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED, .name = "H264 Minimum QP PACKED", .type = V4L2_CTRL_TYPE_INTEGER, @@ -940,6 +1031,36 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .step = 0, }, { + .id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP, + .name = "Iframe initial QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 127, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP, + .name = "Pframe initial QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 127, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP, + .name = "Bframe initial QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 127, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { .id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP, .name = "Iframe initial QP", .type = V4L2_CTRL_TYPE_INTEGER, @@ -1122,7 +1243,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .name = "Set frame level QP", .type = V4L2_CTRL_TYPE_INTEGER, .minimum = 1, - .maximum = 51, + .maximum = 127, .default_value = 1, .step = 1, .qmenu = NULL, @@ -2230,6 +2351,9 @@ unknown_value: return -EINVAL; } +static int msm_venc_validate_qp_value(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl); + static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) { int rc = 0; @@ -2649,6 +2773,81 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) pdata = &quantization; break; } + case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: { + struct v4l2_ctrl *qpp, *qpb; + + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpi = ctrl->val; + quantization.qpp = qpp->val; + quantization.qpb = qpb->val; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: { + struct v4l2_ctrl *qpi, *qpb; + + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpp = ctrl->val; + quantization.qpi = qpi->val; + quantization.qpb = qpb->val; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: { + struct v4l2_ctrl *qpi, *qpp; + + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP); + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpb = ctrl->val; + quantization.qpi = qpi->val; + quantization.qpp = qpp->val; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: { + struct v4l2_ctrl *qpp; + + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpi = ctrl->val; + quantization.qpp = qpp->val; + /* Bframes are not supported for VPX */ + quantization.qpb = 0; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: { + struct v4l2_ctrl *qpi; + + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpp = ctrl->val; + quantization.qpi = qpi->val; + /* Bframes are not supported for VPX */ + quantization.qpb = 0; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: { struct v4l2_ctrl *qp_max; @@ -2689,8 +2888,85 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) pdata = &qp_range; break; } + case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: { + struct v4l2_ctrl *qp_max; + + qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP); + if (ctrl->val >= qp_max->val) { + dprintk(VIDC_ERR, + "Bad range: Min QP (%d) > Max QP(%d)\n", + ctrl->val, qp_max->val); + rc = -ERANGE; + break; + } + + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = qp_max->val; + qp_range.min_qp = ctrl->val; + + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: { + struct v4l2_ctrl *qp_min; + + qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP); + if (ctrl->val <= qp_min->val) { + dprintk(VIDC_ERR, + "Bad range: Max QP (%d) < Min QP(%d)\n", + ctrl->val, qp_min->val); + rc = -ERANGE; + break; + } + + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = ctrl->val; + qp_range.min_qp = qp_min->val; + + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: { + struct v4l2_ctrl *qp_max; + + qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP); + if (ctrl->val >= qp_max->val) { + dprintk(VIDC_ERR, + "Bad range: Min QP (%d) > Max QP(%d)\n", + ctrl->val, qp_max->val); + rc = -ERANGE; + break; + } + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = qp_max->val; + qp_range.min_qp = ctrl->val; + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: { + struct v4l2_ctrl *qp_min; + + qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP); + if (ctrl->val <= qp_min->val) { + dprintk(VIDC_ERR, + "Bad range: Max QP (%d) < Min QP(%d)\n", + ctrl->val, qp_min->val); + rc = -ERANGE; + break; + } + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = ctrl->val; + qp_range.min_qp = qp_min->val; + pdata = &qp_range; + break; + } case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP: { struct v4l2_ctrl *qp_max; + qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP); property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; qp_range.layer_id = 0; @@ -2701,6 +2977,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP: { struct v4l2_ctrl *qp_min; + qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP); property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; qp_range.layer_id = 0; @@ -3222,6 +3499,14 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) pdata = &baselayerid; break; case V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP: + /* Sanity check for the QP boundaries as we are using + * same control to set dynamic QP for all the codecs + */ + rc = msm_venc_validate_qp_value(inst, ctrl); + if (rc) { + dprintk(VIDC_ERR, "Invalid QP Config QP Range\n"); + break; + } property_id = HAL_CONFIG_VENC_FRAME_QP; frameqp = ctrl->val; pdata = &frameqp; @@ -3380,7 +3665,6 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } v4l2_ctrl_lock(ctrl); -#undef TRY_GET_CTRL if (!rc && property_id) { dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n", @@ -3393,6 +3677,59 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) return rc; } +static int msm_venc_validate_qp_value(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl) +{ + int rc = 0, min, max; + struct v4l2_ctrl *temp_ctrl = NULL; + int qp_value = ctrl->val; + +#define VALIDATE_BOUNDARIES(__min, __max, __val) ({\ + int __rc = __val >= __min && \ + __val <= __max; \ + if (!__rc) \ + dprintk(VIDC_ERR, "QP beyond range: min(%d) max(%d) val(%d)", \ + __min, __max, __val); \ + __rc; \ +}) + + switch (inst->fmts[CAPTURE_PORT].fourcc) { + case V4L2_PIX_FMT_VP8: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP); + max = temp_ctrl->maximum; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP); + min = temp_ctrl->minimum; + if (!VALIDATE_BOUNDARIES(min, max, qp_value)) + rc = -EINVAL; + break; + case V4L2_PIX_FMT_H263: + case V4L2_PIX_FMT_MPEG4: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP); + max = temp_ctrl->maximum; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP); + min = temp_ctrl->minimum; + if (!VALIDATE_BOUNDARIES(min, max, qp_value)) + rc = -EINVAL; + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP); + max = temp_ctrl->maximum; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP); + min = temp_ctrl->minimum; + if (!VALIDATE_BOUNDARIES(min, max, qp_value)) + rc = -EINVAL; + break; + default: + dprintk(VIDC_ERR, "%s Invalid Codec\n", __func__); + return -EINVAL; + } + return rc; +#undef VALIDATE_BOUNDARIES +} + +#undef TRY_GET_CTRL + static int try_set_ext_ctrl(struct msm_vidc_inst *inst, struct v4l2_ext_controls *ctrl) { @@ -3408,6 +3745,7 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, struct hal_aspect_ratio sar; struct hal_bitrate bitrate; struct hal_frame_size blur_res; + struct v4l2_ctrl *temp_ctrl; if (!inst || !inst->core || !inst->core->device || !ctrl) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); @@ -3470,6 +3808,48 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; pdata = &quant; break; + case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP: + /* Sanity check for the QP boundaries as we are using + * same control to set Initial QP for all the codecs + */ + temp_ctrl->id = + V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP; + temp_ctrl->val = control[i].value; + rc = msm_venc_validate_qp_value(inst, temp_ctrl); + if (rc) { + dprintk(VIDC_ERR, "Invalid Initial I QP\n"); + break; + } + quant.qpi = control[i].value; + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + pdata = &quant; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP: + temp_ctrl->id = + V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP; + temp_ctrl->val = control[i].value; + rc = msm_venc_validate_qp_value(inst, temp_ctrl); + if (rc) { + dprintk(VIDC_ERR, "Invalid Initial P QP\n"); + break; + } + quant.qpp = control[i].value; + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + pdata = &quant; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP: + temp_ctrl->id = + V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP; + temp_ctrl->val = control[i].value; + rc = msm_venc_validate_qp_value(inst, temp_ctrl); + if (rc) { + dprintk(VIDC_ERR, "Invalid Initial B QP\n"); + break; + } + quant.qpb = control[i].value; + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + pdata = &quant; + break; case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE: search_range.i_frame.x_subsampled = control[i].value; property_id = HAL_PARAM_VENC_SEARCH_RANGE; diff --git a/drivers/misc/compat_qseecom.c b/drivers/misc/compat_qseecom.c index 60bb86a08af7..2e9ffc71e452 100644 --- a/drivers/misc/compat_qseecom.c +++ b/drivers/misc/compat_qseecom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -52,7 +52,7 @@ static int compat_get_qseecom_load_img_req( compat_ulong_t img_len; compat_long_t ifd_data_fd; compat_ulong_t app_arch; - compat_int_t app_id; + compat_uint_t app_id; err = get_user(mdt_len, &data32->mdt_len); err |= put_user(mdt_len, &data->mdt_len); @@ -164,7 +164,7 @@ static int compat_get_qseecom_qseos_app_load_query( { int err = 0; unsigned int i; - compat_int_t app_id; + compat_uint_t app_id; char app_name; compat_ulong_t app_arch; diff --git a/drivers/misc/compat_qseecom.h b/drivers/misc/compat_qseecom.h index 5167bf1cc6af..c934ef87e20a 100644 --- a/drivers/misc/compat_qseecom.h +++ b/drivers/misc/compat_qseecom.h @@ -93,7 +93,7 @@ struct compat_qseecom_load_img_req { compat_long_t ifd_data_fd; /* in */ char img_name[MAX_APP_NAME_SIZE]; /* in */ compat_ulong_t app_arch; /* in */ - compat_int_t app_id; /* out*/ + compat_uint_t app_id; /* out*/ }; struct compat_qseecom_set_sb_mem_param_req { @@ -117,7 +117,7 @@ struct compat_qseecom_qseos_version_req { */ struct compat_qseecom_qseos_app_load_query { char app_name[MAX_APP_NAME_SIZE]; /* in */ - compat_int_t app_id; /* out */ + compat_uint_t app_id; /* out */ compat_ulong_t app_arch; }; diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c index 5b321b17c43e..8f244811f740 100644 --- a/drivers/misc/qpnp-misc.c +++ b/drivers/misc/qpnp-misc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014,2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014,2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,7 +14,7 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/slab.h> -#include <linux/spmi.h> +#include <linux/regmap.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/qpnp-misc.h> @@ -45,8 +45,7 @@ struct qpnp_misc_version { * exclusion between probing and accessing misc * driver information * @dev: Device pointer to the misc device - * @resource: Resource pointer that holds base address - * @spmi: Spmi pointer which holds spmi information + * @regmap: Regmap pointer to the misc device * @version: struct that holds the subtype and dig_major_rev * of the chip. */ @@ -54,10 +53,10 @@ struct qpnp_misc_dev { struct list_head list; struct mutex mutex; struct device *dev; - struct resource *resource; - struct spmi_device *spmi; + struct regmap *regmap; struct qpnp_misc_version version; + u32 base; u8 pwm_sel; bool enable_gp_driver; }; @@ -83,26 +82,29 @@ static struct qpnp_misc_version irq_support_version[] = { {0x16, 0x00}, /* PMDCALIFORNIUM */ }; -static int qpnp_write_byte(struct spmi_device *spmi, u16 addr, u8 val) +static int qpnp_write_byte(struct qpnp_misc_dev *mdev, u16 addr, u8 val) { int rc; - rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, &val, 1); + rc = regmap_write(mdev->regmap, mdev->base + addr, val); if (rc) - pr_err("SPMI write failed rc=%d\n", rc); + pr_err("regmap write failed rc=%d\n", rc); return rc; } -static int qpnp_read_byte(struct spmi_device *spmi, u16 addr, u8 *val) +static int qpnp_read_byte(struct qpnp_misc_dev *mdev, u16 addr, u8 *val) { + unsigned int temp; int rc; - rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, val, 1); + rc = regmap_read(mdev->regmap, mdev->base + addr, &temp); if (rc) { - pr_err("SPMI read failed rc=%d\n", rc); + pr_err("regmap read failed rc=%d\n", rc); return rc; } + + *val = (u8)temp; return rc; } @@ -128,6 +130,47 @@ static bool __misc_irqs_available(struct qpnp_misc_dev *dev) return 1; } +int qpnp_misc_read_reg(struct device_node *node, u16 addr, u8 *val) +{ + struct qpnp_misc_dev *mdev = NULL; + struct qpnp_misc_dev *mdev_found = NULL; + int rc; + u8 temp; + + if (IS_ERR_OR_NULL(node)) { + pr_err("Invalid device node pointer\n"); + return -EINVAL; + } + + mutex_lock(&qpnp_misc_dev_list_mutex); + list_for_each_entry(mdev, &qpnp_misc_dev_list, list) { + if (mdev->dev->of_node == node) { + mdev_found = mdev; + break; + } + } + mutex_unlock(&qpnp_misc_dev_list_mutex); + + if (!mdev_found) { + /* + * No MISC device was found. This API should only + * be called by drivers which have specified the + * misc phandle in their device tree node. + */ + pr_err("no probed misc device found\n"); + return -EPROBE_DEFER; + } + + rc = qpnp_read_byte(mdev, addr, &temp); + if (rc < 0) { + dev_err(mdev->dev, "Failed to read addr %x, rc=%d\n", addr, rc); + return rc; + } + + *val = temp; + return 0; +} + int qpnp_misc_irqs_available(struct device *consumer_dev) { struct device_node *misc_node = NULL; @@ -168,16 +211,24 @@ int qpnp_misc_irqs_available(struct device *consumer_dev) static int qpnp_misc_dt_init(struct qpnp_misc_dev *mdev) { + struct device_node *node = mdev->dev->of_node; u32 val; + int rc; + + rc = of_property_read_u32(node, "reg", &mdev->base); + if (rc < 0 || !mdev->base) { + dev_err(mdev->dev, "Base address not defined or invalid\n"); + return -EINVAL; + } - if (!of_property_read_u32(mdev->dev->of_node, "qcom,pwm-sel", &val)) { + if (!of_property_read_u32(node, "qcom,pwm-sel", &val)) { if (val > PWM_SEL_MAX) { dev_err(mdev->dev, "Invalid value for pwm-sel\n"); return -EINVAL; } mdev->pwm_sel = (u8)val; } - mdev->enable_gp_driver = of_property_read_bool(mdev->dev->of_node, + mdev->enable_gp_driver = of_property_read_bool(node, "qcom,enable-gp-driver"); WARN((mdev->pwm_sel > 0 && !mdev->enable_gp_driver), @@ -197,18 +248,15 @@ static int qpnp_misc_config(struct qpnp_misc_dev *mdev) switch (version_name) { case PMDCALIFORNIUM: if (mdev->pwm_sel > 0 && mdev->enable_gp_driver) { - rc = qpnp_write_byte(mdev->spmi, - mdev->resource->start + REG_PWM_SEL, - mdev->pwm_sel); + rc = qpnp_write_byte(mdev, REG_PWM_SEL, mdev->pwm_sel); if (rc < 0) { dev_err(mdev->dev, "Failed to write PWM_SEL reg\n"); return rc; } - rc = qpnp_write_byte(mdev->spmi, - mdev->resource->start + REG_GP_DRIVER_EN, - GP_DRIVER_EN_BIT); + rc = qpnp_write_byte(mdev, REG_GP_DRIVER_EN, + GP_DRIVER_EN_BIT); if (rc < 0) { dev_err(mdev->dev, "Failed to write GP_DRIVER_EN reg\n"); @@ -223,35 +271,38 @@ static int qpnp_misc_config(struct qpnp_misc_dev *mdev) return 0; } -static int qpnp_misc_probe(struct spmi_device *spmi) +static int qpnp_misc_probe(struct platform_device *pdev) { - struct resource *resource; struct qpnp_misc_dev *mdev = ERR_PTR(-EINVAL); int rc; - resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0); - if (!resource) { - pr_err("Unable to get spmi resource for MISC\n"); - return -EINVAL; - } - - mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL); if (!mdev) return -ENOMEM; - mdev->spmi = spmi; - mdev->dev = &(spmi->dev); - mdev->resource = resource; + mdev->dev = &pdev->dev; + mdev->regmap = dev_get_regmap(mdev->dev->parent, NULL); + if (!mdev->regmap) { + dev_err(mdev->dev, "Parent regmap is unavailable\n"); + return -ENXIO; + } + + rc = qpnp_misc_dt_init(mdev); + if (rc < 0) { + dev_err(mdev->dev, + "Error reading device tree properties, rc=%d\n", rc); + return rc; + } + - rc = qpnp_read_byte(spmi, resource->start + REG_SUBTYPE, - &mdev->version.subtype); + rc = qpnp_read_byte(mdev, REG_SUBTYPE, &mdev->version.subtype); if (rc < 0) { dev_err(mdev->dev, "Failed to read subtype, rc=%d\n", rc); return rc; } - rc = qpnp_read_byte(spmi, resource->start + REG_DIG_MAJOR_REV, - &mdev->version.dig_major_rev); + rc = qpnp_read_byte(mdev, REG_DIG_MAJOR_REV, + &mdev->version.dig_major_rev); if (rc < 0) { dev_err(mdev->dev, "Failed to read dig_major_rev, rc=%d\n", rc); return rc; @@ -261,13 +312,6 @@ static int qpnp_misc_probe(struct spmi_device *spmi) list_add_tail(&mdev->list, &qpnp_misc_dev_list); mutex_unlock(&qpnp_misc_dev_list_mutex); - rc = qpnp_misc_dt_init(mdev); - if (rc < 0) { - dev_err(mdev->dev, - "Error reading device tree properties, rc=%d\n", rc); - return rc; - } - rc = qpnp_misc_config(mdev); if (rc < 0) { dev_err(mdev->dev, @@ -279,7 +323,7 @@ static int qpnp_misc_probe(struct spmi_device *spmi) return 0; } -static struct spmi_driver qpnp_misc_driver = { +static struct platform_driver qpnp_misc_driver = { .probe = qpnp_misc_probe, .driver = { .name = QPNP_MISC_DEV_NAME, @@ -290,12 +334,12 @@ static struct spmi_driver qpnp_misc_driver = { static int __init qpnp_misc_init(void) { - return spmi_driver_register(&qpnp_misc_driver); + return platform_driver_register(&qpnp_misc_driver); } static void __exit qpnp_misc_exit(void) { - return spmi_driver_unregister(&qpnp_misc_driver); + return platform_driver_unregister(&qpnp_misc_driver); } module_init(qpnp_misc_init); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 8d03c36858b3..78f03fc75761 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -2167,7 +2167,8 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( } } -static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req) +static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req, + uint32_t *app_id) { int32_t ret; struct qseecom_command_scm_resp resp; @@ -2175,6 +2176,12 @@ static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req) struct qseecom_registered_app_list *entry = NULL; unsigned long flags = 0; + if (!app_id) { + pr_err("Null pointer to app_id\n"); + return -EINVAL; + } + *app_id = 0; + /* check if app exists and has been registered locally */ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_for_each_entry(entry, @@ -2187,7 +2194,8 @@ static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req) spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags); if (found_app) { pr_debug("Found app with id %d\n", entry->app_id); - return entry->app_id; + *app_id = entry->app_id; + return 0; } memset((void *)&resp, 0, sizeof(resp)); @@ -2210,7 +2218,8 @@ static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req) pr_err("resp type is of listener type instead of app"); return -EINVAL; case QSEOS_APP_ID: - return resp.data; + *app_id = resp.data; + return 0; default: pr_err("invalid resp type (%d) from qsee", resp.resp_type); @@ -2286,11 +2295,10 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0'; strlcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE); - ret = __qseecom_check_app_exists(req); + ret = __qseecom_check_app_exists(req, &app_id); if (ret < 0) goto loadapp_err; - app_id = ret; if (app_id) { pr_debug("App id %d (%s) already exists\n", app_id, (char *)(req.app_name)); @@ -4038,7 +4046,8 @@ static void __qseecom_free_img_data(struct ion_handle **ihandle) *ihandle = NULL; } -static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) +static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, + uint32_t *app_id) { int ret = -1; uint32_t fw_size = 0; @@ -4052,6 +4061,11 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) size_t cmd_len; uint32_t app_arch = 0; + if (!data || !appname || !app_id) { + pr_err("Null pointer to data or appname or appid\n"); + return -EINVAL; + } + *app_id = 0; if (__qseecom_get_fw_size(appname, &fw_size, &app_arch)) return -EIO; data->client.app_arch = app_arch; @@ -4143,14 +4157,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) switch (resp.result) { case QSEOS_RESULT_SUCCESS: - ret = resp.data; + *app_id = resp.data; break; case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) pr_err("process_incomplete_cmd FAILED\n"); else - ret = resp.data; + *app_id = resp.data; break; case QSEOS_RESULT_FAILURE: pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); @@ -4343,6 +4357,7 @@ int qseecom_start_app(struct qseecom_handle **handle, size_t len; ion_phys_addr_t pa; uint32_t fw_size, app_arch; + uint32_t app_id = 0; if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", @@ -4397,18 +4412,18 @@ int qseecom_start_app(struct qseecom_handle **handle, app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE); - ret = __qseecom_check_app_exists(app_ireq); - if (ret < 0) + ret = __qseecom_check_app_exists(app_ireq, &app_id); + if (ret) goto err; strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE); - if (ret > 0) { - pr_warn("App id %d for [%s] app exists\n", ret, + if (app_id) { + pr_warn("App id %d for [%s] app exists\n", app_id, (char *)app_ireq.app_name); spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_for_each_entry(entry, &qseecom.registered_app_list_head, list){ - if (entry->app_id == ret) { + if (entry->app_id == app_id) { entry->ref_cnt++; found_app = true; break; @@ -4423,11 +4438,11 @@ int qseecom_start_app(struct qseecom_handle **handle, /* load the app and get the app_id */ pr_debug("%s: Loading app for the first time'\n", qseecom.pdev->init_name); - ret = __qseecom_load_fw(data, app_name); + ret = __qseecom_load_fw(data, app_name, &app_id); if (ret < 0) goto err; } - data->client.app_id = ret; + data->client.app_id = app_id; if (!found_app) { entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { @@ -4435,7 +4450,7 @@ int qseecom_start_app(struct qseecom_handle **handle, ret = -ENOMEM; goto err; } - entry->app_id = ret; + entry->app_id = app_id; entry->ref_cnt = 1; strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { @@ -5272,7 +5287,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, struct qseecom_check_app_ireq req; struct qseecom_registered_app_list *entry = NULL; unsigned long flags = 0; - uint32_t app_arch = 0; + uint32_t app_arch = 0, app_id = 0; bool found_app = false; /* Copy the relevant information needed for loading the image */ @@ -5287,18 +5302,18 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0'; strlcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE); - ret = __qseecom_check_app_exists(req); - - if ((ret == -EINVAL) || (ret == -ENODEV)) { + ret = __qseecom_check_app_exists(req, &app_id); + if (ret) { pr_err(" scm call to check if app is loaded failed"); return ret; /* scm call failed */ - } else if (ret > 0) { - pr_debug("App id %d (%s) already exists\n", ret, + } + if (app_id) { + pr_debug("App id %d (%s) already exists\n", app_id, (char *)(req.app_name)); spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_for_each_entry(entry, &qseecom.registered_app_list_head, list){ - if (entry->app_id == ret) { + if (entry->app_id == app_id) { app_arch = entry->app_arch; entry->ref_cnt++; found_app = true; @@ -5307,8 +5322,8 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, } spin_unlock_irqrestore( &qseecom.registered_app_list_lock, flags); - data->client.app_id = ret; - query_req.app_id = ret; + data->client.app_id = app_id; + query_req.app_id = app_id; if (app_arch) { data->client.app_arch = app_arch; query_req.app_arch = app_arch; @@ -5330,7 +5345,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, pr_err("kmalloc for app entry failed\n"); return -ENOMEM; } - entry->app_id = ret; + entry->app_id = app_id; entry->ref_cnt = 1; entry->app_arch = data->client.app_arch; strlcpy(entry->app_name, data->client.app_name, diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index ce0ecd1e9b7a..5d6c44b00bc2 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -875,6 +875,14 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, cmd.arg = idata->ic.arg; cmd.flags = idata->ic.flags; + if (idata->ic.postsleep_max_us < idata->ic.postsleep_min_us) { + pr_err("%s: min value: %u must not be greater than max value: %u\n", + __func__, idata->ic.postsleep_min_us, + idata->ic.postsleep_max_us); + WARN_ON(1); + return -EPERM; + } + if (idata->buf_bytes) { data.sg = &sg; data.sg_len = 1; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8101b77c2acf..ec6075ec5767 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -167,6 +167,19 @@ static int mmc_bus_suspend(struct device *dev) if (mmc_bus_needs_resume(host)) return 0; ret = host->bus_ops->suspend(host); + + /* + * bus_ops->suspend may fail due to some reason + * In such cases if we return error to PM framework + * from here without calling pm_generic_resume then mmc + * request may get stuck since PM framework will assume + * that mmc bus is not suspended (because of error) and + * it won't call resume again. + * + * So in case of error call pm_generic_resume(). + */ + if (ret) + pm_generic_resume(dev); return ret; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 414877874190..4567b7526469 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2494,7 +2494,7 @@ static int mmc_test_awake_ext_csd(struct mmc_host *host) static int _mmc_suspend(struct mmc_host *host, bool is_suspend) { - int err = 0; + int err = 0, ret; BUG_ON(!host); BUG_ON(!host->card); @@ -2503,6 +2503,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) if (err) { pr_err("%s: %s: fail to suspend clock scaling (%d)\n", mmc_hostname(host), __func__, err); + if (host->card->cmdq_init) + wake_up(&host->cmdq_ctx.wait); return err; } @@ -2527,12 +2529,12 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) if (mmc_card_doing_bkops(host->card)) { err = mmc_stop_bkops(host->card); if (err) - goto out; + goto out_err; } err = mmc_flush_cache(host->card); if (err) - goto out; + goto out_err; if (mmc_can_sleepawake(host)) { /* @@ -2549,16 +2551,38 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) err = mmc_deselect_cards(host); } - if (!err) { - mmc_power_off(host); - mmc_card_set_suspended(host->card); + if (err) + goto out_err; + mmc_power_off(host); + mmc_card_set_suspended(host->card); + + goto out; + +out_err: + /* + * In case of err let's put controller back in cmdq mode and unhalt + * the controller. + * We expect cmdq_enable and unhalt won't return any error + * since it is anyway enabling few registers. + */ + if (host->card->cmdq_init) { + mmc_host_clk_hold(host); + ret = host->cmdq_ops->enable(host); + if (ret) + pr_err("%s: %s: enabling CMDQ mode failed (%d)\n", + mmc_hostname(host), __func__, ret); + mmc_host_clk_release(host); + mmc_cmdq_halt(host, false); } + out: /* Kick CMDQ thread to process any requests came in while suspending */ if (host->card->cmdq_init) wake_up(&host->cmdq_ctx.wait); mmc_release_host(host); + if (err) + mmc_resume_clk_scaling(host); return err; } diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 1ad5fd0e0a78..a83960fd474f 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -852,6 +852,7 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) struct mmc_request *mrq; struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); int offset = 0; + int err = 0; if (cq_host->offset_changed) offset = CQ_V5_VENDOR_CFG; @@ -865,6 +866,14 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG + offset); cmdq_runtime_pm_put(cq_host); + + if (cq_host->ops->crypto_cfg_end) { + err = cq_host->ops->crypto_cfg_end(mmc, mrq); + if (err) { + pr_err("%s: failed to end ice config: err %d tag %d\n", + mmc_hostname(mmc), err, tag); + } + } if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && cq_host->ops->crypto_cfg_reset) cq_host->ops->crypto_cfg_reset(mmc, tag); diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h index db0cd956ae90..ee5e6549fa4a 100644 --- a/drivers/mmc/host/cmdq_hci.h +++ b/drivers/mmc/host/cmdq_hci.h @@ -223,6 +223,7 @@ struct cmdq_host_ops { int (*reset)(struct mmc_host *mmc); int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq, u32 slot, u64 *ice_ctx); + int (*crypto_cfg_end)(struct mmc_host *mmc, struct mmc_request *mrq); void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot); void (*post_cqe_halt)(struct mmc_host *mmc); }; diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index a6ef06aa6f1d..2799b21fb6e3 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -414,6 +414,37 @@ int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, return 0; } +int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + int err = 0; + struct request *req; + + if (!host->is_crypto_en) + return 0; + + if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { + pr_err("%s: ice is in invalid state %d\n", + mmc_hostname(host->mmc), msm_host->ice.state); + return -EINVAL; + } + + req = mrq->req; + if (req) { + if (msm_host->ice.vops->config_end) { + err = msm_host->ice.vops->config_end(req); + if (err) { + pr_err("%s: ice config end failed %d\n", + mmc_hostname(host->mmc), err); + return err; + } + } + } + + return 0; +} + int sdhci_msm_ice_reset(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h index d8d640437522..7699464cf71e 100644 --- a/drivers/mmc/host/sdhci-msm-ice.h +++ b/drivers/mmc/host/sdhci-msm-ice.h @@ -107,6 +107,7 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, u32 slot); int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, struct mmc_request *mrq, u32 slot, u64 *ice_ctx); +int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq); int sdhci_msm_ice_reset(struct sdhci_host *host); int sdhci_msm_ice_resume(struct sdhci_host *host); int sdhci_msm_ice_suspend(struct sdhci_host *host); @@ -143,6 +144,11 @@ inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, { return 0; } +inline int sdhci_msm_ice_cfg_end(struct sdhci_host *host, + struct mmc_request *mrq) +{ + return 0; +} inline int sdhci_msm_ice_reset(struct sdhci_host *host) { return 0; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 15d1eface2d4..7274a6d2cce0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -4008,6 +4008,7 @@ static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host) static struct sdhci_ops sdhci_msm_ops = { .crypto_engine_cfg = sdhci_msm_ice_cfg, .crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg, + .crypto_engine_cfg_end = sdhci_msm_ice_cfg_end, .crypto_cfg_reset = sdhci_msm_ice_cfg_reset, .crypto_engine_reset = sdhci_msm_ice_reset, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1fdc23365c8f..083cb8cdf1ca 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1668,6 +1668,22 @@ out: return err; } +static int sdhci_crypto_cfg_end(struct sdhci_host *host, + struct mmc_request *mrq) +{ + int err = 0; + + if (host->ops->crypto_engine_cfg_end) { + err = host->ops->crypto_engine_cfg_end(host, mrq); + if (err) { + pr_err("%s: failed to configure crypto\n", + mmc_hostname(host->mmc)); + return err; + } + } + return 0; +} + static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host; @@ -2787,6 +2803,7 @@ static void sdhci_tasklet_finish(unsigned long param) mmiowb(); spin_unlock_irqrestore(&host->lock, flags); + sdhci_crypto_cfg_end(host, mrq); mmc_request_done(host->mmc, mrq); sdhci_runtime_pm_put(host); } @@ -3665,6 +3682,17 @@ out: return err; } +static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc, + struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (!host->is_crypto_en) + return 0; + + return sdhci_crypto_cfg_end(host, mrq); +} + static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) { struct sdhci_host *host = mmc_priv(mmc); @@ -3730,6 +3758,12 @@ static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc, return 0; } +static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc, + struct mmc_request *mrq) +{ + return 0; +} + static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) { @@ -3747,6 +3781,7 @@ static const struct cmdq_host_ops sdhci_cmdq_ops = { .clear_set_dumpregs = sdhci_cmdq_clear_set_dumpregs, .enhanced_strobe_mask = sdhci_enhanced_strobe_mask, .crypto_cfg = sdhci_cmdq_crypto_cfg, + .crypto_cfg_end = sdhci_cmdq_crypto_cfg_end, .crypto_cfg_reset = sdhci_cmdq_crypto_cfg_reset, .post_cqe_halt = sdhci_cmdq_post_cqe_halt, .set_transfer_params = sdhci_cmdq_set_transfer_params, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c4bbdd80f29c..93129b26dc5e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -659,6 +659,8 @@ struct sdhci_ops { struct mmc_request *mrq, u32 slot); int (*crypto_engine_cmdq_cfg)(struct sdhci_host *host, struct mmc_request *mrq, u32 slot, u64 *ice_ctx); + int (*crypto_engine_cfg_end)(struct sdhci_host *host, + struct mmc_request *mrq); int (*crypto_engine_reset)(struct sdhci_host *host); void (*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot); void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2e51590dacbb..8d49acd3c9f5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3506,6 +3506,7 @@ static int ath10k_mac_tx(struct ath10k *ar, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret; + skb_orphan(skb); /* We should disable CCK RATE due to P2P */ if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 081e44b3277a..f6eb131e1e1b 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -96,8 +96,8 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE4: host->target HTT */ { .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, - .src_nentries = 256, - .src_sz_max = 256, + .src_nentries = 2048, + .src_sz_max = 2048, .dest_nentries = 0, .send_cb = ath10k_snoc_htt_tx_cb, }, diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 210ea654c83f..acd5347f2cae 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -15,6 +15,7 @@ */ #include <linux/etherdevice.h> +#include <linux/moduleparam.h> #include "wil6210.h" #include "wmi.h" #include "ftm.h" diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 7bc6149480f2..f8e5ccd7b9ca 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -90,7 +90,7 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) done = budget - quota; if (done < budget) { - napi_complete(napi); + napi_complete_done(napi, done); wil6210_unmask_irq_rx(wil); wil_dbg_txrx(wil, "NAPI RX complete\n"); } diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index 16f64e9fb8d3..913f756f9520 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -98,6 +98,7 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, + {0, 64 * 1024, NULL}, {0, 128 * 1024, NULL}, {0, 128 * 1024, NULL}, }; diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index f48182cc04df..dff565d9e206 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -22,7 +22,7 @@ #include "gsi_reg.h" #define GSI_CMD_TIMEOUT (5*HZ) -#define GSI_STOP_CMD_TIMEOUT_MS 10 +#define GSI_STOP_CMD_TIMEOUT_MS 20 #define GSI_MAX_CH_LOW_WEIGHT 15 #define GSI_MHI_ER_START 10 #define GSI_MHI_ER_END 16 diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index d4b0dd9910e1..553480660722 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3418,11 +3418,14 @@ void ipa_inc_acquire_wakelock(enum ipa_wakelock_ref_client ref_client) return; spin_lock_irqsave(&ipa_ctx->wakelock_ref_cnt.spinlock, flags); if (ipa_ctx->wakelock_ref_cnt.cnt & (1 << ref_client)) - IPAERR("client enum %d mask already set. ref cnt = %d\n", + IPADBG("client enum %d mask already set. ref cnt = %d\n", ref_client, ipa_ctx->wakelock_ref_cnt.cnt); ipa_ctx->wakelock_ref_cnt.cnt |= (1 << ref_client); - if (ipa_ctx->wakelock_ref_cnt.cnt) + if (ipa_ctx->wakelock_ref_cnt.cnt && + !ipa_ctx->wakelock_ref_cnt.wakelock_acquired) { __pm_stay_awake(&ipa_ctx->w_lock); + ipa_ctx->wakelock_ref_cnt.wakelock_acquired = true; + } IPADBG_LOW("active wakelock ref cnt = %d client enum %d\n", ipa_ctx->wakelock_ref_cnt.cnt, ref_client); spin_unlock_irqrestore(&ipa_ctx->wakelock_ref_cnt.spinlock, flags); @@ -3446,8 +3449,11 @@ void ipa_dec_release_wakelock(enum ipa_wakelock_ref_client ref_client) ipa_ctx->wakelock_ref_cnt.cnt &= ~(1 << ref_client); IPADBG_LOW("active wakelock ref cnt = %d client enum %d\n", ipa_ctx->wakelock_ref_cnt.cnt, ref_client); - if (ipa_ctx->wakelock_ref_cnt.cnt == 0) + if (ipa_ctx->wakelock_ref_cnt.cnt == 0 && + ipa_ctx->wakelock_ref_cnt.wakelock_acquired) { __pm_relax(&ipa_ctx->w_lock); + ipa_ctx->wakelock_ref_cnt.wakelock_acquired = false; + } spin_unlock_irqrestore(&ipa_ctx->wakelock_ref_cnt.spinlock, flags); } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index 7b48991cba65..a2665c9e9688 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3147,6 +3147,8 @@ static int ipa_assign_policy_v2(struct ipa_sys_connect_params *in, IPA_GENERIC_AGGR_TIME_LIMIT; if (in->client == IPA_CLIENT_APPS_LAN_CONS) { sys->pyld_hdlr = ipa_lan_rx_pyld_hdlr; + sys->rx_pool_sz = + ipa_ctx->lan_rx_ring_size; if (nr_cpu_ids > 1) { sys->repl_hdlr = ipa_fast_replenish_rx_cache; @@ -3156,8 +3158,6 @@ static int ipa_assign_policy_v2(struct ipa_sys_connect_params *in, sys->repl_hdlr = ipa_replenish_rx_cache; } - sys->rx_pool_sz = - ipa_ctx->lan_rx_ring_size; in->ipa_ep_cfg.aggr.aggr_byte_limit = IPA_GENERIC_AGGR_BYTE_LIMIT; in->ipa_ep_cfg.aggr.aggr_pkt_limit = diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 94d76db6f993..a14d1fee9c35 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -841,6 +841,7 @@ struct ipa_active_clients { struct ipa_wakelock_ref_cnt { spinlock_t spinlock; u32 cnt; + bool wakelock_acquired; }; struct ipa_tag_completion { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index dfc3e06f452b..f8f8fd12161a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -272,6 +272,14 @@ int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx) mutex_lock(&ipa_ctx->lock); list_for_each_entry(entry, &ipa_ctx->intf_list, link) { if (!strncmp(entry->name, tx->name, IPA_RESOURCE_NAME_MAX)) { + /* add the entry check */ + if (entry->num_tx_props != tx->num_tx_props) { + IPAERR("invalid entry number(%u %u)\n", + entry->num_tx_props, + tx->num_tx_props); + mutex_unlock(&ipa_ctx->lock); + return result; + } memcpy(tx->tx, entry->tx, entry->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop)); result = 0; @@ -305,6 +313,14 @@ int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx) mutex_lock(&ipa_ctx->lock); list_for_each_entry(entry, &ipa_ctx->intf_list, link) { if (!strncmp(entry->name, rx->name, IPA_RESOURCE_NAME_MAX)) { + /* add the entry check */ + if (entry->num_rx_props != rx->num_rx_props) { + IPAERR("invalid entry number(%u %u)\n", + entry->num_rx_props, + rx->num_rx_props); + mutex_unlock(&ipa_ctx->lock); + return result; + } memcpy(rx->rx, entry->rx, entry->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop)); result = 0; @@ -338,6 +354,14 @@ int ipa_query_intf_ext_props(struct ipa_ioc_query_intf_ext_props *ext) mutex_lock(&ipa_ctx->lock); list_for_each_entry(entry, &ipa_ctx->intf_list, link) { if (!strcmp(entry->name, ext->name)) { + /* add the entry check */ + if (entry->num_ext_props != ext->num_ext_props) { + IPAERR("invalid entry number(%u %u)\n", + entry->num_ext_props, + ext->num_ext_props); + mutex_unlock(&ipa_ctx->lock); + return result; + } memcpy(ext->ext, entry->ext, entry->num_ext_props * sizeof(struct ipa_ioc_ext_intf_prop)); result = 0; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 9cab7e010c3a..d53121292c03 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -5161,7 +5161,8 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, */ u32 ipa_get_sys_yellow_wm(struct ipa_sys_context *sys) { - if (ipa_ctx->ipa_hw_type == IPA_HW_v2_6L) { + if (ipa_ctx->ipa_hw_type == IPA_HW_v2_6L && + ipa_ctx->ipa_uc_monitor_holb) { return ipa_read_reg(ipa_ctx->mmio, IPA_YELLOW_MARKER_SYS_CFG_OFST); } else { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index b9f57552533e..b687b711dc20 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -275,6 +275,14 @@ int ipa3_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx) mutex_lock(&ipa3_ctx->lock); list_for_each_entry(entry, &ipa3_ctx->intf_list, link) { if (!strcmp(entry->name, tx->name)) { + /* add the entry check */ + if (entry->num_tx_props != tx->num_tx_props) { + IPAERR("invalid entry number(%u %u)\n", + entry->num_tx_props, + tx->num_tx_props); + mutex_unlock(&ipa3_ctx->lock); + return result; + } memcpy(tx->tx, entry->tx, entry->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop)); result = 0; @@ -314,6 +322,14 @@ int ipa3_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx) mutex_lock(&ipa3_ctx->lock); list_for_each_entry(entry, &ipa3_ctx->intf_list, link) { if (!strcmp(entry->name, rx->name)) { + /* add the entry check */ + if (entry->num_rx_props != rx->num_rx_props) { + IPAERR("invalid entry number(%u %u)\n", + entry->num_rx_props, + rx->num_rx_props); + mutex_unlock(&ipa3_ctx->lock); + return result; + } memcpy(rx->rx, entry->rx, entry->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop)); result = 0; @@ -348,6 +364,14 @@ int ipa3_query_intf_ext_props(struct ipa_ioc_query_intf_ext_props *ext) mutex_lock(&ipa3_ctx->lock); list_for_each_entry(entry, &ipa3_ctx->intf_list, link) { if (!strcmp(entry->name, ext->name)) { + /* add the entry check */ + if (entry->num_ext_props != ext->num_ext_props) { + IPAERR("invalid entry number(%u %u)\n", + entry->num_ext_props, + ext->num_ext_props); + mutex_unlock(&ipa3_ctx->lock); + return result; + } memcpy(ext->ext, entry->ext, entry->num_ext_props * sizeof(struct ipa_ioc_ext_intf_prop)); result = 0; diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c index bb1259e3cfa1..a35ed1afc720 100644 --- a/drivers/platform/msm/msm_ext_display.c +++ b/drivers/platform/msm/msm_ext_display.c @@ -285,11 +285,6 @@ static bool msm_ext_disp_validate_connect(struct msm_ext_disp *ext_disp, /* if already connected, block a new connection */ if (ext_disp->current_disp != type) return false; - - /* if same display connected, block same connection type */ - if (ext_disp->flags & flags) - return false; - end: ext_disp->flags |= flags; ext_disp->current_disp = type; diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index dfa83f2304b2..de6c86984e3f 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -1,9 +1,9 @@ obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o pmic-voter.o -obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o +obj-$(CONFIG_SMB1351_USB_CHARGER) += battery.o smb1351-charger.o pmic-voter.o obj-$(CONFIG_MSM_BCL_CTL) += msm_bcl.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o -obj-$(CONFIG_QPNP_SMB2) += qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o battery.o -obj-$(CONFIG_SMB138X_CHARGER) += smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o -obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o +obj-$(CONFIG_QPNP_SMB2) += battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o +obj-$(CONFIG_SMB138X_CHARGER) += battery.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o +obj-$(CONFIG_QPNP_QNOVO) += battery.o qpnp-qnovo.o diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 64f4d46df9a0..771d1cd32714 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -239,7 +239,6 @@ static struct smb_params pm660_params = { struct smb_dt_props { int fcc_ua; int usb_icl_ua; - int otg_cl_ua; int dc_icl_ua; int boost_threshold_ua; int fv_uv; @@ -323,9 +322,9 @@ static int smb2_parse_dt(struct smb2 *chip) chip->dt.usb_icl_ua = -EINVAL; rc = of_property_read_u32(node, - "qcom,otg-cl-ua", &chip->dt.otg_cl_ua); + "qcom,otg-cl-ua", &chg->otg_cl_ua); if (rc < 0) - chip->dt.otg_cl_ua = MICRO_1P5A; + chg->otg_cl_ua = MICRO_1P5A; rc = of_property_read_u32(node, "qcom,dc-icl-ua", &chip->dt.dc_icl_ua); @@ -858,6 +857,7 @@ static int smb2_batt_get_prop(struct power_supply *psy, { struct smb_charger *chg = power_supply_get_drvdata(psy); int rc = 0; + union power_supply_propval pval = {0, }; switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -882,7 +882,14 @@ static int smb2_batt_get_prop(struct power_supply *psy, rc = smblib_get_prop_system_temp_level(chg, val); break; case POWER_SUPPLY_PROP_CHARGER_TEMP: - rc = smblib_get_prop_charger_temp(chg, val); + /* do not query RRADC if charger is not present */ + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) + pr_err("Couldn't get usb present rc=%d\n", rc); + + rc = -ENODATA; + if (pval.intval) + rc = smblib_get_prop_charger_temp(chg, val); break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: rc = smblib_get_prop_charger_temp_max(chg, val); @@ -1386,7 +1393,8 @@ static int smb2_init_hw(struct smb2 *chip) /* set OTG current limit */ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, - chip->dt.otg_cl_ua); + (chg->wa_flags & OTG_WA) ? + chg->param.otg_cl.min_u : chg->otg_cl_ua); if (rc < 0) { pr_err("Couldn't set otg current limit rc=%d\n", rc); return rc; @@ -1649,7 +1657,7 @@ static int smb2_chg_config_init(struct smb2 *chip) break; case PM660_SUBTYPE: chip->chg.smb_version = PM660_SUBTYPE; - chip->chg.wa_flags |= BOOST_BACK_WA; + chip->chg.wa_flags |= BOOST_BACK_WA | OTG_WA; chg->param.freq_buck = pm660_params.freq_buck; chg->param.freq_boost = pm660_params.freq_boost; chg->chg_freq.freq_5V = 600; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 9d296a911daa..4f126854728f 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -489,7 +489,7 @@ static int smblib_set_adapter_allowance(struct smb_charger *chg, if (chg->smb_version == PM660_SUBTYPE) { smblib_dbg(chg, PR_MISC, "voltage not supported=%d\n", allowed_voltage); - allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V; + allowed_voltage = USBIN_ADAPTER_ALLOW_5V_OR_9V; } break; } @@ -1290,11 +1290,14 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) /***************** * OTG REGULATOR * *****************/ - +#define MAX_RETRY 15 +#define MIN_DELAY_US 2000 +#define MAX_DELAY_US 9000 static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); - int rc; + int rc, retry_count = 0, min_delay = MIN_DELAY_US; + u8 stat; smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, @@ -1313,6 +1316,42 @@ static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) return rc; } + if (chg->wa_flags & OTG_WA) { + /* check for softstart */ + do { + usleep_range(min_delay, min_delay + 100); + rc = smblib_read(chg, OTG_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, + "Couldn't read OTG status rc=%d\n", + rc); + goto out; + } + + if (stat & BOOST_SOFTSTART_DONE_BIT) { + rc = smblib_set_charge_param(chg, + &chg->param.otg_cl, chg->otg_cl_ua); + if (rc < 0) + smblib_err(chg, + "Couldn't set otg limit\n"); + break; + } + + /* increase the delay for following iterations */ + if (retry_count > 5) + min_delay = MAX_DELAY_US; + } while (retry_count++ < MAX_RETRY); + + if (retry_count >= MAX_RETRY) { + smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n"); + goto out; + } + } + + return 0; +out: + /* disable OTG if softstart failed */ + smblib_write(chg, CMD_OTG_REG, 0); return rc; } @@ -1346,6 +1385,17 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } + if (chg->wa_flags & OTG_WA) { + /* set OTG current limit to minimum value */ + rc = smblib_set_charge_param(chg, &chg->param.otg_cl, + chg->param.otg_cl.min_u); + if (rc < 0) { + smblib_err(chg, + "Couldn't set otg current limit rc=%d\n", rc); + return rc; + } + } + smblib_dbg(chg, PR_OTG, "disabling OTG\n"); rc = smblib_write(chg, CMD_OTG_REG, 0); if (rc < 0) { @@ -1354,7 +1404,6 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) } smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n"); - rc = smblib_write(chg, CMD_OTG_REG, 0); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0); if (rc < 0) { @@ -2955,6 +3004,14 @@ irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data) return IRQ_HANDLED; } + if (chg->wa_flags & OTG_WA) { + if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT) + smblib_err(chg, "OTG disabled by hw\n"); + + /* not handling software based hiccups for PM660 */ + return IRQ_HANDLED; + } + if (stat & OTG_OVERCURRENT_RT_STS_BIT) schedule_work(&chg->otg_oc_work); @@ -3170,6 +3227,7 @@ irqreturn_t smblib_handle_icl_change(int irq, void *data) || (stat & AICL_DONE_BIT)) delay = 0; + cancel_delayed_work_sync(&chg->icl_change_work); schedule_delayed_work(&chg->icl_change_work, msecs_to_jiffies(delay)); } @@ -3279,11 +3337,22 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (chg->mode == PARALLEL_MASTER) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); + /* the APSD done handler will set the USB supply type */ + apsd_result = smblib_get_apsd_result(chg); + if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) { + if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { + /* force HVDCP2 to 9V if INOV is disabled */ + rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, + FORCE_9V_BIT, FORCE_9V_BIT); + if (rc < 0) + smblib_err(chg, + "Couldn't force 9V HVDCP rc=%d\n", rc); + } + } + /* QC authentication done, parallel charger can be enabled now */ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0); - /* the APSD done handler will set the USB supply type */ - apsd_result = smblib_get_apsd_result(chg); smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", apsd_result->name); } diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 21ccd3ce57c7..22ef78fd9641 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -80,6 +80,7 @@ enum { BOOST_BACK_WA = BIT(1), TYPEC_CC2_REMOVAL_WA_BIT = BIT(2), QC_AUTH_INTERRUPT_WA_BIT = BIT(3), + OTG_WA = BIT(4), }; enum smb_irq_index { @@ -305,11 +306,13 @@ struct smb_charger { int otg_attempts; int vconn_attempts; int default_icl_ua; + int otg_cl_ua; /* workaround flag */ u32 wa_flags; enum cc2_sink_type cc2_sink_detach_flag; int boost_current_ua; + int temp_speed_reading_count; /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 1c7c1e78699f..739d80cd8801 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -45,6 +45,7 @@ #define STACKED_DIODE_EN_BIT BIT(2) #define TDIE_AVG_COUNT 10 +#define MAX_SPEED_READING_TIMES 5 enum { OOB_COMP_WA_BIT = BIT(0), @@ -126,8 +127,16 @@ static int smb138x_get_prop_charger_temp(struct smb138x *chip, union power_supply_propval pval; int rc = 0, avg = 0, i; struct smb_charger *chg = &chip->chg; + int die_avg_count; - for (i = 0; i < TDIE_AVG_COUNT; i++) { + if (chg->temp_speed_reading_count < MAX_SPEED_READING_TIMES) { + chg->temp_speed_reading_count++; + die_avg_count = 1; + } else { + die_avg_count = TDIE_AVG_COUNT; + } + + for (i = 0; i < die_avg_count; i++) { pval.intval = 0; rc = smblib_get_prop_charger_temp(chg, &pval); if (rc < 0) { @@ -137,7 +146,7 @@ static int smb138x_get_prop_charger_temp(struct smb138x *chip, } avg += pval.intval; } - val->intval = avg / TDIE_AVG_COUNT; + val->intval = avg / die_avg_count; return rc; } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a878dc6a97db..88a5c497d5ed 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2931,7 +2931,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, goto out2; if (rdev->supply && (rdev->desc->min_dropout_uV || - !rdev->desc->ops->get_voltage)) { + !(rdev->desc->ops->get_voltage || + rdev->desc->ops->get_voltage_sel))) { int current_supply_uV; int selector; diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 19b1d319ef45..aef28dbeb931 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/ktime.h> #include <linux/module.h> #include <linux/of_irq.h> #include <linux/platform_device.h> @@ -31,6 +32,13 @@ #define INT_RT_STATUS_REG 0x10 #define VREG_OK_RT_STS_BIT BIT(0) +#define SC_ERROR_RT_STS_BIT BIT(1) + +#define LCDB_STS3_REG 0x0A +#define LDO_VREG_OK_BIT BIT(7) + +#define LCDB_STS4_REG 0x0B +#define NCP_VREG_OK_BIT BIT(7) #define LCDB_AUTO_TOUCH_WAKE_CTL_REG 0x40 #define EN_AUTO_TOUCH_WAKE_BIT BIT(7) @@ -185,6 +193,7 @@ struct qpnp_lcdb { struct platform_device *pdev; struct regmap *regmap; u32 base; + int sc_irq; /* TTW params */ bool ttw_enable; @@ -196,6 +205,9 @@ struct qpnp_lcdb { /* status parameters */ bool lcdb_enabled; bool settings_saved; + bool lcdb_sc_disable; + int sc_count; + ktime_t sc_module_enable_time; struct mutex lcdb_mutex; struct mutex read_write_mutex; @@ -572,8 +584,11 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) int rc = 0, timeout, delay; u8 val = 0; - if (lcdb->lcdb_enabled) + if (lcdb->lcdb_enabled || lcdb->lcdb_sc_disable) { + pr_debug("lcdb_enabled=%d lcdb_sc_disable=%d\n", + lcdb->lcdb_enabled, lcdb->lcdb_sc_disable); return 0; + } if (lcdb->ttw_enable) { rc = qpnp_lcdb_ttw_exit(lcdb); @@ -676,6 +691,111 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb) return rc; } +#define LCDB_SC_RESET_CNT_DLY_US 1000000 +#define LCDB_SC_CNT_MAX 10 +static int qpnp_lcdb_handle_sc_event(struct qpnp_lcdb *lcdb) +{ + int rc = 0; + s64 elapsed_time_us; + + mutex_lock(&lcdb->lcdb_mutex); + rc = qpnp_lcdb_disable(lcdb); + if (rc < 0) { + pr_err("Failed to disable lcdb rc=%d\n", rc); + goto unlock_mutex; + } + + /* Check if the SC re-occurred immediately */ + elapsed_time_us = ktime_us_delta(ktime_get(), + lcdb->sc_module_enable_time); + if (elapsed_time_us > LCDB_SC_RESET_CNT_DLY_US) { + lcdb->sc_count = 0; + } else if (lcdb->sc_count > LCDB_SC_CNT_MAX) { + pr_err("SC trigged %d times, disabling LCDB forever!\n", + lcdb->sc_count); + lcdb->lcdb_sc_disable = true; + goto unlock_mutex; + } + lcdb->sc_count++; + lcdb->sc_module_enable_time = ktime_get(); + + /* delay for SC to clear */ + usleep_range(10000, 10100); + + rc = qpnp_lcdb_enable(lcdb); + if (rc < 0) + pr_err("Failed to enable lcdb rc=%d\n", rc); + +unlock_mutex: + mutex_unlock(&lcdb->lcdb_mutex); + return rc; +} + +static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data) +{ + struct qpnp_lcdb *lcdb = data; + int rc; + u8 val, val2[2] = {0}; + + rc = qpnp_lcdb_read(lcdb, lcdb->base + INT_RT_STATUS_REG, &val, 1); + if (rc < 0) + goto irq_handled; + + if (val & SC_ERROR_RT_STS_BIT) { + rc = qpnp_lcdb_read(lcdb, + lcdb->base + LCDB_MISC_CTL_REG, &val, 1); + if (rc < 0) + goto irq_handled; + + if (val & EN_TOUCH_WAKE_BIT) { + /* blanking time */ + usleep_range(300, 310); + /* + * The status registers need to written with any value + * before reading + */ + rc = qpnp_lcdb_write(lcdb, + lcdb->base + LCDB_STS3_REG, val2, 2); + if (rc < 0) + goto irq_handled; + + rc = qpnp_lcdb_read(lcdb, + lcdb->base + LCDB_STS3_REG, val2, 2); + if (rc < 0) + goto irq_handled; + + if (!(val2[0] & LDO_VREG_OK_BIT) || + !(val2[1] & NCP_VREG_OK_BIT)) { + rc = qpnp_lcdb_handle_sc_event(lcdb); + if (rc < 0) { + pr_err("Failed to handle SC rc=%d\n", + rc); + goto irq_handled; + } + } + } else { + /* blanking time */ + usleep_range(2000, 2100); + /* Read the SC status again to confirm true SC */ + rc = qpnp_lcdb_read(lcdb, + lcdb->base + INT_RT_STATUS_REG, &val, 1); + if (rc < 0) + goto irq_handled; + + if (val & SC_ERROR_RT_STS_BIT) { + rc = qpnp_lcdb_handle_sc_event(lcdb); + if (rc < 0) { + pr_err("Failed to handle SC rc=%d\n", + rc); + goto irq_handled; + } + } + } + } +irq_handled: + return IRQ_HANDLED; +} + #define MIN_BST_VOLTAGE_MV 4700 #define MAX_BST_VOLTAGE_MV 6250 #define MIN_VOLTAGE_MV 4000 @@ -1554,6 +1674,18 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb) return rc; } + if (lcdb->sc_irq >= 0) { + lcdb->sc_count = 0; + rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq, + NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT, + "qpnp_lcdb_sc_irq", lcdb); + if (rc < 0) { + pr_err("Unable to request sc(%d) irq rc=%d\n", + lcdb->sc_irq, rc); + return rc; + } + } + if (!is_lcdb_enabled(lcdb)) { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_MODULE_RDY_REG, &val, 1); @@ -1622,6 +1754,10 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb) lcdb->ttw_enable = true; } + lcdb->sc_irq = platform_get_irq_byname(lcdb->pdev, "sc-irq"); + if (lcdb->sc_irq < 0) + pr_debug("sc irq is not defined\n"); + return rc; } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 4e541773c805..2fcd1a4c636c 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -110,13 +110,7 @@ module_param(qmi_timeout, ulong, 0600); } \ } while (0) #else -#define ICNSS_ASSERT(_condition) do { \ - if (!(_condition)) { \ - icnss_pr_err("ASSERT at line %d\n", \ - __LINE__); \ - WARN_ON(1); \ - } \ - } while (0) +#define ICNSS_ASSERT(_condition) do { } while (0) #endif enum icnss_debug_quirks { @@ -213,7 +207,7 @@ struct icnss_clk_info { }; static struct icnss_vreg_info icnss_vreg_info[] = { - {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, true}, + {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false}, {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false}, {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false}, {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false}, diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index 10f71b85a15b..fe5458974406 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -368,6 +368,9 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, struct voice_svc_prvt *prtd; struct voice_svc_write_msg *data = NULL; uint32_t cmd; + struct voice_svc_register *register_data = NULL; + struct voice_svc_cmd_request *request_data = NULL; + uint32_t request_payload_size; pr_debug("%s\n", __func__); @@ -416,12 +419,19 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, */ if (count == (sizeof(struct voice_svc_write_msg) + sizeof(struct voice_svc_register))) { - ret = process_reg_cmd( - (struct voice_svc_register *)data->payload, prtd); + register_data = + (struct voice_svc_register *)data->payload; + if (register_data == NULL) { + pr_err("%s: register data is NULL", __func__); + ret = -EINVAL; + goto done; + } + ret = process_reg_cmd(register_data, prtd); if (!ret) ret = count; } else { - pr_err("%s: invalid payload size\n", __func__); + pr_err("%s: invalid data payload size for register command\n", + __func__); ret = -EINVAL; goto done; } @@ -430,19 +440,40 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, /* * Check that count reflects the expected size to ensure * sufficient memory was allocated. Since voice_svc_cmd_request - * has a variable size, check the minimum value count must be. + * has a variable size, check the minimum value count must be to + * parse the message request then check the minimum size to hold + * the payload of the message request. */ if (count >= (sizeof(struct voice_svc_write_msg) + sizeof(struct voice_svc_cmd_request))) { - ret = voice_svc_send_req( - (struct voice_svc_cmd_request *)data->payload, prtd); - if (!ret) - ret = count; - } else { - pr_err("%s: invalid payload size\n", __func__); - ret = -EINVAL; - goto done; - } + request_data = + (struct voice_svc_cmd_request *)data->payload; + if (request_data == NULL) { + pr_err("%s: request data is NULL", __func__); + ret = -EINVAL; + goto done; + } + + request_payload_size = request_data->payload_size; + + if (count >= (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_cmd_request) + + request_payload_size)) { + ret = voice_svc_send_req(request_data, prtd); + if (!ret) + ret = count; + } else { + pr_err("%s: invalid request payload size\n", + __func__); + ret = -EINVAL; + goto done; + } + } else { + pr_err("%s: invalid data payload size for request command\n", + __func__); + ret = -EINVAL; + goto done; + } break; default: pr_debug("%s: Invalid command: %u\n", __func__, cmd); diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c index cf0b7ff25201..c7059d60d786 100644 --- a/drivers/soc/qcom/qpnp-haptic.c +++ b/drivers/soc/qcom/qpnp-haptic.c @@ -25,6 +25,7 @@ #include <linux/qpnp/pwm.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/qpnp/qpnp-revid.h> #include <linux/qpnp/qpnp-haptic.h> #include "../../staging/android/timed_output.h" @@ -37,6 +38,7 @@ #define QPNP_HAP_LRA_AUTO_RES_HI(b) (b + 0x0C) #define QPNP_HAP_EN_CTL_REG(b) (b + 0x46) #define QPNP_HAP_EN_CTL2_REG(b) (b + 0x48) +#define QPNP_HAP_AUTO_RES_CTRL(b) (b + 0x4B) #define QPNP_HAP_ACT_TYPE_REG(b) (b + 0x4C) #define QPNP_HAP_WAV_SHAPE_REG(b) (b + 0x4D) #define QPNP_HAP_PLAY_MODE_REG(b) (b + 0x4E) @@ -62,13 +64,25 @@ #define QPNP_HAP_ACT_TYPE_MASK 0xFE #define QPNP_HAP_LRA 0x0 #define QPNP_HAP_ERM 0x1 -#define QPNP_HAP_AUTO_RES_MODE_MASK 0x8F +#define QPNP_HAP_AUTO_RES_MODE_MASK GENMASK(6, 4) #define QPNP_HAP_AUTO_RES_MODE_SHIFT 4 -#define QPNP_HAP_LRA_HIGH_Z_MASK 0xF3 +#define QPNP_HAP_PM660_AUTO_RES_MODE_BIT BIT(7) +#define QPNP_HAP_PM660_AUTO_RES_MODE_SHIFT 7 +#define QPNP_HAP_PM660_CALIBRATE_DURATION_MASK GENMASK(6, 5) +#define QPNP_HAP_PM660_CALIBRATE_DURATION_SHIFT 5 +#define QPNP_HAP_PM660_QWD_DRIVE_DURATION_BIT BIT(4) +#define QPNP_HAP_PM660_QWD_DRIVE_DURATION_SHIFT 4 +#define QPNP_HAP_PM660_CALIBRATE_AT_EOP_BIT BIT(3) +#define QPNP_HAP_PM660_CALIBRATE_AT_EOP_SHIFT 3 +#define QPNP_HAP_PM660_LRA_ZXD_CAL_PERIOD_BIT GENMASK(2, 0) +#define QPNP_HAP_LRA_HIGH_Z_MASK GENMASK(3, 2) #define QPNP_HAP_LRA_HIGH_Z_SHIFT 2 -#define QPNP_HAP_LRA_RES_CAL_PER_MASK 0xFC +#define QPNP_HAP_LRA_RES_CAL_PER_MASK GENMASK(1, 0) +#define QPNP_HAP_PM660_LRA_RES_CAL_PER_MASK GENMASK(2, 0) #define QPNP_HAP_RES_CAL_PERIOD_MIN 4 #define QPNP_HAP_RES_CAL_PERIOD_MAX 32 +#define QPNP_HAP_PM660_RES_CAL_PERIOD_MIN 4 +#define QPNP_HAP_PM660_RES_CAL_PERIOD_MAX 256 #define QPNP_HAP_PLAY_MODE_MASK 0xCF #define QPNP_HAP_PLAY_MODE_SHFT 4 #define QPNP_HAP_VMAX_MASK 0xC1 @@ -130,7 +144,6 @@ #define QPNP_HAP_TEST2_AUTO_RES_MASK 0x7F #define QPNP_HAP_SEC_UNLOCK 0xA5 #define AUTO_RES_ENABLE 0x80 -#define AUTO_RES_DISABLE 0x00 #define AUTO_RES_ERR_BIT 0x10 #define SC_FOUND_BIT 0x08 #define SC_MAX_DURATION 5 @@ -148,7 +161,7 @@ #define MISC_SEC_UNLOCK 0xA5 #define PMI8950_MISC_SID 2 -#define POLL_TIME_AUTO_RES_ERR_NS (5 * NSEC_PER_MSEC) +#define POLL_TIME_AUTO_RES_ERR_NS (20 * NSEC_PER_MSEC) #define MAX_POSITIVE_VARIATION_LRA_FREQ 30 #define MAX_NEGATIVE_VARIATION_LRA_FREQ -30 @@ -222,9 +235,14 @@ enum qpnp_hap_auto_res_mode { QPNP_HAP_AUTO_RES_ZXD_EOP, }; +enum qpnp_hap_pm660_auto_res_mode { + QPNP_HAP_PM660_AUTO_RES_ZXD, + QPNP_HAP_PM660_AUTO_RES_QWD, +}; + /* high Z option lines */ enum qpnp_hap_high_z { - QPNP_HAP_LRA_HIGH_Z_NONE, + QPNP_HAP_LRA_HIGH_Z_NONE, /* opt0 for PM660 */ QPNP_HAP_LRA_HIGH_Z_OPT1, QPNP_HAP_LRA_HIGH_Z_OPT2, QPNP_HAP_LRA_HIGH_Z_OPT3, @@ -238,6 +256,11 @@ enum qpnp_hap_mode { QPNP_HAP_PWM, }; +/* status flags */ +enum qpnp_hap_status { + AUTO_RESONANCE_ENABLED = BIT(0), +}; + /* pwm channel info */ struct qpnp_pwm_info { struct pwm_device *pwm_dev; @@ -253,7 +276,6 @@ struct qpnp_pwm_info { * @ auto_res_err_poll_timer - hrtimer for auto-resonance error * @ timed_dev - timed output device * @ work - worker - * @ auto_res_err_work - correct auto resonance error * @ sc_work - worker to handle short circuit condition * @ pwm_info - pwm info * @ lock - mutex lock @@ -267,6 +289,7 @@ struct qpnp_pwm_info { percentage variation on the higher side. * @ drive_period_code_min_limit - calculated drive period code with percentage variation on the lower side + * @ lra_res_cal_period - LRA resonance calibration period * @ play_mode - play mode * @ auto_res_mode - auto resonace mode * @ lra_high_z - high z option line @@ -283,6 +306,7 @@ struct qpnp_pwm_info { * @ wave_s_rep_cnt - waveform sample repeat count * @ play_irq - irq for play * @ sc_irq - irq for short circuit + * @ status_flags - status * @ base - base address * @ act_type - actuator type * @ wave_shape - waveform shape @@ -314,7 +338,6 @@ struct qpnp_hap { struct hrtimer auto_res_err_poll_timer; struct timed_output_dev timed_dev; struct work_struct work; - struct work_struct auto_res_err_work; struct delayed_work sc_work; struct hrtimer hap_test_timer; struct work_struct test_work; @@ -323,8 +346,9 @@ struct qpnp_hap { struct mutex wf_lock; struct completion completion; enum qpnp_hap_mode play_mode; - enum qpnp_hap_auto_res_mode auto_res_mode; enum qpnp_hap_high_z lra_high_z; + int lra_qwd_drive_duration; + int calibrate_at_eop; u32 init_drive_period_code; u32 timeout_ms; u32 time_required_to_generate_back_emf_us; @@ -338,9 +362,11 @@ struct qpnp_hap { u32 wave_s_rep_cnt; u32 play_irq; u32 sc_irq; + u32 status_flags; u16 base; u16 drive_period_code_max_limit; u16 drive_period_code_min_limit; + u16 lra_res_cal_period; u8 drive_period_code_max_limit_percent_variation; u8 drive_period_code_min_limit_percent_variation; u8 act_type; @@ -350,9 +376,10 @@ struct qpnp_hap { u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN]; u8 reg_en_ctl; u8 reg_play; - u8 lra_res_cal_period; u8 sc_duration; u8 ext_pwm_dtest_line; + u8 pmic_subtype; + u8 auto_res_mode; bool vcc_pon_enabled; bool state; bool use_play_irq; @@ -398,6 +425,21 @@ static int qpnp_hap_write_reg(struct qpnp_hap *hap, u8 *data, u16 addr) return rc; } +static int +qpnp_hap_masked_write_reg(struct qpnp_hap *hap, u8 val, u16 addr, u8 mask) +{ + int rc; + + rc = regmap_update_bits(hap->regmap, addr, mask, val); + if (rc < 0) + pr_err("Unable to update bits from 0x%04X, rc = %d\n", addr, + rc); + else + pr_debug("Wrote 0x%02X to addr 0x%04X\n", val, addr); + + return rc; +} + /* helper to access secure registers */ static int qpnp_hap_sec_access(struct qpnp_hap *hap) { @@ -1408,34 +1450,40 @@ static int calculate_lra_code(struct qpnp_hap *hap) static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable) { int rc = 0; - u8 val; + u8 val = 0; + u16 addr; - rc = qpnp_hap_read_reg(hap, &val, QPNP_HAP_TEST2_REG(hap->base)); - if (rc < 0) - return rc; - val &= QPNP_HAP_TEST2_AUTO_RES_MASK; + + if (hap->pmic_subtype == PM660_SUBTYPE) { + addr = QPNP_HAP_AUTO_RES_CTRL(hap->base); + } else { + addr = QPNP_HAP_TEST2_REG(hap->base); + /* TEST2 is a secure access register */ + rc = qpnp_hap_sec_access(hap); + if (rc) + return rc; + } if (enable) val |= AUTO_RES_ENABLE; - else - val |= AUTO_RES_DISABLE; - /* TEST2 is a secure access register */ - rc = qpnp_hap_sec_access(hap); + rc = qpnp_hap_masked_write_reg(hap, val, addr, AUTO_RES_ENABLE); if (rc) return rc; - rc = qpnp_hap_write_reg(hap, &val, QPNP_HAP_TEST2_REG(hap->base)); - if (rc) - return rc; + if (enable) + hap->status_flags |= AUTO_RESONANCE_ENABLED; + else + hap->status_flags &= ~AUTO_RESONANCE_ENABLED; return 0; } static void update_lra_frequency(struct qpnp_hap *hap) { - u8 lra_auto_res_lo = 0, lra_auto_res_hi = 0; + u8 lra_auto_res_lo = 0, lra_auto_res_hi = 0, val; u32 play_rate_code; + int rc; qpnp_hap_read_reg(hap, &lra_auto_res_lo, QPNP_HAP_LRA_AUTO_RES_LO(hap->base)); @@ -1449,16 +1497,29 @@ static void update_lra_frequency(struct qpnp_hap *hap) "lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n", lra_auto_res_lo, lra_auto_res_hi, play_rate_code); + rc = qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base)); + if (rc < 0) + return; + /* - * If the drive period code read from AUTO RES_LO and AUTO_RES_HI - * registers is more than the max limit percent variation read from - * DT or less than the min limit percent variation read from DT, then - * RATE_CFG registers are not uptdated. + * If the drive period code read from AUTO_RES_LO and AUTO_RES_HI + * registers is more than the max limit percent variation or less + * than the min limit percent variation specified through DT, then + * auto-resonance is disabled. */ - if ((play_rate_code <= hap->drive_period_code_min_limit) || - (play_rate_code >= hap->drive_period_code_max_limit)) + if ((val & AUTO_RES_ERR_BIT) || + ((play_rate_code <= hap->drive_period_code_min_limit) || + (play_rate_code >= hap->drive_period_code_max_limit))) { + dev_dbg(&hap->pdev->dev, + "Auto-resonance error, out of 25%%, [min: 0x%x, max: 0x%x]\n", + hap->drive_period_code_min_limit, + hap->drive_period_code_max_limit); + rc = qpnp_hap_auto_res_enable(hap, 0); + if (rc < 0) + dev_dbg(&hap->pdev->dev, "Auto-resonance write failed\n"); return; + } qpnp_hap_write_reg(hap, &lra_auto_res_lo, QPNP_HAP_RATE_CFG1_REG(hap->base)); @@ -1472,15 +1533,11 @@ static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer) { struct qpnp_hap *hap = container_of(timer, struct qpnp_hap, auto_res_err_poll_timer); - u8 val; ktime_t currtime; - qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base)); - if (val & AUTO_RES_ERR_BIT) { - schedule_work(&hap->auto_res_err_work); + if (!(hap->status_flags & AUTO_RESONANCE_ENABLED)) return HRTIMER_NORESTART; - } update_lra_frequency(hap); currtime = ktime_get(); @@ -1489,56 +1546,11 @@ static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer) return HRTIMER_RESTART; } -static void correct_auto_res_error(struct work_struct *auto_res_err_work) -{ - struct qpnp_hap *hap = container_of(auto_res_err_work, - struct qpnp_hap, auto_res_err_work); - - u8 lra_code_lo, lra_code_hi, disable_hap = 0x00; - static u8 lra_freq_index; - ktime_t currtime = ktime_set(0, 0), remaining_time = ktime_set(0, 0); - - if (hrtimer_active(&hap->hap_timer)) - remaining_time = hrtimer_get_remaining(&hap->hap_timer); - - qpnp_hap_play(hap, 0); - qpnp_hap_write_reg(hap, &disable_hap, - QPNP_HAP_EN_CTL_REG(hap->base)); - - if (hap->perform_lra_auto_resonance_search) { - lra_code_lo = - adjusted_lra_play_rate_code[lra_freq_index] - & QPNP_HAP_RATE_CFG1_MASK; - - qpnp_hap_write_reg(hap, &lra_code_lo, - QPNP_HAP_RATE_CFG1_REG(hap->base)); - - lra_code_hi = adjusted_lra_play_rate_code[lra_freq_index] - >> QPNP_HAP_RATE_CFG2_SHFT; - - qpnp_hap_write_reg(hap, &lra_code_hi, - QPNP_HAP_RATE_CFG2_REG(hap->base)); - - lra_freq_index = (lra_freq_index+1) % - ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE; - } - - dev_dbg(&hap->pdev->dev, "Remaining time is %lld\n", - ktime_to_us(remaining_time)); - - if ((ktime_to_us(remaining_time)) > 0) { - currtime = ktime_get(); - hap->state = 1; - hrtimer_forward(&hap->hap_timer, currtime, remaining_time); - schedule_work(&hap->work); - } -} - /* set api for haptics */ static int qpnp_hap_set(struct qpnp_hap *hap, int on) { + u8 auto_res_mode_qwd; int rc = 0; - u8 val = 0; unsigned long timeout_ns = POLL_TIME_AUTO_RES_ERR_NS; u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; @@ -1562,9 +1574,16 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) * and enable it after the sleep of * 'time_required_to_generate_back_emf_us' is completed. */ + if (hap->pmic_subtype == PM660_SUBTYPE) + auto_res_mode_qwd = (hap->auto_res_mode == + QPNP_HAP_PM660_AUTO_RES_QWD); + else + auto_res_mode_qwd = (hap->auto_res_mode == + QPNP_HAP_AUTO_RES_QWD); + if ((hap->act_type == QPNP_HAP_LRA) && (hap->correct_lra_drive_freq || - hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD)) + auto_res_mode_qwd)) qpnp_hap_auto_res_enable(hap, 0); rc = qpnp_hap_mod_enable(hap, on); @@ -1575,7 +1594,7 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) if ((hap->act_type == QPNP_HAP_LRA) && (hap->correct_lra_drive_freq || - hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD)) { + auto_res_mode_qwd)) { usleep_range(back_emf_delay_us, (back_emf_delay_us + 1)); @@ -1601,11 +1620,9 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) return rc; if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq) { - rc = qpnp_hap_read_reg(hap, &val, - QPNP_HAP_STATUS(hap->base)); - if (!(val & AUTO_RES_ERR_BIT)) - update_lra_frequency(hap); + hap->correct_lra_drive_freq && + (hap->status_flags & AUTO_RESONANCE_ENABLED)) { + update_lra_frequency(hap); } rc = qpnp_hap_mod_enable(hap, on); @@ -1810,7 +1827,7 @@ static SIMPLE_DEV_PM_OPS(qpnp_haptic_pm_ops, qpnp_haptic_suspend, NULL); /* Configuration api for haptics registers */ static int qpnp_hap_config(struct qpnp_hap *hap) { - u8 reg = 0, unlock_val; + u8 reg = 0, unlock_val, mask; u32 temp; int rc, i; uint error_code = 0; @@ -1832,24 +1849,66 @@ static int qpnp_hap_config(struct qpnp_hap *hap) /* Configure auto resonance parameters */ if (hap->act_type == QPNP_HAP_LRA) { - if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; - else if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (hap->lra_res_cal_period < + QPNP_HAP_PM660_RES_CAL_PERIOD_MIN) + hap->lra_res_cal_period = + QPNP_HAP_PM660_RES_CAL_PERIOD_MIN; + else if (hap->lra_res_cal_period > + QPNP_HAP_PM660_RES_CAL_PERIOD_MAX) + hap->lra_res_cal_period = + QPNP_HAP_PM660_RES_CAL_PERIOD_MAX; + } else if (hap->pmic_subtype != PM660_SUBTYPE) { + if (hap->lra_res_cal_period < + QPNP_HAP_RES_CAL_PERIOD_MIN) + hap->lra_res_cal_period = + QPNP_HAP_RES_CAL_PERIOD_MIN; + else if (hap->lra_res_cal_period > + QPNP_HAP_RES_CAL_PERIOD_MAX) + hap->lra_res_cal_period = + QPNP_HAP_RES_CAL_PERIOD_MAX; + } + if (hap->pmic_subtype == PM660_SUBTYPE && + hap->auto_res_mode == QPNP_HAP_PM660_AUTO_RES_QWD) { + hap->lra_res_cal_period = 0; + } - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_AUTO_RES_MODE_MASK; - reg |= (hap->auto_res_mode << QPNP_HAP_AUTO_RES_MODE_SHIFT); - reg &= QPNP_HAP_LRA_HIGH_Z_MASK; - reg |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); - reg &= QPNP_HAP_LRA_RES_CAL_PER_MASK; - temp = fls(hap->lra_res_cal_period) - 1; - reg |= (temp - 2); - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); + reg = mask = 0; + if (hap->pmic_subtype == PM660_SUBTYPE) { + reg |= hap->auto_res_mode << + QPNP_HAP_PM660_AUTO_RES_MODE_SHIFT; + mask = QPNP_HAP_PM660_AUTO_RES_MODE_BIT; + reg |= hap->lra_high_z << + QPNP_HAP_PM660_CALIBRATE_DURATION_SHIFT; + mask |= QPNP_HAP_PM660_CALIBRATE_DURATION_MASK; + if (hap->lra_qwd_drive_duration != -EINVAL) { + reg |= hap->lra_qwd_drive_duration << + QPNP_HAP_PM660_QWD_DRIVE_DURATION_SHIFT; + mask |= QPNP_HAP_PM660_QWD_DRIVE_DURATION_BIT; + } + if (hap->calibrate_at_eop != -EINVAL) { + reg |= hap->calibrate_at_eop << + QPNP_HAP_PM660_CALIBRATE_AT_EOP_SHIFT; + mask |= QPNP_HAP_PM660_CALIBRATE_AT_EOP_BIT; + } + if (hap->lra_res_cal_period) { + temp = fls(hap->lra_res_cal_period) - 1; + reg |= (temp - 1); + } + mask |= QPNP_HAP_PM660_LRA_RES_CAL_PER_MASK; + } else { + reg |= (hap->auto_res_mode << + QPNP_HAP_AUTO_RES_MODE_SHIFT); + mask = QPNP_HAP_AUTO_RES_MODE_MASK; + reg |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); + mask |= QPNP_HAP_LRA_HIGH_Z_MASK; + temp = fls(hap->lra_res_cal_period) - 1; + reg |= (temp - 2); + mask |= QPNP_HAP_LRA_RES_CAL_PER_MASK; + } + rc = qpnp_hap_masked_write_reg(hap, reg, + QPNP_HAP_LRA_AUTO_RES_REG(hap->base), + mask); if (rc) return rc; } else { @@ -1895,8 +1954,13 @@ static int qpnp_hap_config(struct qpnp_hap *hap) /* Configure the INTERNAL_PWM register */ if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_253_KHZ) { - hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_253_KHZ; - temp = 0; + if (hap->pmic_subtype == PM660_SUBTYPE) { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ; + temp = 1; + } else { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_253_KHZ; + temp = 0; + } } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_505_KHZ) { hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ; temp = 1; @@ -2023,11 +2087,13 @@ static int qpnp_hap_config(struct qpnp_hap *hap) if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) { hap->drive_period_code_max_limit = - (hap->init_drive_period_code * 100) / - (100 - hap->drive_period_code_max_limit_percent_variation); + (hap->init_drive_period_code * (100 + + hap->drive_period_code_max_limit_percent_variation)) + / 100; hap->drive_period_code_min_limit = - (hap->init_drive_period_code * 100) / - (100 + hap->drive_period_code_min_limit_percent_variation); + (hap->init_drive_period_code * (100 - + hap->drive_period_code_min_limit_percent_variation)) + / 100; dev_dbg(&hap->pdev->dev, "Drive period code max limit %x\n" "Drive period code min limit %x\n", hap->drive_period_code_max_limit, @@ -2134,20 +2200,36 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) } if (hap->act_type == QPNP_HAP_LRA) { - hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; rc = of_property_read_string(pdev->dev.of_node, "qcom,lra-auto-res-mode", &temp_str); if (!rc) { - if (strcmp(temp_str, "none") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_NONE; - else if (strcmp(temp_str, "zxd") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD; - else if (strcmp(temp_str, "qwd") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_QWD; - else if (strcmp(temp_str, "max-qwd") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_MAX_QWD; - else + if (hap->pmic_subtype == PM660_SUBTYPE) { + hap->auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_QWD; + if (strcmp(temp_str, "zxd") == 0) + hap->auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_ZXD; + else if (strcmp(temp_str, "qwd") == 0) + hap->auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_QWD; + } else { hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; + if (strcmp(temp_str, "none") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_NONE; + else if (strcmp(temp_str, "zxd") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_ZXD; + else if (strcmp(temp_str, "qwd") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_QWD; + else if (strcmp(temp_str, "max-qwd") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_MAX_QWD; + else + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_ZXD_EOP; + } } else if (rc != -EINVAL) { dev_err(&pdev->dev, "Unable to read auto res mode\n"); return rc; @@ -2159,6 +2241,11 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { if (strcmp(temp_str, "none") == 0) hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_NONE; + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (strcmp(temp_str, "opt0") == 0) + hap->lra_high_z = + QPNP_HAP_LRA_HIGH_Z_NONE; + } else if (strcmp(temp_str, "opt1") == 0) hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; else if (strcmp(temp_str, "opt2") == 0) @@ -2170,6 +2257,15 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) return rc; } + hap->lra_qwd_drive_duration = -EINVAL; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,lra-qwd-drive-duration", + &hap->lra_qwd_drive_duration); + + hap->calibrate_at_eop = -EINVAL; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,lra-calibrate-at-eop", &hap->calibrate_at_eop); + hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; rc = of_property_read_u32(pdev->dev.of_node, "qcom,lra-res-cal-period", &temp); @@ -2347,6 +2443,34 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) return 0; } +static int qpnp_hap_get_pmic_revid(struct qpnp_hap *hap) +{ + struct pmic_revid_data *pmic_rev_id; + struct device_node *revid_dev_node; + + revid_dev_node = of_parse_phandle(hap->pdev->dev.of_node, + "qcom,pmic-revid", 0); + if (!revid_dev_node) { + pr_err("Missing qcom,pmic-revid property - driver failed\n"); + return -EINVAL; + } + pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR_OR_NULL(pmic_rev_id)) { + pr_err("Unable to get pmic_revid rc=%ld\n", + PTR_ERR(pmic_rev_id)); + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + hap->pmic_subtype = pmic_rev_id->pmic_subtype; + + return 0; +} + static int qpnp_haptic_probe(struct platform_device *pdev) { struct qpnp_hap *hap; @@ -2376,6 +2500,12 @@ static int qpnp_haptic_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, hap); + rc = qpnp_hap_get_pmic_revid(hap); + if (rc) { + pr_err("Unable to check PMIC version rc=%d\n", rc); + return rc; + } + rc = qpnp_hap_parse_dt(hap); if (rc) { dev_err(&pdev->dev, "DT parsing failed\n"); @@ -2405,7 +2535,6 @@ static int qpnp_haptic_probe(struct platform_device *pdev) hap->timed_dev.enable = qpnp_hap_td_enable; if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) { - INIT_WORK(&hap->auto_res_err_work, correct_auto_res_error); hrtimer_init(&hap->auto_res_err_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hap->auto_res_err_poll_timer.function = detect_auto_res_error; diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 8581ed587ead..0d6c1d62c732 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -266,10 +266,9 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) if (!domains_read) { db_rev_count = pd->db_rev_count = resp->db_rev_count; pd->total_domains = resp->total_domains; - if (!pd->total_domains && resp->domain_list_len) { - pr_err("total domains not set\n"); - pd->total_domains = resp->domain_list_len; - } + if (!resp->total_domains) + pr_info("No matching domains found\n"); + pd->domain_list = kmalloc( sizeof(struct servreg_loc_entry_v01) * resp->total_domains, GFP_KERNEL); @@ -286,6 +285,10 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) rc = -EAGAIN; goto out; } + if (resp->domain_list_len > resp->total_domains) { + /* Always read total_domains from the response msg */ + resp->domain_list_len = resp->total_domains; + } /* Copy the response*/ store_get_domain_list_response(pd, resp, domains_read); domains_read += resp->domain_list_len; diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index c1c65cd25558..ebea5b7726e4 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -99,6 +99,7 @@ struct ind_req_resp { */ struct qmi_client_info { int instance_id; + int subsys_state; struct work_struct svc_arrive; struct work_struct svc_exit; struct work_struct svc_rcv_msg; @@ -436,7 +437,7 @@ static void root_service_exit_work(struct work_struct *work) { struct qmi_client_info *data = container_of(work, struct qmi_client_info, svc_exit); - root_service_service_exit(data, ROOT_PD_DOWN); + root_service_service_exit(data, data->subsys_state); } static int service_event_notify(struct notifier_block *this, @@ -453,6 +454,7 @@ static int service_event_notify(struct notifier_block *this, break; case QMI_SERVER_EXIT: pr_debug("Root PD service DOWN\n"); + data->subsys_state = ROOT_PD_DOWN; queue_work(data->svc_event_wq, &data->svc_exit); break; default: @@ -468,7 +470,6 @@ static int ssr_event_notify(struct notifier_block *this, struct qmi_client_info *info = container_of(this, struct qmi_client_info, ssr_notifier); struct notif_data *notif = data; - enum pd_subsys_state state; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: @@ -476,16 +477,16 @@ static int ssr_event_notify(struct notifier_block *this, notif->crashed); switch (notif->crashed) { case CRASH_STATUS_ERR_FATAL: - state = ROOT_PD_ERR_FATAL; + info->subsys_state = ROOT_PD_ERR_FATAL; break; case CRASH_STATUS_WDOG_BITE: - state = ROOT_PD_WDOG_BITE; + info->subsys_state = ROOT_PD_WDOG_BITE; break; default: - state = ROOT_PD_SHUTDOWN; + info->subsys_state = ROOT_PD_SHUTDOWN; break; } - root_service_service_exit(info, state); + queue_work(info->svc_event_wq, &info->svc_exit); break; default: break; diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c index 4ebfc713cb28..cff5b6e3fc63 100644 --- a/drivers/thermal/msm_lmh_dcvs.c +++ b/drivers/thermal/msm_lmh_dcvs.c @@ -78,6 +78,7 @@ enum lmh_hw_trips { }; struct msm_lmh_dcvs_hw { + char sensor_name[THERMAL_NAME_LENGTH]; uint32_t affinity; uint32_t temp_limits[LIMITS_TRIP_MAX]; struct sensor_threshold default_lo, default_hi; @@ -381,7 +382,6 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) int ret; int affinity = -1; struct msm_lmh_dcvs_hw *hw; - char sensor_name[] = "limits_sensor-00"; struct thermal_zone_device *tzdev; struct thermal_cooling_device *cdev; struct device_node *dn = pdev->dev.of_node; @@ -450,9 +450,9 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) * Let's register with thermal framework, so we have the ability * to set low/high thresholds. */ - snprintf(sensor_name, sizeof(sensor_name), "limits_sensor-%02d", + snprintf(hw->sensor_name, sizeof(hw->sensor_name), "limits_sensor-%02d", affinity); - tzdev = thermal_zone_device_register(sensor_name, LIMITS_TRIP_MAX, + tzdev = thermal_zone_device_register(hw->sensor_name, LIMITS_TRIP_MAX, (1 << LIMITS_TRIP_MAX) - 1, hw, &limits_sensor_ops, NULL, 0, 0); if (IS_ERR_OR_NULL(tzdev)) @@ -467,7 +467,7 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) * Since we make a check for hi > lo value, set the hi threshold * before the low threshold */ - id = sensor_get_id(sensor_name); + id = sensor_get_id(hw->sensor_name); if (id < 0) return id; @@ -525,7 +525,7 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) set_bit(1, hw->is_irq_enabled); ret = devm_request_threaded_irq(&pdev->dev, hw->irq_num, NULL, lmh_dcvs_handle_isr, IRQF_TRIGGER_HIGH | IRQF_ONESHOT - | IRQF_NO_SUSPEND, sensor_name, hw); + | IRQF_NO_SUSPEND, hw->sensor_name, hw); if (ret) { pr_err("Error registering for irq. err:%d\n", ret); return ret; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 9622514e3df9..9d795489c285 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2470,6 +2470,7 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) } spin_unlock_irqrestore(&cdev->lock, flags); WARN(cdev, "%s: Unexpected call\n", __func__); + return; } else if (--cdev->delayed_status == 0) { DBG(cdev, "%s: Completing delayed status\n", __func__); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index ab44bd316217..31d3022b6ce7 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1879,8 +1879,8 @@ static int ffs_epfiles_create(struct ffs_data *ffs) ffs->epfiles = epfiles; - ffs_log("exit: epfile name %s state %d setup_state %d flag %lu", - epfile->name, ffs->state, ffs->setup_state, ffs->flags); + ffs_log("exit: eps_count %u state %d setup_state %d flag %lu", + count, ffs->state, ffs->setup_state, ffs->flags); return 0; } @@ -1891,7 +1891,7 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) ENTER(); - ffs_log("enter: epfilename %s", epfile->name); + ffs_log("enter: count %u", count); for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex) || diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index e46edc83430c..be532503954f 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -148,15 +148,10 @@ int gsi_wakeup_host(struct f_gsi *gsi) struct usb_function *func; func = &gsi->function; - gadget = gsi->function.config->cdev->gadget; + gadget = gsi->gadget; log_event_dbg("Entering %s", __func__); - if (!gadget) { - log_event_err("FAILED: d_port->cdev->gadget == NULL"); - return -ENODEV; - } - /* * In Super-Speed mode, remote wakeup is not allowed for suspended * functions which have been disallowed by the host to issue Function @@ -276,7 +271,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) &d_port->ipa_out_channel_params; struct ipa_usb_xdci_connect_params *conn_params = &d_port->ipa_conn_pms; - struct usb_composite_dev *cdev = gsi->function.config->cdev; + struct usb_gadget *gadget = gsi->gadget; struct gsi_channel_info gsi_channel_info; struct ipa_req_chan_out_params ipa_in_channel_out_params; struct ipa_req_chan_out_params ipa_out_channel_out_params; @@ -366,7 +361,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) /* Populate connection params */ conn_params->max_pkt_size = - (cdev->gadget->speed == USB_SPEED_SUPER) ? + (gadget->speed == USB_SPEED_SUPER) ? IPA_USB_SUPER_SPEED_1024B : IPA_USB_HIGH_SPEED_512B; conn_params->ipa_to_usb_xferrscidx = d_port->in_xfer_rsc_index; @@ -392,7 +387,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) conn_params->teth_prot_params.max_packet_number_to_dev = DEFAULT_MAX_PKT_PER_XFER; conn_params->max_supported_bandwidth_mbps = - (cdev->gadget->speed == USB_SPEED_SUPER) ? 3600 : 400; + (gadget->speed == USB_SPEED_SUPER) ? 3600 : 400; memset(&ipa_in_channel_out_params, 0x0, sizeof(ipa_in_channel_out_params)); @@ -604,12 +599,12 @@ static void ipa_work_handler(struct work_struct *w) { struct gsi_data_port *d_port = container_of(w, struct gsi_data_port, usb_ipa_w); + struct f_gsi *gsi = d_port_to_gsi(d_port); u8 event; int ret = 0; - struct usb_gadget *gadget = d_port->gadget; + struct usb_gadget *gadget = gsi->gadget; struct device *dev; struct device *gad_dev; - struct f_gsi *gsi; event = read_event(d_port); @@ -636,7 +631,7 @@ static void ipa_work_handler(struct work_struct *w) break; case STATE_INITIALIZED: if (event == EVT_CONNECT_IN_PROGRESS) { - usb_gadget_autopm_get(d_port->gadget); + usb_gadget_autopm_get(gadget); log_event_dbg("%s: get = %d", __func__, atomic_read(&gad_dev->power.usage_count)); /* allocate buffers used with each TRB */ @@ -661,7 +656,7 @@ static void ipa_work_handler(struct work_struct *w) * EVT_HOST_READY is posted to the state machine * in the handler for this msg. */ - usb_gadget_autopm_get(d_port->gadget); + usb_gadget_autopm_get(gadget); log_event_dbg("%s: get = %d", __func__, atomic_read(&gad_dev->power.usage_count)); /* allocate buffers used with each TRB */ @@ -716,7 +711,7 @@ static void ipa_work_handler(struct work_struct *w) read_event(d_port); ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_CON_IN_PROG_EVT_SUS_DIS", __func__); log_event_dbg("%s: put_async1 = %d", __func__, @@ -726,7 +721,7 @@ static void ipa_work_handler(struct work_struct *w) } ret = ipa_suspend_work_handler(d_port); if (!ret) { - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_CON_IN_PROG_EVT_SUS", __func__); log_event_dbg("%s: put_async2 = %d", __func__, @@ -736,7 +731,7 @@ static void ipa_work_handler(struct work_struct *w) } else if (event == EVT_DISCONNECTED) { ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_CON_IN_PROG_EVT_DIS", __func__); log_event_dbg("%s: put_async3 = %d", @@ -760,7 +755,7 @@ static void ipa_work_handler(struct work_struct *w) ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_CON_EVT_DIS", __func__); log_event_dbg("%s: put_async4 = %d", __func__, atomic_read( @@ -770,7 +765,7 @@ static void ipa_work_handler(struct work_struct *w) read_event(d_port); ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_CON_EVT_SUS_DIS", __func__); log_event_dbg("%s: put_async5 = %d", @@ -780,7 +775,7 @@ static void ipa_work_handler(struct work_struct *w) } ret = ipa_suspend_work_handler(d_port); if (!ret) { - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_CON_EVT_SUS", __func__); log_event_dbg("%s: put_async6 = %d", @@ -805,7 +800,7 @@ static void ipa_work_handler(struct work_struct *w) case STATE_SUSPEND_IN_PROGRESS: if (event == EVT_IPA_SUSPEND) { d_port->sm_state = STATE_SUSPENDED; - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_SUS_IN_PROG_EVT_IPA_SUS", __func__); log_event_dbg("%s: put_async6 = %d", @@ -820,7 +815,7 @@ static void ipa_work_handler(struct work_struct *w) * after IPA disconnect is done in disconnect work * (due to cable disconnect) or in suspended state. */ - usb_gadget_autopm_get_noresume(d_port->gadget); + usb_gadget_autopm_get_noresume(gadget); log_event_dbg("%s: ST_SUS_IN_PROG_EVT_RES", __func__); log_event_dbg("%s: get_nores1 = %d", __func__, atomic_read( @@ -828,7 +823,7 @@ static void ipa_work_handler(struct work_struct *w) } else if (event == EVT_DISCONNECTED) { ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; - usb_gadget_autopm_put_async(d_port->gadget); + usb_gadget_autopm_put_async(gadget); log_event_dbg("%s: ST_SUS_IN_PROG_EVT_DIS", __func__); log_event_dbg("%s: put_async7 = %d", __func__, atomic_read( @@ -838,7 +833,7 @@ static void ipa_work_handler(struct work_struct *w) case STATE_SUSPENDED: if (event == EVT_RESUMED) { - usb_gadget_autopm_get(d_port->gadget); + usb_gadget_autopm_get(gadget); log_event_dbg("%s: ST_SUS_EVT_RES", __func__); log_event_dbg("%s: get = %d", __func__, atomic_read(&gad_dev->power.usage_count)); @@ -1425,7 +1420,6 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi) __le32 *data; struct usb_cdc_notification *event; struct usb_request *req = gsi->c_port.notify_req; - struct usb_composite_dev *cdev = gsi->function.config->cdev; struct gsi_ctrl_pkt *cpkt; unsigned long flags; bool del_free_cpkt = false; @@ -1472,11 +1466,11 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi) /* SPEED_CHANGE data is up/down speeds in bits/sec */ data = req->buf + sizeof(*event); - data[0] = cpu_to_le32(gsi_xfer_bitrate(cdev->gadget)); + data[0] = cpu_to_le32(gsi_xfer_bitrate(gsi->gadget)); data[1] = data[0]; log_event_dbg("notify speed %d", - gsi_xfer_bitrate(cdev->gadget)); + gsi_xfer_bitrate(gsi->gadget)); break; case GSI_CTRL_NOTIFY_OFFLINE: del_free_cpkt = true; @@ -1868,10 +1862,10 @@ static int gsi_alloc_trb_buffer(struct f_gsi *gsi) len_in = gsi->d_port.in_request.buf_len * gsi->d_port.in_request.num_bufs; gsi->d_port.in_request.buf_base_addr = - dma_zalloc_coherent(gsi->d_port.gadget->dev.parent, + dma_zalloc_coherent(gsi->gadget->dev.parent, len_in, &gsi->d_port.in_request.dma, GFP_KERNEL); if (!gsi->d_port.in_request.buf_base_addr) { - dev_err(&gsi->d_port.gadget->dev, + dev_err(&gsi->gadget->dev, "IN buf_base_addr allocate failed %s\n", gsi->function.name); ret = -ENOMEM; @@ -1887,10 +1881,10 @@ static int gsi_alloc_trb_buffer(struct f_gsi *gsi) len_out = gsi->d_port.out_request.buf_len * gsi->d_port.out_request.num_bufs; gsi->d_port.out_request.buf_base_addr = - dma_zalloc_coherent(gsi->d_port.gadget->dev.parent, + dma_zalloc_coherent(gsi->gadget->dev.parent, len_out, &gsi->d_port.out_request.dma, GFP_KERNEL); if (!gsi->d_port.out_request.buf_base_addr) { - dev_err(&gsi->d_port.gadget->dev, + dev_err(&gsi->gadget->dev, "OUT buf_base_addr allocate failed %s\n", gsi->function.name); ret = -ENOMEM; @@ -1903,7 +1897,7 @@ static int gsi_alloc_trb_buffer(struct f_gsi *gsi) fail: if (len_in && gsi->d_port.in_request.buf_base_addr) { - dma_free_coherent(gsi->d_port.gadget->dev.parent, len_in, + dma_free_coherent(gsi->gadget->dev.parent, len_in, gsi->d_port.in_request.buf_base_addr, gsi->d_port.in_request.dma); gsi->d_port.in_request.buf_base_addr = NULL; @@ -1922,7 +1916,7 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi) gsi->d_port.out_request.buf_base_addr) { len = gsi->d_port.out_request.buf_len * gsi->d_port.out_request.num_bufs; - dma_free_coherent(gsi->d_port.gadget->dev.parent, len, + dma_free_coherent(gsi->gadget->dev.parent, len, gsi->d_port.out_request.buf_base_addr, gsi->d_port.out_request.dma); gsi->d_port.out_request.buf_base_addr = NULL; @@ -1932,7 +1926,7 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi) gsi->d_port.in_request.buf_base_addr) { len = gsi->d_port.in_request.buf_len * gsi->d_port.in_request.num_bufs; - dma_free_coherent(gsi->d_port.gadget->dev.parent, len, + dma_free_coherent(gsi->gadget->dev.parent, len, gsi->d_port.in_request.buf_base_addr, gsi->d_port.in_request.dma); gsi->d_port.in_request.buf_base_addr = NULL; @@ -2035,7 +2029,7 @@ static int gsi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) GSI_EP_OP_CONFIG); } - gsi->d_port.gadget = cdev->gadget; + gsi->gadget = cdev->gadget; if (gsi->prot_id == IPA_USB_RNDIS) { gsi_rndis_open(gsi); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 3baf65572afc..262a60e8a450 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -192,7 +192,6 @@ struct gsi_data_port { struct usb_ep *out_ep; struct usb_gsi_request in_request; struct usb_gsi_request out_request; - struct usb_gadget *gadget; int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *driver_data); struct ipa_usb_teth_params ipa_init_params; int in_channel_handle; @@ -228,6 +227,7 @@ struct gsi_data_port { struct f_gsi { struct usb_function function; + struct usb_gadget *gadget; enum ipa_usb_teth_prot prot_id; int ctrl_id; int data_id; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 098df6ced1c3..8e5ab373dce9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1476,6 +1476,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, } break; case USB_SPEED_FULL: + if (usb_endpoint_xfer_bulk(&ep->desc) && max_packet < 8) + max_packet = 8; case USB_SPEED_LOW: break; default: diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 05d96fd8c07c..3f106b428dba 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -38,12 +38,19 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { + struct device_node *node = dev->of_node; + struct usb_xhci_pdata *pdata = dev_get_platdata(dev); + /* * As of now platform drivers don't provide MSI support so we ensure * here that the generic code does not try to make a pci_dev from our * dev struct in order to setup MSI */ xhci->quirks |= XHCI_PLAT; + + if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || + (pdata && pdata->usb3_lpm_capable)) + xhci->quirks |= XHCI_LPM_SUPPORT; } /* called during probe() after chip reset completes */ @@ -129,7 +136,6 @@ static DEVICE_ATTR(config_imod, S_IRUGO | S_IWUSR, static int xhci_plat_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); const struct hc_driver *driver; struct xhci_hcd *xhci; @@ -227,10 +233,6 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd_to_bus(xhci->shared_hcd)->skip_resume = true; - if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || - (pdata && pdata->usb3_lpm_capable)) - xhci->quirks |= XHCI_LPM_SUPPORT; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index 14d998d14eeb..17644e3556b6 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -125,6 +125,7 @@ static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit, commit32->commit_v1.input_layer_cnt; commit->commit_v1.left_roi = commit32->commit_v1.left_roi; commit->commit_v1.right_roi = commit32->commit_v1.right_roi; + commit->commit_v1.bl_level = commit32->commit_v1.bl_level; memcpy(&commit->commit_v1.reserved, &commit32->commit_v1.reserved, sizeof(commit32->commit_v1.reserved)); } diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.h b/drivers/video/fbdev/msm/mdss_compat_utils.h index 626792925cb6..4f44cd1c9471 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.h +++ b/drivers/video/fbdev/msm/mdss_compat_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,9 +19,9 @@ * To allow proper structure padding for 64bit/32bit target */ #ifdef __LP64 -#define MDP_LAYER_COMMIT_V1_PAD 3 +#define MDP_LAYER_COMMIT_V1_PAD 2 #else -#define MDP_LAYER_COMMIT_V1_PAD 4 +#define MDP_LAYER_COMMIT_V1_PAD 3 #endif struct mdp_buf_sync32 { @@ -537,6 +537,7 @@ struct mdp_layer_commit_v1_32 { compat_caddr_t dest_scaler; uint32_t dest_scaler_cnt; compat_caddr_t frc_info; + uint32_t bl_level; /* BL level to be updated in commit */ uint32_t reserved[MDP_LAYER_COMMIT_V1_PAD]; }; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index bd8e710870f7..153c733fdf43 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -54,6 +54,8 @@ struct mdss_dp_attention_node { #define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_640x480p60_4_3 +static int mdss_dp_host_init(struct mdss_panel_data *pdata); +static int mdss_dp_host_deinit(struct mdss_dp_drv_pdata *dp); static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv); static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata); static inline void mdss_dp_link_maintenance(struct mdss_dp_drv_pdata *dp, @@ -64,6 +66,8 @@ static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, enum notification_status status); static int mdss_dp_process_phy_test_pattern_request( struct mdss_dp_drv_pdata *dp); +static int mdss_dp_send_audio_notification( + struct mdss_dp_drv_pdata *dp, int val); static inline void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp) { @@ -474,6 +478,12 @@ static int mdss_dp_clk_ctrl(struct mdss_dp_drv_pdata *dp_drv, else dp_drv->link_clks_on = enable; + pr_debug("%s clocks for %s\n", + enable ? "enable" : "disable", + __mdss_dp_pm_name(pm_type)); + pr_debug("link_clks:%s core_clks:%s\n", + dp_drv->link_clks_on ? "on" : "off", + dp_drv->core_clks_on ? "on" : "off"); error: return ret; } @@ -961,6 +971,14 @@ static int mdss_dp_wait4video_ready(struct mdss_dp_drv_pdata *dp_drv) ret = -EINVAL; } else { ret = 0; + /* + * The audio subsystem should only be notified once the DP + * controller is in SEND_VIDEO state. This will ensure that + * the DP audio engine is able to acknowledge the audio unmute + * request, which will result in the AFE port being configured + * correctly. + */ + mdss_dp_send_audio_notification(dp_drv, true); } pr_debug("End--\n"); @@ -1038,6 +1056,22 @@ static int dp_get_audio_edid_blk(struct platform_device *pdev, return rc; } /* dp_get_audio_edid_blk */ +static void dp_audio_teardown_done(struct platform_device *pdev) +{ + struct mdss_dp_drv_pdata *dp = platform_get_drvdata(pdev); + + if (!dp) { + pr_err("invalid input\n"); + return; + } + + mdss_dp_audio_enable(&dp->ctrl_io, false); + /* Make sure the DP audio engine is disabled */ + wmb(); + + pr_debug("audio engine disabled\n"); +} /* dp_audio_teardown_done */ + static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) { int ret = 0; @@ -1059,6 +1093,8 @@ static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) dp_get_audio_edid_blk; dp->ext_audio_data.codec_ops.cable_status = dp_get_cable_status; + dp->ext_audio_data.codec_ops.teardown_done = + dp_audio_teardown_done; if (!dp->pdev->dev.of_node) { pr_err("%s cannot find dp dev.of_node\n", __func__); @@ -1284,6 +1320,11 @@ static int mdss_dp_enable_mainlink_clocks(struct mdss_dp_drv_pdata *dp) if (dp->pixel_clk_rcg && dp->pixel_parent) clk_set_parent(dp->pixel_clk_rcg, dp->pixel_parent); + if (dp->link_clks_on) { + pr_debug("link clocks already on\n"); + return ret; + } + mdss_dp_set_clock_rate(dp, "ctrl_link_clk", (dp->link_rate * DP_LINK_RATE_MULTIPLIER) / DP_KHZ_TO_HZ); @@ -1308,6 +1349,11 @@ static int mdss_dp_enable_mainlink_clocks(struct mdss_dp_drv_pdata *dp) */ static void mdss_dp_disable_mainlink_clocks(struct mdss_dp_drv_pdata *dp_drv) { + if (!dp_drv->link_clks_on) { + pr_debug("link clocks already off\n"); + return; + } + mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, false); } @@ -1347,7 +1393,7 @@ static void mdss_dp_configure_source_params(struct mdss_dp_drv_pdata *dp, static int mdss_dp_setup_main_link(struct mdss_dp_drv_pdata *dp, bool train) { int ret = 0; - int ready = 0; + bool mainlink_ready = false; pr_debug("enter\n"); mdss_dp_mainlink_ctrl(&dp->ctrl_io, true); @@ -1380,8 +1426,8 @@ send_video: mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO); mdss_dp_wait4video_ready(dp); - ready = mdss_dp_mainlink_ready(dp, BIT(0)); - pr_debug("main link %s\n", ready ? "READY" : "NOT READY"); + mainlink_ready = mdss_dp_mainlink_ready(dp); + pr_debug("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY"); end: return ret; @@ -1543,6 +1589,16 @@ int mdss_dp_on(struct mdss_panel_data *pdata) return 0; } + /* + * During device suspend, host_deinit() is called + * to release DP resources. PM_RESUME can be + * called for any module wake-up. To avoid multiple host + * init/deinit during unrelated resume/suspend events, + * add host initialization call before DP power-on. + */ + if (!dp_drv->dp_initialized) + mdss_dp_host_init(pdata); + return mdss_dp_on_hpd(dp_drv); } @@ -1590,25 +1646,7 @@ static int mdss_dp_off_hpd(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_audio_enable(&dp_drv->ctrl_io, false); - mdss_dp_irq_disable(dp_drv); - - mdss_dp_config_gpios(dp_drv, false); - mdss_dp_pinctrl_set_state(dp_drv, false); - - /* - * The global reset will need DP link ralated clocks to be - * running. Add the global reset just before disabling the - * link clocks and core clocks. - */ - mdss_dp_ctrl_reset(&dp_drv->ctrl_io); - - /* Make sure DP is disabled before clk disable */ - wmb(); - mdss_dp_disable_mainlink_clocks(dp_drv); - mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false); - - mdss_dp_regulator_ctrl(dp_drv, false); - dp_drv->dp_initialized = false; + mdss_dp_host_deinit(dp_drv); dp_drv->power_on = false; dp_drv->sink_info_read = false; @@ -1639,26 +1677,46 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return mdss_dp_off_hpd(dp); } -static int mdss_dp_send_cable_notification( +static int mdss_dp_send_audio_notification( struct mdss_dp_drv_pdata *dp, int val) { int ret = 0; u32 flags = 0; if (!dp) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); ret = -EINVAL; goto end; } - flags |= MSM_EXT_DISP_HPD_VIDEO; - if (!mdss_dp_is_dvi_mode(dp) || dp->audio_test_req) { dp->audio_test_req = false; flags |= MSM_EXT_DISP_HPD_AUDIO; + + if (dp->ext_audio_data.intf_ops.hpd) + ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, + dp->ext_audio_data.type, val, flags); } +end: + return ret; +} + +static int mdss_dp_send_video_notification( + struct mdss_dp_drv_pdata *dp, int val) +{ + int ret = 0; + u32 flags = 0; + + if (!dp) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto end; + } + + flags |= MSM_EXT_DISP_HPD_VIDEO; + if (dp->ext_audio_data.intf_ops.hpd) ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, dp->ext_audio_data.type, val, flags); @@ -1673,6 +1731,19 @@ static void mdss_dp_set_default_resolution(struct mdss_dp_drv_pdata *dp) DEFAULT_VIDEO_RESOLUTION, true); } +static void mdss_dp_set_default_link_parameters(struct mdss_dp_drv_pdata *dp) +{ + const int default_max_link_rate = 0x6; + const int default_max_lane_count = 1; + + dp->dpcd.max_lane_count = default_max_lane_count; + dp->dpcd.max_link_rate = default_max_link_rate; + + pr_debug("max_link_rate = 0x%x, max_lane_count= 0x%x\n", + dp->dpcd.max_link_rate, + dp->dpcd.max_lane_count); +} + static int mdss_dp_edid_init(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; @@ -1776,6 +1847,49 @@ vreg_error: } /** + * mdss_dp_host_deinit() - Uninitialize DP controller + * @dp: Display Port Driver data + * + * Perform required steps to uninitialize DP controller + * and its resources. + */ +static int mdss_dp_host_deinit(struct mdss_dp_drv_pdata *dp) +{ + if (!dp) { + pr_err("Invalid input data\n"); + return -EINVAL; + } + + if (!dp->dp_initialized) { + pr_debug("%s: host deinit done already\n", __func__); + return 0; + } + + mdss_dp_irq_disable(dp); + + mdss_dp_config_gpios(dp, false); + mdss_dp_pinctrl_set_state(dp, false); + + /* + * The global reset will need DP link ralated clocks to be + * running. Add the global reset just before disabling the + * link clocks and core clocks. + */ + mdss_dp_ctrl_reset(&dp->ctrl_io); + + /* Make sure DP is disabled before clk disable */ + wmb(); + mdss_dp_disable_mainlink_clocks(dp); + mdss_dp_clk_ctrl(dp, DP_CORE_PM, false); + + mdss_dp_regulator_ctrl(dp, false); + dp->dp_initialized = false; + pr_debug("Host deinitialized successfully\n"); + + return 0; +} + +/** * mdss_dp_notify_clients() - notifies DP clients of cable connection * @dp: Display Port Driver data * @status: HPD notification status requested @@ -1804,7 +1918,7 @@ static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, goto invalid_request; /* Follow the same programming as for NOTIFY_CONNECT */ mdss_dp_host_init(&dp->panel_data); - mdss_dp_send_cable_notification(dp, true); + mdss_dp_send_video_notification(dp, true); break; case NOTIFY_CONNECT: if ((dp->hpd_notification_status == NOTIFY_CONNECT_IRQ_HPD) || @@ -1812,16 +1926,18 @@ static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, NOTIFY_DISCONNECT_IRQ_HPD)) goto invalid_request; mdss_dp_host_init(&dp->panel_data); - mdss_dp_send_cable_notification(dp, true); + mdss_dp_send_video_notification(dp, true); break; case NOTIFY_DISCONNECT: - mdss_dp_send_cable_notification(dp, false); + mdss_dp_send_audio_notification(dp, false); + mdss_dp_send_video_notification(dp, false); break; case NOTIFY_DISCONNECT_IRQ_HPD: if (dp->hpd_notification_status == NOTIFY_DISCONNECT) goto invalid_request; - mdss_dp_send_cable_notification(dp, false); + mdss_dp_send_audio_notification(dp, false); + mdss_dp_send_video_notification(dp, false); if (!IS_ERR_VALUE(ret) && ret) { reinit_completion(&dp->irq_comp); ret = wait_for_completion_timeout(&dp->irq_comp, @@ -1878,12 +1994,16 @@ static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp) pr_debug("edid read error, setting default resolution\n"); mdss_dp_set_default_resolution(dp); + mdss_dp_set_default_link_parameters(dp); goto notify; } ret = hdmi_edid_parser(dp->panel_data.panel_info.edid_data); if (ret) { - pr_err("edid parse failed\n"); + pr_err("edid parse failed, setting default resolution\n"); + + mdss_dp_set_default_resolution(dp); + mdss_dp_set_default_link_parameters(dp); goto notify; } @@ -2307,7 +2427,7 @@ static ssize_t mdss_dp_wta_hpd(struct device *dev, } else { dp_send_events(dp, EV_USBPD_DISCOVER_MODES); } - } else if (!dp->hpd && dp->power_on) { + } else if (!dp->hpd) { mdss_dp_notify_clients(dp, NOTIFY_DISCONNECT); } end: @@ -2686,6 +2806,22 @@ static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp) } } +/** + * mdss_dp_reset_panel_info() - reset the panel_info data + * @dp: Display Port Driver data + * + * This function will reset the panel resolution to + * HDMI_VFRMT_UNKNOWN if the sink device is not connected. This will help + * to reconfigure the panel resolution during cable connect event. + */ +static void mdss_dp_reset_panel_info(struct mdss_dp_drv_pdata *dp) +{ + if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) { + dp->suspend_vic = HDMI_VFRMT_UNKNOWN; + dp_init_panel_info(dp, dp->suspend_vic); + } +} + static int mdss_dp_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -2705,11 +2841,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, switch (event) { case MDSS_EVENT_UNBLANK: + mdss_dp_ack_state(dp, true); rc = mdss_dp_on(pdata); break; case MDSS_EVENT_PANEL_ON: - mdss_dp_ack_state(dp, true); - mdss_dp_update_hdcp_info(dp); if (dp_is_hdcp_enabled(dp)) { @@ -2754,6 +2889,31 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_CHECK_PARAMS: rc = mdss_dp_check_params(dp, arg); break; + case MDSS_EVENT_SUSPEND: + /* + * Make sure DP host_deinit is called + * when DP host is initialized but not + * powered ON. + * For example, this scenerio happens + * when you connect DP sink while the + * device is in suspend state. + */ + if ((!dp->power_on) && (dp->dp_initialized)) + rc = mdss_dp_host_deinit(dp); + + /* + * For DP suspend/resume use case, CHECK_PARAMS is + * not called if the cable status is not changed. + * Store the sink resolution in suspend and configure + * the resolution during DP resume path. + */ + if (dp->power_on) + dp->suspend_vic = dp->vic; + break; + case MDSS_EVENT_RESUME: + if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) + dp_init_panel_info(dp, dp->suspend_vic); + break; default: pr_debug("unhandled event=%d\n", event); break; @@ -2889,8 +3049,6 @@ static int mdss_dp_event_thread(void *data) return -EINVAL; ev_data = (struct mdss_dp_event_data *)data; - init_waitqueue_head(&ev_data->event_q); - spin_lock_init(&ev_data->event_lock); while (!kthread_should_stop()) { wait_event(ev_data->event_q, @@ -3049,6 +3207,9 @@ static void mdss_dp_event_cleanup(struct mdss_dp_drv_pdata *dp) static int mdss_dp_event_setup(struct mdss_dp_drv_pdata *dp) { + init_waitqueue_head(&dp->dp_event.event_q); + spin_lock_init(&dp->dp_event.event_lock); + dp->ev_thread = kthread_run(mdss_dp_event_thread, (void *)&dp->dp_event, "mdss_dp_event"); if (IS_ERR(dp->ev_thread)) { @@ -3108,6 +3269,27 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr) } else { mdss_dp_notify_clients(dp_drv, NOTIFY_DISCONNECT); } + + /* + * If cable is disconnected during device suspend, + * reset the panel resolution to HDMI_VFRMT_UNKNOWN + * so that new resolution is configured during + * cable connect event + */ + if ((!dp_drv->power_on) && (!dp_drv->dp_initialized)) + mdss_dp_reset_panel_info(dp_drv); + + /* + * If a cable/dongle is connected to the TX device but + * no sink device is connected, we call host + * initialization where orientation settings are + * configured. When the cable/dongle is disconnect, + * call host de-initialization to make sure + * we re-configure the orientation settings during + * the next connect event. + */ + if ((!dp_drv->power_on) && (dp_drv->dp_initialized)) + mdss_dp_host_deinit(dp_drv); } static int mdss_dp_validate_callback(u8 cmd, @@ -3604,6 +3786,16 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_notify_clients(dp_drv, NOTIFY_DISCONNECT); pr_debug("Attention: Notified clients\n"); + /* + * When a DP adaptor is connected and if sink is + * disconnected during device suspend, + * reset the panel resolution to HDMI_VFRMT_UNKNOWN + * so that new resolution is configured during + * connect event. + */ + if ((!dp_drv->power_on) && (!dp_drv->dp_initialized)) + mdss_dp_reset_panel_info(dp_drv); + /** * Manually turn off the DP controller if we are in PHY * testing mode. @@ -3826,6 +4018,7 @@ static int mdss_dp_probe(struct platform_device *pdev) dp_drv->hpd_irq_on = false; mdss_dp_reset_test_data(dp_drv); init_completion(&dp_drv->irq_comp); + dp_drv->suspend_vic = HDMI_VFRMT_UNKNOWN; pr_debug("done\n"); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index d6f5d160aef2..34b652d843aa 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -450,6 +450,7 @@ struct mdss_dp_drv_pdata { bool link_clks_on; bool power_on; bool sink_info_read; + u32 suspend_vic; bool hpd; bool psm_enabled; bool audio_test_req; diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index ca07e80d6613..479c367fdc92 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -2247,12 +2247,8 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) else pattern = 0x02; - dp_write(ep->base + DP_STATE_CTRL, 0x0); - /* Make sure to clear the current pattern before starting a new one */ - wmb(); - - dp_host_train_set(ep, pattern); mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(ep); + dp_host_train_set(ep, pattern); dp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */ do { diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c index 3b9242448198..ea492f54054c 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.c +++ b/drivers/video/fbdev/msm/mdss_dp_util.c @@ -177,23 +177,22 @@ void mdss_dp_mainlink_ctrl(struct dss_io_data *ctrl_io, bool enable) writel_relaxed(mainlink_ctrl, ctrl_io->base + DP_MAINLINK_CTRL); } -int mdss_dp_mainlink_ready(struct mdss_dp_drv_pdata *dp, u32 which) +bool mdss_dp_mainlink_ready(struct mdss_dp_drv_pdata *dp) { u32 data; int cnt = 10; + int const mainlink_ready_bit = BIT(0); while (--cnt) { /* DP_MAINLINK_READY */ data = readl_relaxed(dp->base + DP_MAINLINK_READY); - if (data & which) { - pr_debug("which=%x ready\n", which); - return 1; - } + if (data & mainlink_ready_bit) + return true; udelay(1000); } - pr_err("which=%x NOT ready\n", which); + pr_err("mainlink not ready\n"); - return 0; + return false; } /* DP Configuration controller*/ diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index b3b15a3579fa..8f19e7cdf3cf 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -291,7 +291,7 @@ void mdss_dp_hpd_configure(struct dss_io_data *ctrl_io, bool enable); void mdss_dp_aux_ctrl(struct dss_io_data *ctrl_io, bool enable); void mdss_dp_mainlink_ctrl(struct dss_io_data *ctrl_io, bool enable); void mdss_dp_ctrl_lane_mapping(struct dss_io_data *ctrl_io, char *l_map); -int mdss_dp_mainlink_ready(struct mdss_dp_drv_pdata *dp, u32 which); +bool mdss_dp_mainlink_ready(struct mdss_dp_drv_pdata *dp); void mdss_dp_timing_cfg(struct dss_io_data *ctrl_io, struct mdss_panel_info *pinfo); void mdss_dp_configuration_ctrl(struct dss_io_data *ctrl_io, u32 data); diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 4aa14422899f..88eb794a5ff5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1576,10 +1576,12 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) mdss_dsi_clk_ctrl(sctrl, sctrl->dsi_clk_handle, MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON); - if (mdss_dsi_is_panel_on_lp(pdata)) { + if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_LP) { pr_debug("%s: dsi_unblank with panel always on\n", __func__); if (ctrl_pdata->low_power_config) ret = ctrl_pdata->low_power_config(pdata, false); + if (!ret) + ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_LP; goto error; } @@ -1644,6 +1646,8 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) pr_debug("%s: low power state requested\n", __func__); if (ctrl_pdata->low_power_config) ret = ctrl_pdata->low_power_config(pdata, true); + if (!ret) + ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_LP; goto error; } @@ -1686,7 +1690,8 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) } ATRACE_END("dsi_panel_off"); } - ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; + ctrl_pdata->ctrl_state &= ~(CTRL_STATE_PANEL_INIT | + CTRL_STATE_PANEL_LP); } error: @@ -2550,8 +2555,6 @@ static void mdss_dsi_timing_db_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_ON); MIPI_OUTP((ctrl->ctrl_base + 0x1e8), enable); wmb(); /* ensure timing db is disabled */ - MIPI_OUTP((ctrl->ctrl_base + 0x1e4), enable); - wmb(); /* ensure timing flush is disabled */ mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF); } diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index df24352ff87d..bd9fd6c7d6c5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -166,6 +166,7 @@ enum dsi_pm_type { #define CTRL_STATE_PANEL_INIT BIT(0) #define CTRL_STATE_MDP_ACTIVE BIT(1) #define CTRL_STATE_DSI_ACTIVE BIT(2) +#define CTRL_STATE_PANEL_LP BIT(3) #define DSI_NON_BURST_SYNCH_PULSE 0 #define DSI_NON_BURST_SYNCH_EVENT 1 diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 734d3bee8fd0..98c5eda02f5b 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -766,6 +766,8 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) u32 data0, data1, mask = 0, data_lane_en = 0; struct mdss_dsi_ctrl_pdata *ctrl0, *ctrl1; u32 ln0, ln1, ln_ctrl0, ln_ctrl1, i; + int rc = 0; + /* * Add 2 ms delay suggested by HW team. * Check clk lane stop state after every 200 us @@ -787,9 +789,15 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) ctrl0 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0); ctrl1 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_1); - if (ctrl0->recovery) - ctrl0->recovery->fxn(ctrl0->recovery->data, + if (ctrl0->recovery) { + rc = ctrl0->recovery->fxn(ctrl0->recovery->data, MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW); + if (rc < 0) { + pr_debug("%s: Target is in suspend/shutdown\n", + __func__); + return; + } + } /* * Disable PHY contention detection and receive. * Configure the strength ctrl 1 register. @@ -879,9 +887,15 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) */ udelay(200); } else { - if (ctrl->recovery) - ctrl->recovery->fxn(ctrl->recovery->data, + if (ctrl->recovery) { + rc = ctrl->recovery->fxn(ctrl->recovery->data, MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW); + if (rc < 0) { + pr_debug("%s: Target is in suspend/shutdown\n", + __func__); + return; + } + } /* Disable PHY contention detection and receive */ MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0); @@ -2134,8 +2148,8 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, status = reg_val & DSI_INTR_CMD_DMA_DONE; if (status) { reg_val &= DSI_INTR_MASK_ALL; - /* clear CMD DMA isr only */ - reg_val |= DSI_INTR_CMD_DMA_DONE; + /* clear CMD DMA and BTA_DONE isr only */ + reg_val |= (DSI_INTR_CMD_DMA_DONE | DSI_INTR_BTA_DONE); MIPI_OUTP(ctrl->ctrl_base + 0x0110, reg_val); mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM); complete(&ctrl->dma_comp); @@ -3030,6 +3044,13 @@ static bool mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl) pr_err("%s: status=%x\n", __func__, status); + /* + * if DSI FIFO overflow is masked, + * do not report overflow error + */ + if (MIPI_INP(base + 0x10c) & 0xf0000) + status = status & 0xaaaaffff; + if (status & 0x44440000) {/* DLNx_HS_FIFO_OVERFLOW */ dsi_send_events(ctrl, DSI_EV_DLNx_FIFO_OVERFLOW, 0); /* Ignore FIFO EMPTY when overflow happens */ diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index db27842eaccc..bf66c0cd430c 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -303,10 +303,23 @@ static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev, } } +static enum led_brightness mdss_fb_get_bl_brightness( + struct led_classdev *led_cdev) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent); + enum led_brightness value; + + MDSS_BL_TO_BRIGHT(value, mfd->bl_level, mfd->panel_info->bl_max, + mfd->panel_info->brightness_max); + + return value; +} + static struct led_classdev backlight_led = { .name = "lcd-backlight", .brightness = MDSS_MAX_BL_BRIGHTNESS / 2, .brightness_set = mdss_fb_set_bl_brightness, + .brightness_get = mdss_fb_get_bl_brightness, .max_brightness = MDSS_MAX_BL_BRIGHTNESS, }; @@ -3422,6 +3435,14 @@ int mdss_fb_atomic_commit(struct fb_info *info, mfd->msm_fb_backup.disp_commit.l_roi = commit_v1->left_roi; mfd->msm_fb_backup.disp_commit.r_roi = commit_v1->right_roi; mfd->msm_fb_backup.disp_commit.flags = commit_v1->flags; + if (commit_v1->flags & MDP_COMMIT_UPDATE_BRIGHTNESS) { + MDSS_BRIGHT_TO_BL(mfd->bl_extn_level, commit_v1->bl_level, + mfd->panel_info->bl_max, + mfd->panel_info->brightness_max); + if (!mfd->bl_extn_level && commit_v1->bl_level) + mfd->bl_extn_level = 1; + } else + mfd->bl_extn_level = -1; mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex); atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt); diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index d64580a35775..321531c72a08 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -241,6 +241,10 @@ struct msm_mdp_interface { out = (2 * (v) * (bl_max) + max_bright);\ do_div(out, 2 * max_bright);\ } while (0) +#define MDSS_BL_TO_BRIGHT(out, v, bl_max, max_bright) do {\ + out = ((v) * (max_bright));\ + do_div(out, bl_max);\ + } while (0) struct mdss_fb_file_info { struct file *file; @@ -305,6 +309,7 @@ struct msm_fb_data_type { u32 calib_mode_bl; u32 ad_bl_level; u32 bl_level; + int bl_extn_level; u32 bl_scale; u32 unset_bl_level; bool allow_bl_update; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_cec.c b/drivers/video/fbdev/msm/mdss_hdmi_cec.c index a424d987bb63..a4ed01210e04 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_cec.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_cec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -196,7 +196,7 @@ static void hdmi_cec_msg_recv(struct work_struct *work) msg.sender_id, msg.recvr_id, msg.frame_size); - if (msg.frame_size < 1) { + if (msg.frame_size < 1 || msg.frame_size > MAX_CEC_FRAME_SIZE) { DEV_ERR("%s: invalid message (frame length = %d)\n", __func__, msg.frame_size); return; @@ -216,7 +216,7 @@ static void hdmi_cec_msg_recv(struct work_struct *work) msg.operand[i] = data & 0xFF; } - for (; i < 14; i++) + for (; i < MAX_OPERAND_SIZE; i++) msg.operand[i] = 0; DEV_DBG("%s: opcode 0x%x, wakup_en %d, device_suspend %d\n", __func__, diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 36a866685f21..ada39f5f486a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -164,6 +164,14 @@ enum mdss_mdp_mixer_mux { MDSS_MDP_MIXER_MUX_RIGHT, }; +enum mdss_secure_transition { + SECURE_TRANSITION_NONE, + SD_NON_SECURE_TO_SECURE, + SD_SECURE_TO_NON_SECURE, + SC_NON_SECURE_TO_SECURE, + SC_SECURE_TO_NON_SECURE, +}; + static inline enum mdss_mdp_sspp_index get_pipe_num_from_ndx(u32 ndx) { u32 id; @@ -421,6 +429,9 @@ struct mdss_mdp_ctl_intfs_ops { /* to update lineptr, [1..yres] - enable, 0 - disable */ int (*update_lineptr)(struct mdss_mdp_ctl *ctl, bool enable); int (*avr_ctrl_fnc)(struct mdss_mdp_ctl *, bool enable); + + /* to wait for vsync */ + int (*wait_for_vsync_fnc)(struct mdss_mdp_ctl *ctl); }; struct mdss_mdp_cwb { @@ -953,6 +964,8 @@ struct mdss_overlay_private { struct kthread_worker worker; struct kthread_work vsync_work; struct task_struct *thread; + + u8 secure_transition_state; }; struct mdss_mdp_set_ot_params { diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 7b0207de101a..bec652f7e4ba 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -73,8 +73,18 @@ static void __mdss_mdp_mixer_write_cfg(struct mdss_mdp_mixer *mixer, static inline u64 fudge_factor(u64 val, u32 numer, u32 denom) { - u64 result = (val * (u64)numer); - do_div(result, denom); + u64 result = val; + + if (val) { + u64 temp = -1UL; + + do_div(temp, val); + if (temp > numer) { + /* no overflow, so we can do the operation*/ + result = (val * (u64)numer); + do_div(result, denom); + } + } return result; } @@ -2263,8 +2273,8 @@ static bool __mdss_mdp_compare_bw( __calc_bus_ib_quota(mdata, new_perf, is_nrt, new_perf->bw_ctl); u64 old_ib = __calc_bus_ib_quota(mdata, old_perf, is_nrt, old_perf->bw_ctl); - u64 max_new_bw = max(new_perf->bw_ctl, new_ib); - u64 max_old_bw = max(old_perf->bw_ctl, old_ib); + u64 new_ab = new_perf->bw_ctl; + u64 old_ab = old_perf->bw_ctl; bool update_bw = false; /* @@ -2276,16 +2286,18 @@ static bool __mdss_mdp_compare_bw( * 3. end of writeback/rotator session - last chance to * non-realtime remove vote. */ - if ((params_changed && ((max_new_bw > max_old_bw) || /* ab and ib bw */ + if ((params_changed && + (((new_ib > old_ib) || (new_ab > old_ab)) || (new_perf->bw_writeback > old_perf->bw_writeback))) || - (!params_changed && ((max_new_bw < max_old_bw) || + (!params_changed && + (((new_ib < old_ib) || (new_ab < old_ab)) || (new_perf->bw_writeback < old_perf->bw_writeback))) || (stop_req && is_nrt)) update_bw = true; trace_mdp_compare_bw(new_perf->bw_ctl, new_ib, new_perf->bw_writeback, - max_new_bw, old_perf->bw_ctl, old_ib, old_perf->bw_writeback, - max_old_bw, params_changed, update_bw); + old_perf->bw_ctl, old_ib, old_perf->bw_writeback, + params_changed, update_bw); return update_bw; } @@ -5704,6 +5716,15 @@ static void mdss_mdp_force_border_color(struct mdss_mdp_ctl *ctl) ctl->mixer_right->params_changed++; } +static bool mdss_mdp_handle_backlight_extn(struct mdss_mdp_ctl *ctl) +{ + if (ctl->intf_type == MDSS_INTF_DSI && !ctl->is_video_mode && + ctl->mfd->bl_extn_level >= 0) + return true; + else + return false; +} + int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, struct mdss_mdp_commit_cb *commit_cb) { @@ -5872,6 +5893,15 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, if (ctl->ops.wait_pingpong && !mdata->serialize_wait4pp) mdss_mdp_display_wait4pingpong(ctl, false); + /* + * If backlight needs to change, wait for 1 vsync before setting + * PCC and kickoff + */ + if (mdss_mdp_handle_backlight_extn(ctl) && + ctl->ops.wait_for_vsync_fnc) { + ret = ctl->ops.wait_for_vsync_fnc(ctl); + } + /* Moved pp programming to post ping pong */ if (!ctl->is_video_mode && ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER) { @@ -6020,6 +6050,17 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, if (ret) pr_warn("ctl %d error displaying frame\n", ctl->num); + /* update backlight in commit */ + if (mdss_mdp_handle_backlight_extn(ctl)) { + if (!IS_CALIB_MODE_BL(ctl->mfd) && (!ctl->mfd->ext_bl_ctrl || + !ctl->mfd->bl_level)) { + mutex_lock(&ctl->mfd->bl_lock); + mdss_fb_set_backlight(ctl->mfd, + ctl->mfd->bl_extn_level); + mutex_unlock(&ctl->mfd->bl_lock); + } + } + ctl->play_cnt++; ATRACE_END("flush_kickoff"); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index dfd6226ce602..583cfed598cd 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1197,7 +1197,7 @@ static int mdss_mdp_cmd_wait4readptr(struct mdss_mdp_cmd_ctx *ctx) return rc; } -static void mdss_mdp_cmd_intf_callback(void *data, int event) +static int mdss_mdp_cmd_intf_callback(void *data, int event) { struct mdss_mdp_cmd_ctx *ctx = data; struct mdss_mdp_pp_tear_check *te = NULL; @@ -1206,11 +1206,11 @@ static void mdss_mdp_cmd_intf_callback(void *data, int event) if (!data) { pr_err("%s: invalid ctx\n", __func__); - return; + return -EINVAL; } if (!ctx->ctl) - return; + return -EINVAL; switch (event) { case MDP_INTF_CALLBACK_DSI_WAIT: @@ -1222,7 +1222,7 @@ static void mdss_mdp_cmd_intf_callback(void *data, int event) * just return */ if (ctx->intf_stopped || !is_pingpong_split(ctx->ctl->mfd)) - return; + return -EINVAL; atomic_inc(&ctx->rdptr_cnt); /* enable clks and rd_ptr interrupt */ @@ -1231,7 +1231,7 @@ static void mdss_mdp_cmd_intf_callback(void *data, int event) mixer = mdss_mdp_mixer_get(ctx->ctl, MDSS_MDP_MIXER_MUX_LEFT); if (!mixer) { pr_err("%s: null mixer\n", __func__); - return; + return -EINVAL; } /* wait for read pointer */ @@ -1255,6 +1255,7 @@ static void mdss_mdp_cmd_intf_callback(void *data, int event) pr_debug("%s: unhandled event=%d\n", __func__, event); break; } + return 0; } static void mdss_mdp_cmd_lineptr_done(void *arg) @@ -1280,7 +1281,7 @@ static void mdss_mdp_cmd_lineptr_done(void *arg) spin_unlock(&ctx->clk_lock); } -static void mdss_mdp_cmd_intf_recovery(void *data, int event) +static int mdss_mdp_cmd_intf_recovery(void *data, int event) { struct mdss_mdp_cmd_ctx *ctx = data; unsigned long flags; @@ -1288,11 +1289,11 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event) if (!data) { pr_err("%s: invalid ctx\n", __func__); - return; + return -EINVAL; } if (!ctx->ctl) - return; + return -EINVAL; /* * Currently, only intf_fifo_underflow is @@ -1302,7 +1303,7 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event) if (event != MDP_INTF_DSI_CMD_FIFO_UNDERFLOW) { pr_warn("%s: unsupported recovery event:%d\n", __func__, event); - return; + return -EPERM; } if (atomic_read(&ctx->koff_cnt)) { @@ -1326,6 +1327,7 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event) if (notify_frame_timeout) mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_TIMEOUT); + return 0; } static void mdss_mdp_cmd_pingpong_done(void *arg) @@ -2917,6 +2919,41 @@ static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl, } } +int mdss_mdp_cmd_wait4_vsync(struct mdss_mdp_ctl *ctl) +{ + int rc = 0; + struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; + + if (!ctx) { + pr_err("invalid context to wait for vsync\n"); + return rc; + } + + atomic_inc(&ctx->rdptr_cnt); + + /* enable clks and rd_ptr interrupt */ + mdss_mdp_setup_vsync(ctx, true); + + /* wait for read pointer */ + MDSS_XLOG(atomic_read(&ctx->rdptr_cnt)); + pr_debug("%s: wait for vsync cnt:%d\n", + __func__, atomic_read(&ctx->rdptr_cnt)); + + rc = mdss_mdp_cmd_wait4readptr(ctx); + + /* wait for 1ms to make sure we are out from trigger window */ + usleep_range(1000, 1010); + + /* disable rd_ptr interrupt */ + mdss_mdp_setup_vsync(ctx, false); + + MDSS_XLOG(ctl->num); + pr_debug("%s: out from wait for rd_ptr ctl:%d\n", __func__, ctl->num); + + return rc; +} + + /* * There are 3 partial update possibilities * left only ==> enable left pingpong_done @@ -3170,6 +3207,8 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, ctx->default_pp_num, NULL, NULL); memset(ctx, 0, sizeof(*ctx)); + /* intf stopped, no more kickoff */ + ctx->intf_stopped = 1; return 0; } @@ -3315,7 +3354,11 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state) ctx->intf_stopped = 0; if (sctx) sctx->intf_stopped = 0; - + /* + * Tearcheck was disabled while entering LP2 state. + * Enable it back to allow updates in LP1 state. + */ + mdss_mdp_tearcheck_enable(ctl, true); goto end; } } @@ -3373,6 +3416,7 @@ panel_events: ctl->ops.add_vsync_handler = NULL; ctl->ops.remove_vsync_handler = NULL; ctl->ops.reconfigure = NULL; + ctl->ops.wait_for_vsync_fnc = NULL; end: if (!IS_ERR_VALUE(ret)) { @@ -3773,6 +3817,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl) ctl->ops.pre_programming = mdss_mdp_cmd_pre_programming; ctl->ops.update_lineptr = mdss_mdp_cmd_update_lineptr; ctl->ops.panel_disable_cfg = mdss_mdp_cmd_panel_disable_cfg; + ctl->ops.wait_for_vsync_fnc = mdss_mdp_cmd_wait4_vsync; pr_debug("%s:-\n", __func__); return 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 97be2fd728c8..67cbf076b8ac 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -315,7 +315,7 @@ int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata, return 0; } -static void mdss_mdp_video_intf_recovery(void *data, int event) +static int mdss_mdp_video_intf_recovery(void *data, int event) { struct mdss_mdp_video_ctx *ctx; struct mdss_mdp_ctl *ctl = data; @@ -327,7 +327,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event) if (!data) { pr_err("%s: invalid ctl\n", __func__); - return; + return -EINVAL; } /* @@ -338,7 +338,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event) if (event != MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW) { pr_warn("%s: unsupported recovery event:%d\n", __func__, event); - return; + return -EPERM; } ctx = ctl->intf_ctx[MASTER_CTX]; @@ -353,7 +353,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event) clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */ if (!clk_rate) { pr_err("Unable to get proper clk_rate\n"); - return; + return -EINVAL; } /* * calculate clk_period as pico second to maintain good @@ -363,7 +363,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event) clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate); if (!clk_period) { pr_err("Unable to calculate clock period\n"); - return; + return -EINVAL; } min_ln_cnt = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width; active_lns_cnt = pinfo->yres; @@ -389,7 +389,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event) !ctx->timegen_en) { pr_warn("Target is in suspend or shutdown pending\n"); mutex_unlock(&ctl->offlock); - return; + return -EPERM; } line_cnt = mdss_mdp_video_line_count(ctl); @@ -399,7 +399,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event) pr_debug("%s, Needed lines left line_cnt=%d\n", __func__, line_cnt); mutex_unlock(&ctl->offlock); - return; + return 0; } else { pr_warn("line count is less. line_cnt = %d\n", line_cnt); @@ -1416,6 +1416,8 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps) } } + /* add HW recommended delay to handle panel_vsync */ + udelay(2000); mutex_lock(&ctl->offlock); pdata = ctl->panel_data; if (pdata == NULL) { @@ -1545,7 +1547,8 @@ exit_dfps: if (rc < 0) pr_err("Error in dfps_wait: %d\n", rc); } - + /* add HW recommended delay to handle panel_vsync */ + udelay(2000); /* Disable interface timing double buffer */ rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_TIMING_DB_CTRL, @@ -2345,6 +2348,7 @@ int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl) ctl->ops.early_wake_up_fnc = mdss_mdp_video_early_wake_up; ctl->ops.update_lineptr = mdss_mdp_video_lineptr_ctrl; ctl->ops.avr_ctrl_fnc = mdss_mdp_video_avr_ctrl; + ctl->ops.wait_for_vsync_fnc = NULL; return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index c9e32d69d444..f78600072ed0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -1123,6 +1123,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, int ret = 0; u32 left_lm_w = left_lm_w_from_mfd(mfd); u64 flags; + bool is_right_blend = false; struct mdss_mdp_mixer *mixer = NULL; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -1234,6 +1235,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, * staging, same pipe will be stagged on both layer mixers. */ if (mdata->has_src_split) { + is_right_blend = pipe->is_right_blend; if (left_blend_pipe) { if (__validate_pipe_priorities(left_blend_pipe, pipe)) { pr_err("priority limitation. left:%d rect:%d, right:%d rect:%d\n", @@ -1245,7 +1247,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, goto end; } else { pr_debug("pipe%d is a right_pipe\n", pipe->num); - pipe->is_right_blend = true; + is_right_blend = true; } } else if (pipe->is_right_blend) { /* @@ -1254,7 +1256,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, */ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); - pipe->is_right_blend = false; + is_right_blend = false; } if (is_split_lm(mfd) && __layer_needs_src_split(layer)) { @@ -1280,6 +1282,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, } pipe->src_split_req = false; } + pipe->is_right_blend = is_right_blend; } pipe->multirect.mode = vinfo->multirect.mode; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 9e295815da77..5daa8a7a2752 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -2322,14 +2322,12 @@ set_roi: } /* - * Enables/disable secure (display or camera) sessions + * Check if there is any change in secure state and store it. */ -static int __overlay_secure_ctrl(struct msm_fb_data_type *mfd) +static void __overlay_set_secure_transition_state(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); - struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); struct mdss_mdp_pipe *pipe; - int ret = 0; int sd_in_pipe = 0; int sc_in_pipe = 0; u64 pipes_flags = 0; @@ -2350,25 +2348,53 @@ static int __overlay_secure_ctrl(struct msm_fb_data_type *mfd) MDSS_XLOG(sd_in_pipe, sc_in_pipe, pipes_flags, mdp5_data->sc_enabled, mdp5_data->sd_enabled); pr_debug("sd:%d sd_in_pipe:%d sc:%d sc_in_pipe:%d flags:0x%llx\n", - mdp5_data->sd_enabled, sd_in_pipe, - mdp5_data->sc_enabled, sc_in_pipe, pipes_flags); + mdp5_data->sd_enabled, sd_in_pipe, + mdp5_data->sc_enabled, sc_in_pipe, pipes_flags); + + /* Reset the secure transition state */ + mdp5_data->secure_transition_state = SECURE_TRANSITION_NONE; /* - * Return early in only two conditions: - * 1. All the features are already disabled and state remains - * disabled for the pipes. - * 2. One of the features is already enabled and state remains - * enabled for the pipes. - */ + * Secure transition would be NONE in two conditions: + * 1. All the features are already disabled and state remains + * disabled for the pipes. + * 2. One of the features is already enabled and state remains + * enabled for the pipes. + */ if (!sd_in_pipe && !mdp5_data->sd_enabled && !sc_in_pipe && !mdp5_data->sc_enabled) - return ret; + return; else if ((sd_in_pipe && mdp5_data->sd_enabled) || (sc_in_pipe && mdp5_data->sc_enabled)) + return; + + /* Secure Display */ + if (!mdp5_data->sd_enabled && sd_in_pipe) + mdp5_data->secure_transition_state |= SD_NON_SECURE_TO_SECURE; + else if (mdp5_data->sd_enabled && !sd_in_pipe) + mdp5_data->secure_transition_state |= SD_SECURE_TO_NON_SECURE; + + /* Secure Camera */ + if (!mdp5_data->sc_enabled && sc_in_pipe) + mdp5_data->secure_transition_state |= SC_NON_SECURE_TO_SECURE; + else if (mdp5_data->sc_enabled && !sc_in_pipe) + mdp5_data->secure_transition_state |= SC_SECURE_TO_NON_SECURE; +} + +/* + * Enable/disable secure (display or camera) sessions + */ +static int __overlay_secure_ctrl(struct msm_fb_data_type *mfd) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); + int ret = 0; + + if (mdp5_data->secure_transition_state == SECURE_TRANSITION_NONE) return ret; /* Secure Display */ - if (!mdp5_data->sd_enabled && sd_in_pipe) { + if (mdp5_data->secure_transition_state == SD_NON_SECURE_TO_SECURE) { if (!mdss_get_sd_client_cnt()) { MDSS_XLOG(0x11); /*wait for ping pong done */ @@ -2390,7 +2416,8 @@ static int __overlay_secure_ctrl(struct msm_fb_data_type *mfd) } mdp5_data->sd_enabled = 1; mdss_update_sd_client(mdp5_data->mdata, true); - } else if (mdp5_data->sd_enabled && !sd_in_pipe) { + } else if (mdp5_data->secure_transition_state == + SD_SECURE_TO_NON_SECURE) { /* disable the secure display on last client */ if (mdss_get_sd_client_cnt() == 1) { MDSS_XLOG(0x22); @@ -2408,11 +2435,9 @@ static int __overlay_secure_ctrl(struct msm_fb_data_type *mfd) } /* Secure Camera */ - if (!mdp5_data->sc_enabled && sc_in_pipe) { + if (mdp5_data->secure_transition_state == SC_NON_SECURE_TO_SECURE) { if (!mdss_get_sc_client_cnt()) { MDSS_XLOG(0x33); - if (ctl->ops.wait_pingpong) - mdss_mdp_display_wait4pingpong(ctl, true); ret = mdss_mdp_secure_session_ctrl(1, MDP_SECURE_CAMERA_OVERLAY_SESSION); if (ret) { @@ -2422,7 +2447,8 @@ static int __overlay_secure_ctrl(struct msm_fb_data_type *mfd) } mdp5_data->sc_enabled = 1; mdss_update_sc_client(mdp5_data->mdata, true); - } else if (mdp5_data->sc_enabled && !sc_in_pipe) { + } else if (mdp5_data->secure_transition_state == + SC_SECURE_TO_NON_SECURE) { /* disable the secure camera on last client */ if (mdss_get_sc_client_cnt() == 1) { MDSS_XLOG(0x44); @@ -2501,15 +2527,23 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, list_move(&pipe->list, &mdp5_data->pipes_destroy); } + __overlay_set_secure_transition_state(mfd); /* * go to secure state if required, this should be done * after moving the buffers from the previous commit to - * destroy list + * destroy list. + * For video mode panels, secure display/camera should be disabled + * after flushing the new buffer. Skip secure disable here for those + * cases. */ - ret = __overlay_secure_ctrl(mfd); - if (IS_ERR_VALUE(ret)) { - pr_err("secure operation failed %d\n", ret); - goto commit_fail; + if (!((mfd->panel_info->type == MIPI_VIDEO_PANEL) && + ((mdp5_data->secure_transition_state == SD_SECURE_TO_NON_SECURE) || + (mdp5_data->secure_transition_state == SC_SECURE_TO_NON_SECURE)))) { + ret = __overlay_secure_ctrl(mfd); + if (IS_ERR_VALUE(ret)) { + pr_err("secure operation failed %d\n", ret); + goto commit_fail; + } } /* call this function before any registers programming */ @@ -2581,6 +2615,17 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, mutex_lock(&mdp5_data->ov_lock); + /* Disable secure display/camera for video mode panels */ + if ((mfd->panel_info->type == MIPI_VIDEO_PANEL) && + ((mdp5_data->secure_transition_state == SD_SECURE_TO_NON_SECURE) || + (mdp5_data->secure_transition_state == SC_SECURE_TO_NON_SECURE))) { + ret = __overlay_secure_ctrl(mfd); + if (IS_ERR_VALUE(ret)) { + pr_err("secure operation failed %d\n", ret); + goto commit_fail; + } + } + mdss_fb_update_notify_update(mfd); commit_fail: ATRACE_BEGIN("overlay_cleanup"); @@ -4367,12 +4412,21 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, start_y = 0; } + if ((img->width > mdata->max_cursor_size) || + (img->height > mdata->max_cursor_size) || + (img->depth != 32) || (start_x >= xres) || + (start_y >= yres)) { + pr_err("Invalid cursor image coordinates\n"); + ret = -EINVAL; + goto done; + } + roi.w = min(xres - start_x, img->width - roi.x); roi.h = min(yres - start_y, img->height - roi.y); if ((roi.w > mdata->max_cursor_size) || - (roi.h > mdata->max_cursor_size) || - (img->depth != 32) || (start_x >= xres) || (start_y >= yres)) { + (roi.h > mdata->max_cursor_size)) { + pr_err("Invalid cursor ROI size\n"); ret = -EINVAL; goto done; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h index b79b4c70f5dc..db2f85cb0361 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_trace.h +++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -297,22 +297,20 @@ TRACE_EVENT(mdp_perf_update_bus, TRACE_EVENT(mdp_compare_bw, TP_PROTO(unsigned long long new_ab, unsigned long long new_ib, - unsigned long long new_wb, unsigned long long new_max, + unsigned long long new_wb, unsigned long long old_ab, unsigned long long old_ib, - unsigned long long old_wb, unsigned long long old_max, + unsigned long long old_wb, u32 params_changed, bool update_bw), - TP_ARGS(new_ab, new_ib, new_wb, new_max, - old_ab, old_ib, old_wb, old_max, + TP_ARGS(new_ab, new_ib, new_wb, + old_ab, old_ib, old_wb, params_changed, update_bw), TP_STRUCT__entry( __field(u64, new_ab) __field(u64, new_ib) __field(u64, new_wb) - __field(u64, new_max) __field(u64, old_ab) __field(u64, old_ib) __field(u64, old_wb) - __field(u64, old_max) __field(u32, params_changed) __field(bool, update_bw) ), @@ -320,18 +318,16 @@ TRACE_EVENT(mdp_compare_bw, __entry->new_ab = new_ab; __entry->new_ib = new_ib; __entry->new_wb = new_wb; - __entry->new_max = new_max; __entry->old_ab = old_ab; __entry->old_ib = old_ib; __entry->old_wb = old_wb; - __entry->old_max = old_max; __entry->params_changed = params_changed; __entry->update_bw = update_bw; ), - TP_printk("[ab,ib,wb,max] new[%llu, %llu, %llu, %llu] old[%llu, %llu, %llu, %llu] parm:%d ret:%d", + TP_printk("[ab,ib,wb]new[%llu,%llu,%llu]old[%llu,%llu,%llu]chgd:%d %d", __entry->new_ab, __entry->new_ib, __entry->new_wb, - __entry->new_max, __entry->old_ab, __entry->old_ib, - __entry->old_wb, __entry->old_max, __entry->params_changed, + __entry->old_ab, __entry->old_ib, + __entry->old_wb, __entry->params_changed, __entry->update_bw) ); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index e466c0097540..e75c4a3a7cc1 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -112,12 +112,6 @@ enum { }; enum { - MDSS_PANEL_BLANK_BLANK = 0, - MDSS_PANEL_BLANK_UNBLANK, - MDSS_PANEL_BLANK_LOW_POWER, -}; - -enum { MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0, MDSS_PANEL_LOW_PERSIST_MODE_ON, }; @@ -195,7 +189,7 @@ enum { }; struct mdss_intf_recovery { - void (*fxn)(void *ctx, int event); + int (*fxn)(void *ctx, int event); void *data; }; diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index 0f0c6300642c..cb5329bc9ba8 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -1,6 +1,6 @@ /* * Copyright 2015 Linaro Limited - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -129,5 +129,9 @@ #define CXO_PIL_CDSP_CLK 84 #define CNOC_PERIPH_KEEPALIVE_A_CLK 85 #define MMSSNOC_A_CLK_CPU_VOTE 86 +#define AGGR2_NOC_MSMBUS_CLK 87 +#define AGGR2_NOC_MSMBUS_A_CLK 88 +#define AGGR2_NOC_SMMU_CLK 89 +#define AGGR2_NOC_USB_CLK 90 #endif diff --git a/include/linux/qpnp-misc.h b/include/linux/qpnp-misc.h index ab3302f6ea78..7d95bf24a425 100644 --- a/include/linux/qpnp-misc.h +++ b/include/linux/qpnp-misc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,8 +29,26 @@ */ int qpnp_misc_irqs_available(struct device *consumer_dev); + +/** + * qpnp_misc_read_reg - read register from misc device + * + * @node: device node pointer + * @address: address offset in misc peripheral to be read + * @val: data read from register + * + * This function returns zero if reading the MISC register succeeds. + * + */ + +int qpnp_misc_read_reg(struct device_node *node, u16 addr, u8 *val); #else -static int qpnp_misc_irqs_available(struct device *consumer_dev) +static inline int qpnp_misc_irqs_available(struct device *consumer_dev) +{ + return 0; +} +static inline int qpnp_misc_read_reg(struct device_node *node, u16 addr, + u8 *val) { return 0; } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1ce3ea1fd917..9e88da2764d7 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -71,6 +71,8 @@ struct wiphy; #define CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT 1 #define CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME 1 #define CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN 1 +#define CFG80211_CONNECT_TIMEOUT 1 +#define CFG80211_CONNECT_TIMEOUT_REASON_CODE 1 /* * wireless hardware capability structures @@ -2437,9 +2439,23 @@ struct cfg80211_qos_map { * (invoked with the wireless_dev mutex held) * * @connect: Connect to the ESS with the specified parameters. When connected, - * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. - * If the connection fails for some reason, call cfg80211_connect_result() - * with the status from the AP. + * call cfg80211_connect_result()/cfg80211_connect_bss() with status code + * %WLAN_STATUS_SUCCESS. If the connection fails for some reason, call + * cfg80211_connect_result()/cfg80211_connect_bss() with the status code + * from the AP or cfg80211_connect_timeout() if no frame with status code + * was received. + * The driver is allowed to roam to other BSSes within the ESS when the + * other BSS matches the connect parameters. When such roaming is initiated + * by the driver, the driver is expected to verify that the target matches + * the configured security parameters and to use Reassociation Request + * frame instead of Association Request frame. + * The connect function can also be used to request the driver to perform a + * specific roam when connected to an ESS. In that case, the prev_bssid + * parameter is set to the BSSID of the currently associated BSS as an + * indication of requesting reassociation. + * In both the driver-initiated and new connect() call initiated roaming + * cases, the result of roaming is indicated with a call to + * cfg80211_roamed() or cfg80211_roamed_bss(). * (invoked with the wireless_dev mutex held) * @update_connect_params: Update the connect parameters while connected to a * BSS. The updated parameters can be used by driver/firmware for @@ -4804,6 +4820,12 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you * the real status code for failures. * @gfp: allocation flags + * @timeout_reason: reason for connection timeout. This is used when the + * connection fails due to a timeout instead of an explicit rejection from + * the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is + * not known. This value is used only if @status < 0 to indicate that the + * failure is due to a timeout and not due to explicit rejection by the AP. + * This value is ignored in other cases (@status >= 0). * * It should be called by the underlying driver whenever connect() has * succeeded. This is similar to cfg80211_connect_result(), but with the @@ -4813,7 +4835,8 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, struct cfg80211_bss *bss, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, - size_t resp_ie_len, u16 status, gfp_t gfp); + size_t resp_ie_len, int status, gfp_t gfp, + enum nl80211_timeout_reason timeout_reason); /** * cfg80211_connect_result - notify cfg80211 of connection result @@ -4839,7 +4862,33 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid, u16 status, gfp_t gfp) { cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, - resp_ie_len, status, gfp); + resp_ie_len, status, gfp, + NL80211_TIMEOUT_UNSPECIFIED); +} + +/** + * cfg80211_connect_timeout - notify cfg80211 of connection timeout + * + * @dev: network device + * @bssid: the BSSID of the AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @gfp: allocation flags + * @timeout_reason: reason for connection timeout. + * + * It should be called by the underlying driver whenever connect() has failed + * in a sequence where no explicit authentication/association rejection was + * received from the AP. This could happen, e.g., due to not being able to send + * out the Authentication or Association Request frame or timing out while + * waiting for the response. + */ +static inline void +cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, gfp_t gfp, + enum nl80211_timeout_reason timeout_reason) +{ + cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, NULL, 0, -1, + gfp, timeout_reason); } /** diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index d2f19ac6f536..99fe34d25fc5 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -263,10 +263,10 @@ struct drm_msm_event_resp { #define DRM_MSM_GEM_CPU_FINI 0x05 #define DRM_MSM_GEM_SUBMIT 0x06 #define DRM_MSM_WAIT_FENCE 0x07 -#define DRM_SDE_WB_CONFIG 0x08 -#define DRM_MSM_REGISTER_EVENT 0x09 -#define DRM_MSM_DEREGISTER_EVENT 0x0A -#define DRM_MSM_NUM_IOCTLS 0x0B + +#define DRM_SDE_WB_CONFIG 0x40 +#define DRM_MSM_REGISTER_EVENT 0x41 +#define DRM_MSM_DEREGISTER_EVENT 0x42 /** * Currently DRM framework supports only VSYNC event. diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index 71fdf6d6e9e5..843e02711aa7 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -318,6 +318,7 @@ enum kgsl_timestamp_type { #define KGSL_PROP_HIGHEST_BANK_BIT 0x17 #define KGSL_PROP_DEVICE_BITNESS 0x18 #define KGSL_PROP_DEVICE_QDSS_STM 0x19 +#define KGSL_PROP_DEVICE_QTIMER 0x20 struct kgsl_shadowprop { unsigned long gpuaddr; @@ -330,6 +331,11 @@ struct kgsl_qdss_stm_prop { uint64_t size; }; +struct kgsl_qtimer_prop { + uint64_t gpuaddr; + uint64_t size; +}; + struct kgsl_version { unsigned int drv_major; unsigned int drv_minor; diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index ee68675bfe13..35029f227f8b 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -40,9 +40,9 @@ * To allow proper structure padding for 64bit/32bit target */ #ifdef __LP64 -#define MDP_LAYER_COMMIT_V1_PAD 3 +#define MDP_LAYER_COMMIT_V1_PAD 2 #else -#define MDP_LAYER_COMMIT_V1_PAD 4 +#define MDP_LAYER_COMMIT_V1_PAD 3 #endif /********************************************************************** @@ -166,6 +166,9 @@ VALIDATE/COMMIT FLAG CONFIGURATION /* Flag to indicate dual partial ROI update */ #define MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI 0x20 +/* Flag to update brightness when commit */ +#define MDP_COMMIT_UPDATE_BRIGHTNESS 0x40 + /* Flag to enable concurrent writeback for the frame */ #define MDP_COMMIT_CWB_EN 0x800 @@ -568,6 +571,9 @@ struct mdp_layer_commit_v1 { */ uint32_t dest_scaler_cnt; + /* Backlight level that would update when display commit */ + uint32_t bl_level; + /* 32-bits reserved value for future usage. */ uint32_t reserved[MDP_LAYER_COMMIT_V1_PAD]; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 0505b1f9872b..8a5c59a9ff0e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -486,7 +486,12 @@ * This attribute is ignored if driver does not support roam scan. * It is also sent as an event, with the BSSID and response IEs when the * connection is established or failed to be established. This can be - * determined by the STATUS_CODE attribute. + * determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success, + * non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the + * event, the connection attempt failed due to not being able to initiate + * authentication/association or not receiving a response from the AP. + * Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as + * well to remain backwards compatible. * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), * sent as an event when the card/driver roamed by itself. * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify @@ -1948,6 +1953,10 @@ enum nl80211_commands { * better BSSs. The attribute value is a packed structure * value as specified by &struct nl80211_bss_select_rssi_adjust. * + * @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out. + * u32 attribute with an &enum nl80211_timeout_reason value. This is used, + * e.g., with %NL80211_CMD_CONNECT event. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2357,6 +2366,8 @@ enum nl80211_attrs { NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, + NL80211_ATTR_TIMEOUT_REASON, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -4695,6 +4706,21 @@ enum nl80211_connect_failed_reason { }; /** + * enum nl80211_timeout_reason - timeout reasons + * + * @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified. + * @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out. + * @NL80211_TIMEOUT_AUTH: Authentication timed out. + * @NL80211_TIMEOUT_ASSOC: Association timed out. + */ +enum nl80211_timeout_reason { + NL80211_TIMEOUT_UNSPECIFIED, + NL80211_TIMEOUT_SCAN, + NL80211_TIMEOUT_AUTH, + NL80211_TIMEOUT_ASSOC, +}; + +/** * enum nl80211_scan_flags - scan request control flags * * Scan request control flags are used to control the handling diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index 5c5761d690dd..40c96eef3059 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -92,7 +92,7 @@ struct qseecom_load_img_req { int32_t ifd_data_fd; /* in */ char img_name[MAX_APP_NAME_SIZE]; /* in */ uint32_t app_arch; /* in */ - int app_id; /* out*/ + uint32_t app_id; /* out*/ }; struct qseecom_set_sb_mem_param_req { @@ -116,7 +116,7 @@ struct qseecom_qseos_version_req { */ struct qseecom_qseos_app_load_query { char app_name[MAX_APP_NAME_SIZE]; /* in */ - int app_id; /* out */ + uint32_t app_id; /* out */ uint32_t app_arch; }; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index c8653a9f0e9e..336d318c5187 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -927,9 +927,9 @@ enum v4l2_mpeg_vidc_video_mvc_layout { V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL = 0, V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM = 1 }; - #define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 44) #define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 45) + #define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 46) @@ -969,13 +969,13 @@ enum vl42_mpeg_vidc_video_enable_initial_qp { V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME = 0x4, }; -#define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \ +#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 54) -#define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \ +#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 55) -#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP \ +#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 56) #define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE \ @@ -1211,6 +1211,14 @@ enum v4l2_mpeg_vidc_video_venc_iframesize_type { V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED, }; +#define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 99) +#define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 100) +#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 101) + + /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 746eee61ad0e..f59f034a72b9 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -222,7 +222,7 @@ enum color_fmts { * Y_Stride = align(Width, 128) * UV_Stride = align(Width, 128) * Y_Scanlines = align(Height, 32) - * UV_Scanlines = align(Height/2, 16) + * UV_Scanlines = align((Height + 96)/2, 16) * Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096) * UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096) * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) @@ -231,11 +231,11 @@ enum color_fmts { * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) - * Extradata = 8k + * Extradata = 16k * * Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size + * Y_Meta_Plane_size + UV_Meta_Plane_size - * + max(Extradata, Y_Stride * 48), 4096) + * + Extradata), 4096) */ COLOR_FMT_NV12_UBWC, /* Venus NV12 10-bit UBWC: @@ -311,7 +311,7 @@ enum color_fmts { * Y_Stride = align(Width * 4/3, 128) * UV_Stride = align(Width * 4/3, 128) * Y_Scanlines = align(Height, 32) - * UV_Scanlines = align(Height/2, 16) + * UV_Scanlines = align((Height + 96)/2, 16) * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) @@ -320,11 +320,11 @@ enum color_fmts { * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) - * Extradata = 8k + * Extradata = 16k * * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + * Y_Meta_Plane_size + UV_Meta_Plane_size - * + max(Extradata, Y_Stride * 48), 4096) + * + Extradata), 4096) */ COLOR_FMT_NV12_BPP10_UBWC, /* Venus RGBA8888 format: @@ -970,6 +970,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( break; case COLOR_FMT_NV12_UBWC: case COLOR_FMT_NV12_BPP10_UBWC: + uv_sclines = VENUS_UV_SCANLINES(color_fmt, height + 96); y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); @@ -982,8 +983,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( uv_meta_scanlines, 4096); size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + - uv_meta_plane + - MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + uv_meta_plane + extra_size; size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_P010_UBWC: diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index fac254c4361b..d84bb30d56fa 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -24,6 +24,8 @@ #define ISP_STATS_STREAM_BIT 0x80000000 +#define VFE_HW_LIMIT 1 + struct msm_vfe_cfg_cmd_list; enum ISP_START_PIXEL_PATTERN { @@ -456,6 +458,7 @@ enum msm_vfe_reg_cfg_type { VFE_HW_UPDATE_UNLOCK, SET_WM_UB_SIZE, SET_UB_POLICY, + GET_VFE_HW_LIMIT, }; struct msm_vfe_cfg_cmd2 { @@ -842,6 +845,11 @@ struct msm_isp_dual_hw_master_slave_sync { uint32_t reserved[2]; }; +struct msm_vfe_dual_lpm_mode { + enum msm_vfe_axi_stream_src stream_src[VFE_AXI_SRC_MAX]; + uint32_t num_src; + uint32_t lpm_mode; +}; #define V4L2_PIX_FMT_QBGGR8 v4l2_fourcc('Q', 'B', 'G', '8') #define V4L2_PIX_FMT_QGBRG8 v4l2_fourcc('Q', 'G', 'B', '8') #define V4L2_PIX_FMT_QGRBG8 v4l2_fourcc('Q', 'G', 'R', '8') @@ -902,6 +910,7 @@ enum msm_isp_ioctl_cmd_code { MSM_ISP_FETCH_ENG_MULTI_PASS_START, MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, MSM_ISP_REQUEST_BUF_VER2, + MSM_ISP_DUAL_HW_LPM_MODE, }; #define VIDIOC_MSM_VFE_REG_CFG \ @@ -1022,4 +1031,8 @@ enum msm_isp_ioctl_cmd_code { #define VIDIOC_MSM_ISP_REQUEST_BUF_VER2 \ _IOWR('V', MSM_ISP_REQUEST_BUF_VER2, struct msm_isp_buf_request_ver2) +#define VIDIOC_MSM_ISP_DUAL_HW_LPM_MODE \ + _IOWR('V', MSM_ISP_DUAL_HW_LPM_MODE, \ + struct msm_vfe_dual_lpm_mode) + #endif /* __MSMB_ISP__ */ diff --git a/include/uapi/media/msmb_pproc.h b/include/uapi/media/msmb_pproc.h index b65669b87a21..8f454571e69d 100644 --- a/include/uapi/media/msmb_pproc.h +++ b/include/uapi/media/msmb_pproc.h @@ -16,6 +16,7 @@ #define MSM_CPP_MAX_FRAME_LENGTH 4096 #define MSM_CPP_MAX_FW_NAME_LEN 32 #define MAX_FREQ_TBL 10 +#define MSM_OUTPUT_BUF_CNT 8 enum msm_cpp_frame_type { MSM_CPP_OFFLINE_FRAME, @@ -76,7 +77,7 @@ struct msm_cpp_frame_info_t { uint32_t feature_mask; uint8_t we_disable; struct msm_cpp_buffer_info_t input_buffer_info; - struct msm_cpp_buffer_info_t output_buffer_info[8]; + struct msm_cpp_buffer_info_t output_buffer_info[MSM_OUTPUT_BUF_CNT]; struct msm_cpp_buffer_info_t duplicate_buffer_info; struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2]; uint32_t reserved; diff --git a/include/uapi/video/msm_hdmi_modes.h b/include/uapi/video/msm_hdmi_modes.h index 43ca6bab4c62..5b4b2b492be4 100644 --- a/include/uapi/video/msm_hdmi_modes.h +++ b/include/uapi/video/msm_hdmi_modes.h @@ -271,7 +271,7 @@ struct msm_hdmi_mode_timing_info { 720, 5, 5, 20, false, 74250, 60000, false, true, HDMI_RES_AR_16_9, 0} #define HDMI_VFRMT_1920x1080i60_16_9_TIMING \ {HDMI_VFRMT_1920x1080i60_16_9, 1920, 88, 44, 148, false, \ - 540, 2, 5, 5, false, 74250, 60000, false, true, HDMI_RES_AR_16_9, 0} + 540, 2, 5, 5, false, 74250, 60000, true, true, HDMI_RES_AR_16_9, 0} #define HDMI_VFRMT_1440x480i60_4_3_TIMING \ {HDMI_VFRMT_1440x480i60_4_3, 1440, 38, 124, 114, true, \ 240, 4, 3, 15, true, 27000, 60000, true, true, HDMI_RES_AR_4_3, 0} diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index f07343b54fe5..2cb46d51d715 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -57,6 +57,8 @@ #include <linux/trace_events.h> #include <linux/suspend.h> +#include <soc/qcom/watchdog.h> + #include "tree.h" #include "rcu.h" @@ -1298,6 +1300,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) rcu_check_gp_kthread_starvation(rsp); +#ifdef CONFIG_RCU_STALL_WATCHDOG_BITE + /* Induce watchdog bite */ + msm_trigger_wdog_bite(); +#endif + force_quiescent_state(rsp); /* Kick them all. */ } @@ -1333,6 +1340,11 @@ static void print_cpu_stall(struct rcu_state *rsp) jiffies + 3 * rcu_jiffies_till_stall_check() + 3); raw_spin_unlock_irqrestore(&rnp->lock, flags); +#ifdef CONFIG_RCU_STALL_WATCHDOG_BITE + /* Induce non secure watchdog bite to collect context */ + msm_trigger_wdog_bite(); +#endif + /* * Attempt to revive the RCU machinery by forcing a context switch. * diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 9b15d6eb1622..66d9e907aa07 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3991,6 +3991,7 @@ static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) { kfree(s->saved_cmdlines); kfree(s->map_cmdline_to_pid); + kfree(s->saved_tgids); kfree(s); } diff --git a/kernel/watchdog.c b/kernel/watchdog.c index f2813e137b23..91fa701b4a24 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -27,6 +27,7 @@ #include <linux/kvm_para.h> #include <linux/perf_event.h> #include <linux/kthread.h> +#include <soc/qcom/watchdog.h> /* * The run state of the lockup detectors is controlled by the content of the @@ -366,8 +367,11 @@ static void watchdog_check_hardlockup_other_cpu(void) if (per_cpu(hard_watchdog_warn, next_cpu) == true) return; - if (hardlockup_panic) - panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu); + if (hardlockup_panic) { + pr_err("Watchdog detected hard LOCKUP on cpu %u", + next_cpu); + msm_trigger_wdog_bite(); + } else WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu); @@ -430,6 +434,9 @@ static void watchdog_overflow_callback(struct perf_event *event, return; pr_emerg("Watchdog detected hard LOCKUP on cpu %d", this_cpu); + if (hardlockup_panic) + msm_trigger_wdog_bite(); + print_modules(); print_irqtrace_events(current); if (regs) @@ -552,6 +559,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", smp_processor_id(), duration, current->comm, task_pid_nr(current)); + + if (softlockup_panic) + msm_trigger_wdog_bite(); __this_cpu_write(softlockup_task_ptr_saved, current); print_modules(); print_irqtrace_events(current); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 902657d4cac5..3cd6011f209d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1455,6 +1455,17 @@ config RCU_CPU_STALL_TIMEOUT RCU grace period persists, additional CPU stall warnings are printed at more widely spaced intervals. +config RCU_STALL_WATCHDOG_BITE + bool "RCU stall induce watchdog bite" + depends on RCU_STALL_COMMON && QCOM_WATCHDOG_V2 + help + Induce watchdog bite if RCU grace period extends more than + specified no of seconds instead of just warning messages. + This helps to collect ram dumps and cpu context for + postmortem analysis. Generally if a given RCU grace period + extends more than the specified number of seconds, + a CPU stall warning is printed. + config RCU_TRACE bool "Enable tracing for RCU" depends on DEBUG_KERNEL diff --git a/net/wireless/core.h b/net/wireless/core.h index 46495dd821c8..2ec028ea7775 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -215,7 +215,8 @@ struct cfg80211_event { size_t req_ie_len; size_t resp_ie_len; struct cfg80211_bss *bss; - u16 status; + int status; /* -1 = failed; 0..65535 = status code */ + enum nl80211_timeout_reason timeout_reason; } cr; struct { const u8 *req_ie; @@ -375,8 +376,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, - u16 status, bool wextev, - struct cfg80211_bss *bss); + int status, bool wextev, + struct cfg80211_bss *bss, + enum nl80211_timeout_reason timeout_reason); void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap); int cfg80211_disconnect(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 594eeea9533b..36baa8d22108 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -48,7 +48,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, /* update current_bss etc., consumes the bss reference */ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, - status_code == WLAN_STATUS_SUCCESS, bss); + status_code == WLAN_STATUS_SUCCESS, bss, + NL80211_TIMEOUT_UNSPECIFIED); } EXPORT_SYMBOL(cfg80211_rx_assoc_resp); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index dcae8ae9bfad..08bd3f3d27e3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -408,6 +408,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = { .len = sizeof(struct nl80211_bss_select_rssi_adjust) }, + [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -12264,7 +12265,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, - u16 status, gfp_t gfp) + int status, + enum nl80211_timeout_reason timeout_reason, + gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -12282,7 +12285,12 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) || - nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status) || + nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, + status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE : + status) || + (status < 0 && + (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) || + nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) || (req_ie && nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) || (resp_ie && diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 84d4edf1d545..a749c9be2836 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -55,7 +55,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, - u16 status, gfp_t gfp); + int status, + enum nl80211_timeout_reason timeout_reason, + gfp_t gfp); void nl80211_send_roamed(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index e5b962d2ffe7..9c7f0ce35a06 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -34,10 +34,11 @@ struct cfg80211_conn { CFG80211_CONN_SCAN_AGAIN, CFG80211_CONN_AUTHENTICATE_NEXT, CFG80211_CONN_AUTHENTICATING, - CFG80211_CONN_AUTH_FAILED, + CFG80211_CONN_AUTH_FAILED_TIMEOUT, CFG80211_CONN_ASSOCIATE_NEXT, CFG80211_CONN_ASSOCIATING, CFG80211_CONN_ASSOC_FAILED, + CFG80211_CONN_ASSOC_FAILED_TIMEOUT, CFG80211_CONN_DEAUTH, CFG80211_CONN_CONNECTED, } state; @@ -162,7 +163,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) return err; } -static int cfg80211_conn_do_work(struct wireless_dev *wdev) +static int cfg80211_conn_do_work(struct wireless_dev *wdev, + enum nl80211_timeout_reason *treason) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_connect_params *params; @@ -193,7 +195,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) NULL, 0, params->key, params->key_len, params->key_idx, NULL, 0); - case CFG80211_CONN_AUTH_FAILED: + case CFG80211_CONN_AUTH_FAILED_TIMEOUT: + *treason = NL80211_TIMEOUT_AUTH; return -ENOTCONN; case CFG80211_CONN_ASSOCIATE_NEXT: if (WARN_ON(!rdev->ops->assoc)) @@ -220,6 +223,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) WLAN_REASON_DEAUTH_LEAVING, false); return err; + case CFG80211_CONN_ASSOC_FAILED_TIMEOUT: + *treason = NL80211_TIMEOUT_ASSOC; + /* fall through */ case CFG80211_CONN_ASSOC_FAILED: cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, NULL, 0, @@ -243,6 +249,7 @@ void cfg80211_conn_work(struct work_struct *work) container_of(work, struct cfg80211_registered_device, conn_work); struct wireless_dev *wdev; u8 bssid_buf[ETH_ALEN], *bssid = NULL; + enum nl80211_timeout_reason treason; rtnl_lock(); @@ -264,12 +271,12 @@ void cfg80211_conn_work(struct work_struct *work) memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); bssid = bssid_buf; } - if (cfg80211_conn_do_work(wdev)) { + treason = NL80211_TIMEOUT_UNSPECIFIED; + if (cfg80211_conn_do_work(wdev, &treason)) { __cfg80211_connect_result( wdev->netdev, bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - false, NULL); + NULL, 0, NULL, 0, -1, false, NULL, + treason); } wdev_unlock(wdev); } @@ -374,7 +381,8 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) } else if (status_code != WLAN_STATUS_SUCCESS) { __cfg80211_connect_result(wdev->netdev, mgmt->bssid, NULL, 0, NULL, 0, - status_code, false, NULL); + status_code, false, NULL, + NL80211_TIMEOUT_UNSPECIFIED); } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; schedule_work(&rdev->conn_work); @@ -422,7 +430,7 @@ void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) if (!wdev->conn) return; - wdev->conn->state = CFG80211_CONN_AUTH_FAILED; + wdev->conn->state = CFG80211_CONN_AUTH_FAILED_TIMEOUT; schedule_work(&rdev->conn_work); } @@ -444,7 +452,7 @@ void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) if (!wdev->conn) return; - wdev->conn->state = CFG80211_CONN_ASSOC_FAILED; + wdev->conn->state = CFG80211_CONN_ASSOC_FAILED_TIMEOUT; schedule_work(&rdev->conn_work); } @@ -565,7 +573,9 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, /* we're good if we have a matching bss struct */ if (bss) { - err = cfg80211_conn_do_work(wdev); + enum nl80211_timeout_reason treason; + + err = cfg80211_conn_do_work(wdev, &treason); cfg80211_put_bss(wdev->wiphy, bss); } else { /* otherwise we'll need to scan for the AP first */ @@ -662,8 +672,9 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, - u16 status, bool wextev, - struct cfg80211_bss *bss) + int status, bool wextev, + struct cfg80211_bss *bss, + enum nl80211_timeout_reason timeout_reason) { struct wireless_dev *wdev = dev->ieee80211_ptr; const u8 *country_ie; @@ -682,7 +693,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, - status, GFP_KERNEL); + status, timeout_reason, GFP_KERNEL); #ifdef CONFIG_CFG80211_WEXT if (wextev) { @@ -771,7 +782,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, struct cfg80211_bss *bss, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, - size_t resp_ie_len, u16 status, gfp_t gfp) + size_t resp_ie_len, int status, gfp_t gfp, + enum nl80211_timeout_reason timeout_reason) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); @@ -811,6 +823,7 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, cfg80211_hold_bss(bss_from_pub(bss)); ev->cr.bss = bss; ev->cr.status = status; + ev->cr.timeout_reason = timeout_reason; spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); diff --git a/net/wireless/util.c b/net/wireless/util.c index dfd0766abd6f..305370cfd1e0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -878,7 +878,7 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) ev->cr.resp_ie, ev->cr.resp_ie_len, ev->cr.status, ev->cr.status == WLAN_STATUS_SUCCESS, - ev->cr.bss); + ev->cr.bss, ev->cr.timeout_reason); break; case EVENT_ROAMED: __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie, diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index 5ecd7870bb3b..e5e71939f529 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -48,18 +48,11 @@ #define BUS_DOWN 1 /* - *50 Milliseconds sufficient for DSP bring up in the modem + * 50 Milliseconds sufficient for DSP bring up in the lpass * after Sub System Restart */ #define ADSP_STATE_READY_TIMEOUT_MS 50 -enum { - BOOST_SWITCH = 0, - BOOST_ALWAYS, - BYPASS_ALWAYS, - BOOST_ON_FOREVER, -}; - #define EAR_PMD 0 #define EAR_PMU 1 #define SPK_PMD 2 @@ -81,12 +74,10 @@ enum { ((value - min_value)/step_size) enum { - RX_MIX1_INP_SEL_ZERO = 0, - RX_MIX1_INP_SEL_IIR1, - RX_MIX1_INP_SEL_IIR2, - RX_MIX1_INP_SEL_RX1, - RX_MIX1_INP_SEL_RX2, - RX_MIX1_INP_SEL_RX3, + BOOST_SWITCH = 0, + BOOST_ALWAYS, + BYPASS_ALWAYS, + BOOST_ON_FOREVER, }; static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -874,11 +865,12 @@ static int msm_anlg_cdc_dig_register_notifier(void *handle, struct notifier_block *nblock, bool enable) { - struct sdm660_cdc *handle_cdc = handle; + struct sdm660_cdc_priv *handle_cdc = handle; if (enable) return blocking_notifier_chain_register(&handle_cdc->notifier, nblock); + return blocking_notifier_chain_unregister(&handle_cdc->notifier, nblock); } @@ -893,10 +885,10 @@ static int msm_anlg_cdc_mbhc_register_notifier(struct wcd_mbhc *wcd_mbhc, if (enable) return blocking_notifier_chain_register( - &sdm660_cdc->notifier, + &sdm660_cdc->notifier_mbhc, nblock); - return blocking_notifier_chain_unregister(&sdm660_cdc->notifier, + return blocking_notifier_chain_unregister(&sdm660_cdc->notifier_mbhc, nblock); } @@ -944,7 +936,7 @@ static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16, static void msm_anlg_cdc_dig_notifier_call(struct snd_soc_codec *codec, const enum dig_cdc_notify_event event) { - struct sdm660_cdc *sdm660_cdc = codec->control_data; + struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec); pr_debug("%s: notifier call event %d\n", __func__, event); blocking_notifier_call_chain(&sdm660_cdc->notifier, @@ -958,7 +950,7 @@ static void msm_anlg_cdc_notifier_call(struct snd_soc_codec *codec, snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: notifier call event %d\n", __func__, event); - blocking_notifier_call_chain(&sdm660_cdc->notifier, event, + blocking_notifier_call_chain(&sdm660_cdc->notifier_mbhc, event, &sdm660_cdc->mbhc); } @@ -2045,12 +2037,6 @@ static const char * const wsa_spk_text[] = { "ZERO", "WSA" }; - - -static const char * const iir_inp1_text[] = { - "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3" -}; - static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(adc2_mux_text), adc2_mux_text); @@ -2598,7 +2584,7 @@ static int msm_anlg_cdc_codec_enable_micbias(struct snd_soc_dapm_widget *w, static void update_clkdiv(void *handle, int val) { - struct sdm660_cdc *handle_cdc = handle; + struct sdm660_cdc_priv *handle_cdc = handle; struct snd_soc_codec *codec = handle_cdc->codec; snd_soc_update_bits(codec, @@ -2608,10 +2594,7 @@ static void update_clkdiv(void *handle, int val) static int get_cdc_version(void *handle) { - struct sdm660_cdc *handle_cdc = handle; - struct snd_soc_codec *codec = handle_cdc->codec; - struct sdm660_cdc_priv *sdm660_cdc = - snd_soc_codec_get_drvdata(codec); + struct sdm660_cdc_priv *sdm660_cdc = handle; return get_codec_version(sdm660_cdc); } @@ -3680,11 +3663,12 @@ static int msm_anlg_cdc_bringup(struct snd_soc_codec *codec) MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5); snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00); + return 0; } static struct regulator *msm_anlg_cdc_find_regulator( - const struct sdm660_cdc *sdm660_cdc, + const struct sdm660_cdc_priv *sdm660_cdc, const char *name) { int i; @@ -3779,6 +3763,7 @@ static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec) msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN); set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask); snd_soc_card_change_online_state(codec->component.card, 0); + return 0; } @@ -3906,7 +3891,7 @@ EXPORT_SYMBOL(msm_anlg_cdc_update_int_spk_boost); static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec) { - struct sdm660_cdc *sdm660_cdc = codec->control_data; + struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec); struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data; u8 reg_val; @@ -4060,63 +4045,54 @@ EXPORT_SYMBOL(msm_anlg_codec_info_create_codec_entry); static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec) { - struct sdm660_cdc_priv *sdm660_cdc_priv; - struct sdm660_cdc *handle_cdc; + struct sdm660_cdc_priv *sdm660_cdc; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int ret; - sdm660_cdc_priv = devm_kzalloc(codec->dev, - sizeof(struct sdm660_cdc_priv), - GFP_KERNEL); - if (!sdm660_cdc_priv) - return -ENOMEM; - - codec->control_data = dev_get_drvdata(codec->dev); - snd_soc_codec_set_drvdata(codec, sdm660_cdc_priv); - sdm660_cdc_priv->codec = codec; - handle_cdc = codec->control_data; - handle_cdc->codec = codec; + sdm660_cdc = dev_get_drvdata(codec->dev); + sdm660_cdc->codec = codec; /* codec resmgr module init */ - sdm660_cdc_priv->spkdrv_reg = - msm_anlg_cdc_find_regulator(codec->control_data, + sdm660_cdc->spkdrv_reg = + msm_anlg_cdc_find_regulator(sdm660_cdc, MSM89XX_VDD_SPKDRV_NAME); - sdm660_cdc_priv->pmic_rev = + sdm660_cdc->pmic_rev = snd_soc_read(codec, MSM89XX_PMIC_DIGITAL_REVISION1); - sdm660_cdc_priv->codec_version = + sdm660_cdc->codec_version = snd_soc_read(codec, MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE); - sdm660_cdc_priv->analog_major_rev = + sdm660_cdc->analog_major_rev = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_REVISION4); - if (sdm660_cdc_priv->codec_version == CONGA) { + if (sdm660_cdc->codec_version == CONGA) { dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__, - sdm660_cdc_priv->codec_version); - sdm660_cdc_priv->ext_spk_boost_set = true; + sdm660_cdc->codec_version); + sdm660_cdc->ext_spk_boost_set = true; } else { dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__, - sdm660_cdc_priv->pmic_rev); - if (sdm660_cdc_priv->pmic_rev == TOMBAK_1_0 && - sdm660_cdc_priv->codec_version == CAJON_2_0) { - if (sdm660_cdc_priv->analog_major_rev == 0x02) { - sdm660_cdc_priv->codec_version = DRAX_CDC; + sdm660_cdc->pmic_rev); + if (sdm660_cdc->pmic_rev == TOMBAK_1_0 && + sdm660_cdc->codec_version == CAJON_2_0) { + if (sdm660_cdc->analog_major_rev == 0x02) { + sdm660_cdc->codec_version = DRAX_CDC; dev_dbg(codec->dev, "%s : Drax codec detected\n", __func__); } else { - sdm660_cdc_priv->codec_version = DIANGU; + sdm660_cdc->codec_version = DIANGU; dev_dbg(codec->dev, "%s : Diangu detected\n", __func__); } - } else if (sdm660_cdc_priv->pmic_rev == TOMBAK_1_0 && + } else if (sdm660_cdc->pmic_rev == TOMBAK_1_0 && (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL) & 0x80)) { - sdm660_cdc_priv->codec_version = CAJON; + sdm660_cdc->codec_version = CAJON; dev_dbg(codec->dev, "%s : Cajon detected\n", __func__); - } else if (sdm660_cdc_priv->pmic_rev == TOMBAK_2_0 && + } else if (sdm660_cdc->pmic_rev == TOMBAK_2_0 && (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL) & 0x80)) { - sdm660_cdc_priv->codec_version = CAJON_2_0; + sdm660_cdc->codec_version = CAJON_2_0; dev_dbg(codec->dev, "%s : Cajon 2.0 detected\n", __func__); } @@ -4125,8 +4101,8 @@ static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec) * set to default boost option BOOST_SWITCH, user mixer path can change * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen. */ - sdm660_cdc_priv->boost_option = BOOST_SWITCH; - sdm660_cdc_priv->hph_mode = NORMAL_MODE; + sdm660_cdc->boost_option = BOOST_SWITCH; + sdm660_cdc->hph_mode = NORMAL_MODE; msm_anlg_cdc_dt_parse_boost_info(codec); msm_anlg_cdc_set_boost_v(codec); @@ -4143,50 +4119,52 @@ static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec) wcd9xxx_spmi_set_codec(codec); - sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = + sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].supply = msm_anlg_cdc_find_regulator( - codec->control_data, + sdm660_cdc, on_demand_supply_name[ON_DEMAND_MICBIAS]); - atomic_set(&sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, + atomic_set(&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].ref, 0); - BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc_priv->notifier); - - sdm660_cdc_priv->fw_data = devm_kzalloc(codec->dev, - sizeof(*(sdm660_cdc_priv->fw_data)), + sdm660_cdc->fw_data = devm_kzalloc(codec->dev, + sizeof(*(sdm660_cdc->fw_data)), GFP_KERNEL); - if (!sdm660_cdc_priv->fw_data) + if (!sdm660_cdc->fw_data) return -ENOMEM; - set_bit(WCD9XXX_MBHC_CAL, sdm660_cdc_priv->fw_data->cal_bit); - ret = wcd_cal_create_hwdep(sdm660_cdc_priv->fw_data, + set_bit(WCD9XXX_MBHC_CAL, sdm660_cdc->fw_data->cal_bit); + ret = wcd_cal_create_hwdep(sdm660_cdc->fw_data, WCD9XXX_CODEC_HWDEP_NODE, codec); if (ret < 0) { dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret); return ret; } - wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb, &intr_ids, + wcd_mbhc_init(&sdm660_cdc->mbhc, codec, &mbhc_cb, &intr_ids, wcd_mbhc_registers, true); - sdm660_cdc_priv->int_mclk0_enabled = false; + sdm660_cdc->int_mclk0_enabled = false; /*Update speaker boost configuration*/ - sdm660_cdc_priv->spk_boost_set = spkr_boost_en; + sdm660_cdc->spk_boost_set = spkr_boost_en; pr_debug("%s: speaker boost configured = %d\n", - __func__, sdm660_cdc_priv->spk_boost_set); + __func__, sdm660_cdc->spk_boost_set); /* Set initial MICBIAS voltage level */ msm_anlg_cdc_set_micb_v(codec); /* Set initial cap mode */ msm_anlg_cdc_configure_cap(codec, false, false); + + snd_soc_dapm_ignore_suspend(dapm, "PDM Playback"); + snd_soc_dapm_ignore_suspend(dapm, "PDM Capture"); + return 0; } static int msm_anlg_cdc_soc_remove(struct snd_soc_codec *codec) { struct sdm660_cdc_priv *sdm660_cdc_priv = - snd_soc_codec_get_drvdata(codec); + dev_get_drvdata(codec->dev); sdm660_cdc_priv->spkdrv_reg = NULL; sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL; @@ -4198,7 +4176,7 @@ static int msm_anlg_cdc_soc_remove(struct snd_soc_codec *codec) } static int msm_anlg_cdc_enable_static_supplies_to_optimum( - struct sdm660_cdc *sdm660_cdc, + struct sdm660_cdc_priv *sdm660_cdc, struct sdm660_cdc_pdata *pdata) { int i; @@ -4231,7 +4209,7 @@ static int msm_anlg_cdc_enable_static_supplies_to_optimum( } static int msm_anlg_cdc_disable_static_supplies_to_optimum( - struct sdm660_cdc *sdm660_cdc, + struct sdm660_cdc_priv *sdm660_cdc, struct sdm660_cdc_pdata *pdata) { int i; @@ -4255,24 +4233,10 @@ static int msm_anlg_cdc_disable_static_supplies_to_optimum( static int msm_anlg_cdc_suspend(struct snd_soc_codec *codec) { - struct msm_asoc_mach_data *pdata = NULL; - struct sdm660_cdc *sdm660_cdc = codec->control_data; + struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec); struct sdm660_cdc_pdata *sdm660_cdc_pdata = sdm660_cdc->dev->platform_data; - pdata = snd_soc_card_get_drvdata(codec->component.card); - pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n", - __func__, atomic_read(&pdata->int_mclk0_rsc_ref), - atomic_read(&pdata->int_mclk0_enabled)); - if (atomic_read(&pdata->int_mclk0_enabled) == true) { - cancel_delayed_work_sync(&pdata->disable_int_mclk0_work); - mutex_lock(&pdata->cdc_int_mclk0_mutex); - pdata->digital_cdc_core_clk.enable = 0; - afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX, - &pdata->digital_cdc_core_clk); - atomic_set(&pdata->int_mclk0_enabled, false); - mutex_unlock(&pdata->cdc_int_mclk0_mutex); - } msm_anlg_cdc_disable_static_supplies_to_optimum(sdm660_cdc, sdm660_cdc_pdata); return 0; @@ -4281,7 +4245,7 @@ static int msm_anlg_cdc_suspend(struct snd_soc_codec *codec) static int msm_anlg_cdc_resume(struct snd_soc_codec *codec) { struct msm_asoc_mach_data *pdata = NULL; - struct sdm660_cdc *sdm660_cdc = codec->control_data; + struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec); struct sdm660_cdc_pdata *sdm660_cdc_pdata = sdm660_cdc->dev->platform_data; @@ -4311,7 +4275,7 @@ static struct snd_soc_codec_driver soc_codec_dev_sdm660_cdc = { .get_regmap = msm_anlg_get_regmap, }; -static int msm_anlg_cdc_init_supplies(struct sdm660_cdc *sdm660_cdc, +static int msm_anlg_cdc_init_supplies(struct sdm660_cdc_priv *sdm660_cdc, struct sdm660_cdc_pdata *pdata) { int ret; @@ -4386,7 +4350,7 @@ err: } static int msm_anlg_cdc_enable_static_supplies( - struct sdm660_cdc *sdm660_cdc, + struct sdm660_cdc_priv *sdm660_cdc, struct sdm660_cdc_pdata *pdata) { int i; @@ -4411,7 +4375,7 @@ static int msm_anlg_cdc_enable_static_supplies( return ret; } -static void msm_anlg_cdc_disable_supplies(struct sdm660_cdc *sdm660_cdc, +static void msm_anlg_cdc_disable_supplies(struct sdm660_cdc_priv *sdm660_cdc, struct sdm660_cdc_pdata *pdata) { int i; @@ -4438,7 +4402,7 @@ static const struct of_device_id sdm660_codec_of_match[] = { static void msm_anlg_add_child_devices(struct work_struct *work) { - struct sdm660_cdc *pdata; + struct sdm660_cdc_priv *pdata; struct platform_device *pdev; struct device_node *node; struct msm_dig_ctrl_data *dig_ctrl_data = NULL, *temp; @@ -4446,7 +4410,7 @@ static void msm_anlg_add_child_devices(struct work_struct *work) struct msm_dig_ctrl_platform_data *platdata; char plat_dev_name[MSM_DIG_CDC_STRING_LEN]; - pdata = container_of(work, struct sdm660_cdc, + pdata = container_of(work, struct sdm660_cdc_priv, msm_anlg_add_child_devices_work); if (!pdata) { pr_err("%s: Memory for pdata does not exist\n", @@ -4527,7 +4491,7 @@ err: static int msm_anlg_cdc_probe(struct platform_device *pdev) { int ret = 0; - struct sdm660_cdc *sdm660_cdc = NULL; + struct sdm660_cdc_priv *sdm660_cdc = NULL; struct sdm660_cdc_pdata *pdata; int adsp_state; @@ -4554,7 +4518,7 @@ static int msm_anlg_cdc_probe(struct platform_device *pdev) __func__); goto rtn; } - sdm660_cdc = devm_kzalloc(&pdev->dev, sizeof(struct sdm660_cdc), + sdm660_cdc = devm_kzalloc(&pdev->dev, sizeof(struct sdm660_cdc_priv), GFP_KERNEL); if (sdm660_cdc == NULL) { ret = -ENOMEM; @@ -4578,7 +4542,6 @@ static int msm_anlg_cdc_probe(struct platform_device *pdev) /* Allow supplies to be ready */ usleep_range(5, 6); - dev_set_drvdata(&pdev->dev, sdm660_cdc); wcd9xxx_spmi_set_dev(pdev, 0); wcd9xxx_spmi_set_dev(pdev, 1); if (wcd9xxx_spmi_irq_init()) { @@ -4588,6 +4551,7 @@ static int msm_anlg_cdc_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: irq initialization passed\n", __func__); } + dev_set_drvdata(&pdev->dev, sdm660_cdc); ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sdm660_cdc, @@ -4599,6 +4563,9 @@ static int msm_anlg_cdc_probe(struct platform_device *pdev) __func__, ret); goto err_supplies; } + BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier); + BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier_mbhc); + sdm660_cdc->dig_plat_data.handle = (void *) sdm660_cdc; sdm660_cdc->dig_plat_data.update_clkdiv = update_clkdiv; sdm660_cdc->dig_plat_data.get_cdc_version = get_cdc_version; @@ -4617,7 +4584,7 @@ rtn: static int msm_anlg_cdc_remove(struct platform_device *pdev) { - struct sdm660_cdc *sdm660_cdc = dev_get_drvdata(&pdev->dev); + struct sdm660_cdc_priv *sdm660_cdc = dev_get_drvdata(&pdev->dev); struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data; snd_soc_unregister_codec(&pdev->dev); diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h index e0626d3be971..0c9e9a6aeb6a 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -172,7 +172,7 @@ struct msm_dig_ctrl_platform_data { bool enable); }; -struct sdm660_cdc { +struct sdm660_cdc_priv { struct device *dev; u32 num_of_supplies; struct regulator_bulk_data *supplies; @@ -182,15 +182,6 @@ struct sdm660_cdc { /* digital codec data structure */ struct msm_dig_ctrl_data *dig_ctrl_data; struct blocking_notifier_head notifier; -}; - -struct sdm660_cdc_pdata { - struct wcd_micbias_setting micbias; - struct sdm660_cdc_regulator regulator[MAX_REGULATOR]; -}; - -struct sdm660_cdc_priv { - struct snd_soc_codec *codec; u16 pmic_rev; u16 codec_version; u16 analog_major_rev; @@ -207,7 +198,7 @@ struct sdm660_cdc_priv { bool ext_spk_boost_set; struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX]; struct regulator *spkdrv_reg; - struct blocking_notifier_head notifier; + struct blocking_notifier_head notifier_mbhc; /* mbhc module */ struct wcd_mbhc mbhc; /* cal info for codec */ @@ -222,6 +213,12 @@ struct sdm660_cdc_priv { struct snd_info_entry *version_entry; }; +struct sdm660_cdc_pdata { + struct wcd_micbias_setting micbias; + struct sdm660_cdc_regulator regulator[MAX_REGULATOR]; +}; + + extern int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm); diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index f1c3b4050323..91faee1ffd32 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -79,7 +79,7 @@ static int msm_digcdc_clock_control(bool flag) if (atomic_read(&pdata->int_mclk0_enabled) == false) { pdata->digital_cdc_core_clk.enable = 1; ret = afe_set_lpass_clock_v2( - AFE_PORT_ID_PRIMARY_MI2S_RX, + AFE_PORT_ID_INT0_MI2S_RX, &pdata->digital_cdc_core_clk); if (ret < 0) { pr_err("%s:failed to enable the MCLK\n", @@ -285,7 +285,7 @@ static int msm_dig_cdc_codec_enable_interpolator(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - struct msm_dig *msm_dig_cdc = dev_get_drvdata(codec->dev); + struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name); @@ -542,14 +542,14 @@ static void tx_hpf_corner_freq_callback(struct work_struct *work) struct delayed_work *hpf_delayed_work; struct hpf_work *hpf_work; struct snd_soc_codec *codec; - struct msm_dig *msm_dig_cdc; + struct msm_dig_priv *msm_dig_cdc; u16 tx_mux_ctl_reg; u8 hpf_cut_of_freq; hpf_delayed_work = to_delayed_work(work); hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); codec = hpf_work->dig_cdc->codec; - msm_dig_cdc = codec->control_data; + msm_dig_cdc = hpf_work->dig_cdc; hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq; tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL + @@ -826,8 +826,7 @@ static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct msm_asoc_mach_data *pdata = NULL; unsigned int decimator; - struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec); - struct msm_dig *msm_dig_cdc = codec->control_data; + struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec); char *dec_name = NULL; char *widget_name = NULL; char *temp; @@ -897,7 +896,7 @@ static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01); for (i = 0; i < NUM_DECIMATORS; i++) { if (decimator == i + 1) - dig_cdc->dec_active[i] = true; + msm_dig_cdc->dec_active[i] = true; } dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg); @@ -957,7 +956,7 @@ static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00); for (i = 0; i < NUM_DECIMATORS; i++) { if (decimator == i + 1) - dig_cdc->dec_active[i] = false; + msm_dig_cdc->dec_active[i] = false; } break; } @@ -972,7 +971,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, { enum dig_cdc_notify_event event = (enum dig_cdc_notify_event)val; struct snd_soc_codec *codec = registered_digcodec; - struct msm_dig *msm_dig_cdc = codec->control_data; + struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec); struct msm_asoc_mach_data *pdata = NULL; pdata = snd_soc_card_get_drvdata(codec->component.card); @@ -1155,36 +1154,35 @@ int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root, return -ENOMEM; } msm_dig->version_entry = version_entry; + if (msm_dig->get_cdc_version) + msm_dig->version = msm_dig->get_cdc_version(msm_dig->handle); + else + msm_dig->version = DRAX_CDC; + return 0; } EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry); static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec) { - struct msm_dig_priv *dig_cdc = NULL; - struct msm_dig *msm_dig_cdc = dev_get_drvdata(codec->dev); + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int i, ret; - dig_cdc = devm_kzalloc(codec->dev, sizeof(struct msm_dig_priv), - GFP_KERNEL); - if (!dig_cdc) - return -ENOMEM; - snd_soc_codec_set_drvdata(codec, dig_cdc); - dig_cdc->codec = codec; - codec->control_data = msm_dig_cdc; + msm_dig_cdc->codec = codec; snd_soc_add_codec_controls(codec, compander_kcontrols, ARRAY_SIZE(compander_kcontrols)); for (i = 0; i < NUM_DECIMATORS; i++) { - tx_hpf_work[i].dig_cdc = dig_cdc; + tx_hpf_work[i].dig_cdc = msm_dig_cdc; tx_hpf_work[i].decimator = i + 1; INIT_DELAYED_WORK(&tx_hpf_work[i].dwork, tx_hpf_corner_freq_callback); } for (i = 0; i < MSM89XX_RX_MAX; i++) - dig_cdc->comp_enabled[i] = COMPANDER_NONE; + msm_dig_cdc->comp_enabled[i] = COMPANDER_NONE; /* Register event notifier */ msm_dig_cdc->nblock.notifier_call = msm_dig_cdc_event_notify; @@ -1198,15 +1196,23 @@ static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec) return ret; } } - /* Assign to DRAX_CDC for initial version */ - dig_cdc->version = DRAX_CDC; registered_digcodec = codec; + + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "ADC1_IN"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_IN"); + snd_soc_dapm_ignore_suspend(dapm, "ADC3_IN"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX1"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3"); + return 0; } static int msm_dig_cdc_soc_remove(struct snd_soc_codec *codec) { - struct msm_dig *msm_dig_cdc = dev_get_drvdata(codec->dev); + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); if (msm_dig_cdc->register_notifier) msm_dig_cdc->register_notifier(msm_dig_cdc->handle, @@ -1968,14 +1974,32 @@ static struct snd_soc_dai_driver msm_codec_dais[] = { static struct regmap *msm_digital_get_regmap(struct device *dev) { - struct msm_dig *msm_dig_cdc = dev_get_drvdata(dev); + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev); return msm_dig_cdc->regmap; } +static int msm_dig_cdc_suspend(struct snd_soc_codec *codec) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); + + msm_dig_cdc->dapm_bias_off = 1; + return 0; +} + +static int msm_dig_cdc_resume(struct snd_soc_codec *codec) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); + + msm_dig_cdc->dapm_bias_off = 0; + return 0; +} + static struct snd_soc_codec_driver soc_msm_dig_codec = { .probe = msm_dig_cdc_soc_probe, .remove = msm_dig_cdc_soc_remove, + .suspend = msm_dig_cdc_suspend, + .resume = msm_dig_cdc_resume, .controls = msm_dig_snd_controls, .num_controls = ARRAY_SIZE(msm_dig_snd_controls), .dapm_widgets = msm_dig_dapm_widgets, @@ -2005,10 +2029,10 @@ static int msm_dig_cdc_probe(struct platform_device *pdev) { int ret; u32 dig_cdc_addr; - struct msm_dig *msm_dig_cdc; + struct msm_dig_priv *msm_dig_cdc; struct dig_ctrl_platform_data *pdata; - msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig), + msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig_priv), GFP_KERNEL); if (!msm_dig_cdc) return -ENOMEM; @@ -2019,7 +2043,6 @@ static int msm_dig_cdc_probe(struct platform_device *pdev) ret = -EINVAL; goto rtn; } - dev_set_drvdata(&pdev->dev, msm_dig_cdc); ret = of_property_read_u32(pdev->dev.of_node, "reg", &dig_cdc_addr); @@ -2044,6 +2067,7 @@ static int msm_dig_cdc_probe(struct platform_device *pdev) msm_dig_cdc->handle = pdata->handle; msm_dig_cdc->register_notifier = pdata->register_notifier; + dev_set_drvdata(&pdev->dev, msm_dig_cdc); snd_soc_register_codec(&pdev->dev, &soc_msm_dig_codec, msm_codec_dais, ARRAY_SIZE(msm_codec_dais)); dev_dbg(&pdev->dev, "%s: registered DIG CODEC 0x%x\n", @@ -2058,6 +2082,44 @@ static int msm_dig_cdc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int msm_dig_suspend(struct device *dev) +{ + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(registered_digcodec->component.card); + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev); + + if (msm_dig_cdc->dapm_bias_off) { + pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n", + __func__, atomic_read(&pdata->int_mclk0_rsc_ref), + atomic_read(&pdata->int_mclk0_enabled)); + + if (atomic_read(&pdata->int_mclk0_enabled) == true) { + cancel_delayed_work_sync( + &pdata->disable_int_mclk0_work); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX, + &pdata->digital_cdc_core_clk); + atomic_set(&pdata->int_mclk0_enabled, false); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + } + } + + return 0; +} + +static int msm_dig_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops msm_dig_pm_ops = { + .suspend = msm_dig_suspend, + .resume = msm_dig_resume, +}; +#endif + static const struct of_device_id msm_dig_cdc_of_match[] = { {.compatible = "qcom,msm-digital-codec"}, {}, @@ -2068,6 +2130,9 @@ static struct platform_driver msm_digcodec_driver = { .owner = THIS_MODULE, .name = DRV_NAME, .of_match_table = msm_dig_cdc_of_match, +#ifdef CONFIG_PM + .pm = &msm_dig_pm_ops, +#endif }, .probe = msm_dig_cdc_probe, .remove = msm_dig_cdc_remove, diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h index 4cb82cd421b0..f0e7a9cf9228 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,13 +43,11 @@ struct msm_dig_priv { /* Entry for version info */ struct snd_info_entry *entry; struct snd_info_entry *version_entry; -}; - -struct msm_dig { char __iomem *dig_base; struct regmap *regmap; struct notifier_block nblock; u32 mute_mask; + int dapm_bias_off; void *handle; void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 4fa80c679b46..8e986a74ffff 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -56,8 +56,8 @@ #define FLAC_BLK_SIZE_LIMIT 65535 /* Timestamp mode payload offsets */ -#define TS_LSW_OFFSET 6 -#define TS_MSW_OFFSET 7 +#define CAPTURE_META_DATA_TS_OFFSET_LSW 6 +#define CAPTURE_META_DATA_TS_OFFSET_MSW 7 /* decoder parameter length */ #define DDP_DEC_MAX_NUM_PARAM 18 @@ -410,6 +410,7 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd) int buffer_length; uint64_t bytes_available; struct audio_aio_write_param param; + struct snd_codec_metadata *buff_addr; if (!atomic_read(&prtd->start)) { pr_err("%s: stream is not in started state\n", __func__); @@ -442,23 +443,34 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd) } if (buffer_length) { - param.paddr = prtd->buffer_paddr + prtd->byte_offset; + param.paddr = prtd->buffer_paddr + prtd->byte_offset; WARN(prtd->byte_offset % 32 != 0, "offset %x not multiple of 32", prtd->byte_offset); } else - param.paddr = prtd->buffer_paddr; - + param.paddr = prtd->buffer_paddr; param.len = buffer_length; - param.msw_ts = 0; - param.lsw_ts = 0; - param.flags = NO_TIMESTAMP; + if (prtd->ts_header_offset) { + buff_addr = (struct snd_codec_metadata *) + (prtd->buffer + prtd->byte_offset); + param.len = buff_addr->length; + param.msw_ts = (uint32_t) + ((buff_addr->timestamp & 0xFFFFFFFF00000000LL) >> 32); + param.lsw_ts = (uint32_t) (buff_addr->timestamp & 0xFFFFFFFFLL); + param.paddr += prtd->ts_header_offset; + param.flags = SET_TIMESTAMP; + param.metadata_len = prtd->ts_header_offset; + } else { + param.msw_ts = 0; + param.lsw_ts = 0; + param.flags = NO_TIMESTAMP; + param.metadata_len = 0; + } param.uid = buffer_length; - param.metadata_len = 0; param.last_buffer = prtd->last_buffer; pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n", - __func__, buffer_length, prtd->byte_offset); + __func__, param.len, prtd->byte_offset); if (q6asm_async_write(prtd->audio_client, ¶m) < 0) { pr_err("%s:q6asm_async_write failed\n", __func__); } else { @@ -577,9 +589,21 @@ static void compr_event_handler(uint32_t opcode, * written to ADSP in the last write, update offset and * total copied data accordingly. */ - - prtd->byte_offset += token; - prtd->copied_total += token; + if (prtd->ts_header_offset) { + /* Always assume that the data will be sent to DSP on + * frame boundary. + * i.e, one frame of userspace write will result in + * one kernel write to DSP. This is needed as + * timestamp will be sent per frame. + */ + prtd->byte_offset += + prtd->codec_param.buffer.fragment_size; + prtd->copied_total += + prtd->codec_param.buffer.fragment_size; + } else { + prtd->byte_offset += token; + prtd->copied_total += token; + } if (prtd->byte_offset >= prtd->buffer_size) prtd->byte_offset -= prtd->buffer_size; @@ -634,10 +658,10 @@ static void compr_event_handler(uint32_t opcode, *buff_addr = prtd->ts_header_offset; buff_addr++; /* Write the TS LSW */ - *buff_addr = payload[TS_LSW_OFFSET]; + *buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_LSW]; buff_addr++; /* Write the TS MSW */ - *buff_addr = payload[TS_MSW_OFFSET]; + *buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_MSW]; } /* Always assume read_size is same as fragment_size */ read_size = prtd->codec_param.buffer.fragment_size; @@ -1320,6 +1344,12 @@ static int msm_compr_configure_dsp_for_playback prtd->buffer_paddr = ac->port[dir].buf[0].phys; prtd->buffer_size = runtime->fragments * runtime->fragment_size; + /* Bit-0 of flags represent timestamp mode */ + if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) + prtd->ts_header_offset = sizeof(struct snd_codec_metadata); + else + prtd->ts_header_offset = 0; + ret = msm_compr_send_media_format_block(cstream, ac->stream_id, false); if (ret < 0) { pr_err("%s, failed to send media format block\n", __func__); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 9c247124a383..c0ca9b24f544 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -836,6 +836,182 @@ static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd) return ret; } +static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_RX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate = 48000; + + app_type = ucontrol->value.integer.value[0]; + acdb_dev_id = ucontrol->value.integer.value[1]; + if (ucontrol->value.integer.value[2] != 0) + sample_rate = ucontrol->value.integer.value[2]; + + ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type, + be_id, app_type, + acdb_dev_id, sample_rate); + if (ret < 0) + pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_put failed, err %d\n", + __func__, ret); + + pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); + return ret; +} + +static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_RX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type, + be_id, &app_type, + &acdb_dev_id, + &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_get failed, err: %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + + pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); +done: + return ret; +} + +static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_TX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate = 48000; + + app_type = ucontrol->value.integer.value[0]; + acdb_dev_id = ucontrol->value.integer.value[1]; + if (ucontrol->value.integer.value[2] != 0) + sample_rate = ucontrol->value.integer.value[2]; + + ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type, + be_id, app_type, + acdb_dev_id, sample_rate); + if (ret < 0) + pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_put failed, err: %d\n", + __func__, ret); + + pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); + + return ret; +} + +static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_TX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type, + be_id, &app_type, + &acdb_dev_id, + &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_get failed, err: %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); +done: + return ret; +} + +static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_pcm *pcm = rtd->pcm; + struct snd_pcm_usr *app_type_info; + struct snd_kcontrol *kctl; + const char *playback_mixer_ctl_name = "Audio Stream"; + const char *capture_mixer_ctl_name = "Audio Stream Capture"; + const char *deviceNo = "NN"; + const char *suffix = "App Type Cfg"; + int ctl_len, ret = 0; + + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ctl_len = strlen(playback_mixer_ctl_name) + 1 + + strlen(deviceNo) + 1 + + strlen(suffix) + 1; + pr_debug("%s: Playback app type cntrl add\n", __func__); + ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + NULL, 1, ctl_len, rtd->dai_link->be_id, + &app_type_info); + if (ret < 0) { + pr_err("%s: playback app type cntrl add failed, err: %d\n", + __func__, ret); + return ret; + } + kctl = app_type_info->kctl; + snprintf(kctl->id.name, ctl_len, "%s %d %s", + playback_mixer_ctl_name, rtd->pcm->device, suffix); + kctl->put = msm_pcm_playback_app_type_cfg_ctl_put; + kctl->get = msm_pcm_playback_app_type_cfg_ctl_get; + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ctl_len = strlen(capture_mixer_ctl_name) + 1 + + strlen(deviceNo) + 1 + strlen(suffix) + 1; + pr_debug("%s: Capture app type cntrl add\n", __func__); + ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE, + NULL, 1, ctl_len, rtd->dai_link->be_id, + &app_type_info); + if (ret < 0) { + pr_err("%s: capture app type cntrl add failed, err: %d\n", + __func__, ret); + return ret; + } + kctl = app_type_info->kctl; + snprintf(kctl->id.name, ctl_len, "%s %d %s", + capture_mixer_ctl_name, rtd->pcm->device, suffix); + kctl->put = msm_pcm_capture_app_type_cfg_ctl_put; + kctl->get = msm_pcm_capture_app_type_cfg_ctl_get; + } + + return 0; +} + + static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -862,6 +1038,13 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm topology control %d\n", __func__, ret); } + + ret = msm_pcm_add_app_type_controls(rtd); + if (ret) { + pr_err("%s: Could not add app type controls failed %d\n", + __func__, ret); + } + pcm->nonatomic = true; exit: return ret; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index c3db926be5d9..e8bf562acc4f 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -2758,14 +2758,9 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_widget_list *wlist = dapm_kcontrol_get_wlist(kcontrol); struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - int mux = ucontrol->value.enumerated.item[0]; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_update *update = NULL; - if (mux >= e->items) { - pr_err("%s: Invalid mux value %d\n", __func__, mux); - return -EINVAL; - } mutex_lock(&routing_lock); switch (ucontrol->value.integer.value[0]) { @@ -2868,7 +2863,8 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, pr_debug("%s: msm_route_ec_ref_rx = %d\n", __func__, msm_route_ec_ref_rx); mutex_unlock(&routing_lock); - snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e, update); + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + msm_route_ec_ref_rx, e, update); return 0; } diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index c3a4719542ef..f38108258306 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -7466,9 +7466,13 @@ int q6asm_async_write(struct audio_client *ac, else if (ac->io_mode == io_compressed || ac->io_mode == io_compressed_stream) lbuf_phys_addr = (param->paddr - param->metadata_len); - else - lbuf_phys_addr = param->paddr; - + else { + if (param->flags & SET_TIMESTAMP) + lbuf_phys_addr = param->paddr - + sizeof(struct snd_codec_metadata); + else + lbuf_phys_addr = param->paddr; + } dev_vdbg(ac->dev, "%s: token[0x%x], buf_addr[%pK], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_phys_addr: 0x[%pK]\n", __func__, write.hdr.token, ¶m->paddr, diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index 37b34b231b72..228e84ae8e1d 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -1255,7 +1255,6 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *ana_cdc = rtd->codec_dais[ANA_CDC]->codec; struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(ana_cdc); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux; struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card); struct snd_card *card; int ret = -ENOMEM; @@ -1299,17 +1298,6 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_sync(dapm); - /* - * Send speaker configuration only for WSA8810. - * Defalut configuration is for WSA8815. - */ - if (rtd_aux && rtd_aux->component) - if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) || - !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) { - msm_sdw_set_spkr_mode(rtd->codec, SPKR_MODE_1); - msm_sdw_set_spkr_gain_offset(rtd->codec, - RX_GAIN_OFFSET_M1P5_DB); - } msm_anlg_cdc_spk_ext_pa_cb(enable_spk_ext_pa, ana_cdc); msm_dig_cdc_hph_comp_cb(msm_config_hph_compander_gpio, dig_cdc); @@ -1344,6 +1332,7 @@ static int msm_sdw_audrx_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux; struct snd_card *card; snd_soc_add_codec_controls(codec, msm_sdw_controls, @@ -1357,6 +1346,18 @@ static int msm_sdw_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_SDW"); snd_soc_dapm_sync(dapm); + + /* + * Send speaker configuration only for WSA8810. + * Default configuration is for WSA8815. + */ + if (rtd_aux && rtd_aux->component) + if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) || + !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) { + msm_sdw_set_spkr_mode(rtd->codec, SPKR_MODE_1); + msm_sdw_set_spkr_gain_offset(rtd->codec, + RX_GAIN_OFFSET_M1P5_DB); + } card = rtd->card->snd_card; if (!codec_root) codec_root = snd_register_module_info(card->module, "codecs", |
