diff options
172 files changed, 5019 insertions, 8031 deletions
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/mhi/msm_mhi.txt b/Documentation/devicetree/bindings/mhi/msm_mhi.txt index da8b021efc73..5f950604d186 100644 --- a/Documentation/devicetree/bindings/mhi/msm_mhi.txt +++ b/Documentation/devicetree/bindings/mhi/msm_mhi.txt @@ -5,37 +5,148 @@ Modem Host Interface protocol. The bindings referred to below, enable the correct configuration of the interface and required sideband signals. -Required properties: - - compatible: should be "qcom,mhi" - - Refer to "Documentation/devicetree/bindings/esoc/esoc_client.txt" for - below properties: - - esoc-names - - esoc-0 - - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for - below optional properties: - - qcom,msm-bus,name - - qcom,msm-bus,num-cases - - qcom,msm-bus,num-paths - - qcom,msm-bus,vectors-KBps - - mhi-chan-cfg-#: mhi channel configuration parameters for platform - - mhi-event-cfg-#: mhi event ring configuration parameters for platform - - mhi-event-rings: number of event rings supported by platform - - mhi-dev-address-win-size: size of the MHI device addressing window +============== +Node Structure +============== -Example: +Main node properties: + +- compatible + Usage: required + Value type: <string> + Definition: "qcom,mhi" + +- qcom,pci-dev_id + Usage: required + Value type: <u32> + Definition: Device id reported by modem + +- qcom,pci-domain + Usage: required + Value type: <u32> + Definition: PCIE root complex device connected to + +- qcom,pci-bus + Usage: required + Value type: <u32> + Definition: PCIE bus device connected to + +- qcom,pci-slot + Usage: required + Value type: <u32> + Definition: PCIE slot (dev_id/function) device connected to + +- esoc-names + Usage: optional + Value type: <string> + Definition: esoc name for the device + +- esoc-0 + Usage: required if "esoc-names" is defined + Value type: phandle + Definition: A phandle pointing to the esoc node. + +- qcom,msm-bus,name + Usage: required if MHI is bus master + Value type: string + Definition: string representing the client name + +- qcom,msm-bus,num-cases + Usage: required if MHI is bus master + Value type: <u32> + Definition: Number of use cases MHI support. Must be set to 2. + +- qcom,msm-bus,num-paths + Usage: required if MHI is bus master + Value type: <u32> + Definition: Total number of master-slave pairs. Must be set to one. - mhi: qcom,mhi { - compatible = "qcom,mhi"; - esoc-names = "mdm"; - esoc-0 = <&mdm1>; - qcom,msm-bus,name = "mhi"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <100 512 0 0>, - <100 512 1200000000 1200000000>; - mhi-event-rings = <6>; - mhi-chan-cfg-102 = <0x66 0x80 0x5 0x62>; - mhi-event-cfg-0 = <0x80 0x0 0x0 0x11>; - mhi-dev-address-win-size= <0x10 0x00000000>; - }; +- qcom,msm-bus,vectors-KBps + Usage: required if MHI is bus master + Value type: Array of <u32> + Definition: Array of tuples which define the bus bandwidth requirements. + Each tuple is of length 4, values are master-id, slave-id, + arbitrated bandwidth in KBps, and instantaneous bandwidth in + KBps. + +- mhi-chan-cfg-# + Usage: required + Value type: Array of <u32> + Definition: mhi channel configuration parameters for platform + defined as below <A B C D>: + A = chan number + B = maximum descriptors + C = event ring associated with channel + D = flags defined by mhi_macros.h GET_CHAN_PROPS + +- mhi-event-rings + Usage: required + Value type: <u32> + Definition: Number of event rings device support + +- mhi-event-cfg-# + Usage: required + Value type: Array of <u32> + Definition: mhi event ring configuration parameters for platform + defined as below <A B C D E F>: + A = maximum event descriptors + B = MSI associated with event + C = interrupt moderation (see MHI specification) + D = Associated channel + E = priority of the event ring. 0 being the highest. + F = flags defined by mhi_macros.h GET_EV_PROPS + +- qcom,mhi-address-window + Usage: required + Value type: Array of <u64> + Definition: start DDR address and ending DDR address device can access. + +- qcom,mhi-manage-boot + Usage: optional + Value type: bool + Definition: Determine whether MHI host manages firmware download to device. + +- qcom,mhi-fw-image + Usage: required if MHI host managing firmware download process + Value type: string + Definition: firmware image name + +- qcom,mhi-max-sbl + Usage: required if MHI host managing firmware download process + Value type: <u32> + Definition: Maximum size in bytes SBL image device support. + +- qcom,mhi-sg-size + Usage: required if MHI host managing firmware download process + Value type: <u32> + Definition: Segment size in bytes for each segment in bytes. + +- qcom,mhi-bb-required + Usage: optional + Value type: bool + Definition: Determine whether MHI device require bounce buffer + during active transfer. If true, during channel open host + will pre-allocate transfer buffers. + +======== +Example: +======== +mhi: qcom,mhi { + compatible = "qcom,mhi"; + qcom,pci-dev_id = <0x0301>; + qcom,pci-domain = <2>; + qcom,pci-bus = <4>; + qcom,pci-slot = <0>; + qcom,mhi-address-window = <0x0 0x80000000 0x0 0xbfffffff>; + esoc-names = "mdm"; + esoc-0 = <&mdm1>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 1200000000 1200000000>; + mhi-event-rings = <1>; + mhi-chan-cfg-102 = <0x66 0x80 0x5 0x62>; + mhi-event-cfg-0 = <0x80 0x0 0x0 0x0 0 1 0x11>; +}; diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt index 626ca2124366..acc850773210 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt @@ -9,8 +9,26 @@ receive(RX)/transmit(TX) control. Required properties: - compatible: "qcom,wcn3990-wifi"; + - reg: Memory regions defined as starting address and size + - reg-names: Names of the memory regions defined in reg entry + - interrupts: Copy engine interrupt table Example: - qcom,msm_ath10k@18000000 { + msm_ath10k_wlan: qcom,msm_ath10k_wlan@18800000 { compatible = "qcom,wcn3990-wifi"; + reg = <0x18800000 0x800000>; + reg-names = "membase"; + interrupts = + <0 130 0 /* CE0 */ >, + <0 131 0 /* CE1 */ >, + <0 132 0 /* CE2 */ >, + <0 133 0 /* CE3 */ >, + <0 134 0 /* CE4 */ >, + <0 135 0 /* CE5 */ >, + <0 136 0 /* CE6 */ >, + <0 137 0 /* CE7 */ >, + <0 138 0 /* CE8 */ >, + <0 139 0 /* CE9 */ >, + <0 140 0 /* CE10 */ >, + <0 141 0 /* CE11 */ >; }; diff --git a/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt b/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt index 5ec2fb51833e..d377a28e6617 100644 --- a/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt +++ b/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt @@ -1,25 +1,53 @@ MSM MHI RMNET interface device -MHI RMNET provides a network interface over PCIe -to transfer IP packets between modem and apps. - -Required properties: -- compatible : "qcom,mhi-rmnet" -- At least one of MHI channel - - qcom,mhi-rx-channel : MHI channel number for incoming data - - qcom,mhi-tx-channel : MHI channel number for outgoing data -- Default MRU for interface - - qcom,mhi-mru -- Alias id to identify interface instance +MHI RMNET provides a network interface over PCIe to transfer IP packets +between modem and apps. +============== +Node Structure +============== + +Main node properties: + +- compatible + Usage: required + Value type: <string> + Definition: "qcom,mhi-rmnet" + +- qcom,mhi-rx-channel + Usage: optional if mhi-tx-channel is defined. + Value type: <u32> + Definition: MHI channel number for incoming data + +- qcom,mhi-tx-channel + Usage: optional if mhi-rx-channel is defined. + Value type: <u32> + Definition: MHI channel number for outgoing data + +- qcom,mhi-mru + Usage: required + Value type: <u32> + Definition: Default payload size for receive path. + +- qcom,mhi-max-mru + Usage: optional + Value type: <u32> + Definition: Maximum payload interface support on receive path. If + not defined MHI_MAX_MRU is used. + +- qcom,mhi-max-mtu + Usage: optional + Value type: <u32> + Definition: Maximum payload interface support on transmit path. If + not defined MHI_MAX_MTU is used. + +======== Example: - aliases { - mhi_rmnet0 = &mhi_rmnet_0; - }; - mhi_rmnet_0: qcom,mhi-rmnet@0 { - compatible = "qcom,mhi-rmnet"; - qcom,mhi-rx-channel = <101>; - qcom,mhi-tx-channel = <100>; - qcom,mhi-mru = <8000>; - status = "okay"; - }; +======== +mhi_rmnet_0: qcom,mhi-rmnet@0 { + compatible = "qcom,mhi-rmnet"; + qcom,mhi-rx-channel = <101>; + qcom,mhi-tx-channel = <100>; + qcom,mhi-mru = <8000>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi index 6c17bca64a86..62115cf6f98a 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.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 @@ -35,6 +35,18 @@ qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; qcom,mdss-dsi-on-command = [ + 29 01 00 00 01 00 02 00 00 + 29 01 00 00 01 00 04 FF 25 03 01 + 29 01 00 00 01 00 02 00 80 + 29 01 00 00 01 00 03 FF 25 03 + 29 01 00 00 01 00 02 00 80 + 29 01 00 00 01 00 10 + A7 27 00 FF 01 15 11 02 + 98 0F 07 70 69 14 00 00 + 29 01 00 00 01 00 02 00 C0 + 29 01 00 00 01 00 10 + A7 13 00 FF 01 FF 10 02 + 08 0F 07 74 69 14 00 00 15 01 00 00 00 00 02 35 00 05 01 00 00 78 00 02 11 00 05 01 00 00 32 00 02 29 00]; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi index 39d3db3067e6..615118f5413d 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi @@ -59,7 +59,7 @@ 15 01 00 00 00 00 02 5d 81 15 01 00 00 00 00 02 5e 00 15 01 00 00 00 00 02 5f 01 - 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 72 11 15 01 00 00 00 00 02 68 03 /* CMD2_P4 */ 15 01 00 00 00 00 02 ff 24 @@ -214,6 +214,7 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-bl-max-level = <4095>; qcom,adjust-timer-wakeup-ms = <1>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi index 353b3b2b09bd..0a9ef5ee14b6 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -54,7 +54,7 @@ 15 01 00 00 00 00 02 5d 81 15 01 00 00 00 00 02 5e 00 15 01 00 00 00 00 02 5f 01 - 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 72 11 15 01 00 00 00 00 02 68 03 /* CMD2_P4 */ 15 01 00 00 00 00 02 ff 24 @@ -208,6 +208,7 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; qcom,mdss-pan-physical-width-dimension = <74>; qcom,mdss-pan-physical-height-dimension = <131>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi index 6ff016676de7..69f24bbfc3c0 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -47,6 +47,7 @@ 04 00]; qcom,adjust-timer-wakeup-ms = <1>; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-bl-max-level = <4095>; @@ -83,7 +84,7 @@ 15 01 00 00 00 00 02 5D 81 15 01 00 00 00 00 02 5E 00 15 01 00 00 00 00 02 5F 01 - 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 72 11 15 01 00 00 00 00 02 68 03 /* CMD2_P4 */ 15 01 00 00 00 00 02 ff 24 diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi index d179acd043ed..ab6266e9e6b8 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -54,7 +54,7 @@ 15 01 00 00 00 00 02 5D 81 15 01 00 00 00 00 02 5E 00 15 01 00 00 00 00 02 5F 01 - 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 72 11 15 01 00 00 00 00 02 68 03 /* CMD2_P4 */ 15 01 00 00 00 00 02 FF 24 diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi index 49afd34c50e7..60f0811ce987 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi @@ -75,7 +75,7 @@ 15 01 00 00 00 00 02 15 12 15 01 00 00 00 00 02 16 12 15 01 00 00 00 00 02 30 01 - 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 72 11 15 01 00 00 00 00 02 58 82 15 01 00 00 00 00 02 59 00 15 01 00 00 00 00 02 5a 02 diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi index 068459bf2504..7e83d25e9e43 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi @@ -71,7 +71,7 @@ 15 01 00 00 00 00 02 15 12 15 01 00 00 00 00 02 16 12 15 01 00 00 00 00 02 30 01 - 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 72 11 15 01 00 00 00 00 02 58 82 15 01 00 00 00 00 02 59 00 15 01 00 00 00 00 02 5a 02 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 463d352f8791..38f4802b1624 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -315,7 +315,8 @@ dpdm-supply = <&qusb_phy0>; qcom,thermal-mitigation - = <3000000 1500000 1000000 500000>; + = <3000000 2500000 2000000 1500000 + 1000000 500000>; qcom,chgr@1000 { reg = <0x1000 0x100>; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi index e7a61f42dff1..707eca4e9ddd 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi @@ -29,6 +29,16 @@ qcom,switch-source = <&pmi8998_switch1>; status = "ok"; }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "rear_vana_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + enable-active-high; + gpio = <&tlmm 27 0>; + vin-supply = <&pmi8998_bob>; + }; }; &cci { @@ -37,14 +47,11 @@ reg = <0x0>; compatible = "qcom,actuator"; qcom,cci-master = <0>; - gpios = <&tlmm 27 0>; - qcom,gpio-vaf = <0>; - qcom,gpio-req-tbl-num = <0>; - qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "CAM_VAF"; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_actuator_vaf_active>; - pinctrl-1 = <&cam_actuator_vaf_suspend>; + cam_vaf-supply = <&actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; }; actuator1: qcom,actuator@1 { @@ -52,14 +59,11 @@ reg = <0x1>; compatible = "qcom,actuator"; qcom,cci-master = <1>; - gpios = <&tlmm 27 0>; - qcom,gpio-vaf = <0>; - qcom,gpio-req-tbl-num = <0>; - qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "CAM_VAF"; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_actuator_vaf_active>; - pinctrl-1 = <&cam_actuator_vaf_suspend>; + cam_vaf-supply = <&actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; }; ois0: qcom,ois@0 { @@ -78,24 +82,23 @@ status = "disabled"; }; - tof0:qcom,tof@0{ + tof0: qcom,tof@0 { cell-index = <0>; reg = <0x29>; compatible = "st,stmvl53l0"; qcom,cci-master = <0>; cam_cci-supply = <&pm8998_lvs1>; - cam_laser-supply = <&pmi8998_bob>; + cam_laser-supply = <&actuator_regulator>; qcom,cam-vreg-name = "cam_cci", "cam_laser"; qcom,cam-vreg-min-voltage = <0 0>; - qcom,cam-vreg-max-voltage = <0 3600000>; + qcom,cam-vreg-max-voltage = <0 2800000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_tof_active>; pinctrl-1 = <&cam_tof_suspend>; - gpios = <&tlmm 27 0>, - <&tlmm 126 0>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <0 0>; - qcom,gpio-req-tbl-label = "CAM_TOF", "CAM_CE"; + gpios = <&tlmm 126 0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_CE"; }; eeprom0: qcom,eeprom@0 { diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi index c5384eaf17a1..17dcfb560b73 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -29,6 +29,16 @@ qcom,switch-source = <&pmi8998_switch1>; status = "ok"; }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "rear_vana_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + enable-active-high; + gpio = <&tlmm 27 0>; + vin-supply = <&pmi8998_bob>; + }; }; &cci { @@ -37,14 +47,11 @@ reg = <0x0>; compatible = "qcom,actuator"; qcom,cci-master = <0>; - gpios = <&tlmm 27 0>; - qcom,gpio-vaf = <0>; - qcom,gpio-req-tbl-num = <0>; - qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "CAM_VAF"; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_actuator_vaf_active>; - pinctrl-1 = <&cam_actuator_vaf_suspend>; + cam_vaf-supply = <&actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; }; actuator1: qcom,actuator@1 { @@ -52,33 +59,32 @@ reg = <0x1>; compatible = "qcom,actuator"; qcom,cci-master = <1>; - gpios = <&tlmm 27 0>; - qcom,gpio-vaf = <0>; - qcom,gpio-req-tbl-num = <0>; - qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "CAM_VAF"; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_actuator_vaf_active>; - pinctrl-1 = <&cam_actuator_vaf_suspend>; + cam_vaf-supply = <&actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; }; - tof0:qcom,tof@0{ + + tof0: qcom,tof@0 { cell-index = <0>; reg = <0x29>; compatible = "st,stmvl53l0"; qcom,cci-master = <0>; cam_cci-supply = <&pm8998_lvs1>; - cam_laser-supply = <&pmi8998_bob>; + cam_laser-supply = <&actuator_regulator>; qcom,cam-vreg-name = "cam_cci", "cam_laser"; qcom,cam-vreg-min-voltage = <0 0>; - qcom,cam-vreg-max-voltage = <0 3600000>; + qcom,cam-vreg-max-voltage = <0 2800000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_tof_active>; pinctrl-1 = <&cam_tof_suspend>; - gpios = <&tlmm 27 0>, <&tlmm 126 0>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <0 0>; - qcom,gpio-req-tbl-label = "CAM_TOF", "CAM_CE"; + gpios = <&tlmm 126 0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_CE"; }; + ois0: qcom,ois@0 { cell-index = <0>; reg = <0x0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk-hdk.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk-hdk.dtsi index 4b3748e5a40a..0c6985a46b81 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk-hdk.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk-hdk.dtsi @@ -43,4 +43,19 @@ drive-strength = <8>; /* 2 MA */ }; }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <8>; /* 2 MA */ + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi index 52d0fdb4a523..41e783e6bf1f 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -144,6 +144,10 @@ /delete-node/qcom,ois@0; }; +&soc { + /delete-node/gpio-regulator@0; +}; + &cci { actuator0: qcom,actuator@0 { cell-index = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi index 52d0fdb4a523..722c18a26388 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -132,6 +132,10 @@ }; }; +&soc { + /delete-node/gpio-regulator@0; +}; + &cci { /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi index 87b1146bd361..8b68ece2239f 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -170,6 +170,10 @@ }; }; +&soc { + /delete-node/gpio-regulator@0; +}; + &cci { /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index 4914363b414a..d2e18db982ef 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -956,12 +956,12 @@ cam_tof_active: cam_tof_active { mux { - pins = "gpio27", "gpio126"; + pins = "gpio26", "gpio126"; function = "gpio"; }; config { - pins = "gpio27", "gpio126"; + pins = "gpio26", "gpio126"; bias-disable; drive-strength = <2>; /* 2 MA */ }; @@ -969,12 +969,12 @@ cam_tof_suspend: cam_tof_suspend { mux { - pins = "gpio27", "gpio126"; + pins = "gpio26", "gpio126"; function = "gpio"; }; config { - pins = "gpio27", "gpio126"; + pins = "gpio26", "gpio126"; bias-pull-down; /* PULL DOWN */ drive-strength = <2>; /* 2 MA */ }; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi index 7ed28e4c8813..3c76519acdcf 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi @@ -51,6 +51,30 @@ qcom,mdss-pref-prim-intf = "dsi"; }; +&mdss_hdmi_tx { + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", + "hdmi_active", "hdmi_sleep"; + pinctrl-0 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; + pinctrl-1 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_active &mdss_hdmi_cec_suspend>; + pinctrl-2 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_cec_active &mdss_hdmi_ddc_suspend>; + pinctrl-3 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_active &mdss_hdmi_cec_active>; + pinctrl-4 = <&mdss_hdmi_5v_suspend &mdss_hdmi_hpd_suspend + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; +}; + +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 77 0>; + qcom,aux-sel-gpio = <&tlmm 78 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; +}; + &mdss_dsi { hw-config = "split_dsi"; }; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 66ca39ee6ebc..02b7a44ee0d2 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -3068,6 +3068,8 @@ msm_ath10k_wlan: qcom,msm_ath10k_wlan { status = "disabled"; compatible = "qcom,wcn3990-wifi"; + reg = <0x18800000 0x800000>; + reg-names = "membase"; interrupts = <0 413 0 /* CE0 */ >, <0 414 0 /* CE1 */ >, diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi index 72f606168691..362916f3b712 100644 --- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi @@ -758,7 +758,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 1920000 2880000>; + <62 512 1200000 1200000>; status = "ok"; }; @@ -800,7 +800,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 1920000 2880000>; + <62 512 1200000 1200000>; qcom,max-ds-factor = <128>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi index cf76144ba3a8..43a01094662a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi @@ -71,6 +71,8 @@ 24 1e 08 09 05 03 04 a0 24 1e 08 09 05 03 04 a0 24 1a 08 09 05 03 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "bta_check"; }; &dsi_truly_1080_vid { 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.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index b3175fed4dcc..623ca54de94b 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -1208,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; diff --git a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi index 0b216a16c7e8..c1cb6441cd43 100644 --- a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi @@ -271,7 +271,7 @@ gpio@c200 { status = "ok"; qcom,mode = <1>; - qcom,pull = <5>; + qcom,pull = <4>; qcom,vin-sel = <0>; qcom,src-sel = <2>; qcom,master-en = <1>; diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi index 14b009656890..1f886f7f368f 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi @@ -761,7 +761,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 1920000 2880000>; + <62 512 1200000 1200000>; status = "ok"; }; @@ -803,7 +803,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 1920000 2880000>; + <62 512 1200000 1200000>; qcom,max-ds-factor = <128>; status = "ok"; }; 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-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index 0fc24dc6e72b..e93190ffcf44 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>; @@ -145,6 +146,8 @@ 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,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "bta_check"; }; &dsi_dual_nt36850_truly_cmd { @@ -191,6 +194,8 @@ 20 1d 05 07 03 03 04 a0 20 12 05 06 03 13 04 a0]; qcom,config-select = <&dsi_nt35597_truly_dsc_cmd_config2>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "bta_check"; }; &dsi_dual_nt35597_video { @@ -260,3 +265,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-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi index 941fe808188c..ed3b3d89d392 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi @@ -236,7 +236,7 @@ }; &mem_client_3_size { - qcom,peripheral-size = <0x500000>; + qcom,peripheral-size = <0xf00000>; }; &pm660_fg { 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-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-qrd.dts index 9ad1bed8bbfa..4d120e83cb9b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dts @@ -64,3 +64,24 @@ &pm660l_wled { qcom,led-strings-list = [00 01]; }; + +&soc { + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm660l_l3>; + vcc_dig-supply = <&pm660_l13>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3008000>; + qcom,afe-vtg-max = <3008000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1808000>; + qcom,dig-vtg-max = <1808000>; + qcom,fb-resume-delay-us = <10000>; + qcom,afe-force-power-on; + qcom,afe-power-on-delay-us = <1000>; + qcom,afe-power-off-delay-us = <6>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index 77e8505408d0..0e869f0e1352 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -211,24 +211,6 @@ debounce-interval = <15>; }; }; - - hbtp { - compatible = "qcom,hbtp-input"; - pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; - pinctrl-0 = <&ts_rst_active>; - pinctrl-1 = <&ts_rst_suspend>; - vcc_ana-supply = <&pm660l_l3>; - vcc_dig-supply = <&pm660_l13>; - qcom,afe-load = <20000>; - qcom,afe-vtg-min = <3008000>; - qcom,afe-vtg-max = <3008000>; - qcom,dig-load = <40000>; - qcom,dig-vtg-min = <1808000>; - qcom,dig-vtg-max = <1808000>; - qcom,fb-resume-delay-us = <10000>; - qcom,afe-power-on-delay-us = <1000>; - qcom,afe-power-off-delay-us = <6>; - }; }; / { diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 8f875e2f5ce2..e79396e4e3f5 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -370,7 +370,7 @@ alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0x2000000>; + size = <0 0x2c00000>; linux,cma-default; }; @@ -613,6 +613,7 @@ compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x0>; qcom,client-id = <1>; + qcom,allocate-boot-time; label = "modem"; }; }; @@ -1435,7 +1436,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; diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 6fee388eb386..e2ee3ba909eb 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -21,7 +21,7 @@ ifneq ($(DTB_NAMES),) DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST)) else -DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb) +DTB_OBJS := $(shell find -L $(obj)/dts/ -name \*.dtb) endif $(obj)/Image: vmlinux FORCE diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 811779ba58b2..ec1e55035c81 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -294,6 +294,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_STMVL53L0=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index d3b7ec7c4f2b..6378a1cdad7f 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -298,6 +298,7 @@ CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y +CONFIG_INPUT_STMVL53L0=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set diff --git a/drivers/base/core.c b/drivers/base/core.c index bbe8e2efc677..3fa9096b27c2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1116,7 +1116,13 @@ int device_add(struct device *dev) error = dpm_sysfs_add(dev); if (error) goto DPMError; - device_pm_add(dev); + if ((dev->pm_domain) || (dev->type && dev->type->pm) + || (dev->class && (dev->class->pm || dev->class->resume)) + || (dev->bus && (dev->bus->pm || dev->bus->resume)) || + (dev->driver && dev->driver->pm)) { + device_pm_add(dev); + } + if (MAJOR(dev->devt)) { error = device_create_file(dev, &dev_attr_dev); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6c5bc3fadfcf..a88590bb0b10 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -162,6 +162,12 @@ void device_pm_move_before(struct device *deva, struct device *devb) pr_debug("PM: Moving %s:%s before %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); + if (!((devb->pm_domain) || (devb->type && devb->type->pm) + || (devb->class && (devb->class->pm || devb->class->resume)) + || (devb->bus && (devb->bus->pm || devb->bus->resume)) || + (devb->driver && devb->driver->pm))) { + device_pm_add(devb); + } /* Delete deva from dpm_list and reinsert before devb. */ list_move_tail(&deva->power.entry, &devb->power.entry); } @@ -176,6 +182,12 @@ void device_pm_move_after(struct device *deva, struct device *devb) pr_debug("PM: Moving %s:%s after %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); + if (!((devb->pm_domain) || (devb->type && devb->type->pm) + || (devb->class && (devb->class->pm || devb->class->resume)) + || (devb->bus && (devb->bus->pm || devb->bus->resume)) || + (devb->driver && devb->driver->pm))) { + device_pm_add(devb); + } /* Delete deva from dpm_list and reinsert after devb. */ list_move(&deva->power.entry, &devb->power.entry); } diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 061177173ab8..1ed366fd3d71 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -92,6 +92,9 @@ static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, return; } + if (dai->id == BTFM_FM_SLIM_TX) + goto out; + /* Search for dai->id matched port handler */ for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && @@ -105,6 +108,7 @@ static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, } btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan); +out: btfm_slim_hw_deinit(btfmslim); } @@ -167,6 +171,61 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, return ret; } +static int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = -EINVAL, i; + struct btfmslim *btfmslim = dai->dev->platform_data; + struct btfmslim_ch *ch; + uint8_t rxport, grp = false, nchan = 1; + + BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, + dai->id, dai->rate); + + switch (dai->id) { + case BTFM_FM_SLIM_TX: + grp = true; nchan = 2; + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + rxport = 1; + break; + case BTFM_SLIM_NUM_CODEC_DAIS: + default: + BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); + goto out; + } + + if (dai->id != BTFM_FM_SLIM_TX) { + ret = 0; + goto out; + } + + /* Search for dai->id matched port handler */ + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != dai->id); ch++, i++) + ; + + if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || + (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { + BTFMSLIM_ERR("ch is invalid!!"); + goto out; + } + + btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan); + +out: + return ret; +} + /* This function will be called once during boot up */ static int btfm_slim_dai_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, @@ -306,6 +365,7 @@ static struct snd_soc_dai_ops btfmslim_dai_ops = { .shutdown = btfm_slim_dai_shutdown, .hw_params = btfm_slim_dai_hw_params, .prepare = btfm_slim_dai_prepare, + .hw_free = btfm_slim_dai_hw_free, .set_channel_map = btfm_slim_dai_set_channel_map, .get_channel_map = btfm_slim_dai_get_channel_map, }; diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index 72e28da4bd3b..d61454ac6e84 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -39,6 +39,7 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim) { int ret = 0; uint8_t reg_val; + uint16_t reg; BTFMSLIM_DBG(""); @@ -46,20 +47,20 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim) return -EINVAL; /* Get SB_SLAVE_HW_REV_MSB value*/ - ret = btfm_slim_read(btfmslim, CHRK_SB_SLAVE_HW_REV_MSB, 1, - ®_val, IFD); + reg = CHRK_SB_SLAVE_HW_REV_MSB; + ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to read (%d)", ret); + BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg); goto error; } BTFMSLIM_DBG("Major Rev: 0x%x, Minor Rev: 0x%x", (reg_val & 0xF0) >> 4, (reg_val & 0x0F)); /* Get SB_SLAVE_HW_REV_LSB value*/ - ret = btfm_slim_read(btfmslim, CHRK_SB_SLAVE_HW_REV_LSB, 1, - ®_val, IFD); + reg = CHRK_SB_SLAVE_HW_REV_LSB; + ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to read (%d)", ret); + BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg); goto error; } BTFMSLIM_DBG("Step Rev: 0x%x", reg_val); @@ -80,41 +81,41 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, if (rxport) { /* Port enable */ reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10); - } else { /* txport */ - /* Multiple Channel Setting - only FM Tx will be multiple - * channel - */ - if (enable && (port_num == CHRK_SB_PGD_PORT_TX1_FM || - port_num == CHRK_SB_PGD_PORT_TX2_FM)) { - - reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) | - (0x1 << CHRK_SB_PGD_PORT_TX2_FM); - reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); - ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); - if (ret) { - BTFMSLIM_ERR("failed to write (%d)", ret); - goto error; - } - } + goto enable_disable_rxport; + } + /* txport */ + if (!enable) + goto enable_disable_txport; - /* Enable Tx port hw auto recovery for underrun or - * overrun error - */ - reg_val = (enable) ? (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY | - CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY) : 0x0; + /* Multiple Channel Setting - only for FM Tx */ + if (port_num == CHRK_SB_PGD_PORT_TX1_FM || + port_num == CHRK_SB_PGD_PORT_TX2_FM) { - ret = btfm_slim_write(btfmslim, - CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num), 1, - ®_val, IFD); + reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) | + (0x1 << CHRK_SB_PGD_PORT_TX2_FM); + reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to write (%d)", ret); + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); goto error; } + } - /* Port enable */ - reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num); + /* Enable Tx port hw auto recovery for underrun or overrun error */ + reg_val = (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY | + CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY); + reg = CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); + goto error; } +enable_disable_txport: + /* Port enable */ + reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num); + +enable_disable_rxport: if (enable) /* Set water mark to 1 and enable the port */ reg_val = CHRK_SB_PGD_PORT_ENABLE | CHRK_SB_PGD_PORT_WM_LB; @@ -123,7 +124,7 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) - BTFMSLIM_ERR("failed to write (%d)", ret); + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); error: return ret; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 7820f5625266..e0106a7e31fa 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1435,6 +1435,12 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, int err = 0; struct timespec invoket; + VERIFY(err, fl->sctx); + if (err) + goto bail; + VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS); + if (err) + goto bail; if (fl->profile) getnstimeofday(&invoket); if (!kernel) { diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index df26e2522baf..8b0e1f32bdc5 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -665,8 +665,7 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch) atomic_set(&(ch->opened), 0); ctxt = SET_CH_CTXT(id, ch->type); ch->client_info.mhi_client_cb = mhi_notifier; - return mhi_register_channel(&ch->hdl, ch->chan, 0, &ch->client_info, - (void *)(uintptr_t)ctxt); + return mhi_register_channel(&ch->hdl, NULL); } int diag_mhi_init() diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index e8e48015d3af..4a9e034f939f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2874,8 +2874,6 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) goto err_out; } - clk_debug_measure_add(core->hw, core->dentry); - ret = 0; goto out; @@ -3005,10 +3003,8 @@ static int __init clk_debug_init(void) return -ENOMEM; mutex_lock(&clk_debug_lock); - hlist_for_each_entry(core, &clk_debug_list, debug_node) { - clk_register_debug(core->hw, core->dentry); + hlist_for_each_entry(core, &clk_debug_list, debug_node) clk_debug_create_one(core, rootdir); - } inited = 1; mutex_unlock(&clk_debug_lock); diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 25bf4bc85f5c..87af7af7aac2 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -23,8 +23,6 @@ void __clk_free_clk(struct clk *clk); /* Debugfs API to print the enabled clocks */ void clock_debug_print_enabled(void); -int clk_register_debug(struct clk_hw *hw, struct dentry *dentry); -void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry); void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f); #else diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 317091a8003d..4c18181c047c 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -12,7 +12,7 @@ clk-qcom-y += clk-regmap-mux.o clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o clk-qcom-y += clk-hfpll.o clk-qcom-y += reset.o clk-voter.o -clk-qcom-y += clk-dummy.o +clk-qcom-y += clk-dummy.o clk-debug.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o gdsc-regulator.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index ca6010db8d78..3e9cd9909b86 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -21,6 +21,7 @@ #include <linux/regmap.h> #include "clk-branch.h" +#include "clk-debug.h" #include "clk-regmap.h" #include "common.h" @@ -250,6 +251,7 @@ const struct clk_ops clk_branch2_ops = { .is_enabled = clk_is_enabled_regmap, .set_flags = clk_branch_set_flags, .list_registers = clk_branch2_list_registers, + .debug_init = clk_debug_measure_add, }; EXPORT_SYMBOL_GPL(clk_branch2_ops); @@ -384,6 +386,7 @@ const struct clk_ops clk_gate2_ops = { .is_enabled = clk_is_enabled_regmap, .list_registers = clk_gate2_list_registers, .set_flags = clk_gate2_set_flags, + .debug_init = clk_debug_measure_add, }; EXPORT_SYMBOL_GPL(clk_gate2_ops); diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 6b00bee337a1..f82ddc3b008b 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -39,6 +39,7 @@ #include "common.h" #include "clk-regmap.h" #include "clk-rcg.h" +#include "clk-debug.h" enum { LMH_LITE_CLK_SRC, @@ -757,6 +758,7 @@ static struct clk_ops clk_ops_cpu_osm = { .round_rate = clk_osm_round_rate, .list_rate = clk_osm_list_rate, .recalc_rate = clk_osm_recalc_rate, + .debug_init = clk_debug_measure_add, }; static const struct parent_map gcc_parent_map_1[] = { diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c new file mode 100644 index 000000000000..50d0d01188ed --- /dev/null +++ b/drivers/clk/qcom/clk-debug.c @@ -0,0 +1,277 @@ +/* + * 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/platform_device.h> +#include <linux/clk-provider.h> +#include <linux/of.h> + +#include "clk-regmap.h" +#include "clk-debug.h" +#include "common.h" + +static struct clk_hw *measure; + +static DEFINE_SPINLOCK(clk_reg_lock); +static DEFINE_MUTEX(clk_debug_lock); + +#define TCXO_DIV_4_HZ 4800000 +#define SAMPLE_TICKS_1_MS 0x1000 +#define SAMPLE_TICKS_14_MS 0x10000 + +#define XO_DIV4_CNT_DONE BIT(25) +#define CNT_EN BIT(20) +#define MEASURE_CNT BM(24, 0) + +/* Sample clock for 'ticks' reference clock ticks. */ +static u32 run_measurement(unsigned ticks, struct regmap *regmap, + u32 ctl_reg, u32 status_reg) +{ + u32 regval; + + /* Stop counters and set the XO4 counter start value. */ + regmap_write(regmap, ctl_reg, ticks); + + regmap_read(regmap, status_reg, ®val); + + /* Wait for timer to become ready. */ + while ((regval & XO_DIV4_CNT_DONE) != 0) { + cpu_relax(); + regmap_read(regmap, status_reg, ®val); + } + + /* Run measurement and wait for completion. */ + regmap_write(regmap, ctl_reg, (CNT_EN|ticks)); + + regmap_read(regmap, status_reg, ®val); + + while ((regval & XO_DIV4_CNT_DONE) == 0) { + cpu_relax(); + regmap_read(regmap, status_reg, ®val); + } + + /* Return measured ticks. */ + regmap_read(regmap, status_reg, ®val); + regval &= MEASURE_CNT; + + return regval; +} + +/* + * Perform a hardware rate measurement for a given clock. + * FOR DEBUG USE ONLY: Measurements take ~15 ms! + */ +static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw) +{ + unsigned long flags, ret = 0; + u32 gcc_xo4_reg, multiplier; + u64 raw_count_short, raw_count_full; + struct clk_debug_mux *meas = to_clk_measure(hw); + struct measure_clk_data *data = meas->priv; + + clk_prepare_enable(data->cxo); + + spin_lock_irqsave(&clk_reg_lock, flags); + + multiplier = meas->multiplier + 1; + + /* Enable CXO/4 and RINGOSC branch. */ + regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg); + gcc_xo4_reg |= BIT(0); + regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg); + + /* + * The ring oscillator counter will not reset if the measured clock + * is not running. To detect this, run a short measurement before + * the full measurement. If the raw results of the two are the same + * then the clock must be off. + */ + + /* Run a short measurement. (~1 ms) */ + raw_count_short = run_measurement(SAMPLE_TICKS_1_MS, meas->regmap[GCC], + data->ctl_reg, data->status_reg); + + /* Run a full measurement. (~14 ms) */ + raw_count_full = run_measurement(SAMPLE_TICKS_14_MS, meas->regmap[GCC], + data->ctl_reg, data->status_reg); + + gcc_xo4_reg &= ~BIT(0); + regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg); + + /* Return 0 if the clock is off. */ + if (raw_count_full == raw_count_short) + ret = 0; + else { + /* Compute rate in Hz. */ + raw_count_full = ((raw_count_full * 10) + 15) * TCXO_DIV_4_HZ; + do_div(raw_count_full, ((SAMPLE_TICKS_14_MS * 10) + 35)); + ret = (raw_count_full * multiplier); + } + + spin_unlock_irqrestore(&clk_reg_lock, flags); + + clk_disable_unprepare(data->cxo); + + return ret; +} + +static u8 clk_debug_mux_get_parent(struct clk_hw *hw) +{ + struct clk_debug_mux *meas = to_clk_measure(hw); + int i, num_parents = clk_hw_get_num_parents(hw); + + for (i = 0; i < num_parents; i++) { + if (!strcmp(meas->parent[i].parents, + hw->init->parent_names[i])) { + pr_debug("%s: Clock name %s index %d\n", __func__, + hw->init->name, i); + return i; + } + } + + return 0; +} + +static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_debug_mux *meas = to_clk_measure(hw); + unsigned long lsb = 0; + u32 regval = 0; + int dbg_cc = 0; + + dbg_cc = meas->parent[index].dbg_cc; + + if (dbg_cc != GCC) { + regmap_read(meas->regmap[dbg_cc], 0x0, ®val); + + /* Clear & Set post divider bits */ + if (meas->parent[index].post_div_mask) { + regval &= ~meas->parent[index].post_div_mask; + lsb = find_first_bit((unsigned long *) + &meas->parent[index].post_div_mask, 32); + regval |= (meas->parent[index].post_div_val << lsb) & + meas->parent[index].post_div_mask; + meas->multiplier = meas->parent[index].post_div_val; + } + + if (meas->parent[index].mask) + regval &= ~meas->parent[index].mask << + meas->parent[index].shift; + else + regval &= ~meas->mask; + + regval |= (meas->parent[index].next_sel & meas->mask); + + if (meas->parent[index].en_mask == 0xFF) + /* Skip en_mask */ + regval = regval; + else if (meas->parent[index].en_mask) + regval |= meas->parent[index].en_mask; + else + regval |= meas->en_mask; + + regmap_write(meas->regmap[dbg_cc], 0x0, regval); + } + + /* update the debug sel for GCC */ + regmap_read(meas->regmap[GCC], meas->debug_offset, ®val); + + /* clear post divider bits */ + regval &= ~BM(15, 12); + lsb = find_first_bit((unsigned long *) + &meas->parent[index].post_div_mask, 32); + regval |= (meas->parent[index].post_div_val << lsb) & + meas->parent[index].post_div_mask; + meas->multiplier = meas->parent[index].post_div_val; + regval &= ~meas->mask; + regval |= (meas->parent[index].sel & meas->mask); + regval |= meas->en_mask; + + regmap_write(meas->regmap[GCC], meas->debug_offset, regval); + + return 0; +} + +const struct clk_ops clk_debug_mux_ops = { + .get_parent = clk_debug_mux_get_parent, + .set_parent = clk_debug_mux_set_parent, +}; +EXPORT_SYMBOL(clk_debug_mux_ops); + +static int clk_debug_measure_get(void *data, u64 *val) +{ + struct clk_hw *hw = data, *par; + int ret = 0; + unsigned long meas_rate, sw_rate; + + mutex_lock(&clk_debug_lock); + + ret = clk_set_parent(measure->clk, hw->clk); + if (!ret) { + par = measure; + while (par && par != hw) { + if (par->init->ops->enable) + par->init->ops->enable(par); + par = clk_hw_get_parent(par); + } + *val = clk_debug_mux_measure_rate(measure); + } + + meas_rate = clk_get_rate(hw->clk); + sw_rate = clk_get_rate(clk_hw_get_parent(measure)->clk); + if (sw_rate && meas_rate >= (sw_rate * 2)) + *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); + + mutex_unlock(&clk_debug_lock); + + return ret; +} + +DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get, + NULL, "%lld\n"); + +int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry) +{ + if (IS_ERR_OR_NULL(measure)) { + pr_err_once("Please check if `measure` clk is registered!!!\n"); + return 0; + } + + if (clk_set_parent(measure->clk, hw->clk)) + return 0; + + debugfs_create_file("clk_measure", S_IRUGO, dentry, hw, + &clk_measure_fops); + return 0; +} +EXPORT_SYMBOL(clk_debug_measure_add); + +int clk_register_debug(struct clk_hw *hw) +{ + if (IS_ERR_OR_NULL(measure)) { + if (hw->init->flags & CLK_IS_MEASURE) { + measure = hw; + return 0; + } + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(clk_register_debug); + diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h new file mode 100644 index 000000000000..40e8730a9466 --- /dev/null +++ b/drivers/clk/qcom/clk-debug.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 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 + * 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. + */ + +#ifndef __QCOM_CLK_DEBUG_H__ +#define __QCOM_CLK_DEBUG_H__ + +#include "../clk.h" + +/* Debugfs Measure Clocks */ + +/** + * struct measure_clk_data - Structure of clk measure + * + * @cxo: XO clock. + * @xo_div4_cbcr: offset of debug XO/4 div register. + * @ctl_reg: offset of debug control register. + * @status_reg: offset of debug status register. + * + */ +struct measure_clk_data { + struct clk *cxo; + u32 xo_div4_cbcr; + u32 ctl_reg; + u32 status_reg; +}; + +/** + * List of Debug clock controllers. + */ +enum debug_cc { + GCC, + MMCC, + GPU, + CPU, +}; + +/** + * struct clk_src - Struture of clock source for debug mux + * + * @parents: clock name to be used as parent for debug mux. + * @sel: debug mux index at global clock controller. + * @dbg_cc: indicates the clock controller for recursive debug clock + * controllers. + * @next_sel: indicates the debug mux index at recursive debug mux. + * @mask: indicates the mask required at recursive debug mux. + * @shift: indicates the shift required at recursive debug mux. + * @en_mask: indicates the enable bit mask at recursive debug mux. + * Incase the recursive debug mux does not have a enable bit, + * 0xFF should be used to indicate the same, otherwise global + * enable bit would be used. + * @post_div_mask: indicates the post div mask to be used at debug/recursive + * debug mux. + * @post_div_val: indicates the post div value to be used at debug/recursive + * debug mux. + */ +struct clk_src { + const char *parents; + int sel; + enum debug_cc dbg_cc; + int next_sel; + u32 mask; + u32 shift; + u32 en_mask; + u32 post_div_mask; + u32 post_div_val; +}; + +#define MUX_SRC_LIST(...) \ + .parent = (struct clk_src[]){__VA_ARGS__}, \ + .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__})) + +/** + * struct clk_debug_mux - Struture of clock debug mux + * + * @parent: structure of clk_src + * @num_parents: number of parents + * @regmap: regmaps of debug mux + * @num_parent_regmap: number of regmap of debug mux + * @priv: private measure_clk_data to be used by debug mux + * @en_mask: indicates the enable bit mask at global clock + * controller debug mux. + * @mask: indicates the mask to be used at global clock + * controller debug mux. + * @debug_offset: debug mux offset. + * @hw: handle between common and hardware-specific interfaces. + * @multiplier: internally used by debug mux as post div multiplier. + */ +struct clk_debug_mux { + struct clk_src *parent; + int num_parents; + struct regmap **regmap; + int num_parent_regmap; + void *priv; + u32 en_mask; + u32 mask; + u32 debug_offset; + struct clk_hw hw; + + /* internal */ + u32 multiplier; +}; + +#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw) + +extern const struct clk_ops clk_debug_mux_ops; + +int clk_register_debug(struct clk_hw *hw); +int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry); + +#endif diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c index e06a829e508c..c08136563e31 100644 --- a/drivers/clk/qcom/clk-dummy.c +++ b/drivers/clk/qcom/clk-dummy.c @@ -1,5 +1,5 @@ /* - * 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 @@ -17,6 +17,8 @@ #include <linux/slab.h> #include <linux/reset-controller.h> +#include "clk-debug.h" + struct clk_dummy { struct clk_hw hw; struct reset_controller_dev reset; @@ -65,6 +67,7 @@ struct clk_ops clk_dummy_ops = { .round_rate = dummy_clk_round_rate, .recalc_rate = dummy_clk_recalc_rate, .set_flags = dummy_clk_set_flags, + .debug_init = clk_debug_measure_add, }; EXPORT_SYMBOL_GPL(clk_dummy_ops); diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 58fbd07e6f15..0bcada9aac5d 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 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 @@ -192,5 +192,6 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_gfx3d_src_ops; extern const struct clk_ops clk_dp_ops; +extern const struct clk_ops clk_esc_ops; #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 632d0f4ac9c1..ff0c8327fabe 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1349,3 +1349,73 @@ const struct clk_ops clk_gfx3d_src_ops = { .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_gfx3d_src_ops); + +static int clk_esc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + unsigned long parent_rate, div; + u32 mask = BIT(rcg->hid_width) - 1; + struct clk_hw *p; + unsigned long rate = req->rate; + + if (rate == 0) + return -EINVAL; + + p = req->best_parent_hw; + req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate); + + div = ((2 * parent_rate) / rate) - 1; + div = min_t(u32, div, mask); + + req->rate = calc_rate(parent_rate, 0, 0, 0, div); + + return 0; +} + +static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct freq_tbl f = { 0 }; + unsigned long div; + int i, num_parents = clk_hw_get_num_parents(hw); + u32 mask = BIT(rcg->hid_width) - 1; + u32 cfg; + + div = ((2 * parent_rate) / rate) - 1; + div = min_t(u32, div, mask); + + f.pre_div = div; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f.src = rcg->parent_map[i].src; + return clk_rcg2_configure(rcg, &f); + } + } + + return -EINVAL; +} + +static int clk_esc_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_esc_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_esc_ops = { + .is_enabled = clk_rcg2_is_enabled, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .determine_rate = clk_esc_determine_rate, + .set_rate = clk_esc_set_rate, + .set_rate_and_parent = clk_esc_set_rate_and_parent, + .list_registers = clk_rcg2_list_registers, +}; +EXPORT_SYMBOL(clk_esc_ops); diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 5345e9086627..8dcdf2929ca6 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -30,6 +30,7 @@ #include <dt-bindings/mfd/qcom-rpm.h> #include "clk-voter.h" +#include "clk-debug.h" #define QCOM_RPM_KEY_SOFTWARE_ENABLE 0x6e657773 #define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370 @@ -463,6 +464,7 @@ static const struct clk_ops clk_smd_rpm_ops = { .round_rate = clk_smd_rpm_round_rate, .recalc_rate = clk_smd_rpm_recalc_rate, .is_enabled = clk_smd_rpm_is_enabled, + .debug_init = clk_debug_measure_add, }; static const struct clk_ops clk_smd_rpm_branch_ops = { @@ -471,6 +473,7 @@ static const struct clk_ops clk_smd_rpm_branch_ops = { .round_rate = clk_smd_rpm_round_rate, .recalc_rate = clk_smd_rpm_recalc_rate, .is_enabled = clk_smd_rpm_is_enabled, + .debug_init = clk_debug_measure_add, }; /* msm8916 */ diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index f6ce3106ab6f..8ecb207a97e5 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -1,5 +1,7 @@ /* - * Copyright (c) 2013-2014, 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 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 @@ -287,239 +289,4 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) } EXPORT_SYMBOL_GPL(qcom_cc_probe); -/* Debugfs Support */ -static struct clk_hw *measure; - -DEFINE_SPINLOCK(clk_reg_lock); - -/* Sample clock for 'ticks' reference clock ticks. */ -static u32 run_measurement(unsigned ticks, struct regmap *regmap, - u32 ctl_reg, u32 status_reg) -{ - u32 regval; - - /* Stop counters and set the XO4 counter start value. */ - regmap_write(regmap, ctl_reg, ticks); - - regmap_read(regmap, status_reg, ®val); - - /* Wait for timer to become ready. */ - while ((regval & BIT(25)) != 0) { - cpu_relax(); - regmap_read(regmap, status_reg, ®val); - } - - /* Run measurement and wait for completion. */ - regmap_write(regmap, ctl_reg, (BIT(20)|ticks)); - regmap_read(regmap, ctl_reg, ®val); - - regmap_read(regmap, status_reg, ®val); - - while ((regval & BIT(25)) == 0) { - cpu_relax(); - regmap_read(regmap, status_reg, ®val); - } - - /* Return measured ticks. */ - regmap_read(regmap, status_reg, ®val); - regval &= BM(24, 0); - - return regval; -} - -/* - * Perform a hardware rate measurement for a given clock. - * FOR DEBUG USE ONLY: Measurements take ~15 ms! - */ -static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw) -{ - unsigned long flags, ret = 0; - u32 gcc_xo4_reg, sample_ticks = 0x10000, multiplier; - u64 raw_count_short, raw_count_full; - struct clk_debug_mux *meas = to_clk_measure(hw); - struct measure_clk_data *data = meas->priv; - - clk_prepare_enable(data->cxo); - - spin_lock_irqsave(&clk_reg_lock, flags); - - multiplier = meas->multiplier + 1; - - /* Enable CXO/4 and RINGOSC branch. */ - regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg); - gcc_xo4_reg |= BIT(0); - regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg); - - /* - * The ring oscillator counter will not reset if the measured clock - * is not running. To detect this, run a short measurement before - * the full measurement. If the raw results of the two are the same - * then the clock must be off. - */ - - /* Run a short measurement. (~1 ms) */ - raw_count_short = run_measurement(0x1000, meas->regmap[GCC], - data->ctl_reg, data->status_reg); - - /* Run a full measurement. (~14 ms) */ - raw_count_full = run_measurement(sample_ticks, meas->regmap[GCC], - data->ctl_reg, data->status_reg); - - gcc_xo4_reg &= ~BIT(0); - regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg); - - /* Return 0 if the clock is off. */ - if (raw_count_full == raw_count_short) - ret = 0; - else { - /* Compute rate in Hz. */ - raw_count_full = ((raw_count_full * 10) + 15) * 4800000; - do_div(raw_count_full, ((sample_ticks * 10) + 35)); - ret = (raw_count_full * multiplier); - } - - spin_unlock_irqrestore(&clk_reg_lock, flags); - - clk_disable_unprepare(data->cxo); - - return ret; -} - -static u8 clk_debug_mux_get_parent(struct clk_hw *hw) -{ - struct clk_debug_mux *meas = to_clk_measure(hw); - int i, num_parents = clk_hw_get_num_parents(hw); - - for (i = 0; i < num_parents; i++) { - if (!strcmp(meas->parent[i].parents, - hw->init->parent_names[i])) { - pr_debug("%s :Clock name %s index %d\n", __func__, - hw->init->name, i); - return i; - } - } - - return 0; -} - -static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_debug_mux *meas = to_clk_measure(hw); - unsigned long lsb = 0; - u32 regval = 0; - int dbg_cc = 0; - - dbg_cc = meas->parent[index].dbg_cc; - - if (dbg_cc != GCC) { - regmap_read(meas->regmap[dbg_cc], 0x0, ®val); - - /* Clear & Set post divider bits */ - if (meas->parent[index].post_div_mask) { - regval &= ~meas->parent[index].post_div_mask; - lsb = find_first_bit((unsigned long *) - &meas->parent[index].post_div_mask, 32); - regval |= (meas->parent[index].post_div_val << lsb) & - meas->parent[index].post_div_mask; - meas->multiplier = meas->parent[index].post_div_val; - } - - if (meas->parent[index].mask) - regval &= ~meas->parent[index].mask << - meas->parent[index].shift; - else - regval &= ~meas->mask; - - regval |= (meas->parent[index].next_sel & meas->mask); - - if (meas->parent[index].en_mask == 0xFF) - /* Skip en_mask */ - regval = regval; - else if (meas->parent[index].en_mask) - regval |= meas->parent[index].en_mask; - else - regval |= meas->en_mask; - - regmap_write(meas->regmap[dbg_cc], 0x0, regval); - } - - /* update the debug sel for GCC */ - regmap_read(meas->regmap[GCC], meas->debug_offset, ®val); - - /* clear post divider bits */ - regval &= ~BM(15, 12); - lsb = find_first_bit((unsigned long *) - &meas->parent[index].post_div_mask, 32); - regval |= (meas->parent[index].post_div_val << lsb) & - meas->parent[index].post_div_mask; - meas->multiplier = meas->parent[index].post_div_val; - regval &= ~meas->mask; - regval |= (meas->parent[index].sel & meas->mask); - regval |= meas->en_mask; - - regmap_write(meas->regmap[GCC], meas->debug_offset, regval); - - return 0; -} - -const struct clk_ops clk_debug_mux_ops = { - .get_parent = clk_debug_mux_get_parent, - .set_parent = clk_debug_mux_set_parent, -}; -EXPORT_SYMBOL_GPL(clk_debug_mux_ops); - -static int clk_debug_measure_get(void *data, u64 *val) -{ - struct clk_hw *hw = data, *par; - int ret = 0; - unsigned long meas_rate, sw_rate; - - ret = clk_set_parent(measure->clk, hw->clk); - if (!ret) { - par = measure; - while (par && par != hw) { - if (par->init->ops->enable) - par->init->ops->enable(par); - par = clk_hw_get_parent(par); - } - *val = clk_debug_mux_measure_rate(measure); - } - - meas_rate = clk_get_rate(hw->clk); - sw_rate = clk_get_rate(clk_hw_get_parent(measure)->clk); - if (sw_rate && meas_rate >= (sw_rate * 2)) - *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); - - return ret; -} - -DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get, - NULL, "%lld\n"); - -void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry) -{ - if (IS_ERR_OR_NULL(measure)) - return; - - if (clk_set_parent(measure->clk, hw->clk)) - return; - - debugfs_create_file("measure", S_IRUGO, dentry, hw, - &clk_measure_fops); -} -EXPORT_SYMBOL_GPL(clk_debug_measure_add); - -int clk_register_debug(struct clk_hw *hw, struct dentry *dentry) -{ - if (IS_ERR_OR_NULL(measure)) { - if (hw->init->flags & CLK_IS_MEASURE) - measure = hw; - if (!IS_ERR_OR_NULL(measure)) - clk_debug_measure_add(hw, dentry); - } - - return 0; -} -EXPORT_SYMBOL_GPL(clk_register_debug); - MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 95408a47fef0..c532444a0d40 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -13,7 +13,7 @@ #ifndef __QCOM_CLK_COMMON_H__ #define __QCOM_CLK_COMMON_H__ -#include "../clk.h" +#include "clk-debug.h" struct platform_device; struct regmap_config; @@ -54,107 +54,9 @@ extern int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc); extern struct clk_ops clk_dummy_ops; -/* Debugfs Measure Clocks */ - -/** - * struct measure_clk_data - Structure of clk measure - * - * @cxo: XO clock. - * @xo_div4_cbcr: offset of debug XO/4 div register. - * @ctl_reg: offset of debug control register. - * @status_reg: offset of debug status register. - * - */ -struct measure_clk_data { - struct clk *cxo; - u32 xo_div4_cbcr; - u32 ctl_reg; - u32 status_reg; -}; - -/** - * List of Debug clock controllers. - */ -enum debug_cc { - GCC, - MMCC, - GPU, - CPU, -}; - -/** - * struct clk_src - Struture of clock source for debug mux - * - * @parents: clock name to be used as parent for debug mux. - * @sel: debug mux index at global clock controller. - * @dbg_cc: indicates the clock controller for recursive debug clock - * controllers. - * @next_sel: indicates the debug mux index at recursive debug mux. - * @mask: indicates the mask required at recursive debug mux. - * @shift: indicates the shift required at recursive debug mux. - * @en_mask: indicates the enable bit mask at recursive debug mux. - * Incase the recursive debug mux does not have a enable bit, - * 0xFF should be used to indicate the same, otherwise global - * enable bit would be used. - * @post_div_mask: indicates the post div mask to be used at debug/recursive - * debug mux. - * @post_div_val: indicates the post div value to be used at debug/recursive - * debug mux. - */ -struct clk_src { - const char *parents; - int sel; - enum debug_cc dbg_cc; - int next_sel; - u32 mask; - u32 shift; - u32 en_mask; - u32 post_div_mask; - u32 post_div_val; -}; - -#define MUX_SRC_LIST(...) \ - .parent = (struct clk_src[]){__VA_ARGS__}, \ - .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__})) - -/** - * struct clk_debug_mux - Struture of clock debug mux - * - * @parent: structure of clk_src - * @num_parents: number of parents - * @regmap: regmaps of debug mux - * @num_parent_regmap: number of regmap of debug mux - * @priv: private measure_clk_data to be used by debug mux - * @en_mask: indicates the enable bit mask at global clock - * controller debug mux. - * @mask: indicates the mask to be used at global clock - * controller debug mux. - * @debug_offset: Start of debug mux offset. - * @hw: handle between common and hardware-specific interfaces. - * @multiplier: internally used by debug mux as post div multiplier. - */ -struct clk_debug_mux { - struct clk_src *parent; - int num_parents; - struct regmap **regmap; - int num_parent_regmap; - void *priv; - u32 en_mask; - u32 mask; - u32 debug_offset; - struct clk_hw hw; - - /* internal */ - u32 multiplier; -}; - #define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) #define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) -#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw) - -extern const struct clk_ops clk_debug_mux_ops; - #define WARN_CLK(core, name, cond, fmt, ...) do { \ clk_debug_print_hw(core, NULL); \ WARN(cond, "%s: " fmt, name, ##__VA_ARGS__); \ diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index c282253da584..b55310e091af 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -27,6 +27,7 @@ #include "clk-alpha-pll.h" #include "clk-branch.h" +#include "clk-debug.h" #include "common.h" #include "clk-pll.h" #include "clk-regmap.h" @@ -3328,7 +3329,11 @@ static int clk_debug_660_probe(struct platform_device *pdev) return PTR_ERR(clk); } - dev_info(&pdev->dev, "Registered debug mux successfully\n"); + ret = clk_register_debug(&gcc_debug_mux.hw); + if (ret) + dev_err(&pdev->dev, "Could not register Measure clock\n"); + else + dev_info(&pdev->dev, "Registered debug mux successfully\n"); return ret; } diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index 0bf7ef05ed06..910c36c65b6a 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -978,12 +978,11 @@ static struct clk_rcg2 esc0_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = mmcc_parent_map_1, - .freq_tbl = ftbl_dp_aux_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "esc0_clk_src", .parent_names = mmcc_parent_names_1, .num_parents = 4, - .ops = &clk_rcg2_ops, + .ops = &clk_esc_ops, VDD_DIG_FMAX_MAP1( LOWER, 19200000), }, @@ -994,12 +993,11 @@ static struct clk_rcg2 esc1_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = mmcc_parent_map_1, - .freq_tbl = ftbl_dp_aux_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "esc1_clk_src", .parent_names = mmcc_parent_names_1, .num_parents = 4, - .ops = &clk_rcg2_ops, + .ops = &clk_esc_ops, VDD_DIG_FMAX_MAP1( LOWER, 19200000), }, diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index bf3a24b3eb01..dc4214f7a302 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(); @@ -1100,6 +1133,7 @@ static struct platform_driver tz_log_driver = { .name = "tz_log", .owner = THIS_MODULE, .of_match_table = tzlog_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; 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/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/misc/Kconfig b/drivers/input/misc/Kconfig index 5cfa1848e37c..dd98d8c8fd1f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -834,4 +834,14 @@ config INPUT_DRV2667_HAPTICS source "drivers/input/misc/ots_pat9125/Kconfig" +config INPUT_STMVL53L0 + tristate "STM VL53L0 Proximity support" + depends on INPUT && I2C + help + Say Y here if you want to use STMicroelectronics's proximity sensor + through I2C interface. + + To compile this driver as a module, choose M here: the + module will be called stmvl53l0. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a5ab4b762d31..44c026abcb6f 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -80,3 +80,4 @@ obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/ +obj-$(CONFIG_INPUT_STMVL53L0) += vl53L0/ diff --git a/drivers/input/misc/vl53L0/Makefile b/drivers/input/misc/vl53L0/Makefile index 4a6be55094b6..f105e1c3c60f 100644 --- a/drivers/input/misc/vl53L0/Makefile +++ b/drivers/input/misc/vl53L0/Makefile @@ -9,12 +9,12 @@ FEATURE_USE_CCI := true ifeq ($(FEATURE_USE_CCI), true) ccflags-y += -Idrivers/input/misc/vl53L0/inc -DCAMERA_CCI else -ccflags-y += -Idrivers/input/misc/vl53L0/inc +ccflags-y += -Idrivers/input/misc/vl53L0/inc endif ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io ccflags-y += -Idrivers/media/platform/msm/camera_v2 ccflags-y += -Idrivers/media/platform/msm/camera_v2/common ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci -obj-$(CONFIG_STMVL53L0) += stmvl53l0.o +obj-$(CONFIG_INPUT_STMVL53L0) += stmvl53l0.o stmvl53l0-objs := stmvl53l0_module.o stmvl53l0_module-i2c.o stmvl53l0_module-cci.o src/vl53l0_api_calibration.o src/vl53l0_api_core.o src/vl53l0_api_histogram.o src/vl53l0_api_ranging.o src/vl53l0_api_strings.o src/vl53l0_api.o src/vl53l0_platform.o src/vl53l0_i2c_platform.o src/vl53l0_port_i2c.o src/vl53l010_api.o src/vl53l010_tuning.o 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 02fa0cbbe392..000000000000 --- a/drivers/input/touchscreen/gt9xx/goodix_tool.c +++ /dev/null @@ -1,600 +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)) -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 */ -} __packed; - -static struct st_cmd_head cmd_head; -static u8 *cmd_data; - -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_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; - - 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_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_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_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_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_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_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_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_data, 0, cmd_head.data_len + 1); - memcpy(cmd_data, &userbuf[CMD_HEAD_LENGTH], - cmd_head.data_len); - - if (gup_update_proc((void *)cmd_data) == FAIL) { - ret = -EBUSY; - goto exit; - } - } - ret = CMD_HEAD_LENGTH; - -exit: - memset(&cmd_head, 0, sizeof(cmd_head)); - cmd_head.wr = 0xFF; - - 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_data, cmd_head.addr, cmd_head.addr_len); - - pr_debug("[CMD HEAD DATA] ADDR:0x%02x%02x.\n", cmd_data[0], - cmd_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_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_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_data = NULL; - - i = GTP_I2C_RETRY_5; - while ((!cmd_data) && i) { - cmd_data = devm_kzalloc(&client->dev, - i * DATA_LENGTH_UINT, GFP_KERNEL); - if (cmd_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/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 5f2b66286c0c..6a8a9492c771 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -89,6 +89,7 @@ #define ARM_LPAE_PTE_TYPE_TABLE 3 #define ARM_LPAE_PTE_TYPE_PAGE 3 +#define ARM_LPAE_PTE_SH_MASK (((arm_lpae_iopte)0x3) << 8) #define ARM_LPAE_PTE_NSTABLE (((arm_lpae_iopte)1) << 63) #define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53) #define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10) @@ -928,8 +929,9 @@ static bool __arm_lpae_is_iova_coherent(struct arm_lpae_io_pgtable *data, ARM_LPAE_PTE_ATTRINDX_SHIFT)) >> ARM_LPAE_PTE_ATTRINDX_SHIFT; if ((attr_idx == ARM_LPAE_MAIR_ATTR_IDX_CACHE) && - ((*ptep & ARM_LPAE_PTE_SH_IS) || - (*ptep & ARM_LPAE_PTE_SH_OS))) + (((*ptep & ARM_LPAE_PTE_SH_MASK) == ARM_LPAE_PTE_SH_IS) + || + (*ptep & ARM_LPAE_PTE_SH_MASK) == ARM_LPAE_PTE_SH_OS)) return true; } else { if (*ptep & ARM_LPAE_PTE_MEMATTR_OIWB) 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..9cdcabb762c0 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 @@ -342,8 +342,14 @@ static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr) mapping->ion_fd); } } - pr_err("Cannot find vaddr:%pK in SMMU. %s uses invalid virtual address\n", - vaddr, iommu_cb_set.cb_info[idx].name); + if (!strcmp(iommu_cb_set.cb_info[idx].name, "vfe")) + pr_err_ratelimited("Cannot find vaddr:%pK in SMMU.\n" + " %s uses invalid virtual address\n", + vaddr, iommu_cb_set.cb_info[idx].name); + else + pr_err("Cannot find vaddr:%pK in SMMU.\n" + " %s uses invalid virtual address\n", + vaddr, iommu_cb_set.cb_info[idx].name); return; } @@ -894,8 +900,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 +921,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 +966,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 +985,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_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 c8cc66a564ce..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; 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..b351e0e765a9 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_NOMINAL] + [vfe_dev->hw_info->vfe_clk_idx]) && + prev_clk_rate < + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL] + [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_NOMINAL] + [vfe_dev->hw_info->vfe_clk_idx]) && + prev_clk_rate >= + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL] + [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_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index 9ce2218d5e0d..011b02e380f4 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 @@ -1074,7 +1074,7 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev_ioctl, uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; uint32_t num_stats_comp_mask = 0; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data; + struct msm_vfe_stats_shared_data *stats_data = NULL; int num_stream = 0; struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX]; struct msm_isp_timestamp timestamp; @@ -1136,10 +1136,12 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev_ioctl, comp_stats_mask[stream_info->composite_flag-1] |= 1 << idx; - ISP_DBG("%s: stats_mask %x %x active streams %d\n", + ISP_DBG("%s: stats_mask %x %x\n", __func__, comp_stats_mask[0], - comp_stats_mask[1], - stats_data->num_active_stream); + comp_stats_mask[1]); + if (stats_data) + ISP_DBG("%s: active_streams = %d\n", __func__, + stats_data->num_active_stream); streams[num_stream++] = stream_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 22246f613462..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 @@ -1428,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/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 1628c098622f..9d52107c9993 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -1662,7 +1662,7 @@ static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd, static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ispif_device *ispif = v4l2_get_subdevdata(sd); - int rc; + int rc = 0; mutex_lock(&ispif->mutex); if (0 == ispif->open_cnt) { 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 08aab077eec7..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", @@ -2955,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) { @@ -3337,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); @@ -4391,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/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index 5c7b4df40d5d..e170c9ffafc7 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -539,6 +539,7 @@ static void *sde_rotator_get_userptr(void *alloc_ctx, buf->ctx = ctx; buf->rot_dev = rot_dev; if (ctx->secure_camera) { + buf->buffer = NULL; buf->handle = ion_import_dma_buf(iclient, buf->fd); if (IS_ERR_OR_NULL(buf->handle)) { @@ -552,6 +553,7 @@ static void *sde_rotator_get_userptr(void *alloc_ctx, buf->ctx->session_id, buf->fd, &buf->handle); } else { + buf->handle = NULL; buf->buffer = dma_buf_get(buf->fd); if (IS_ERR_OR_NULL(buf->buffer)) { SDEDEV_ERR(rot_dev->dev, @@ -578,6 +580,8 @@ error_buf_get: static void sde_rotator_put_userptr(void *buf_priv) { struct sde_rotator_buf_handle *buf = buf_priv; + struct ion_client *iclient; + struct sde_rotator_device *rot_dev; if (IS_ERR_OR_NULL(buf)) return; @@ -588,6 +592,9 @@ static void sde_rotator_put_userptr(void *buf_priv) return; } + rot_dev = buf->ctx->rot_dev; + iclient = buf->rot_dev->mdata->iclient; + SDEDEV_DBG(buf->rot_dev->dev, "put dmabuf s:%d fd:%d buf:%pad\n", buf->ctx->session_id, buf->fd, &buf->buffer); @@ -597,6 +604,11 @@ static void sde_rotator_put_userptr(void *buf_priv) buf->buffer = NULL; } + if (buf->handle) { + ion_free(iclient, buf->handle); + buf->handle = NULL; + } + kfree(buf_priv); } diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c index 0eaf1960ec27..882e3dcd6277 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c @@ -768,10 +768,17 @@ static int sde_mdp_get_img(struct sde_fb_data *img, len = &data->len; data->flags |= img->flags; data->offset = img->offset; - if (data->flags & SDE_ROT_EXT_DMA_BUF) + + if ((data->flags & SDE_SECURE_CAMERA_SESSION) && + IS_ERR_OR_NULL(img->handle)) { + SDEROT_ERR("error on ion_import_fb\n"); + ret = PTR_ERR(img->handle); + img->handle = NULL; + return ret; + } else if (data->flags & SDE_ROT_EXT_DMA_BUF) { data->srcp_dma_buf = img->buffer; - else if (IS_ERR(data->srcp_dma_buf)) { - SDEROT_ERR("error on ion_import_fd\n"); + } else if (IS_ERR(data->srcp_dma_buf)) { + SDEROT_ERR("error on dma_buf\n"); ret = PTR_ERR(data->srcp_dma_buf); data->srcp_dma_buf = NULL; return ret; @@ -845,8 +852,6 @@ static int sde_mdp_get_img(struct sde_fb_data *img, ret = 0; } while (0); - if (!IS_ERR_OR_NULL(ihandle)) - ion_free(iclient, ihandle); return ret; } diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index b7e2c297a1ad..24eb8fff905b 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -528,7 +528,6 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .step = 1, .menu_skip_mask = 0, .qmenu = NULL, - .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, }, { .id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2, diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 4739fc999c82..bc72c4a56c91 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -4472,7 +4472,7 @@ static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info) struct venus_hfi_device *device = dev; u32 smem_block_size = 0; u8 *smem_table_ptr; - char version[VENUS_VERSION_LENGTH]; + char version[VENUS_VERSION_LENGTH] = ""; const u32 smem_image_index_venus = 14 * 128; if (!device || !fw_info) { diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c index 8f244811f740..c1570e32f749 100644 --- a/drivers/misc/qpnp-misc.c +++ b/drivers/misc/qpnp-misc.c @@ -342,7 +342,7 @@ static void __exit qpnp_misc_exit(void) return platform_driver_unregister(&qpnp_misc_driver); } -module_init(qpnp_misc_init); +subsys_initcall(qpnp_misc_init); module_exit(qpnp_misc_exit); MODULE_DESCRIPTION(QPNP_MISC_DEV_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/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c index 9117ea7d08c0..6b23a8f61f35 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c +++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,13 +27,13 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/of_device.h> +#include <linux/rtnetlink.h> #define RMNET_MHI_DRIVER_NAME "rmnet_mhi" #define RMNET_MHI_DEV_NAME "rmnet_mhi%d" #define MHI_DEFAULT_MTU 8000 #define MHI_MAX_MRU 0xFFFF #define MHI_NAPI_WEIGHT_VALUE 12 -#define MHI_RX_HEADROOM 64 #define WATCHDOG_TIMEOUT (30 * HZ) #define RMNET_IPC_LOG_PAGES (100) @@ -79,6 +79,7 @@ struct __packed mhi_skb_priv { struct rmnet_mhi_private { struct list_head node; + u32 dev_id; struct mhi_client_handle *tx_client_handle; struct mhi_client_handle *rx_client_handle; enum MHI_CLIENT_CHANNEL tx_channel; @@ -87,6 +88,8 @@ struct rmnet_mhi_private { struct sk_buff_head rx_buffers; atomic_t rx_pool_len; u32 mru; + u32 max_mru; + u32 max_mtu; struct napi_struct napi; gfp_t allocation_flags; uint32_t tx_buffers_max; @@ -118,9 +121,9 @@ static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr, if (rmnet_mhi_ptr->frag_skb) { /* Merge the new skb into the old fragment */ temp_skb = skb_copy_expand(rmnet_mhi_ptr->frag_skb, - MHI_RX_HEADROOM, - skb->len, - GFP_ATOMIC); + 0, + skb->len, + GFP_ATOMIC); if (!temp_skb) { kfree(rmnet_mhi_ptr->frag_skb); rmnet_mhi_ptr->frag_skb = NULL; @@ -207,9 +210,8 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, return -ENOMEM; } skb_priv = (struct mhi_skb_priv *)(skb->cb); - skb_priv->dma_size = cur_mru - MHI_RX_HEADROOM; + skb_priv->dma_size = cur_mru; skb_priv->dma_addr = 0; - skb_reserve(skb, MHI_RX_HEADROOM); /* These steps must be in atomic context */ spin_lock_irqsave(&rmnet_mhi_ptr->alloc_lock, flags); @@ -584,7 +586,10 @@ static int rmnet_mhi_stop(struct net_device *dev) static int rmnet_mhi_change_mtu(struct net_device *dev, int new_mtu) { - if (0 > new_mtu || MHI_MAX_MTU < new_mtu) + struct rmnet_mhi_private *rmnet_mhi_ptr = + *(struct rmnet_mhi_private **)netdev_priv(dev); + + if (new_mtu < 0 || rmnet_mhi_ptr->max_mtu < new_mtu) return -EINVAL; dev->mtu = new_mtu; @@ -667,11 +672,11 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) switch (ext_cmd.extended_ioctl) { case RMNET_IOCTL_SET_MRU: - if (!ext_cmd.u.data || ext_cmd.u.data > MHI_MAX_MRU) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Can't set MRU, value %u is invalid\n", - ext_cmd.u.data); + if (!ext_cmd.u.data || + ext_cmd.u.data > rmnet_mhi_ptr->max_mru) { + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, + "Can't set MRU, value:%u is invalid max:%u\n", + ext_cmd.u.data, rmnet_mhi_ptr->max_mru); return -EINVAL; } rmnet_log(rmnet_mhi_ptr, @@ -793,6 +798,8 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) int ret = 0; struct rmnet_mhi_private **rmnet_mhi_ctxt = NULL; int r = 0; + char ifalias[IFALIASZ]; + struct mhi_client_handle *client_handle = NULL; rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered.\n"); @@ -826,6 +833,7 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) } else { rmnet_mhi_ptr->tx_enabled = 1; } + client_handle = rmnet_mhi_ptr->tx_client_handle; } if (rmnet_mhi_ptr->rx_client_handle != NULL) { rmnet_log(rmnet_mhi_ptr, @@ -841,7 +849,26 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) } else { rmnet_mhi_ptr->rx_enabled = 1; } + /* Both tx & rx client handle contain same device info */ + client_handle = rmnet_mhi_ptr->rx_client_handle; } + + if (!client_handle) { + ret = -EINVAL; + goto net_dev_alloc_fail; + } + + snprintf(ifalias, + sizeof(ifalias), + "%s_%04x_%02u.%02u.%02u_%u", + RMNET_MHI_DRIVER_NAME, + client_handle->dev_id, + client_handle->domain, + client_handle->bus, + client_handle->slot, + rmnet_mhi_ptr->dev_id); + + rtnl_lock(); rmnet_mhi_ptr->dev = alloc_netdev(sizeof(struct rmnet_mhi_private *), RMNET_MHI_DEV_NAME, @@ -854,7 +881,9 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) goto net_dev_alloc_fail; } SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev); + dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias)); rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev); + rtnl_unlock(); *rmnet_mhi_ctxt = rmnet_mhi_ptr; ret = dma_set_mask(&(rmnet_mhi_ptr->dev->dev), @@ -981,17 +1010,16 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) } } -static struct mhi_client_info_t rmnet_mhi_info = {rmnet_mhi_cb}; - #ifdef CONFIG_DEBUG_FS struct dentry *dentry; static void rmnet_mhi_create_debugfs(struct rmnet_mhi_private *rmnet_mhi_ptr) { - char node_name[15]; + char node_name[32]; int i; const umode_t mode = (S_IRUSR | S_IWUSR); struct dentry *file; + struct mhi_client_handle *client_handle; const struct { char *name; @@ -1047,8 +1075,20 @@ static void rmnet_mhi_create_debugfs(struct rmnet_mhi_private *rmnet_mhi_ptr) }, }; - snprintf(node_name, sizeof(node_name), "%s%d", - RMNET_MHI_DRIVER_NAME, rmnet_mhi_ptr->pdev->id); + /* Both tx & rx client handle contain same device info */ + client_handle = rmnet_mhi_ptr->rx_client_handle; + if (!client_handle) + client_handle = rmnet_mhi_ptr->tx_client_handle; + + snprintf(node_name, + sizeof(node_name), + "%s_%04x_%02u.%02u.%02u_%u", + RMNET_MHI_DRIVER_NAME, + client_handle->dev_id, + client_handle->domain, + client_handle->bus, + client_handle->slot, + rmnet_mhi_ptr->dev_id); if (IS_ERR_OR_NULL(dentry)) return; @@ -1109,11 +1149,16 @@ static int rmnet_mhi_probe(struct platform_device *pdev) int rc; u32 channel; struct rmnet_mhi_private *rmnet_mhi_ptr; - char node_name[15]; + struct mhi_client_handle *client_handle = NULL; + char node_name[32]; + struct mhi_client_info_t client_info; if (unlikely(!pdev->dev.of_node)) return -ENODEV; + if (!mhi_is_device_ready(&pdev->dev, "qcom,mhi")) + return -EPROBE_DEFER; + pdev->id = of_alias_get_id(pdev->dev.of_node, "mhi_rmnet"); if (unlikely(pdev->id < 0)) return -ENODEV; @@ -1135,15 +1180,50 @@ static int rmnet_mhi_probe(struct platform_device *pdev) } rc = of_property_read_u32(pdev->dev.of_node, + "cell-index", + &rmnet_mhi_ptr->dev_id); + if (unlikely(rc)) { + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "failed to get valid 'cell-index'\n"); + goto probe_fail; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mhi-max-mru", + &rmnet_mhi_ptr->max_mru); + if (likely(rc)) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "max-mru not defined, setting to max %d\n", + MHI_MAX_MRU); + rmnet_mhi_ptr->max_mru = MHI_MAX_MRU; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mhi-max-mtu", + &rmnet_mhi_ptr->max_mtu); + if (likely(rc)) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "max-mtu not defined, setting to max %d\n", + MHI_MAX_MTU); + rmnet_mhi_ptr->max_mtu = MHI_MAX_MTU; + } + + client_info.dev = &pdev->dev; + client_info.node_name = "qcom,mhi"; + client_info.mhi_client_cb = rmnet_mhi_cb; + client_info.user_data = rmnet_mhi_ptr; + + rc = of_property_read_u32(pdev->dev.of_node, "qcom,mhi-tx-channel", &channel); if (rc == 0) { rmnet_mhi_ptr->tx_channel = channel; + client_info.chan = channel; + client_info.max_payload = rmnet_mhi_ptr->max_mtu; + rc = mhi_register_channel(&rmnet_mhi_ptr->tx_client_handle, - rmnet_mhi_ptr->tx_channel, - 0, - &rmnet_mhi_info, - rmnet_mhi_ptr); + &client_info); if (unlikely(rc)) { rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, @@ -1152,6 +1232,7 @@ static int rmnet_mhi_probe(struct platform_device *pdev) rc); goto probe_fail; } + client_handle = rmnet_mhi_ptr->tx_client_handle; } rc = of_property_read_u32(pdev->dev.of_node, @@ -1159,11 +1240,10 @@ static int rmnet_mhi_probe(struct platform_device *pdev) &channel); if (rc == 0) { rmnet_mhi_ptr->rx_channel = channel; + client_info.max_payload = rmnet_mhi_ptr->max_mru; + client_info.chan = channel; rc = mhi_register_channel(&rmnet_mhi_ptr->rx_client_handle, - rmnet_mhi_ptr->rx_channel, - 0, - &rmnet_mhi_info, - rmnet_mhi_ptr); + &client_info); if (unlikely(rc)) { rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, @@ -1172,22 +1252,31 @@ static int rmnet_mhi_probe(struct platform_device *pdev) rc); goto probe_fail; } - + /* overwriting tx_client_handle is ok because dev_id and + * bdf are same for both channels + */ + client_handle = rmnet_mhi_ptr->rx_client_handle; INIT_WORK(&rmnet_mhi_ptr->alloc_work, rmnet_mhi_alloc_work); spin_lock_init(&rmnet_mhi_ptr->alloc_lock); } /* We must've have @ least one valid channel */ - if (!rmnet_mhi_ptr->rx_client_handle && - !rmnet_mhi_ptr->tx_client_handle) { + if (!client_handle) { rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, "No registered channels\n"); rc = -ENODEV; goto probe_fail; } - snprintf(node_name, sizeof(node_name), "%s%d", - RMNET_MHI_DRIVER_NAME, pdev->id); + snprintf(node_name, + sizeof(node_name), + "%s_%04x_%02u.%02u.%02u_%u", + RMNET_MHI_DRIVER_NAME, + client_handle->dev_id, + client_handle->domain, + client_handle->bus, + client_handle->slot, + rmnet_mhi_ptr->dev_id); rmnet_mhi_ptr->rmnet_ipc_log = ipc_log_context_create(RMNET_IPC_LOG_PAGES, node_name, 0); 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..dc5f6fdaa9dc 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, }, @@ -1002,24 +1002,28 @@ static void ath10k_snoc_free_irq(struct ath10k *ar) static int ath10k_snoc_get_soc_info(struct ath10k *ar) { - int ret; - struct icnss_soc_info soc_info; + struct resource *res; struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct platform_device *pdev; - memset(&soc_info, 0, sizeof(soc_info)); - - ret = icnss_get_soc_info(&soc_info); - if (ret < 0) { - ath10k_err(ar, "%s: icnss_get_soc_info error = %d", - __func__, ret); - return ret; + pdev = ar_snoc->dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase"); + if (!res) { + ath10k_err(ar, "Memory base not found in DT\n"); + return -EINVAL; } - ar_snoc->mem = soc_info.v_addr; - ar_snoc->mem_pa = soc_info.p_addr; + ar_snoc->mem_pa = res->start; + ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa, + resource_size(res)); + if (!ar_snoc->mem) { + ath10k_err(ar, "Memory base ioremap failed: phy addr: %pa\n", + &ar_snoc->mem_pa); + return -EINVAL; + } - ar_snoc->target_info.soc_version = soc_info.soc_id; - ar_snoc->target_info.target_version = soc_info.soc_id; + ar_snoc->target_info.soc_version = ATH10K_HW_WCN3990; + ar_snoc->target_info.target_version = ATH10K_HW_WCN3990; ar_snoc->target_info.target_revision = 0; ath10k_dbg(ar, ATH10K_DBG_SNOC, @@ -1034,10 +1038,8 @@ static int ath10k_snoc_get_soc_info(struct ath10k *ar) static int ath10k_snoc_wlan_enable(struct ath10k *ar) { struct icnss_wlan_enable_cfg cfg; - int pipe_num, i; + int pipe_num; struct ath10k_ce_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX]; - struct ce_tgt_pipe_cfg *tmp_tgt_cfg; - struct ce_svc_pipe_cfg *tmp_svc_cfg; for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) { tgt_cfg[pipe_num].pipe_num = @@ -1066,12 +1068,6 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar) cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) &target_shadow_reg_cfg_map; - for (i = 0; i < cfg.num_ce_tgt_cfg; i++) - tmp_tgt_cfg = cfg.ce_tgt_cfg + i; - - for (i = 0; i < cfg.num_ce_svc_pipe_cfg; i++) - tmp_svc_cfg = cfg.ce_svc_cfg + i; - return icnss_wlan_enable(&cfg, ICNSS_MISSION, "5.1.0.26N"); } diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index a0acb2d0cb79..7260bef314a4 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -80,12 +80,20 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) } } - if (wil->platform_ops.suspend) + /* Disable PCIe IRQ to prevent sporadic IRQs when PCIe is suspending */ + wil_dbg_pm(wil, "Disabling PCIe IRQ before suspending\n"); + wil_disable_irq(wil); + + if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle); + if (rc) + wil_enable_irq(wil); + } out: wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); + return rc; } @@ -104,6 +112,9 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) } } + wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); + wil_enable_irq(wil); + /* if netif up, bring hardware up * During open(), IFF_UP set after actual device method * invocation. This prevent recursive call to wil_up() diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index dff565d9e206..8502d71519f4 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2743,9 +2743,10 @@ void gsi_get_inst_ram_offset_and_size(unsigned long *base_offset, unsigned long *size) { if (base_offset) - *base_offset = GSI_GSI_INST_RAM_BASE_OFFS; + *base_offset = GSI_GSI_INST_RAM_n_OFFS(0); if (size) - *size = GSI_GSI_INST_RAM_SIZE; + *size = GSI_GSI_INST_RAM_n_WORD_SZ * + (GSI_GSI_INST_RAM_n_MAXn + 1); } EXPORT_SYMBOL(gsi_get_inst_ram_offset_and_size); diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h index d0462aad72d2..653cdd4823c6 100644 --- a/drivers/platform/msm/gsi/gsi_reg.h +++ b/drivers/platform/msm/gsi/gsi_reg.h @@ -688,8 +688,9 @@ #define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff #define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 +#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 #define GSI_GSI_INST_RAM_n_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00004000 + 0x4 * (n)) + (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) #define GSI_GSI_INST_RAM_n_RMSK 0xffffffff #define GSI_GSI_INST_RAM_n_MAXn 4095 #define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 @@ -1842,7 +1843,5 @@ #define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff #define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 -#define GSI_GSI_INST_RAM_BASE_OFFS 0x4000 -#define GSI_GSI_INST_RAM_SIZE 0x4000 #endif /* __GSI_REG_H__ */ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index a2665c9e9688..25364e8efa38 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -1974,6 +1974,8 @@ static void ipa_cleanup_wlan_rx_common_cache(void) struct ipa_rx_pkt_wrapper *rx_pkt; struct ipa_rx_pkt_wrapper *tmp; + spin_lock_bh(&ipa_ctx->wc_memb.wlan_spinlock); + list_for_each_entry_safe(rx_pkt, tmp, &ipa_ctx->wc_memb.wlan_comm_desc_list, link) { list_del(&rx_pkt->link); @@ -1994,6 +1996,8 @@ static void ipa_cleanup_wlan_rx_common_cache(void) IPAERR("wlan comm buff total cnt: %d\n", ipa_ctx->wc_memb.wlan_comm_total_cnt); + spin_unlock_bh(&ipa_ctx->wc_memb.wlan_spinlock); + } static void ipa_alloc_wlan_rx_common_cache(u32 size) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c index e2ac9bfceed7..119d17cae9f5 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c @@ -655,9 +655,8 @@ int qmi_filter_notify_send(struct ipa_fltr_installed_notif_req_msg_v01 *req) /* check if the filter rules from IPACM is valid */ if (req->filter_index_list_len == 0) { - IPAWANERR(" delete UL filter rule for pipe %d\n", + IPAWANDBG(" delete UL filter rule for pipe %d\n", req->source_pipe_index); - return -EINVAL; } else if (req->filter_index_list_len > QMI_IPA_MAX_FILTERS_V01) { IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n", req->source_pipe_index, diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c index d14f8da15595..00d52d0d9115 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c @@ -361,6 +361,7 @@ int ipa2_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, ep_dl->uc_offload_state |= IPA_UC_OFFLOAD_CONNECTED; IPAERR("client %d (ep: %d) connected\n", in->dl.client, ipa_ep_idx_dl); + ipa_inc_acquire_wakelock(IPA_WAKELOCK_REF_CLIENT_ODU_RX); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); @@ -436,6 +437,7 @@ int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, ipa_disable_data_path(ipa_ep_idx_dl); memset(&ipa_ctx->ep[ipa_ep_idx_dl], 0, sizeof(struct ipa_ep_context)); IPADBG("dl client (ep: %d) disconnected\n", ipa_ep_idx_dl); + ipa_dec_release_wakelock(IPA_WAKELOCK_REF_CLIENT_ODU_RX); fail: dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 3086311b5c2a..335e5283cc29 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -786,9 +786,8 @@ int ipa3_qmi_filter_notify_send( /* check if the filter rules from IPACM is valid */ if (req->rule_id_len == 0) { - IPAWANERR(" delete UL filter rule for pipe %d\n", + IPAWANDBG(" delete UL filter rule for pipe %d\n", req->source_pipe_index); - return -EINVAL; } else if (req->rule_id_len > QMI_IPA_MAX_FILTERS_V01) { IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n", req->source_pipe_index, diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h index 3d40d114437a..4bce96102525 100644 --- a/drivers/platform/msm/mhi/mhi.h +++ b/drivers/platform/msm/mhi/mhi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,7 +29,6 @@ #include <linux/list.h> #include <linux/dma-mapping.h> -extern struct mhi_pcie_devices mhi_devices; struct mhi_device_ctxt; enum MHI_DEBUG_LEVEL { @@ -49,23 +48,56 @@ struct pcie_core_info { u32 mhi_ver; void __iomem *bar0_base; void __iomem *bar0_end; - void __iomem *bar2_base; - void __iomem *bar2_end; u32 irq_base; u32 max_nr_msis; + u32 domain; + u32 bus; + u32 slot; struct pci_saved_state *pcie_state; + bool pci_master; +}; + +struct firmware_info { + const char *fw_image; + size_t max_sbl_len; + size_t segment_size; +}; + +struct bhie_mem_info { + void *pre_aligned; + void *aligned; + size_t alloc_size; + size_t size; + phys_addr_t phys_addr; + dma_addr_t dma_handle; +}; + +struct bhie_vec_table { + struct scatterlist *sg_list; + struct bhie_mem_info *bhie_mem_info; + struct bhi_vec_entry *bhi_vec_entry; + unsigned segment_count; + u32 sequence; /* sequence to indicate new xfer */ }; struct bhi_ctxt_t { void __iomem *bhi_base; + void *unaligned_image_loc; + dma_addr_t dma_handle; + size_t alloc_size; void *image_loc; dma_addr_t phy_image_loc; size_t image_size; - void *unaligned_image_loc; dev_t bhi_dev; struct cdev cdev; - struct class *bhi_class; struct device *dev; + u32 alignment; + u32 poll_timeout; + /* BHI/E vector table */ + bool manage_boot; /* fw download done by MHI host */ + struct work_struct fw_load_work; + struct firmware_info firmware_info; + struct bhie_vec_table fw_table; }; enum MHI_CHAN_DIR { @@ -316,6 +348,11 @@ struct mhi_ring { u32 msi_disable_cntr; u32 msi_enable_cntr; spinlock_t ring_lock; + struct dma_pool *dma_pool; + struct tasklet_struct ev_task; + struct work_struct ev_worker; + struct mhi_device_ctxt *mhi_dev_ctxt; + int index; }; enum MHI_CMD_STATUS { @@ -344,25 +381,27 @@ enum MHI_INIT_ERROR_STAGE { }; enum STATE_TRANSITION { - STATE_TRANSITION_RESET = 0x0, - STATE_TRANSITION_READY = 0x1, - STATE_TRANSITION_M0 = 0x2, - STATE_TRANSITION_M1 = 0x3, - STATE_TRANSITION_M2 = 0x4, - STATE_TRANSITION_M3 = 0x5, - STATE_TRANSITION_BHI = 0x6, - STATE_TRANSITION_SBL = 0x7, - STATE_TRANSITION_AMSS = 0x8, - STATE_TRANSITION_LINK_DOWN = 0x9, - STATE_TRANSITION_WAKE = 0xA, - STATE_TRANSITION_SYS_ERR = 0xFF, - STATE_TRANSITION_reserved = 0x80000000 + STATE_TRANSITION_RESET = MHI_STATE_RESET, + STATE_TRANSITION_READY = MHI_STATE_READY, + STATE_TRANSITION_M0 = MHI_STATE_M0, + STATE_TRANSITION_M1 = MHI_STATE_M1, + STATE_TRANSITION_M2 = MHI_STATE_M2, + STATE_TRANSITION_M3 = MHI_STATE_M3, + STATE_TRANSITION_BHI, + STATE_TRANSITION_SBL, + STATE_TRANSITION_AMSS, + STATE_TRANSITION_LINK_DOWN, + STATE_TRANSITION_WAKE, + STATE_TRANSITION_BHIE, + STATE_TRANSITION_SYS_ERR, + STATE_TRANSITION_MAX }; enum MHI_EXEC_ENV { MHI_EXEC_ENV_PBL = 0x0, MHI_EXEC_ENV_SBL = 0x1, MHI_EXEC_ENV_AMSS = 0x2, + MHI_EXEC_ENV_BHIE = 0x3, MHI_EXEC_ENV_reserved = 0x80000000 }; @@ -382,7 +421,7 @@ struct mhi_chan_cfg { union mhi_cmd_pkt cmd_pkt; }; -struct mhi_client_handle { +struct mhi_client_config { struct mhi_chan_info chan_info; struct mhi_device_ctxt *mhi_dev_ctxt; struct mhi_client_info_t client_info; @@ -412,9 +451,12 @@ struct mhi_state_work_queue { struct mhi_buf_info { dma_addr_t bb_p_addr; + dma_addr_t pre_alloc_p_addr; void *bb_v_addr; + void *pre_alloc_v_addr; void *client_buf; size_t buf_len; + size_t pre_alloc_len; size_t filled_size; enum dma_data_direction dir; int bb_active; @@ -431,23 +473,19 @@ struct mhi_counters { u32 bb_used[MHI_MAX_CHANNELS]; atomic_t device_wake; atomic_t outbound_acks; - atomic_t events_pending; u32 *msi_counter; u32 mhi_reset_cntr; + u32 link_down_cntr; + u32 link_up_cntr; }; struct mhi_flags { u32 mhi_initialized; u32 link_up; - int stop_threads; - u32 kill_threads; - u32 ev_thread_stopped; - u32 st_thread_stopped; + bool bb_required; }; struct mhi_wait_queues { - wait_queue_head_t *mhi_event_wq; - wait_queue_head_t *state_change_event; wait_queue_head_t *m0_event; wait_queue_head_t *m3_event; wait_queue_head_t *bhi_event; @@ -486,13 +524,17 @@ struct mhi_dev_space { }; struct mhi_device_ctxt { + struct list_head node; + struct pcie_core_info core; + struct msm_pcie_register_event mhi_pci_link_event; + struct pci_dev *pcie_device; + struct bhi_ctxt_t bhi_ctxt; + struct platform_device *plat_dev; enum MHI_PM_STATE mhi_pm_state; /* Host driver state */ enum MHI_STATE mhi_state; /* protocol state */ enum MHI_EXEC_ENV dev_exec_env; struct mhi_dev_space dev_space; - struct mhi_pcie_dev_info *dev_info; - struct pcie_core_info *dev_props; struct mhi_ring chan_bb_list[MHI_MAX_CHANNELS]; struct mhi_ring mhi_local_chan_ctxt[MHI_MAX_CHANNELS]; @@ -500,12 +542,9 @@ struct mhi_device_ctxt { struct mhi_ring mhi_local_cmd_ctxt[NR_OF_CMD_RINGS]; struct mhi_chan_cfg mhi_chan_cfg[MHI_MAX_CHANNELS]; - struct mhi_client_handle *client_handle_list[MHI_MAX_CHANNELS]; struct mhi_event_ring_cfg *ev_ring_props; - struct task_struct *event_thread_handle; - struct task_struct *st_thread_handle; - struct tasklet_struct ev_task; /* Process control Events */ + struct work_struct st_thread_worker; struct work_struct process_m1_worker; struct mhi_wait_queues mhi_ev_wq; struct dev_mmio_info mmio_info; @@ -517,7 +556,9 @@ struct mhi_device_ctxt { struct hrtimer m1_timer; ktime_t m1_timeout; + u32 poll_reset_timeout_ms; + struct notifier_block mhi_ssr_nb; struct esoc_desc *esoc_handle; void *esoc_ssr_handle; @@ -534,35 +575,47 @@ struct mhi_device_ctxt { struct wakeup_source w_lock; char *chan_info; - struct dentry *mhi_parent_folder; -}; + struct dentry *child; + struct dentry *parent; + void *mhi_ipc_log; + + /* Shadow functions since not all device supports runtime pm */ + int (*bus_master_rt_get)(struct pci_dev *pci_dev); + void (*bus_master_rt_put)(struct pci_dev *pci_dev); + void (*runtime_get)(struct mhi_device_ctxt *mhi_dev_ctxt); + void (*runtime_put)(struct mhi_device_ctxt *mhi_dev_ctxt); + void (*assert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt, + bool force_set); + void (*deassert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt); -struct mhi_pcie_dev_info { - struct pcie_core_info core; - struct mhi_device_ctxt mhi_ctxt; - struct msm_pcie_register_event mhi_pci_link_event; - struct pci_dev *pcie_device; - struct pci_driver *mhi_pcie_driver; - struct bhi_ctxt_t bhi_ctxt; - struct platform_device *plat_dev; - u32 link_down_cntr; - u32 link_up_cntr; + struct completion cmd_complete; }; -struct mhi_pcie_devices { - struct mhi_pcie_dev_info device_list[MHI_MAX_SUPPORTED_DEVICES]; - s32 nr_of_devices; +struct mhi_device_driver { + struct mutex lock; + struct list_head head; + struct class *mhi_bhi_class; + struct dentry *parent; }; struct mhi_event_ring_cfg { u32 nr_desc; u32 msi_vec; u32 intmod; + enum MHI_CLIENT_CHANNEL chan; u32 flags; + /* + * Priority of event handling: + * 0 = highest, handle events in isr (reserved for future) + * 1 = handles event using tasklet + * 2 = handles events using workerthread + */ + u32 priority; enum MHI_RING_CLASS class; enum MHI_EVENT_RING_STATE state; irqreturn_t (*mhi_handler_ptr)(int , void *); }; +#define MHI_EV_PRIORITY_TASKLET (1) struct mhi_data_buf { dma_addr_t bounce_buffer; @@ -570,18 +623,20 @@ struct mhi_data_buf { u32 bounce_flag; }; +extern struct mhi_device_driver *mhi_device_drv; + irqreturn_t mhi_msi_ipa_handlr(int irq_number, void *dev_id); int mhi_reset_all_thread_queues( struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_add_elements_to_event_rings( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION new_state); -int get_nr_avail_ring_elements(struct mhi_ring *ring); +int get_nr_avail_ring_elements(struct mhi_device_ctxt *mhi_dev_ctxt, + struct mhi_ring *ring); int get_nr_enclosed_el(struct mhi_ring *ring, void *loc_1, void *loc_2, u32 *nr_el); int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt); -int mhi_init_device_ctxt(struct mhi_pcie_dev_info *dev_info, - struct mhi_device_ctxt *mhi_dev_ctxt); +int mhi_init_device_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_init_local_event_ring(struct mhi_device_ctxt *mhi_dev_ctxt, u32 nr_ev_el, u32 event_ring_index); int mhi_send_cmd(struct mhi_device_ctxt *dest_device, @@ -618,25 +673,24 @@ enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt, union mhi_cmd_pkt **cmd_pkt, u32 event_index); int parse_cmd_event(struct mhi_device_ctxt *ctxt, union mhi_event_pkt *event, u32 event_index); -int parse_event_thread(void *ctxt); int mhi_test_for_device_ready( struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_test_for_device_reset( struct mhi_device_ctxt *mhi_dev_ctxt); int validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr); int validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr); -int mhi_state_change_thread(void *ctxt); +void mhi_state_change_worker(struct work_struct *work); int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION new_state); int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt); enum hrtimer_restart mhi_initiate_m1(struct hrtimer *timer); int mhi_pci_suspend(struct device *dev); int mhi_pci_resume(struct device *dev); -int mhi_init_pcie_device(struct mhi_pcie_dev_info *mhi_pcie_dev); +int mhi_init_pcie_device(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_init_pm_sysfs(struct device *dev); void mhi_rem_pm_sysfs(struct device *dev); void mhi_pci_remove(struct pci_dev *mhi_device); -int mhi_ctxt_init(struct mhi_pcie_dev_info *mhi_pcie_dev); +int mhi_ctxt_init(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_get_chan_max_buffers(u32 chan); int mhi_esoc_register(struct mhi_device_ctxt *mhi_dev_ctxt); void mhi_link_state_cb(struct msm_pcie_notify *notify); @@ -644,6 +698,10 @@ void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_CB_REASON reason); void mhi_notify_client(struct mhi_client_handle *client_handle, enum MHI_CB_REASON reason); +void mhi_master_mode_runtime_get(struct mhi_device_ctxt *mhi_dev_ctxt); +void mhi_master_mode_runtime_put(struct mhi_device_ctxt *mhi_dev_ctxt); +void mhi_slave_mode_runtime_get(struct mhi_device_ctxt *mhi_dev_ctxt); +void mhi_slave_mode_runtime_put(struct mhi_device_ctxt *mhi_dev_ctxt); void mhi_deassert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt); void mhi_assert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt, bool force_set); @@ -691,10 +749,13 @@ void init_event_ctxt_array(struct mhi_device_ctxt *mhi_dev_ctxt); int create_local_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt); enum MHI_STATE mhi_get_m_state(struct mhi_device_ctxt *mhi_dev_ctxt); void process_m1_transition(struct work_struct *work); -int set_mhi_base_state(struct mhi_pcie_dev_info *mhi_pcie_dev); +int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt); void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_STATE new_state); const char *state_transition_str(enum STATE_TRANSITION state); -void mhi_ctrl_ev_task(unsigned long data); +void mhi_ev_task(unsigned long data); +void process_event_ring(struct work_struct *work); +int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt); +int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt); #endif diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index 113791a62c38..0cc8967757ec 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include <linux/firmware.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/slab.h> @@ -23,89 +24,207 @@ static int bhi_open(struct inode *mhi_inode, struct file *file_handle) { - file_handle->private_data = &mhi_devices.device_list[0]; + struct mhi_device_ctxt *mhi_dev_ctxt; + + mhi_dev_ctxt = container_of(mhi_inode->i_cdev, + struct mhi_device_ctxt, + bhi_ctxt.cdev); + file_handle->private_data = mhi_dev_ctxt; return 0; } -static ssize_t bhi_write(struct file *file, - const char __user *buf, - size_t count, loff_t *offp) +static int bhi_alloc_bhie_xfer(struct mhi_device_ctxt *mhi_dev_ctxt, + size_t size, + struct bhie_vec_table *vec_table) { - int ret_val = 0; - u32 pcie_word_val = 0; - u32 i = 0; - struct bhi_ctxt_t *bhi_ctxt = - &(((struct mhi_pcie_dev_info *)file->private_data)->bhi_ctxt); - struct mhi_device_ctxt *mhi_dev_ctxt = - &((struct mhi_pcie_dev_info *)file->private_data)->mhi_ctxt; - size_t amount_copied = 0; - uintptr_t align_len = 0x1000; - u32 tx_db_val = 0; - rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; - const long bhi_timeout_ms = 1000; - long timeout; + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct device *dev = &mhi_dev_ctxt->plat_dev->dev; + const phys_addr_t align = bhi_ctxt->alignment - 1; + size_t seg_size = bhi_ctxt->firmware_info.segment_size; + /* We need one additional entry for Vector Table */ + int segments = DIV_ROUND_UP(size, seg_size) + 1; + int i; + struct scatterlist *sg_list; + struct bhie_mem_info *bhie_mem_info, *info; - if (buf == NULL || 0 == count) - return -EIO; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Total size:%lu total_seg:%d seg_size:%lu\n", + size, segments, seg_size); - if (count > BHI_MAX_IMAGE_SIZE) + sg_list = kcalloc(segments, sizeof(*sg_list), GFP_KERNEL); + if (!sg_list) return -ENOMEM; - timeout = wait_event_interruptible_timeout( - *mhi_dev_ctxt->mhi_ev_wq.bhi_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_BHI, - msecs_to_jiffies(bhi_timeout_ms)); - if (timeout <= 0 && mhi_dev_ctxt->mhi_state != MHI_STATE_BHI) - return -EIO; + bhie_mem_info = kcalloc(segments, sizeof(*bhie_mem_info), GFP_KERNEL); + if (!bhie_mem_info) + goto alloc_bhi_mem_info_error; - mhi_log(MHI_MSG_INFO, "Entered. User Image size 0x%zx\n", count); + /* Allocate buffers for bhi/e vector table */ + for (i = 0; i < segments; i++) { + size_t size = seg_size; - bhi_ctxt->unaligned_image_loc = kmalloc(count + (align_len - 1), - GFP_KERNEL); + /* Last entry if for vector table */ + if (i == segments - 1) + size = sizeof(struct bhi_vec_entry) * i; + info = &bhie_mem_info[i]; + info->size = size; + info->alloc_size = info->size + align; + info->pre_aligned = + dma_alloc_coherent(dev, info->alloc_size, + &info->dma_handle, GFP_KERNEL); + if (!info->pre_aligned) + goto alloc_dma_error; + + info->phys_addr = (info->dma_handle + align) & ~align; + info->aligned = info->pre_aligned + + (info->phys_addr - info->dma_handle); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Seg:%d unaligned Img: 0x%llx aligned:0x%llx\n", + i, info->dma_handle, info->phys_addr); + } + + sg_init_table(sg_list, segments); + sg_set_buf(sg_list, info->aligned, info->size); + sg_dma_address(sg_list) = info->phys_addr; + sg_dma_len(sg_list) = info->size; + vec_table->sg_list = sg_list; + vec_table->bhie_mem_info = bhie_mem_info; + vec_table->bhi_vec_entry = info->aligned; + vec_table->segment_count = segments; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "BHI/E table successfully allocated\n"); + return 0; + +alloc_dma_error: + for (i = i - 1; i >= 0; i--) + dma_free_coherent(dev, + bhie_mem_info[i].alloc_size, + bhie_mem_info[i].pre_aligned, + bhie_mem_info[i].dma_handle); + kfree(bhie_mem_info); +alloc_bhi_mem_info_error: + kfree(sg_list); + return -ENOMEM; +} + +static int bhi_alloc_pbl_xfer(struct mhi_device_ctxt *mhi_dev_ctxt, + size_t size) +{ + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + const phys_addr_t align_len = bhi_ctxt->alignment; + size_t alloc_size = size + (align_len - 1); + struct device *dev = &mhi_dev_ctxt->plat_dev->dev; + + bhi_ctxt->unaligned_image_loc = + dma_alloc_coherent(dev, alloc_size, &bhi_ctxt->dma_handle, + GFP_KERNEL); if (bhi_ctxt->unaligned_image_loc == NULL) return -ENOMEM; - mhi_log(MHI_MSG_INFO, "Unaligned Img Loc: %p\n", - bhi_ctxt->unaligned_image_loc); - bhi_ctxt->image_loc = - (void *)((uintptr_t)bhi_ctxt->unaligned_image_loc + - (align_len - (((uintptr_t)bhi_ctxt->unaligned_image_loc) % - align_len))); + bhi_ctxt->alloc_size = alloc_size; + bhi_ctxt->phy_image_loc = (bhi_ctxt->dma_handle + (align_len - 1)) & + ~(align_len - 1); + bhi_ctxt->image_loc = bhi_ctxt->unaligned_image_loc + + (bhi_ctxt->phy_image_loc - bhi_ctxt->dma_handle); + bhi_ctxt->image_size = size; - mhi_log(MHI_MSG_INFO, "Aligned Img Loc: %p\n", bhi_ctxt->image_loc); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "alloc_size:%lu image_size:%lu unal_addr:0x%llx0x al_addr:0x%llx\n", + bhi_ctxt->alloc_size, bhi_ctxt->image_size, + bhi_ctxt->dma_handle, bhi_ctxt->phy_image_loc); - bhi_ctxt->image_size = count; + return 0; +} - if (0 != copy_from_user(bhi_ctxt->image_loc, buf, count)) { - ret_val = -ENOMEM; - goto bhi_copy_error; +/* Load firmware via bhie protocol */ +static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table; + const struct bhie_mem_info *bhie_mem_info = + &fw_table->bhie_mem_info[fw_table->segment_count - 1]; + u32 val; + const u32 tx_sequence = fw_table->sequence++; + unsigned long timeout; + rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; + + /* Program TX/RX Vector table */ + read_lock_bh(pm_xfer_lock); + if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + read_unlock_bh(pm_xfer_lock); + return -EIO; } - amount_copied = count; - /* Flush the writes, in anticipation for a device read */ - wmb(); - mhi_log(MHI_MSG_INFO, - "Copied image from user at addr: %p\n", bhi_ctxt->image_loc); - bhi_ctxt->phy_image_loc = dma_map_single( - &mhi_dev_ctxt->dev_info->plat_dev->dev, - bhi_ctxt->image_loc, - bhi_ctxt->image_size, - DMA_TO_DEVICE); - - if (dma_mapping_error(NULL, bhi_ctxt->phy_image_loc)) { - ret_val = -EIO; - goto bhi_copy_error; + + val = HIGH_WORD(bhie_mem_info->phys_addr); + mhi_reg_write(mhi_dev_ctxt, + bhi_ctxt->bhi_base, + BHIE_TXVECADDR_HIGH_OFFS, + val); + val = LOW_WORD(bhie_mem_info->phys_addr); + mhi_reg_write(mhi_dev_ctxt, + bhi_ctxt->bhi_base, + BHIE_TXVECADDR_LOW_OFFS, + val); + val = (u32)bhie_mem_info->size; + mhi_reg_write(mhi_dev_ctxt, + bhi_ctxt->bhi_base, + BHIE_TXVECSIZE_OFFS, + val); + + /* Ring DB to begin Xfer */ + mhi_reg_write_field(mhi_dev_ctxt, + bhi_ctxt->bhi_base, + BHIE_TXVECDB_OFFS, + BHIE_TXVECDB_SEQNUM_BMSK, + BHIE_TXVECDB_SEQNUM_SHFT, + tx_sequence); + read_unlock_bh(pm_xfer_lock); + + timeout = jiffies + msecs_to_jiffies(bhi_ctxt->poll_timeout); + while (time_before(jiffies, timeout)) { + u32 current_seq, status; + + read_lock_bh(pm_xfer_lock); + if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + read_unlock_bh(pm_xfer_lock); + return -EIO; + } + val = mhi_reg_read(bhi_ctxt->bhi_base, BHIE_TXVECSTATUS_OFFS); + read_unlock_bh(pm_xfer_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "TXVEC_STATUS:0x%x\n", val); + current_seq = (val & BHIE_TXVECSTATUS_SEQNUM_BMSK) >> + BHIE_TXVECSTATUS_SEQNUM_SHFT; + status = (val & BHIE_TXVECSTATUS_STATUS_BMSK) >> + BHIE_TXVECSTATUS_STATUS_SHFT; + if ((status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) && + (current_seq == tx_sequence)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Image transfer complete\n"); + return 0; + } + msleep(BHI_POLL_SLEEP_TIME_MS); } - mhi_log(MHI_MSG_INFO, - "Mapped image to DMA addr 0x%lx:\n", - (uintptr_t)bhi_ctxt->phy_image_loc); - bhi_ctxt->image_size = count; + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error xfering image via BHIE\n"); + return -EIO; +} + +static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + u32 pcie_word_val = 0; + u32 tx_db_val = 0; + unsigned long timeout; + rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; /* Write the image size */ read_lock_bh(pm_xfer_lock); if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { read_unlock_bh(pm_xfer_lock); - goto bhi_copy_error; + return -EIO; } pcie_word_val = HIGH_WORD(bhi_ctxt->phy_image_loc); mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, @@ -129,16 +248,15 @@ static ssize_t bhi_write(struct file *file, pcie_word_val = mhi_reg_read(bhi_ctxt->bhi_base, BHI_IMGTXDB); mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGTXDB, 0xFFFFFFFF, 0, ++pcie_word_val); - - mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_INTVEC, 0); read_unlock_bh(pm_xfer_lock); - for (i = 0; i < BHI_POLL_NR_RETRIES; ++i) { + timeout = jiffies + msecs_to_jiffies(bhi_ctxt->poll_timeout); + while (time_before(jiffies, timeout)) { u32 err = 0, errdbg1 = 0, errdbg2 = 0, errdbg3 = 0; read_lock_bh(pm_xfer_lock); if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { read_unlock_bh(pm_xfer_lock); - goto bhi_copy_error; + return -EIO; } err = mhi_reg_read(bhi_ctxt->bhi_base, BHI_ERRCODE); errdbg1 = mhi_reg_read(bhi_ctxt->bhi_base, BHI_ERRDBG1); @@ -149,34 +267,83 @@ static ssize_t bhi_write(struct file *file, BHI_STATUS_MASK, BHI_STATUS_SHIFT); read_unlock_bh(pm_xfer_lock); - mhi_log(MHI_MSG_CRITICAL, - "BHI STATUS 0x%x, err:0x%x errdbg1:0x%x errdbg2:0x%x errdbg3:0x%x\n", - tx_db_val, err, errdbg1, errdbg2, errdbg3); - if (BHI_STATUS_SUCCESS != tx_db_val) - mhi_log(MHI_MSG_CRITICAL, - "Incorrect BHI status: %d retry: %d\n", - tx_db_val, i); - else + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "%s 0x%x %s:0x%x %s:0x%x %s:0x%x %s:0x%x\n", + "BHI STATUS", tx_db_val, + "err", err, + "errdbg1", errdbg1, + "errdbg2", errdbg2, + "errdbg3", errdbg3); + if (tx_db_val == BHI_STATUS_SUCCESS) break; - usleep_range(20000, 25000); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "retrying...\n"); + msleep(BHI_POLL_SLEEP_TIME_MS); + } + + return (tx_db_val == BHI_STATUS_SUCCESS) ? 0 : -EIO; +} + +static ssize_t bhi_write(struct file *file, + const char __user *buf, + size_t count, loff_t *offp) +{ + int ret_val = 0; + struct mhi_device_ctxt *mhi_dev_ctxt = file->private_data; + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + long timeout; + + if (buf == NULL || 0 == count) + return -EIO; + + if (count > BHI_MAX_IMAGE_SIZE) + return -ENOMEM; + + ret_val = bhi_alloc_pbl_xfer(mhi_dev_ctxt, count); + if (ret_val) + return -ENOMEM; + + if (copy_from_user(bhi_ctxt->image_loc, buf, count)) { + ret_val = -ENOMEM; + goto bhi_copy_error; } - dma_unmap_single(&mhi_dev_ctxt->dev_info->plat_dev->dev, - bhi_ctxt->phy_image_loc, - bhi_ctxt->image_size, DMA_TO_DEVICE); - kfree(bhi_ctxt->unaligned_image_loc); + timeout = wait_event_interruptible_timeout( + *mhi_dev_ctxt->mhi_ev_wq.bhi_event, + mhi_dev_ctxt->mhi_state == MHI_STATE_BHI, + msecs_to_jiffies(bhi_ctxt->poll_timeout)); + if (timeout <= 0 && mhi_dev_ctxt->mhi_state != MHI_STATE_BHI) { + ret_val = -EIO; + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Timed out waiting for BHI\n"); + goto bhi_copy_error; + } + ret_val = bhi_load_firmware(mhi_dev_ctxt); + if (ret_val) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to load bhi image\n"); + } + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, + bhi_ctxt->alloc_size, + bhi_ctxt->unaligned_image_loc, + bhi_ctxt->dma_handle); + + /* Regardless of failure set to RESET state */ ret_val = mhi_init_state_transition(mhi_dev_ctxt, STATE_TRANSITION_RESET); if (ret_val) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to start state change event\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to start state change event\n"); } - return amount_copied; + return count; bhi_copy_error: - kfree(bhi_ctxt->unaligned_image_loc); - return amount_copied; + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, + bhi_ctxt->alloc_size, + bhi_ctxt->unaligned_image_loc, + bhi_ctxt->dma_handle); + + return ret_val; } static const struct file_operations bhi_fops = { @@ -184,48 +351,159 @@ static const struct file_operations bhi_fops = { .open = bhi_open, }; -int bhi_probe(struct mhi_pcie_dev_info *mhi_pcie_device) +int bhi_expose_dev_bhi(struct mhi_device_ctxt *mhi_dev_ctxt) { - struct bhi_ctxt_t *bhi_ctxt = &mhi_pcie_device->bhi_ctxt; - int ret_val = 0; - int r; + int ret_val; + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + const struct pcie_core_info *core = &mhi_dev_ctxt->core; + char node_name[32]; - if (NULL == mhi_pcie_device || 0 == mhi_pcie_device->core.bar0_base - || 0 == mhi_pcie_device->core.bar0_end) - return -EIO; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Creating dev node\n"); ret_val = alloc_chrdev_region(&bhi_ctxt->bhi_dev, 0, 1, "bhi"); if (IS_ERR_VALUE(ret_val)) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to alloc char device %d\n", - ret_val); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to alloc char device %d\n", ret_val); return -EIO; } - bhi_ctxt->bhi_class = class_create(THIS_MODULE, "bhi"); - if (IS_ERR(bhi_ctxt->bhi_class)) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to instantiate class %d\n", - ret_val); - r = PTR_RET(bhi_ctxt->bhi_class); - goto err_class_create; - } cdev_init(&bhi_ctxt->cdev, &bhi_fops); bhi_ctxt->cdev.owner = THIS_MODULE; ret_val = cdev_add(&bhi_ctxt->cdev, bhi_ctxt->bhi_dev, 1); - bhi_ctxt->dev = device_create(bhi_ctxt->bhi_class, NULL, - bhi_ctxt->bhi_dev, NULL, - "bhi"); + snprintf(node_name, sizeof(node_name), + "bhi_%04X_%02u.%02u.%02u", + core->dev_id, core->domain, core->bus, core->slot); + bhi_ctxt->dev = device_create(mhi_device_drv->mhi_bhi_class, + NULL, + bhi_ctxt->bhi_dev, + NULL, + node_name); if (IS_ERR(bhi_ctxt->dev)) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to add bhi cdev\n"); - r = PTR_RET(bhi_ctxt->dev); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to add bhi cdev\n"); + ret_val = PTR_RET(bhi_ctxt->dev); goto err_dev_create; } return 0; + err_dev_create: cdev_del(&bhi_ctxt->cdev); - class_destroy(bhi_ctxt->bhi_class); -err_class_create: unregister_chrdev_region(MAJOR(bhi_ctxt->bhi_dev), 1); - return r; + return ret_val; +} + +void bhi_firmware_download(struct work_struct *work) +{ + struct mhi_device_ctxt *mhi_dev_ctxt; + struct bhi_ctxt_t *bhi_ctxt; + int ret; + long timeout; + + mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt, + bhi_ctxt.fw_load_work); + bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n"); + + wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, + mhi_dev_ctxt->mhi_state == MHI_STATE_BHI); + + ret = bhi_load_firmware(mhi_dev_ctxt); + if (ret) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to Load sbl firmware\n"); + return; + } + mhi_init_state_transition(mhi_dev_ctxt, + STATE_TRANSITION_RESET); + + timeout = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, + mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE, + msecs_to_jiffies(bhi_ctxt->poll_timeout)); + if (!timeout) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to Enter EXEC_ENV_BHIE\n"); + return; + } + + ret = bhi_load_bhie_firmware(mhi_dev_ctxt); + if (ret) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to Load amss firmware\n"); + } +} + +int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct firmware_info *fw_info = &bhi_ctxt->firmware_info; + struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table; + const struct firmware *firmware; + struct scatterlist *itr; + int ret, i; + size_t remainder; + const u8 *image; + + /* expose dev node to userspace */ + if (bhi_ctxt->manage_boot == false) + return bhi_expose_dev_bhi(mhi_dev_ctxt); + + /* Make sure minimum buffer we allocate for BHI/E is >= sbl image */ + while (fw_info->segment_size < fw_info->max_sbl_len) + fw_info->segment_size <<= 1; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "max sbl image size:%lu segment size:%lu\n", + fw_info->max_sbl_len, fw_info->segment_size); + + /* Read the fw image */ + ret = request_firmware(&firmware, fw_info->fw_image, + &mhi_dev_ctxt->plat_dev->dev); + if (ret) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error request firmware for:%s ret:%d\n", + fw_info->fw_image, ret); + return ret; + } + + ret = bhi_alloc_bhie_xfer(mhi_dev_ctxt, + firmware->size, + fw_table); + if (ret) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error Allocating memory for firmware image\n"); + release_firmware(firmware); + return ret; + } + + /* Copy the fw image to vector table */ + remainder = firmware->size; + image = firmware->data; + for (i = 0, itr = &fw_table->sg_list[1]; + i < fw_table->segment_count - 1; i++, itr++) { + size_t to_copy = min(remainder, fw_info->segment_size); + + memcpy(fw_table->bhie_mem_info[i].aligned, image, to_copy); + fw_table->bhi_vec_entry[i].phys_addr = + fw_table->bhie_mem_info[i].phys_addr; + fw_table->bhi_vec_entry[i].size = to_copy; + sg_set_buf(itr, fw_table->bhie_mem_info[i].aligned, to_copy); + sg_dma_address(itr) = fw_table->bhie_mem_info[i].phys_addr; + sg_dma_len(itr) = to_copy; + remainder -= to_copy; + image += to_copy; + } + + /* + * Re-use BHI/E pointer for BHI since we guranteed BHI/E segment + * is >= to SBL image. + */ + bhi_ctxt->phy_image_loc = sg_dma_address(&fw_table->sg_list[1]); + bhi_ctxt->image_size = fw_info->max_sbl_len; + + fw_table->sequence++; + release_firmware(firmware); + + /* Schedule a worker thread and wait for BHI Event */ + schedule_work(&bhi_ctxt->fw_load_work); + return 0; } diff --git a/drivers/platform/msm/mhi/mhi_bhi.h b/drivers/platform/msm/mhi/mhi_bhi.h index ca44f69cea42..15137ba5dfdf 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.h +++ b/drivers/platform/msm/mhi/mhi_bhi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,6 +42,38 @@ #define BHI_STATUS_SUCCESS (2) #define BHI_STATUS_RESET (0) +/* BHIE Offsets */ +#define BHIE_OFFSET (0x0124) /* BHIE register space offset from BHI base */ +#define BHIE_MSMSOCID_OFFS (BHIE_OFFSET + 0x0000) +#define BHIE_TXVECADDR_LOW_OFFS (BHIE_OFFSET + 0x002C) +#define BHIE_TXVECADDR_HIGH_OFFS (BHIE_OFFSET + 0x0030) +#define BHIE_TXVECSIZE_OFFS (BHIE_OFFSET + 0x0034) +#define BHIE_TXVECDB_OFFS (BHIE_OFFSET + 0x003C) +#define BHIE_TXVECDB_SEQNUM_BMSK (0x3FFFFFFF) +#define BHIE_TXVECDB_SEQNUM_SHFT (0) +#define BHIE_TXVECSTATUS_OFFS (BHIE_OFFSET + 0x0044) +#define BHIE_TXVECSTATUS_SEQNUM_BMSK (0x3FFFFFFF) +#define BHIE_TXVECSTATUS_SEQNUM_SHFT (0) +#define BHIE_TXVECSTATUS_STATUS_BMSK (0xC0000000) +#define BHIE_TXVECSTATUS_STATUS_SHFT (30) +#define BHIE_TXVECSTATUS_STATUS_RESET (0x00) +#define BHIE_TXVECSTATUS_STATUS_XFER_COMPL (0x02) +#define BHIE_TXVECSTATUS_STATUS_ERROR (0x03) +#define BHIE_RXVECADDR_LOW_OFFS (BHIE_OFFSET + 0x0060) +#define BHIE_RXVECADDR_HIGH_OFFS (BHIE_OFFSET + 0x0064) +#define BHIE_RXVECSIZE_OFFS (BHIE_OFFSET + 0x0068) +#define BHIE_RXVECDB_OFFS (BHIE_OFFSET + 0x0070) +#define BHIE_RXVECDB_SEQNUM_BMSK (0x3FFFFFFF) +#define BHIE_RXVECDB_SEQNUM_SHFT (0) +#define BHIE_RXVECSTATUS_OFFS (BHIE_OFFSET + 0x0078) +#define BHIE_RXVECSTATUS_SEQNUM_BMSK (0x3FFFFFFF) +#define BHIE_RXVECSTATUS_SEQNUM_SHFT (0) +#define BHIE_RXVECSTATUS_STATUS_BMSK (0xC0000000) +#define BHIE_RXVECSTATUS_STATUS_SHFT (30) +#define BHIE_RXVECSTATUS_STATUS_RESET (0x00) +#define BHIE_RXVECSTATUS_STATUS_XFER_COMPL (0x02) +#define BHIE_RXVECSTATUS_STATUS_ERROR (0x03) + #define BHI_MAJOR_VERSION 0x0 #define BHI_MINOR_VERSION 0x1 @@ -51,10 +83,12 @@ #define BHI_READBUF_SIZE sizeof(bhi_info_type) #define BHI_MAX_IMAGE_SIZE (256 * 1024) +#define BHI_DEFAULT_ALIGNMENT (0x1000) -#define BHI_POLL_SLEEP_TIME 1000 -#define BHI_POLL_NR_RETRIES 10 +#define BHI_POLL_SLEEP_TIME_MS 100 +#define BHI_POLL_TIMEOUT_MS 2000 -int bhi_probe(struct mhi_pcie_dev_info *mhi_pcie_device); +int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt); +void bhi_firmware_download(struct work_struct *work); #endif diff --git a/drivers/platform/msm/mhi/mhi_event.c b/drivers/platform/msm/mhi/mhi_event.c index fe163f3895a5..ae677bae63dc 100644 --- a/drivers/platform/msm/mhi/mhi_event.c +++ b/drivers/platform/msm/mhi/mhi_event.c @@ -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 @@ -26,41 +26,57 @@ int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt) int r, i; char dt_prop[MAX_BUF_SIZE]; const struct device_node *np = - mhi_dev_ctxt->dev_info->plat_dev->dev.of_node; + mhi_dev_ctxt->plat_dev->dev.of_node; r = of_property_read_u32(np, "mhi-event-rings", &mhi_dev_ctxt->mmio_info.nr_event_rings); if (r) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to pull event ring info from DT, %d\n", r); - goto dt_error; + return -EINVAL; } mhi_dev_ctxt->ev_ring_props = kzalloc(sizeof(struct mhi_event_ring_cfg) * mhi_dev_ctxt->mmio_info.nr_event_rings, GFP_KERNEL); - if (!mhi_dev_ctxt->ev_ring_props) { - r = -ENOMEM; - goto dt_error; - } + if (!mhi_dev_ctxt->ev_ring_props) + return -ENOMEM; for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i) { + u32 dt_configs[6]; + int no_elements; + scnprintf(dt_prop, MAX_BUF_SIZE, "%s%d", "mhi-event-cfg-", i); - r = of_property_read_u32_array(np, dt_prop, - (u32 *)&mhi_dev_ctxt->ev_ring_props[i], - 4); + no_elements = of_property_count_elems_of_size(np, dt_prop, + sizeof(dt_configs)); + if (no_elements != 1) + goto dt_error; + r = of_property_read_u32_array( + np, + dt_prop, + dt_configs, + sizeof(dt_configs) / sizeof(u32)); if (r) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to pull ev ring %d info from DT %d\n", i, r); goto dt_error; } - mhi_log(MHI_MSG_INFO, - "Pulled ev ring %d,desc:0x%x,msi_vec:0x%x,intmod%d flags0x%x\n", - i, mhi_dev_ctxt->ev_ring_props[i].nr_desc, - mhi_dev_ctxt->ev_ring_props[i].msi_vec, - mhi_dev_ctxt->ev_ring_props[i].intmod, - mhi_dev_ctxt->ev_ring_props[i].flags); + mhi_dev_ctxt->ev_ring_props[i].nr_desc = dt_configs[0]; + mhi_dev_ctxt->ev_ring_props[i].msi_vec = dt_configs[1]; + mhi_dev_ctxt->ev_ring_props[i].intmod = dt_configs[2]; + mhi_dev_ctxt->ev_ring_props[i].chan = dt_configs[3]; + mhi_dev_ctxt->ev_ring_props[i].priority = dt_configs[4]; + mhi_dev_ctxt->ev_ring_props[i].flags = dt_configs[5]; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "ev ring %d,desc:0x%x,msi:0x%x,intmod%d chan:%u priority:%u flags0x%x\n", + i, + mhi_dev_ctxt->ev_ring_props[i].nr_desc, + mhi_dev_ctxt->ev_ring_props[i].msi_vec, + mhi_dev_ctxt->ev_ring_props[i].intmod, + mhi_dev_ctxt->ev_ring_props[i].chan, + mhi_dev_ctxt->ev_ring_props[i].priority, + mhi_dev_ctxt->ev_ring_props[i].flags); if (GET_EV_PROPS(EV_MANAGED, mhi_dev_ctxt->ev_ring_props[i].flags)) mhi_dev_ctxt->ev_ring_props[i].mhi_handler_ptr = @@ -76,14 +92,18 @@ int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_dev_ctxt->ev_ring_props[i].class = MHI_SW_RING; mhi_dev_ctxt->mmio_info.nr_sw_event_rings++; } - mhi_log(MHI_MSG_INFO, - "Detected %d SW EV rings and %d HW EV rings out of %d EV rings\n", - mhi_dev_ctxt->mmio_info.nr_sw_event_rings, - mhi_dev_ctxt->mmio_info.nr_hw_event_rings, - mhi_dev_ctxt->mmio_info.nr_event_rings); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Detected %d SW EV rings and %d HW EV rings out of %d EV rings\n", + mhi_dev_ctxt->mmio_info.nr_sw_event_rings, + mhi_dev_ctxt->mmio_info.nr_hw_event_rings, + mhi_dev_ctxt->mmio_info.nr_event_rings); } + + return 0; dt_error: - return r; + kfree(mhi_dev_ctxt->ev_ring_props); + mhi_dev_ctxt->ev_ring_props = NULL; + return -EINVAL; } int create_local_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt) @@ -110,6 +130,9 @@ int create_local_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_local_event_ctxt[i]; spin_lock_init(&mhi_ring->ring_lock); + tasklet_init(&mhi_ring->ev_task, mhi_ev_task, + (unsigned long)mhi_ring); + INIT_WORK(&mhi_ring->ev_worker, process_event_ring); } return r; @@ -139,6 +162,8 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index) static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list, struct mhi_ring *ring, + struct mhi_device_ctxt *mhi_dev_ctxt, + int index, u32 el_per_ring, u32 intmodt_val, u32 msi_vec, @@ -148,6 +173,8 @@ static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list, ev_list->mhi_msi_vector = msi_vec; ev_list->mhi_event_ring_len = el_per_ring*sizeof(union mhi_event_pkt); MHI_SET_EV_CTXT(EVENT_CTXT_INTMODT, ev_list, intmodt_val); + ring->mhi_dev_ctxt = mhi_dev_ctxt; + ring->index = index; ring->len = ((size_t)(el_per_ring)*sizeof(union mhi_event_pkt)); ring->el_size = sizeof(union mhi_event_pkt); ring->overwrite_en = 0; @@ -180,6 +207,7 @@ void init_event_ctxt_array(struct mhi_device_ctxt *mhi_dev_ctxt) event_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[i]; mhi_local_event_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[i]; mhi_event_ring_init(event_ctxt, mhi_local_event_ctxt, + mhi_dev_ctxt, i, mhi_dev_ctxt->ev_ring_props[i].nr_desc, mhi_dev_ctxt->ev_ring_props[i].intmod, mhi_dev_ctxt->ev_ring_props[i].msi_vec, @@ -195,7 +223,7 @@ int init_local_ev_ring_by_type(struct mhi_device_ctxt *mhi_dev_ctxt, int ret_val = 0; u32 i; - mhi_log(MHI_MSG_INFO, "Entered\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++) { if (GET_EV_PROPS(EV_TYPE, mhi_dev_ctxt->ev_ring_props[i].flags) == type && @@ -207,9 +235,10 @@ int init_local_ev_ring_by_type(struct mhi_device_ctxt *mhi_dev_ctxt, return ret_val; } ring_ev_db(mhi_dev_ctxt, i); - mhi_log(MHI_MSG_INFO, "Finished ev ring init %d\n", i); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Finished ev ring init %d\n", i); } - mhi_log(MHI_MSG_INFO, "Exited\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); return 0; } @@ -228,7 +257,7 @@ int mhi_add_elements_to_event_rings(struct mhi_device_ctxt *mhi_dev_ctxt, MHI_ER_DATA_TYPE); break; default: - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Unrecognized event stage, %d\n", new_state); ret_val = -EINVAL; break; @@ -247,23 +276,18 @@ int mhi_init_local_event_ring(struct mhi_device_ctxt *mhi_dev_ctxt, &mhi_dev_ctxt->mhi_local_event_ctxt[ring_index]; spinlock_t *lock = &event_ctxt->ring_lock; - if (NULL == mhi_dev_ctxt || 0 == nr_ev_el) { - mhi_log(MHI_MSG_ERROR, "Bad Input data, quitting\n"); - return -EINVAL; - } - spin_lock_irqsave(lock, flags); - mhi_log(MHI_MSG_INFO, "mmio_addr = 0x%p, mmio_len = 0x%llx\n", - mhi_dev_ctxt->mmio_info.mmio_addr, - mhi_dev_ctxt->mmio_info.mmio_len); - mhi_log(MHI_MSG_INFO, "Initializing event ring %d with %d desc\n", - ring_index, nr_ev_el); + mhi_log(mhi_dev_ctxt, + MHI_MSG_INFO, + "Initializing event ring %d with %d desc\n", + ring_index, + nr_ev_el); for (i = 0; i < nr_ev_el - 1; ++i) { ret_val = ctxt_add_element(event_ctxt, (void *)&ev_pkt); if (0 != ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to insert el in ev ctxt\n"); break; } @@ -279,7 +303,8 @@ void mhi_reset_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_event_ctxt *ev_ctxt; struct mhi_ring *local_ev_ctxt; - mhi_log(MHI_MSG_VERBOSE, "Resetting event index %d\n", index); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Resetting event index %d\n", index); ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[index]; local_ev_ctxt = diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c index 395e19c91f35..f1c562974816 100644 --- a/drivers/platform/msm/mhi/mhi_iface.c +++ b/drivers/platform/msm/mhi/mhi_iface.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,12 +32,11 @@ #include "mhi_hwio.h" #include "mhi_bhi.h" -struct mhi_pcie_devices mhi_devices; +struct mhi_device_driver *mhi_device_drv; static int mhi_pci_probe(struct pci_dev *pcie_device, const struct pci_device_id *mhi_device_id); static int __exit mhi_plat_remove(struct platform_device *pdev); -void *mhi_ipc_log; static DEFINE_PCI_DEVICE_TABLE(mhi_pcie_device_id) = { { MHI_PCIE_VENDOR_ID, MHI_PCIE_DEVICE_ID_9x35, @@ -59,129 +58,71 @@ static const struct of_device_id mhi_plat_match[] = { static void mhi_msm_fixup(struct pci_dev *pcie_device) { if (pcie_device->class == PCI_CLASS_NOT_DEFINED) { - mhi_log(MHI_MSG_INFO, "Setting msm pcie class\n"); pcie_device->class = PCI_CLASS_STORAGE_SCSI; } } -int mhi_ctxt_init(struct mhi_pcie_dev_info *mhi_pcie_dev) +int mhi_ctxt_init(struct mhi_device_ctxt *mhi_dev_ctxt) { int ret_val = 0; - u32 i = 0, j = 0; - u32 requested_msi_number = 32, actual_msi_number = 0; - struct mhi_device_ctxt *mhi_dev_ctxt = NULL; - struct pci_dev *pcie_device = NULL; + u32 j = 0; - if (NULL == mhi_pcie_dev) - return -EINVAL; - pcie_device = mhi_pcie_dev->pcie_device; - - ret_val = mhi_init_pcie_device(mhi_pcie_dev); - if (ret_val) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to initialize pcie device, ret %d\n", - ret_val); - return -ENODEV; - } - ret_val = mhi_init_device_ctxt(mhi_pcie_dev, &mhi_pcie_dev->mhi_ctxt); - if (ret_val) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to initialize main MHI ctxt ret %d\n", - ret_val); - goto msi_config_err; - } - ret_val = mhi_esoc_register(&mhi_pcie_dev->mhi_ctxt); + ret_val = mhi_init_device_ctxt(mhi_dev_ctxt); if (ret_val) { - mhi_log(MHI_MSG_ERROR, - "Failed to register with esoc ret %d.\n", - ret_val); - } - - device_disable_async_suspend(&pcie_device->dev); - ret_val = pci_enable_msi_range(pcie_device, 1, requested_msi_number); - if (IS_ERR_VALUE(ret_val)) { - mhi_log(MHI_MSG_ERROR, - "Failed to enable MSIs for pcie dev ret_val %d.\n", - ret_val); - goto msi_config_err; - } else if (ret_val) { - mhi_log(MHI_MSG_INFO, - "Hrmmm, got fewer MSIs than we requested. Requested %d, got %d.\n", - requested_msi_number, ret_val); - actual_msi_number = ret_val; - } else { - mhi_log(MHI_MSG_VERBOSE, - "Got all requested MSIs, moving on\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to initialize main MHI ctxt ret %d\n", ret_val); + return ret_val; } - mhi_dev_ctxt = &mhi_pcie_dev->mhi_ctxt; for (j = 0; j < mhi_dev_ctxt->mmio_info.nr_event_rings; j++) { - mhi_log(MHI_MSG_VERBOSE, - "MSI_number = %d, event ring number = %d\n", - mhi_dev_ctxt->ev_ring_props[j].msi_vec, j); - - ret_val = request_irq(pcie_device->irq + + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "MSI_number = %d, event ring number = %d\n", + mhi_dev_ctxt->ev_ring_props[j].msi_vec, j); + + /* outside of requested irq boundary */ + if (mhi_dev_ctxt->core.max_nr_msis <= + mhi_dev_ctxt->ev_ring_props[j].msi_vec) { + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "max msi supported:%d request:%d ev:%d\n", + mhi_dev_ctxt->core.max_nr_msis, + mhi_dev_ctxt->ev_ring_props[j].msi_vec, + j); + goto irq_error; + } + ret_val = request_irq(mhi_dev_ctxt->core.irq_base + mhi_dev_ctxt->ev_ring_props[j].msi_vec, mhi_dev_ctxt->ev_ring_props[j].mhi_handler_ptr, IRQF_NO_SUSPEND, "mhi_drv", - (void *)&pcie_device->dev); + (void *)mhi_dev_ctxt); if (ret_val) { - mhi_log(MHI_MSG_ERROR, - "Failed to register handler for MSI ret_val = %d\n", - ret_val); - goto msi_config_err; + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to register handler for MSI ret_val = %d\n", + ret_val); + goto irq_error; } } - mhi_pcie_dev->core.irq_base = pcie_device->irq; - mhi_log(MHI_MSG_VERBOSE, - "Setting IRQ Base to 0x%x\n", mhi_pcie_dev->core.irq_base); - mhi_pcie_dev->core.max_nr_msis = requested_msi_number; - ret_val = mhi_init_pm_sysfs(&pcie_device->dev); - if (ret_val) { - mhi_log(MHI_MSG_ERROR, "Failed to setup sysfs ret %d\n", - ret_val); - goto sysfs_config_err; - } - if (!mhi_init_debugfs(&mhi_pcie_dev->mhi_ctxt)) - mhi_log(MHI_MSG_ERROR, "Failed to init debugfs.\n"); - - mhi_pcie_dev->mhi_ctxt.mmio_info.mmio_addr = - mhi_pcie_dev->core.bar0_base; - pcie_device->dev.platform_data = &mhi_pcie_dev->mhi_ctxt; - mhi_pcie_dev->mhi_ctxt.dev_info->plat_dev->dev.platform_data = - &mhi_pcie_dev->mhi_ctxt; - ret_val = mhi_reg_notifiers(&mhi_pcie_dev->mhi_ctxt); - if (ret_val) { - mhi_log(MHI_MSG_ERROR, "Failed to register for notifiers\n"); - goto mhi_state_transition_error; - } - mhi_log(MHI_MSG_INFO, - "Finished all driver probing returning ret_val %d.\n", - ret_val); - return ret_val; -mhi_state_transition_error: + mhi_dev_ctxt->mmio_info.mmio_addr = mhi_dev_ctxt->core.bar0_base; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "exit\n"); + return 0; + +irq_error: kfree(mhi_dev_ctxt->state_change_work_item_list.q_lock); - kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq); - kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event); kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event); kfree(mhi_dev_ctxt->mhi_ev_wq.m3_event); kfree(mhi_dev_ctxt->mhi_ev_wq.bhi_event); - dma_free_coherent(&mhi_dev_ctxt->dev_info->plat_dev->dev, + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, mhi_dev_ctxt->dev_space.dev_mem_len, mhi_dev_ctxt->dev_space.dev_mem_start, mhi_dev_ctxt->dev_space.dma_dev_mem_start); kfree(mhi_dev_ctxt->ev_ring_props); - mhi_rem_pm_sysfs(&pcie_device->dev); -sysfs_config_err: - for (; i >= 0; --i) - free_irq(pcie_device->irq + i, &pcie_device->dev); - debugfs_remove_recursive(mhi_pcie_dev->mhi_ctxt.mhi_parent_folder); -msi_config_err: - pci_disable_device(pcie_device); - return ret_val; + for (j = j - 1; j >= 0; --j) + free_irq(mhi_dev_ctxt->core.irq_base + j, NULL); + + return -EINVAL; } static const struct dev_pm_ops pm_ops = { @@ -204,73 +145,154 @@ static int mhi_pci_probe(struct pci_dev *pcie_device, const struct pci_device_id *mhi_device_id) { int ret_val = 0; - struct mhi_pcie_dev_info *mhi_pcie_dev = NULL; struct platform_device *plat_dev; - struct mhi_device_ctxt *mhi_dev_ctxt; - u32 nr_dev = mhi_devices.nr_of_devices; + struct mhi_device_ctxt *mhi_dev_ctxt = NULL, *itr; + u32 domain = pci_domain_nr(pcie_device->bus); + u32 bus = pcie_device->bus->number; + u32 dev_id = pcie_device->device; + u32 slot = PCI_SLOT(pcie_device->devfn); + unsigned long msi_requested, msi_required; + struct msm_pcie_register_event *mhi_pci_link_event; + + /* Find correct device context based on bdf & dev_id */ + mutex_lock(&mhi_device_drv->lock); + list_for_each_entry(itr, &mhi_device_drv->head, node) { + struct pcie_core_info *core = &itr->core; + + if (core->domain == domain && + core->bus == bus && + core->dev_id == dev_id && + core->slot == slot) { + mhi_dev_ctxt = itr; + break; + } + } + mutex_unlock(&mhi_device_drv->lock); + if (!mhi_dev_ctxt) + return -EPROBE_DEFER; - mhi_log(MHI_MSG_INFO, "Entering\n"); - mhi_pcie_dev = &mhi_devices.device_list[mhi_devices.nr_of_devices]; - if (mhi_devices.nr_of_devices + 1 > MHI_MAX_SUPPORTED_DEVICES) { - mhi_log(MHI_MSG_ERROR, "Error: Too many devices\n"); - return -ENOMEM; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Processing Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n", + domain, bus, dev_id, slot); + + ret_val = of_property_read_u32(mhi_dev_ctxt->plat_dev->dev.of_node, + "mhi-event-rings", + (u32 *)&msi_required); + if (ret_val) { + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to pull ev ring info from DT, %d\n", ret_val); + return ret_val; } - mhi_devices.nr_of_devices++; - plat_dev = mhi_devices.device_list[nr_dev].plat_dev; + plat_dev = mhi_dev_ctxt->plat_dev; pcie_device->dev.of_node = plat_dev->dev.of_node; - mhi_dev_ctxt = &mhi_devices.device_list[nr_dev].mhi_ctxt; mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE; INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition); + INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker); mutex_init(&mhi_dev_ctxt->pm_lock); rwlock_init(&mhi_dev_ctxt->pm_xfer_lock); spin_lock_init(&mhi_dev_ctxt->dev_wake_lock); - tasklet_init(&mhi_dev_ctxt->ev_task, - mhi_ctrl_ev_task, - (unsigned long)mhi_dev_ctxt); - + init_completion(&mhi_dev_ctxt->cmd_complete); mhi_dev_ctxt->flags.link_up = 1; - ret_val = mhi_set_bus_request(mhi_dev_ctxt, 1); - mhi_pcie_dev->pcie_device = pcie_device; - mhi_pcie_dev->mhi_pcie_driver = &mhi_pcie_driver; - mhi_pcie_dev->mhi_pci_link_event.events = - (MSM_PCIE_EVENT_LINKDOWN | MSM_PCIE_EVENT_WAKEUP); - mhi_pcie_dev->mhi_pci_link_event.user = pcie_device; - mhi_pcie_dev->mhi_pci_link_event.callback = mhi_link_state_cb; - mhi_pcie_dev->mhi_pci_link_event.notify.data = mhi_pcie_dev; - ret_val = msm_pcie_register_event(&mhi_pcie_dev->mhi_pci_link_event); + + /* Setup bus scale */ + mhi_dev_ctxt->bus_scale_table = msm_bus_cl_get_pdata(plat_dev); + if (!mhi_dev_ctxt->bus_scale_table) + return -ENODATA; + mhi_dev_ctxt->bus_client = msm_bus_scale_register_client + (mhi_dev_ctxt->bus_scale_table); + if (!mhi_dev_ctxt->bus_client) + return -EINVAL; + mhi_set_bus_request(mhi_dev_ctxt, 1); + + mhi_dev_ctxt->pcie_device = pcie_device; + + mhi_pci_link_event = &mhi_dev_ctxt->mhi_pci_link_event; + mhi_pci_link_event->events = + (MSM_PCIE_EVENT_LINKDOWN | MSM_PCIE_EVENT_WAKEUP); + mhi_pci_link_event->user = pcie_device; + mhi_pci_link_event->callback = mhi_link_state_cb; + mhi_pci_link_event->notify.data = mhi_dev_ctxt; + ret_val = msm_pcie_register_event(mhi_pci_link_event); if (ret_val) { - mhi_log(MHI_MSG_ERROR, - "Failed to register for link notifications %d.\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to reg for link notifications %d\n", ret_val); + return ret_val; + } + + dev_set_drvdata(&pcie_device->dev, mhi_dev_ctxt); + + mhi_dev_ctxt->core.pci_master = true; + ret_val = mhi_init_pcie_device(mhi_dev_ctxt); + if (ret_val) { + mhi_log(mhi_dev_ctxt, + MHI_MSG_CRITICAL, + "Failed to initialize pcie device, ret %d\n", ret_val); return ret_val; } + pci_set_master(pcie_device); + device_disable_async_suspend(&pcie_device->dev); - /* Initialize MHI CNTXT */ - ret_val = mhi_ctxt_init(mhi_pcie_dev); + ret_val = mhi_esoc_register(mhi_dev_ctxt); if (ret_val) { - mhi_log(MHI_MSG_ERROR, - "MHI Initialization failed, ret %d\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to reg with esoc ret %d\n", ret_val); + } + + /* # of MSI requested must be power of 2 */ + msi_requested = 1 << find_last_bit(&msi_required, 32); + if (msi_requested < msi_required) + msi_requested <<= 1; + + ret_val = pci_enable_msi_range(pcie_device, 1, msi_requested); + if (IS_ERR_VALUE(ret_val) || (ret_val < msi_requested)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to enable MSIs for pcie dev ret_val %d.\n", ret_val); + return -EIO; + } + + mhi_dev_ctxt->core.max_nr_msis = msi_requested; + mhi_dev_ctxt->core.irq_base = pcie_device->irq; + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Setting IRQ Base to 0x%x\n", mhi_dev_ctxt->core.irq_base); + + /* Initialize MHI CNTXT */ + ret_val = mhi_ctxt_init(mhi_dev_ctxt); + if (ret_val) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "MHI Initialization failed, ret %d\n", ret_val); goto deregister_pcie; } - pci_set_master(mhi_pcie_dev->pcie_device); + + mhi_init_pm_sysfs(&pcie_device->dev); + mhi_init_debugfs(mhi_dev_ctxt); + mhi_reg_notifiers(mhi_dev_ctxt); + + /* setup shadow pm functions */ + mhi_dev_ctxt->assert_wake = mhi_assert_device_wake; + mhi_dev_ctxt->deassert_wake = mhi_deassert_device_wake; + mhi_dev_ctxt->runtime_get = mhi_master_mode_runtime_get; + mhi_dev_ctxt->runtime_put = mhi_master_mode_runtime_put; mutex_lock(&mhi_dev_ctxt->pm_lock); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->mhi_pm_state = MHI_PM_POR; - ret_val = set_mhi_base_state(mhi_pcie_dev); + ret_val = set_mhi_base_state(mhi_dev_ctxt); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); if (ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, + MHI_MSG_ERROR, "Error Setting MHI Base State %d\n", ret_val); goto unlock_pm_lock; } if (mhi_dev_ctxt->base_state == STATE_TRANSITION_BHI) { - ret_val = bhi_probe(mhi_pcie_dev); + ret_val = bhi_probe(mhi_dev_ctxt); if (ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Error with bhi_probe ret:%d", ret_val); goto unlock_pm_lock; } @@ -312,33 +334,144 @@ static int mhi_pci_probe(struct pci_dev *pcie_device, unlock_pm_lock: mutex_unlock(&mhi_dev_ctxt->pm_lock); deregister_pcie: - msm_pcie_deregister_event(&mhi_pcie_dev->mhi_pci_link_event); + msm_pcie_deregister_event(&mhi_dev_ctxt->mhi_pci_link_event); return ret_val; } static int mhi_plat_probe(struct platform_device *pdev) { - u32 nr_dev = mhi_devices.nr_of_devices; + int r = 0, len; struct mhi_device_ctxt *mhi_dev_ctxt; - int r = 0; + struct pcie_core_info *core; + char node[32]; + struct device_node *of_node = pdev->dev.of_node; + u64 address_window[2]; - mhi_log(MHI_MSG_INFO, "Entered\n"); - mhi_dev_ctxt = &mhi_devices.device_list[nr_dev].mhi_ctxt; + if (of_node == NULL) + return -ENODEV; - mhi_dev_ctxt->bus_scale_table = msm_bus_cl_get_pdata(pdev); - if (!mhi_dev_ctxt->bus_scale_table) - return -ENODATA; - mhi_dev_ctxt->bus_client = msm_bus_scale_register_client - (mhi_dev_ctxt->bus_scale_table); - if (!mhi_dev_ctxt->bus_client) - return -EINVAL; + pdev->id = of_alias_get_id(of_node, "mhi"); + if (pdev->id < 0) + return -ENODEV; - mhi_devices.device_list[nr_dev].plat_dev = pdev; - r = dma_set_mask(&pdev->dev, MHI_DMA_MASK); + mhi_dev_ctxt = devm_kzalloc(&pdev->dev, + sizeof(*mhi_dev_ctxt), + GFP_KERNEL); + if (!mhi_dev_ctxt) + return -ENOMEM; + + if (!of_find_property(of_node, "qcom,mhi-address-window", &len)) + return -ENODEV; + + if (len != sizeof(address_window)) + return -ENODEV; + + r = of_property_read_u64_array(of_node, + "qcom,mhi-address-window", + address_window, + sizeof(address_window) / sizeof(u64)); + if (r) + return r; + + core = &mhi_dev_ctxt->core; + r = of_property_read_u32(of_node, "qcom,pci-dev_id", &core->dev_id); + if (r) + return r; + + r = of_property_read_u32(of_node, "qcom,pci-slot", &core->slot); + if (r) + return r; + + r = of_property_read_u32(of_node, "qcom,pci-domain", &core->domain); if (r) - mhi_log(MHI_MSG_CRITICAL, + return r; + + r = of_property_read_u32(of_node, "qcom,pci-bus", &core->bus); + if (r) + return r; + + snprintf(node, sizeof(node), + "mhi_%04x_%02u.%02u.%02u", + core->dev_id, core->domain, core->bus, core->slot); + mhi_dev_ctxt->mhi_ipc_log = + ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0); + if (!mhi_dev_ctxt->mhi_ipc_log) + pr_err("%s: Error creating ipc_log buffer\n", __func__); + + r = of_property_read_u32(of_node, "qcom,mhi-ready-timeout", + &mhi_dev_ctxt->poll_reset_timeout_ms); + if (r) + mhi_dev_ctxt->poll_reset_timeout_ms = + MHI_READY_STATUS_TIMEOUT_MS; + + mhi_dev_ctxt->dev_space.start_win_addr = address_window[0]; + mhi_dev_ctxt->dev_space.end_win_addr = address_window[1]; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Start Addr:0x%llx End_Addr:0x%llx\n", + mhi_dev_ctxt->dev_space.start_win_addr, + mhi_dev_ctxt->dev_space.end_win_addr); + + r = of_property_read_u32(of_node, "qcom,bhi-alignment", + &mhi_dev_ctxt->bhi_ctxt.alignment); + if (r) + mhi_dev_ctxt->bhi_ctxt.alignment = BHI_DEFAULT_ALIGNMENT; + + r = of_property_read_u32(of_node, "qcom,bhi-poll-timeout", + &mhi_dev_ctxt->bhi_ctxt.poll_timeout); + if (r) + mhi_dev_ctxt->bhi_ctxt.poll_timeout = BHI_POLL_TIMEOUT_MS; + + mhi_dev_ctxt->bhi_ctxt.manage_boot = + of_property_read_bool(pdev->dev.of_node, + "qcom,mhi-manage-boot"); + if (mhi_dev_ctxt->bhi_ctxt.manage_boot) { + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct firmware_info *fw_info = &bhi_ctxt->firmware_info; + + r = of_property_read_string(of_node, "qcom,mhi-fw-image", + &fw_info->fw_image); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error reading DT node 'qcom,mhi-fw-image'\n"); + return r; + } + r = of_property_read_u32(of_node, "qcom,mhi-max-sbl", + (u32 *)&fw_info->max_sbl_len); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error reading DT node 'qcom,mhi-max-sbl'\n"); + return r; + } + r = of_property_read_u32(of_node, "qcom,mhi-sg-size", + (u32 *)&fw_info->segment_size); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error reading DT node 'qcom,mhi-sg-size'\n"); + return r; + } + INIT_WORK(&bhi_ctxt->fw_load_work, bhi_firmware_download); + } + + mhi_dev_ctxt->flags.bb_required = + of_property_read_bool(pdev->dev.of_node, + "qcom,mhi-bb-required"); + + mhi_dev_ctxt->plat_dev = pdev; + platform_set_drvdata(pdev, mhi_dev_ctxt); + + r = dma_set_mask(&pdev->dev, MHI_DMA_MASK); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to set mask for DMA ret %d\n", r); - mhi_log(MHI_MSG_INFO, "Exited\n"); + return r; + } + + mhi_dev_ctxt->parent = mhi_device_drv->parent; + mutex_lock(&mhi_device_drv->lock); + list_add_tail(&mhi_dev_ctxt->node, &mhi_device_drv->head); + mutex_unlock(&mhi_device_drv->lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); + return 0; } @@ -354,42 +487,59 @@ static struct platform_driver mhi_plat_driver = { static void __exit mhi_exit(void) { - ipc_log_context_destroy(mhi_ipc_log); pci_unregister_driver(&mhi_pcie_driver); platform_driver_unregister(&mhi_plat_driver); } static int __exit mhi_plat_remove(struct platform_device *pdev) { - platform_driver_unregister(&mhi_plat_driver); + struct mhi_device_ctxt *mhi_dev_ctxt = platform_get_drvdata(pdev); + + ipc_log_context_destroy(mhi_dev_ctxt->mhi_ipc_log); return 0; } static int __init mhi_init(void) { int r; + struct mhi_device_driver *mhi_dev_drv; + + mhi_dev_drv = kmalloc(sizeof(*mhi_dev_drv), GFP_KERNEL); + if (mhi_dev_drv == NULL) + return -ENOMEM; + + mutex_init(&mhi_dev_drv->lock); + mutex_lock(&mhi_dev_drv->lock); + INIT_LIST_HEAD(&mhi_dev_drv->head); + mutex_unlock(&mhi_dev_drv->lock); + mhi_dev_drv->mhi_bhi_class = class_create(THIS_MODULE, "bhi"); + if (IS_ERR(mhi_dev_drv->mhi_bhi_class)) { + pr_err("Error creating mhi_bhi_class\n"); + goto class_error; + } + mhi_dev_drv->parent = debugfs_create_dir("mhi", NULL); + mhi_device_drv = mhi_dev_drv; - mhi_log(MHI_MSG_INFO, "Entered\n"); r = platform_driver_register(&mhi_plat_driver); if (r) { - mhi_log(MHI_MSG_INFO, "Failed to probe platform ret %d\n", r); - return r; + pr_err("%s: Failed to probe platform ret %d\n", __func__, r); + goto platform_error; } r = pci_register_driver(&mhi_pcie_driver); if (r) { - mhi_log(MHI_MSG_INFO, - "Failed to register pcie drv ret %d\n", r); + pr_err("%s: Failed to register pcie drv ret %d\n", __func__, r); goto error; } - mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0); - if (!mhi_ipc_log) { - mhi_log(MHI_MSG_ERROR, - "Failed to create IPC logging context\n"); - } - mhi_log(MHI_MSG_INFO, "Exited\n"); + return 0; error: - pci_unregister_driver(&mhi_pcie_driver); + platform_driver_unregister(&mhi_plat_driver); +platform_error: + class_destroy(mhi_device_drv->mhi_bhi_class); + +class_error: + kfree(mhi_dev_drv); + mhi_device_drv = NULL; return r; } @@ -407,7 +557,7 @@ DECLARE_PCI_FIXUP_HEADER(MHI_PCIE_VENDOR_ID, module_exit(mhi_exit); -module_init(mhi_init); +subsys_initcall(mhi_init); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("MHI_CORE"); diff --git a/drivers/platform/msm/mhi/mhi_init.c b/drivers/platform/msm/mhi/mhi_init.c index a496c81239bf..b6edf707798b 100644 --- a/drivers/platform/msm/mhi/mhi_init.c +++ b/drivers/platform/msm/mhi/mhi_init.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -53,12 +53,12 @@ size_t calculate_mhi_space(struct mhi_device_ctxt *mhi_dev_ctxt) (NR_OF_CMD_RINGS * sizeof(struct mhi_chan_ctxt)) + (mhi_dev_ctxt->mmio_info.nr_event_rings * sizeof(struct mhi_event_ctxt)); - mhi_log(MHI_MSG_INFO, "Reserved %zd bytes for context info\n", - mhi_dev_mem); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Reserved %zd bytes for context info\n", mhi_dev_mem); /*Calculate size needed for cmd TREs */ mhi_dev_mem += (CMD_EL_PER_RING * sizeof(union mhi_cmd_pkt)); - mhi_log(MHI_MSG_INFO, "Final bytes for MHI device space %zd\n", - mhi_dev_mem); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Final bytes for MHI device space %zd\n", mhi_dev_mem); return mhi_dev_mem; } @@ -105,23 +105,6 @@ void init_local_chan_ctxt(struct mhi_ring *chan_ctxt, chan_ctxt->overwrite_en = 0; } -int populate_bb_list(struct list_head *bb_list, int num_bb) -{ - struct mhi_buf_info *mhi_buf = NULL; - int i; - - for (i = 0; i < num_bb; ++i) { - mhi_buf = kzalloc(sizeof(struct mhi_buf_info), GFP_KERNEL); - if (!mhi_buf) - return -ENOMEM; - mhi_buf->bb_p_addr = 0; - mhi_buf->bb_v_addr = NULL; - mhi_log(MHI_MSG_INFO, - "Allocated BB v_addr 0x%p, p_addr 0x%llx\n", - mhi_buf->bb_v_addr, (u64)mhi_buf->bb_p_addr); - } - return 0; -} /** * mhi_cmd_ring_init- Initialization of the command ring * @@ -153,91 +136,6 @@ static int mhi_cmd_ring_init(struct mhi_cmd_ctxt *cmd_ctxt, return 0; } -/* - * The device can have severe addressing limitations, and in this case - * the MHI driver may be restricted on where memory can be allocated. - * - * The allocation of the MHI control data structures takes place as one - * big, physically contiguous allocation. - * The device's addressing window, must be placed around that control segment - * allocation. - * Here we attempt to do this by building an addressing window around the - * initial allocated control segment. - * - * The window size is specified by the device and must be contiguous, - * but depending on where the control segment was allocated, it may be - * necessary to leave more room, before the ctrl segment start or after - * the ctrl segment end. - * The following assumptions are made: - * Assumption: 1. size of allocated ctrl seg << (device allocation window / 2) - * 2. allocated ctrl seg is physically contiguous - */ -static int calculate_mhi_addressing_window(struct mhi_device_ctxt *mhi_dev_ctxt) -{ - u64 dma_dev_mem_start = 0; - u64 dma_seg_size = 0; - u64 dma_max_addr = (dma_addr_t)(-1); - u64 dev_address_limit = 0; - int r = 0; - const struct device_node *np = - mhi_dev_ctxt->dev_info->plat_dev->dev.of_node; - - dma_dev_mem_start = mhi_dev_ctxt->dev_space.dma_dev_mem_start; - r = of_property_read_u64(np, "mhi-dev-address-win-size", - &dev_address_limit); - if (r) { - mhi_log(MHI_MSG_ERROR, - "Failed to get device addressing limit ret %d", - r); - return r; - } - /* Mask off the last 3 bits for address calculation */ - dev_address_limit &= ~0x7; - mhi_log(MHI_MSG_INFO, "Device Addressing limit 0x%llx\n", - dev_address_limit); - dma_seg_size = dev_address_limit / 2; - - /* - * The region of the allocated control segment is within the - * first half of the device's addressing limit - */ - if (dma_dev_mem_start < dma_seg_size) { - mhi_dev_ctxt->dev_space.start_win_addr = 0; - mhi_dev_ctxt->dev_space.end_win_addr = - dma_dev_mem_start + dma_seg_size + - (dma_seg_size - dma_dev_mem_start); - } else if (dma_dev_mem_start >= dma_seg_size && - dma_dev_mem_start <= (dma_max_addr - dma_seg_size)) { - /* - * The start of the control segment is located past - * halfway point of the device's addressing limit - * Place the control segment in the middle of the device's - * addressing range - */ - mhi_dev_ctxt->dev_space.start_win_addr = - dma_dev_mem_start - dma_seg_size; - mhi_dev_ctxt->dev_space.end_win_addr = - dma_dev_mem_start + dma_seg_size; - } else if (dma_dev_mem_start > (dma_max_addr - dma_seg_size)) { - /* - * The start of the control segment is located at the tail end - * of the host addressing space. Leave extra addressing space - * at window start - */ - mhi_dev_ctxt->dev_space.start_win_addr = dma_dev_mem_start; - mhi_dev_ctxt->dev_space.start_win_addr -= - dma_seg_size + (dma_seg_size - - (dma_max_addr - dma_dev_mem_start)); - mhi_dev_ctxt->dev_space.end_win_addr = dma_max_addr; - } - mhi_log(MHI_MSG_INFO, - "MHI start address at 0x%llx, Window Start 0x%llx Window End 0x%llx\n", - (u64)dma_dev_mem_start, - (u64)mhi_dev_ctxt->dev_space.start_win_addr, - (u64)mhi_dev_ctxt->dev_space.end_win_addr); - return 0; -} - int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) { size_t mhi_mem_index = 0, ring_len; @@ -249,12 +147,12 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) calculate_mhi_space(mhi_dev_ctxt); mhi_dev_ctxt->dev_space.dev_mem_start = - dma_alloc_coherent(&mhi_dev_ctxt->dev_info->pcie_device->dev, + dma_alloc_coherent(&mhi_dev_ctxt->plat_dev->dev, mhi_dev_ctxt->dev_space.dev_mem_len, &mhi_dev_ctxt->dev_space.dma_dev_mem_start, GFP_KERNEL); if (!mhi_dev_ctxt->dev_space.dev_mem_start) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to allocate memory of size %zd bytes\n", mhi_dev_ctxt->dev_space.dev_mem_len); return -ENOMEM; @@ -263,26 +161,20 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) dma_dev_mem_start = mhi_dev_ctxt->dev_space.dma_dev_mem_start; memset(dev_mem_start, 0, mhi_dev_ctxt->dev_space.dev_mem_len); - r = calculate_mhi_addressing_window(mhi_dev_ctxt); - if (r) { - mhi_log(MHI_MSG_ERROR, - "Failed to calculate addressing window ret %d", r); - return r; - } + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Starting Seg address: virt 0x%p, dma 0x%llx\n", + dev_mem_start, (u64)dma_dev_mem_start); - mhi_log(MHI_MSG_INFO, "Starting Seg address: virt 0x%p, dma 0x%llx\n", - dev_mem_start, (u64)dma_dev_mem_start); - - mhi_log(MHI_MSG_INFO, "Initializing CCABAP at virt 0x%p, dma 0x%llx\n", - dev_mem_start + mhi_mem_index, - (u64)dma_dev_mem_start + mhi_mem_index); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Initializing CCABAP at dma 0x%llx\n", + (u64)dma_dev_mem_start + mhi_mem_index); mhi_dev_ctxt->dev_space.ring_ctxt.cc_list = dev_mem_start; mhi_dev_ctxt->dev_space.ring_ctxt.dma_cc_list = dma_dev_mem_start; mhi_mem_index += MHI_MAX_CHANNELS * sizeof(struct mhi_chan_ctxt); - mhi_log(MHI_MSG_INFO, "Initializing CRCBAP at virt 0x%p, dma 0x%llx\n", - dev_mem_start + mhi_mem_index, - (u64)dma_dev_mem_start + mhi_mem_index); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Initializing CRCBAP at dma 0x%llx\n", + (u64)dma_dev_mem_start + mhi_mem_index); mhi_dev_ctxt->dev_space.ring_ctxt.cmd_ctxt = dev_mem_start + mhi_mem_index; @@ -290,9 +182,9 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) dma_dev_mem_start + mhi_mem_index; mhi_mem_index += NR_OF_CMD_RINGS * sizeof(struct mhi_chan_ctxt); - mhi_log(MHI_MSG_INFO, "Initializing ECABAP at virt 0x%p, dma 0x%llx\n", - dev_mem_start + mhi_mem_index, - (u64)dma_dev_mem_start + mhi_mem_index); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Initializing ECABAP at dma 0x%llx\n", + (u64)dma_dev_mem_start + mhi_mem_index); mhi_dev_ctxt->dev_space.ring_ctxt.ec_list = dev_mem_start + mhi_mem_index; mhi_dev_ctxt->dev_space.ring_ctxt.dma_ec_list = @@ -300,10 +192,9 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_mem_index += mhi_dev_ctxt->mmio_info.nr_event_rings * sizeof(struct mhi_event_ctxt); - mhi_log(MHI_MSG_INFO, - "Initializing CMD context at virt 0x%p, dma 0x%llx\n", - dev_mem_start + mhi_mem_index, - (u64)dma_dev_mem_start + mhi_mem_index); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Initializing CMD context at dma 0x%llx\n", + (u64)dma_dev_mem_start + mhi_mem_index); /* TODO: Initialize both the local and device cmd context */ ring_len = (CMD_EL_PER_RING * sizeof(union mhi_cmd_pkt)); @@ -322,7 +213,7 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) ring_len = sizeof(union mhi_event_pkt) * mhi_dev_ctxt->ev_ring_props[i].nr_desc; ring_addr = dma_alloc_coherent( - &mhi_dev_ctxt->dev_info->pcie_device->dev, + &mhi_dev_ctxt->plat_dev->dev, ring_len, &ring_dma_addr, GFP_KERNEL); if (!ring_addr) goto err_ev_alloc; @@ -330,9 +221,9 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) ring_dma_addr, ring_len); init_local_ev_ctxt(&mhi_dev_ctxt->mhi_local_event_ctxt[i], ring_addr, ring_len); - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Initializing EV_%d TRE list at virt 0x%p dma 0x%llx\n", - i, ring_addr, (u64)ring_dma_addr); + i, ring_addr, (u64)ring_dma_addr); } return 0; @@ -344,12 +235,12 @@ err_ev_alloc: dev_ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[i]; ev_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[i]; - dma_free_coherent(&mhi_dev_ctxt->dev_info->pcie_device->dev, + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, ev_ctxt->len, ev_ctxt->base, dev_ev_ctxt->mhi_event_ring_base_addr); } - dma_free_coherent(&mhi_dev_ctxt->dev_info->pcie_device->dev, + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, mhi_dev_ctxt->dev_space.dev_mem_len, mhi_dev_ctxt->dev_space.dev_mem_start, mhi_dev_ctxt->dev_space.dma_dev_mem_start); @@ -359,44 +250,28 @@ err_ev_alloc: static int mhi_init_events(struct mhi_device_ctxt *mhi_dev_ctxt) { - mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq = kmalloc( - sizeof(wait_queue_head_t), - GFP_KERNEL); - if (NULL == mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq) { - mhi_log(MHI_MSG_ERROR, "Failed to init event"); - return -ENOMEM; - } - mhi_dev_ctxt->mhi_ev_wq.state_change_event = - kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); - if (NULL == mhi_dev_ctxt->mhi_ev_wq.state_change_event) { - mhi_log(MHI_MSG_ERROR, "Failed to init event"); - goto error_event_handle_alloc; - } /* Initialize the event which signals M0 */ mhi_dev_ctxt->mhi_ev_wq.m0_event = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); if (NULL == mhi_dev_ctxt->mhi_ev_wq.m0_event) { - mhi_log(MHI_MSG_ERROR, "Failed to init event"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to init event"); goto error_state_change_event_handle; } /* Initialize the event which signals M0 */ mhi_dev_ctxt->mhi_ev_wq.m3_event = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); if (NULL == mhi_dev_ctxt->mhi_ev_wq.m3_event) { - mhi_log(MHI_MSG_ERROR, "Failed to init event"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to init event"); goto error_m0_event; } /* Initialize the event which signals M0 */ mhi_dev_ctxt->mhi_ev_wq.bhi_event = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); if (NULL == mhi_dev_ctxt->mhi_ev_wq.bhi_event) { - mhi_log(MHI_MSG_ERROR, "Failed to init event"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to init event"); goto error_bhi_event; } - /* Initialize the event which starts the event parsing thread */ - init_waitqueue_head(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq); - /* Initialize the event which starts the state change thread */ - init_waitqueue_head(mhi_dev_ctxt->mhi_ev_wq.state_change_event); + /* Initialize the event which triggers clients waiting to send */ init_waitqueue_head(mhi_dev_ctxt->mhi_ev_wq.m0_event); /* Initialize the event which triggers D3hot */ @@ -409,9 +284,6 @@ error_bhi_event: error_m0_event: kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event); error_state_change_event_handle: - kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event); -error_event_handle_alloc: - kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq); return -ENOMEM; } @@ -448,102 +320,70 @@ static void mhi_init_wakelock(struct mhi_device_ctxt *mhi_dev_ctxt) wakeup_source_init(&mhi_dev_ctxt->w_lock, "mhi_wakeup_source"); } -static int mhi_spawn_threads(struct mhi_device_ctxt *mhi_dev_ctxt) -{ - mhi_dev_ctxt->event_thread_handle = kthread_run(parse_event_thread, - mhi_dev_ctxt, - "mhi_ev_thrd"); - if (IS_ERR(mhi_dev_ctxt->event_thread_handle)) - return PTR_ERR(mhi_dev_ctxt->event_thread_handle); - mhi_dev_ctxt->st_thread_handle = kthread_run(mhi_state_change_thread, - mhi_dev_ctxt, - "mhi_st_thrd"); - if (IS_ERR(mhi_dev_ctxt->event_thread_handle)) - return PTR_ERR(mhi_dev_ctxt->event_thread_handle); - return 0; -} - /** * @brief Main initialization function for a mhi struct device context * All threads, events mutexes, mhi specific data structures * are initialized here * - * @param dev_info [IN ] pcie struct device information structure to - which this mhi context belongs * @param mhi_struct device [IN/OUT] reference to a mhi context to be populated * * @return errno */ -int mhi_init_device_ctxt(struct mhi_pcie_dev_info *dev_info, - struct mhi_device_ctxt *mhi_dev_ctxt) +int mhi_init_device_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt) { int r = 0; - if (NULL == dev_info || NULL == mhi_dev_ctxt) - return -EINVAL; - - mhi_log(MHI_MSG_VERBOSE, "Entered\n"); - - mhi_dev_ctxt->dev_info = dev_info; - mhi_dev_ctxt->dev_props = &dev_info->core; + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Entered\n"); r = mhi_populate_event_cfg(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to get event ring properties ret %d\n", r); goto error_during_props; } r = mhi_init_sync(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, "Failed to initialize mhi sync\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to initialize mhi sync\n"); goto error_during_sync; } r = create_local_ev_ctxt(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to initialize local event ctxt ret %d\n", r); goto error_during_local_ev_ctxt; } r = init_mhi_dev_mem(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to initialize device memory ret %d\n", r); goto error_during_dev_mem_init; } r = mhi_init_events(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to initialize mhi events ret %d\n", r); goto error_wq_init; } r = mhi_reset_all_thread_queues(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to initialize work queues ret %d\n", r); goto error_during_thread_init; } init_event_ctxt_array(mhi_dev_ctxt); mhi_dev_ctxt->mhi_state = MHI_STATE_RESET; - r = mhi_spawn_threads(mhi_dev_ctxt); - if (r) { - mhi_log(MHI_MSG_ERROR, "Failed to spawn threads ret %d\n", r); - goto error_during_thread_spawn; - } mhi_init_wakelock(mhi_dev_ctxt); return r; -error_during_thread_spawn: - kfree(mhi_dev_ctxt->state_change_work_item_list.q_lock); error_during_thread_init: - kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq); - kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event); kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event); kfree(mhi_dev_ctxt->mhi_ev_wq.m3_event); kfree(mhi_dev_ctxt->mhi_ev_wq.bhi_event); error_wq_init: - dma_free_coherent(&mhi_dev_ctxt->dev_info->pcie_device->dev, + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, mhi_dev_ctxt->dev_space.dev_mem_len, mhi_dev_ctxt->dev_space.dev_mem_start, mhi_dev_ctxt->dev_space.dma_dev_mem_start); @@ -623,7 +463,8 @@ int mhi_reset_all_thread_queues( ret_val = mhi_init_state_change_thread_work_queue( &mhi_dev_ctxt->state_change_work_item_list); if (ret_val) - mhi_log(MHI_MSG_ERROR, "Failed to reset STT work queue\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to reset STT work queue\n"); return ret_val; } diff --git a/drivers/platform/msm/mhi/mhi_isr.c b/drivers/platform/msm/mhi/mhi_isr.c index d7c604419593..9aa9aeb7e646 100644 --- a/drivers/platform/msm/mhi/mhi_isr.c +++ b/drivers/platform/msm/mhi/mhi_isr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,13 +29,14 @@ static int mhi_process_event_ring( struct mhi_ring *local_ev_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[ev_index]; + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "enter ev_index:%u\n", ev_index); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); if (unlikely(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE)) { - mhi_log(MHI_MSG_ERROR, "Invalid MHI PM State\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Invalid MHI PM State\n"); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); return -EIO; } - mhi_assert_device_wake(mhi_dev_ctxt, false); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[ev_index]; @@ -77,10 +78,9 @@ static int mhi_process_event_ring( &cmd_pkt, ev_index); MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan); cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "MHI CCE received ring 0x%x chan:%u\n", - ev_index, - chan); + ev_index, chan); spin_lock_irqsave(&cfg->event_lock, flags); cfg->cmd_pkt = *cmd_pkt; cfg->cmd_event_pkt = @@ -102,9 +102,8 @@ static int mhi_process_event_ring( __pm_stay_awake(&mhi_dev_ctxt->w_lock); chan = MHI_EV_READ_CHID(EV_CHID, &event_to_process); if (unlikely(!VALID_CHAN_NR(chan))) { - mhi_log(MHI_MSG_ERROR, - "Invalid chan:%d\n", - chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid chan:%d\n", chan); break; } ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; @@ -115,6 +114,7 @@ static int mhi_process_event_ring( ev_index); spin_unlock_bh(&ring->ring_lock); __pm_relax(&mhi_dev_ctxt->w_lock); + event_quota--; break; } case MHI_PKT_TYPE_STATE_CHANGE_EVENT: @@ -122,13 +122,15 @@ static int mhi_process_event_ring( enum STATE_TRANSITION new_state; unsigned long flags; new_state = MHI_READ_STATE(&event_to_process); - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "MHI STE received ring 0x%x State:%s\n", - ev_index, - state_transition_str(new_state)); + ev_index, state_transition_str(new_state)); - /* If transitioning to M1 schedule worker thread */ - if (new_state == STATE_TRANSITION_M1) { + switch (new_state) { + case STATE_TRANSITION_M0: + process_m0_transition(mhi_dev_ctxt); + break; + case STATE_TRANSITION_M1: write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); mhi_dev_ctxt->mhi_state = @@ -142,9 +144,15 @@ static int mhi_process_event_ring( write_unlock_irqrestore(&mhi_dev_ctxt-> pm_xfer_lock, flags); - } else { - mhi_init_state_transition(mhi_dev_ctxt, - new_state); + break; + case STATE_TRANSITION_M3: + process_m3_transition(mhi_dev_ctxt); + break; + default: + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Unsupported STE received ring 0x%x State:%s\n", + ev_index, + state_transition_str(new_state)); } break; } @@ -152,9 +160,8 @@ static int mhi_process_event_ring( { enum STATE_TRANSITION new_state; - mhi_log(MHI_MSG_INFO, - "MHI EEE received ring 0x%x\n", - ev_index); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI EEE received ring 0x%x\n", ev_index); __pm_stay_awake(&mhi_dev_ctxt->w_lock); __pm_relax(&mhi_dev_ctxt->w_lock); switch (MHI_READ_EXEC_ENV(&event_to_process)) { @@ -168,21 +175,25 @@ static int mhi_process_event_ring( mhi_init_state_transition(mhi_dev_ctxt, new_state); break; + case MHI_EXEC_ENV_BHIE: + new_state = STATE_TRANSITION_BHIE; + mhi_init_state_transition(mhi_dev_ctxt, + new_state); } break; } case MHI_PKT_TYPE_STALE_EVENT: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Stale Event received for chan:%u\n", MHI_EV_READ_CHID(EV_CHID, local_rp)); break; case MHI_PKT_TYPE_SYS_ERR_EVENT: - mhi_log(MHI_MSG_INFO, - "MHI System Error Detected. Triggering Reset\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI System Error Detected. Triggering Reset\n"); BUG(); break; default: - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Unsupported packet type code 0x%x\n", MHI_TRB_READ_INFO(EV_TRB_TYPE, &event_to_process)); @@ -197,181 +208,139 @@ static int mhi_process_event_ring( ev_ctxt->mhi_event_read_ptr); spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags); ret_val = 0; - --event_quota; } read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "exit ev_index:%u\n", ev_index); return ret_val; } -int parse_event_thread(void *ctxt) +void mhi_ev_task(unsigned long data) { - struct mhi_device_ctxt *mhi_dev_ctxt = ctxt; - u32 i = 0; - int ret_val = 0; - int ret_val_process_event = 0; - atomic_t *ev_pen_ptr = &mhi_dev_ctxt->counters.events_pending; + struct mhi_ring *mhi_ring = (struct mhi_ring *)data; + struct mhi_device_ctxt *mhi_dev_ctxt = + mhi_ring->mhi_dev_ctxt; + int ev_index = mhi_ring->index; - /* Go through all event rings */ - for (;;) { - ret_val = - wait_event_interruptible( - *mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq, - ((atomic_read( - &mhi_dev_ctxt->counters.events_pending) > 0) && - !mhi_dev_ctxt->flags.stop_threads) || - mhi_dev_ctxt->flags.kill_threads || - (mhi_dev_ctxt->flags.stop_threads && - !mhi_dev_ctxt->flags.ev_thread_stopped)); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter\n"); + /* Process event ring */ + mhi_process_event_ring(mhi_dev_ctxt, ev_index, U32_MAX); - switch (ret_val) { - case -ERESTARTSYS: - return 0; - default: - if (mhi_dev_ctxt->flags.kill_threads) { - mhi_log(MHI_MSG_INFO, - "Caught exit signal, quitting\n"); - return 0; - } - if (mhi_dev_ctxt->flags.stop_threads) { - mhi_dev_ctxt->flags.ev_thread_stopped = 1; - continue; - } - break; - } - mhi_dev_ctxt->flags.ev_thread_stopped = 0; - atomic_dec(&mhi_dev_ctxt->counters.events_pending); - for (i = 1; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i) { - if (mhi_dev_ctxt->mhi_state == MHI_STATE_SYS_ERR) { - mhi_log(MHI_MSG_INFO, - "SYS_ERR detected, not processing events\n"); - atomic_set(&mhi_dev_ctxt-> - counters.events_pending, - 0); - break; - } - if (GET_EV_PROPS(EV_MANAGED, - mhi_dev_ctxt->ev_ring_props[i].flags)) { - ret_val_process_event = - mhi_process_event_ring(mhi_dev_ctxt, - i, - mhi_dev_ctxt-> - ev_ring_props[i].nr_desc); - if (ret_val_process_event == -EINPROGRESS) - atomic_inc(ev_pen_ptr); - } - } - } + enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, ev_index)); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n"); } -void mhi_ctrl_ev_task(unsigned long data) +void process_event_ring(struct work_struct *work) { + struct mhi_ring *mhi_ring = + container_of(work, struct mhi_ring, ev_worker); struct mhi_device_ctxt *mhi_dev_ctxt = - (struct mhi_device_ctxt *)data; - const unsigned CTRL_EV_RING = 0; - struct mhi_event_ring_cfg *ring_props = - &mhi_dev_ctxt->ev_ring_props[CTRL_EV_RING]; + mhi_ring->mhi_dev_ctxt; + int ev_index = mhi_ring->index; + + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter\n"); + /* Process event ring */ + mhi_process_event_ring(mhi_dev_ctxt, ev_index, U32_MAX); - mhi_log(MHI_MSG_VERBOSE, "Enter\n"); - /* Process control event ring */ - mhi_process_event_ring(mhi_dev_ctxt, - CTRL_EV_RING, - ring_props->nr_desc); - enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, CTRL_EV_RING)); - mhi_log(MHI_MSG_VERBOSE, "Exit\n"); + enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, ev_index)); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n"); } struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle) { int ret_val; + struct mhi_client_config *client_config = client_handle->client_config; - client_handle->result.buf_addr = NULL; - client_handle->result.bytes_xferd = 0; - client_handle->result.transaction_status = 0; - ret_val = mhi_process_event_ring(client_handle->mhi_dev_ctxt, - client_handle->event_ring_index, + client_config->result.buf_addr = NULL; + client_config->result.bytes_xferd = 0; + client_config->result.transaction_status = 0; + ret_val = mhi_process_event_ring(client_config->mhi_dev_ctxt, + client_config->event_ring_index, 1); if (ret_val) - mhi_log(MHI_MSG_INFO, "NAPI failed to process event ring\n"); - return &(client_handle->result); + mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO, + "NAPI failed to process event ring\n"); + return &(client_config->result); } void mhi_mask_irq(struct mhi_client_handle *client_handle) { + struct mhi_client_config *client_config = client_handle->client_config; struct mhi_device_ctxt *mhi_dev_ctxt = - client_handle->mhi_dev_ctxt; + client_config->mhi_dev_ctxt; struct mhi_ring *ev_ring = &mhi_dev_ctxt-> - mhi_local_event_ctxt[client_handle->event_ring_index]; + mhi_local_event_ctxt[client_config->event_ring_index]; - disable_irq_nosync(MSI_TO_IRQ(mhi_dev_ctxt, client_handle->msi_vec)); + disable_irq_nosync(MSI_TO_IRQ(mhi_dev_ctxt, client_config->msi_vec)); ev_ring->msi_disable_cntr++; } void mhi_unmask_irq(struct mhi_client_handle *client_handle) { + struct mhi_client_config *client_config = client_handle->client_config; struct mhi_device_ctxt *mhi_dev_ctxt = - client_handle->mhi_dev_ctxt; + client_config->mhi_dev_ctxt; struct mhi_ring *ev_ring = &mhi_dev_ctxt-> - mhi_local_event_ctxt[client_handle->event_ring_index]; + mhi_local_event_ctxt[client_config->event_ring_index]; ev_ring->msi_enable_cntr++; - enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, client_handle->msi_vec)); + enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, client_config->msi_vec)); } irqreturn_t mhi_msi_handlr(int irq_number, void *dev_id) { - struct device *mhi_device = dev_id; - struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->platform_data; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_id; int msi = IRQ_TO_MSI(mhi_dev_ctxt, irq_number); + struct mhi_ring *mhi_ring = &mhi_dev_ctxt->mhi_local_event_ctxt[msi]; + struct mhi_event_ring_cfg *ring_props = + &mhi_dev_ctxt->ev_ring_props[msi]; - if (!mhi_dev_ctxt) { - mhi_log(MHI_MSG_ERROR, "Failed to get a proper context\n"); - return IRQ_HANDLED; - } mhi_dev_ctxt->counters.msi_counter[ IRQ_TO_MSI(mhi_dev_ctxt, irq_number)]++; - mhi_log(MHI_MSG_VERBOSE, "Got MSI 0x%x\n", msi); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Got MSI 0x%x\n", msi); trace_mhi_msi(IRQ_TO_MSI(mhi_dev_ctxt, irq_number)); - - if (msi) { - atomic_inc(&mhi_dev_ctxt->counters.events_pending); - wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq); - } else { - disable_irq_nosync(irq_number); - tasklet_schedule(&mhi_dev_ctxt->ev_task); - } + disable_irq_nosync(irq_number); + if (ring_props->priority <= MHI_EV_PRIORITY_TASKLET) + tasklet_schedule(&mhi_ring->ev_task); + else + schedule_work(&mhi_ring->ev_worker); return IRQ_HANDLED; } irqreturn_t mhi_msi_ipa_handlr(int irq_number, void *dev_id) { - struct device *mhi_device = dev_id; - u32 client_index; - struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->platform_data; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_id; + struct mhi_event_ring_cfg *ev_ring_props; struct mhi_client_handle *client_handle; + struct mhi_client_config *client_config; struct mhi_client_info_t *client_info; struct mhi_cb_info cb_info; int msi_num = (IRQ_TO_MSI(mhi_dev_ctxt, irq_number)); mhi_dev_ctxt->counters.msi_counter[msi_num]++; - mhi_log(MHI_MSG_VERBOSE, "Got MSI 0x%x\n", msi_num); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Got MSI 0x%x\n", msi_num); trace_mhi_msi(msi_num); - client_index = MHI_MAX_CHANNELS - - (mhi_dev_ctxt->mmio_info.nr_event_rings - msi_num); - client_handle = mhi_dev_ctxt->client_handle_list[client_index]; - client_info = &client_handle->client_info; - if (likely(client_handle)) { - client_handle->result.user_data = - client_handle->user_data; - if (likely(client_info->mhi_client_cb)) { - cb_info.result = &client_handle->result; - cb_info.cb_reason = MHI_CB_XFER; - cb_info.chan = client_handle->chan_info.chan_nr; - cb_info.result->transaction_status = 0; - client_info->mhi_client_cb(&cb_info); - } + + /* Obtain client config from MSI */ + ev_ring_props = &mhi_dev_ctxt->ev_ring_props[msi_num]; + client_handle = mhi_dev_ctxt->client_handle_list[ev_ring_props->chan]; + if (unlikely(!client_handle)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Recv MSI for unreg chan:%u\n", ev_ring_props->chan); + return IRQ_HANDLED; } + + client_config = client_handle->client_config; + client_info = &client_config->client_info; + client_config->result.user_data = + client_config->user_data; + cb_info.result = &client_config->result; + cb_info.cb_reason = MHI_CB_XFER; + cb_info.chan = client_config->chan_info.chan_nr; + cb_info.result->transaction_status = 0; + client_info->mhi_client_cb(&cb_info); + return IRQ_HANDLED; } diff --git a/drivers/platform/msm/mhi/mhi_macros.h b/drivers/platform/msm/mhi/mhi_macros.h index 133c0eeb034e..fc0e6f4bc27d 100644 --- a/drivers/platform/msm/mhi/mhi_macros.h +++ b/drivers/platform/msm/mhi/mhi_macros.h @@ -39,7 +39,6 @@ #define MHI_WORK_Q_MAX_SIZE 128 #define MAX_XFER_WORK_ITEMS 100 -#define MHI_MAX_SUPPORTED_DEVICES 1 #define MHI_PCIE_VENDOR_ID 0x17CB #define MHI_PCIE_DEVICE_ID_9x35 0x0300 @@ -70,9 +69,9 @@ ((enum MHI_CLIENT_CHANNEL)(_CHAN_NR) < MHI_CLIENT_RESERVED_1_LOWER)) #define IRQ_TO_MSI(_MHI_DEV_CTXT, _IRQ_NR) \ - ((_IRQ_NR) - (_MHI_DEV_CTXT)->dev_info->core.irq_base) + ((_IRQ_NR) - (_MHI_DEV_CTXT)->core.irq_base) #define MSI_TO_IRQ(_MHI_DEV_CTXT, _MSI_NR) \ - ((_MHI_DEV_CTXT)->dev_info->core.irq_base + (_MSI_NR)) + ((_MHI_DEV_CTXT)->core.irq_base + (_MSI_NR)) #define VALID_CHAN_NR(_CHAN_NR) (IS_HARDWARE_CHANNEL(_CHAN_NR) || \ IS_SOFTWARE_CHANNEL(_CHAN_NR)) @@ -84,8 +83,8 @@ #define MHI_HW_INTMOD_VAL_MS 2 /* Timeout Values */ -#define MHI_READY_STATUS_TIMEOUT_MS 50 -#define MHI_THREAD_SLEEP_TIMEOUT_MS 20 +#define MHI_READY_STATUS_TIMEOUT_MS 500 +#define MHI_THREAD_SLEEP_TIMEOUT_MS 100 #define MHI_RESUME_WAKE_RETRIES 20 #define IS_HW_EV_RING(_mhi_dev_ctxt, _EV_INDEX) (_EV_INDEX >= \ diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c index 430dc918af7e..644004672cd2 100644 --- a/drivers/platform/msm/mhi/mhi_main.c +++ b/drivers/platform/msm/mhi/mhi_main.c @@ -27,13 +27,23 @@ #include "mhi.h" #include "mhi_hwio.h" #include "mhi_macros.h" +#include "mhi_bhi.h" #include "mhi_trace.h" static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, union mhi_cmd_pkt *cmd_pkt); - -static int enable_bb_ctxt(struct mhi_ring *bb_ctxt, int nr_el) +static void disable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, + struct mhi_ring *bb_ctxt); + +static int enable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, + struct mhi_ring *bb_ctxt, + int nr_el, + int chan, + size_t max_payload) { + int i; + struct mhi_buf_info *mhi_buf_info; + bb_ctxt->el_size = sizeof(struct mhi_buf_info); bb_ctxt->len = bb_ctxt->el_size * nr_el; bb_ctxt->base = kzalloc(bb_ctxt->len, GFP_KERNEL); @@ -42,7 +52,46 @@ static int enable_bb_ctxt(struct mhi_ring *bb_ctxt, int nr_el) bb_ctxt->ack_rp = bb_ctxt->base; if (!bb_ctxt->base) return -ENOMEM; + + if (mhi_dev_ctxt->flags.bb_required) { + char pool_name[32]; + + snprintf(pool_name, sizeof(pool_name), "mhi%d_%d", + mhi_dev_ctxt->plat_dev->id, chan); + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Creating pool %s for chan:%d payload: 0x%lx\n", + pool_name, chan, max_payload); + + bb_ctxt->dma_pool = dma_pool_create(pool_name, + &mhi_dev_ctxt->plat_dev->dev, max_payload, 0, 0); + if (unlikely(!bb_ctxt->dma_pool)) + goto dma_pool_error; + + mhi_buf_info = (struct mhi_buf_info *)bb_ctxt->base; + for (i = 0; i < nr_el; i++, mhi_buf_info++) { + mhi_buf_info->pre_alloc_v_addr = + dma_pool_alloc(bb_ctxt->dma_pool, GFP_KERNEL, + &mhi_buf_info->pre_alloc_p_addr); + if (unlikely(!mhi_buf_info->pre_alloc_v_addr)) + goto dma_alloc_error; + mhi_buf_info->pre_alloc_len = max_payload; + } + } + return 0; + +dma_alloc_error: + for (--i, --mhi_buf_info; i >= 0; i--, mhi_buf_info--) + dma_pool_free(bb_ctxt->dma_pool, mhi_buf_info->pre_alloc_v_addr, + mhi_buf_info->pre_alloc_p_addr); + + dma_pool_destroy(bb_ctxt->dma_pool); + bb_ctxt->dma_pool = NULL; +dma_pool_error: + kfree(bb_ctxt->base); + bb_ctxt->base = NULL; + return -ENOMEM; } static void mhi_write_db(struct mhi_device_ctxt *mhi_dev_ctxt, @@ -66,7 +115,7 @@ static void mhi_update_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_trb_write_ptr = val; } else if (mhi_dev_ctxt->mmio_info.event_db_addr == io_addr) { if (chan < mhi_dev_ctxt->mmio_info.nr_event_rings) { - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "EV ctxt: %ld val 0x%llx WP 0x%llx RP: 0x%llx", chan, val, mhi_dev_ctxt->dev_space.ring_ctxt. @@ -76,7 +125,7 @@ static void mhi_update_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[chan]. mhi_event_write_ptr = val; } else { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Bad EV ring index: %lx\n", chan); } } @@ -84,65 +133,48 @@ static void mhi_update_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, wmb(); } -int mhi_init_pcie_device(struct mhi_pcie_dev_info *mhi_pcie_dev) +int mhi_init_pcie_device(struct mhi_device_ctxt *mhi_dev_ctxt) { int ret_val = 0; long int sleep_time = 100; - struct pci_dev *pcie_device = - (struct pci_dev *)mhi_pcie_dev->pcie_device; + struct pci_dev *pcie_device = mhi_dev_ctxt->pcie_device; + struct pcie_core_info *core = &mhi_dev_ctxt->core; do { - ret_val = pci_enable_device(mhi_pcie_dev->pcie_device); + ret_val = pci_enable_device(pcie_device); if (0 != ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to enable pcie struct device r: %d\n", ret_val); - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Sleeping for ~ %li uS, and retrying.\n", sleep_time); msleep(sleep_time); } } while (ret_val != 0); - mhi_log(MHI_MSG_INFO, "Successfully enabled pcie device.\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Successfully enabled pcie device.\n"); - mhi_pcie_dev->core.bar0_base = - ioremap_nocache(pci_resource_start(pcie_device, 0), - pci_resource_len(pcie_device, 0)); - if (!mhi_pcie_dev->core.bar0_base) + core->bar0_base = ioremap_nocache(pci_resource_start(pcie_device, 0), + pci_resource_len(pcie_device, 0)); + if (!core->bar0_base) goto mhi_device_list_error; - mhi_pcie_dev->core.bar0_end = mhi_pcie_dev->core.bar0_base + - pci_resource_len(pcie_device, 0); - mhi_pcie_dev->core.bar2_base = - ioremap_nocache(pci_resource_start(pcie_device, 2), - pci_resource_len(pcie_device, 2)); - if (!mhi_pcie_dev->core.bar2_base) - goto io_map_err; - - mhi_pcie_dev->core.bar2_end = mhi_pcie_dev->core.bar2_base + - pci_resource_len(pcie_device, 2); - - if (!mhi_pcie_dev->core.bar0_base) { - mhi_log(MHI_MSG_ERROR, - "Failed to register for pcie resources\n"); - goto mhi_pcie_read_ep_config_err; - } + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Device BAR0 address is at 0x%p\n", core->bar0_base); - mhi_log(MHI_MSG_INFO, "Device BAR0 address is at 0x%p\n", - mhi_pcie_dev->core.bar0_base); ret_val = pci_request_region(pcie_device, 0, "mhi"); if (ret_val) - mhi_log(MHI_MSG_ERROR, "Could not request BAR0 region\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Could not request BAR0 region\n"); - mhi_pcie_dev->core.manufact_id = pcie_device->vendor; - mhi_pcie_dev->core.dev_id = pcie_device->device; + core->manufact_id = pcie_device->vendor; + core->dev_id = pcie_device->device; return 0; -io_map_err: - iounmap((void *)mhi_pcie_dev->core.bar0_base); + mhi_device_list_error: pci_disable_device(pcie_device); -mhi_pcie_read_ep_config_err: return -EIO; } @@ -156,7 +188,7 @@ static void mhi_move_interrupts(struct mhi_device_ctxt *mhi_dev_ctxt, u32 cpu) GET_EV_PROPS(EV_TYPE, mhi_dev_ctxt->ev_ring_props[i].flags)) { irq_to_affin = mhi_dev_ctxt->ev_ring_props[i].msi_vec; - irq_to_affin += mhi_dev_ctxt->dev_props->irq_base; + irq_to_affin += mhi_dev_ctxt->core.irq_base; irq_set_affinity(irq_to_affin, get_cpu_mask(cpu)); } } @@ -198,8 +230,9 @@ int get_chan_props(struct mhi_device_ctxt *mhi_dev_ctxt, int chan, scnprintf(dt_prop, MAX_BUF_SIZE, "%s%d", "mhi-chan-cfg-", chan); r = of_property_read_u32_array( - mhi_dev_ctxt->dev_info->plat_dev->dev.of_node, - dt_prop, (u32 *)chan_info, + mhi_dev_ctxt->plat_dev->dev.of_node, + dt_prop, + (u32 *)chan_info, sizeof(struct mhi_chan_info) / sizeof(u32)); return r; } @@ -211,9 +244,10 @@ int mhi_release_chan_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, if (cc_list == NULL || ring == NULL) return -EINVAL; - dma_free_coherent(&mhi_dev_ctxt->dev_info->pcie_device->dev, - ring->len, ring->base, - cc_list->mhi_trb_ring_base_addr); + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, + ring->len, + ring->base, + cc_list->mhi_trb_ring_base_addr); mhi_init_chan_ctxt(cc_list, 0, 0, 0, 0, 0, ring, MHI_CHAN_STATE_DISABLED, false, @@ -221,38 +255,37 @@ int mhi_release_chan_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, return 0; } -void free_tre_ring(struct mhi_client_handle *client_handle) +void free_tre_ring(struct mhi_device_ctxt *mhi_dev_ctxt, int chan) { struct mhi_chan_ctxt *chan_ctxt; - struct mhi_device_ctxt *mhi_dev_ctxt = client_handle->mhi_dev_ctxt; - int chan = client_handle->chan_info.chan_nr; int r; chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; r = mhi_release_chan_ctxt(mhi_dev_ctxt, chan_ctxt, &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]); if (r) - mhi_log(MHI_MSG_ERROR, - "Failed to release chan %d ret %d\n", chan, r); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to release chan %d ret %d\n", chan, r); } -static int populate_tre_ring(struct mhi_client_handle *client_handle) +static int populate_tre_ring(struct mhi_client_config *client_config) { dma_addr_t ring_dma_addr; void *ring_local_addr; struct mhi_chan_ctxt *chan_ctxt; - struct mhi_device_ctxt *mhi_dev_ctxt = client_handle->mhi_dev_ctxt; - u32 chan = client_handle->chan_info.chan_nr; - u32 nr_desc = client_handle->chan_info.max_desc; + struct mhi_device_ctxt *mhi_dev_ctxt = client_config->mhi_dev_ctxt; + u32 chan = client_config->chan_info.chan_nr; + u32 nr_desc = client_config->chan_info.max_desc; - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered chan %d requested desc %d\n", chan, nr_desc); chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; - ring_local_addr = dma_alloc_coherent( - &mhi_dev_ctxt->dev_info->pcie_device->dev, - nr_desc * sizeof(union mhi_xfer_pkt), - &ring_dma_addr, GFP_KERNEL); + ring_local_addr = + dma_alloc_coherent(&mhi_dev_ctxt->plat_dev->dev, + nr_desc * sizeof(union mhi_xfer_pkt), + &ring_dma_addr, + GFP_KERNEL); if (ring_local_addr == NULL) return -ENOMEM; @@ -261,15 +294,15 @@ static int populate_tre_ring(struct mhi_client_handle *client_handle) (uintptr_t)ring_local_addr, nr_desc, GET_CHAN_PROPS(CHAN_DIR, - client_handle->chan_info.flags), - client_handle->chan_info.ev_ring, + client_config->chan_info.flags), + client_config->chan_info.ev_ring, &mhi_dev_ctxt->mhi_local_chan_ctxt[chan], MHI_CHAN_STATE_ENABLED, GET_CHAN_PROPS(PRESERVE_DB_STATE, - client_handle->chan_info.flags), + client_config->chan_info.flags), GET_CHAN_PROPS(BRSTMODE, - client_handle->chan_info.flags)); - mhi_log(MHI_MSG_INFO, "Exited\n"); + client_config->chan_info.flags)); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); return 0; } @@ -283,85 +316,64 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) struct mhi_cmd_complete_event_pkt cmd_event_pkt; union mhi_cmd_pkt cmd_pkt; enum MHI_EVENT_CCS ev_code; + struct mhi_client_config *client_config = client_handle->client_config; - if (!client_handle || client_handle->magic != MHI_HANDLE_MAGIC) + if (client_config->magic != MHI_HANDLE_MAGIC) return -EINVAL; - mhi_dev_ctxt = client_handle->mhi_dev_ctxt; - ret_val = get_chan_props(mhi_dev_ctxt, - client_handle->chan_info.chan_nr, - &client_handle->chan_info); - if (ret_val) - return ret_val; + mhi_dev_ctxt = client_config->mhi_dev_ctxt; - chan = client_handle->chan_info.chan_nr; + chan = client_config->chan_info.chan_nr; cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; chan_ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; mutex_lock(&cfg->chan_lock); - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered: Client opening chan 0x%x\n", chan); if (mhi_dev_ctxt->dev_exec_env < GET_CHAN_PROPS(CHAN_BRINGUP_STAGE, - client_handle->chan_info.flags)) { - mhi_log(MHI_MSG_INFO, + client_config->chan_info.flags)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Chan %d, MHI exec_env %d, not ready!\n", - chan, - mhi_dev_ctxt->dev_exec_env); + chan, mhi_dev_ctxt->dev_exec_env); mutex_unlock(&cfg->chan_lock); return -ENOTCONN; } - ret_val = populate_tre_ring(client_handle); + ret_val = populate_tre_ring(client_config); if (ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to initialize tre ring chan %d ret %d\n", - chan, - ret_val); - mutex_unlock(&cfg->chan_lock); - return ret_val; - } - client_handle->event_ring_index = - mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]. - mhi_event_ring_index; - ret_val = enable_bb_ctxt(&mhi_dev_ctxt->chan_bb_list[chan], - client_handle->chan_info.max_desc); - if (ret_val) { - mhi_log(MHI_MSG_ERROR, - "Failed to initialize bb ctxt chan %d ret %d\n", - chan, - ret_val); - mutex_unlock(&cfg->chan_lock); - return ret_val; + chan, ret_val); + goto error_tre_ring; } + client_config->event_ring_index = + mhi_dev_ctxt->dev_space.ring_ctxt. + cc_list[chan].mhi_event_ring_index; - client_handle->msi_vec = + client_config->msi_vec = mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[ - client_handle->event_ring_index].mhi_msi_vector; - client_handle->intmod_t = + client_config->event_ring_index].mhi_msi_vector; + client_config->intmod_t = mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[ - client_handle->event_ring_index].mhi_intmodt; + client_config->event_ring_index].mhi_intmodt; init_completion(&cfg->cmd_complete); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); if (unlikely(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE)) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "MHI State is disabled\n"); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mutex_unlock(&cfg->chan_lock); - return -EIO; + ret_val = -EIO; + goto error_pm_state; } - WARN_ON(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE); - mhi_assert_device_wake(mhi_dev_ctxt, false); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); + mhi_dev_ctxt->runtime_get(mhi_dev_ctxt); - spin_lock_irq(&chan_ring->ring_lock); - chan_ring->ch_state = MHI_CHAN_STATE_ENABLED; - spin_unlock_irq(&chan_ring->ring_lock); - ret_val = mhi_send_cmd(client_handle->mhi_dev_ctxt, + ret_val = mhi_send_cmd(client_config->mhi_dev_ctxt, MHI_COMMAND_START_CHAN, chan); if (ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to send start cmd for chan %d ret %d\n", chan, ret_val); goto error_completion; @@ -369,9 +381,9 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) ret_val = wait_for_completion_timeout(&cfg->cmd_complete, msecs_to_jiffies(MHI_MAX_CMD_TIMEOUT)); if (!ret_val) { - mhi_log(MHI_MSG_ERROR, - "Failed to receive cmd completion for %d\n", - chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to receive cmd completion for %d\n", chan); + ret_val = -EIO; goto error_completion; } else { ret_val = 0; @@ -385,76 +397,159 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) ev_code = MHI_EV_READ_CODE(EV_TRB_CODE, ((union mhi_event_pkt *)&cmd_event_pkt)); if (ev_code != MHI_EVENT_CC_SUCCESS) { - mhi_log(MHI_MSG_ERROR, - "Error to receive event completion ev_code:0x%x\n", - ev_code); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error to receive event comp. ev_code:0x%x\n", ev_code); ret_val = -EIO; goto error_completion; } - client_handle->chan_status = 1; - -error_completion: + spin_lock_irq(&chan_ring->ring_lock); + chan_ring->ch_state = MHI_CHAN_STATE_ENABLED; + spin_unlock_irq(&chan_ring->ring_lock); + client_config->chan_status = 1; read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info->pcie_device->dev); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); mutex_unlock(&cfg->chan_lock); - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "chan:%d opened successfully\n", chan); + return 0; + +error_completion: + read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); + read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); +error_pm_state: + free_tre_ring(mhi_dev_ctxt, chan); +error_tre_ring: + mutex_unlock(&cfg->chan_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited chan 0x%x ret:%d\n", chan, ret_val); return ret_val; } EXPORT_SYMBOL(mhi_open_channel); +bool mhi_is_device_ready(const struct device * const dev, + const char *node_name) +{ + struct mhi_device_ctxt *itr; + const struct device_node *of_node; + bool match_found = false; + + if (!mhi_device_drv) + return false; + if (dev->of_node == NULL) + return false; + + of_node = of_parse_phandle(dev->of_node, node_name, 0); + if (!of_node) + return false; + + mutex_lock(&mhi_device_drv->lock); + list_for_each_entry(itr, &mhi_device_drv->head, node) { + struct platform_device *pdev = itr->plat_dev; + + if (pdev->dev.of_node == of_node) { + match_found = true; + break; + } + } + mutex_unlock(&mhi_device_drv->lock); + return match_found; +} +EXPORT_SYMBOL(mhi_is_device_ready); + int mhi_register_channel(struct mhi_client_handle **client_handle, - enum MHI_CLIENT_CHANNEL chan, s32 device_index, - struct mhi_client_info_t *client_info, void *user_data) + struct mhi_client_info_t *client_info) { - struct mhi_device_ctxt *mhi_dev_ctxt = NULL; + struct mhi_device_ctxt *mhi_dev_ctxt = NULL, *itr; + const struct device_node *of_node; + struct mhi_client_config *client_config; + const char *node_name; + enum MHI_CLIENT_CHANNEL chan; + int ret; - if (!VALID_CHAN_NR(chan)) + if (!client_info || client_info->dev->of_node == NULL) return -EINVAL; - if (NULL == client_handle || device_index < 0) + node_name = client_info->node_name; + chan = client_info->chan; + of_node = of_parse_phandle(client_info->dev->of_node, node_name, 0); + if (!of_node || !mhi_device_drv || chan >= MHI_MAX_CHANNELS) return -EINVAL; - mhi_dev_ctxt = &(mhi_devices.device_list[device_index].mhi_ctxt); + /* Traverse thru the list */ + mutex_lock(&mhi_device_drv->lock); + list_for_each_entry(itr, &mhi_device_drv->head, node) { + struct platform_device *pdev = itr->plat_dev; + + if (pdev->dev.of_node == of_node) { + mhi_dev_ctxt = itr; + break; + } + } + mutex_unlock(&mhi_device_drv->lock); - if (NULL != mhi_dev_ctxt->client_handle_list[chan]) - return -EISCONN; + if (!mhi_dev_ctxt) + return -EINVAL; - mhi_log(MHI_MSG_INFO, - "Opened channel 0x%x for client\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Registering channel 0x%x for client\n", chan); *client_handle = kzalloc(sizeof(struct mhi_client_handle), GFP_KERNEL); if (NULL == *client_handle) return -ENOMEM; + (*client_handle)->client_config = + kzalloc(sizeof(*(*client_handle)->client_config), GFP_KERNEL); + if ((*client_handle)->client_config == NULL) { + kfree(*client_handle); + *client_handle = NULL; + return -ENOMEM; + } mhi_dev_ctxt->client_handle_list[chan] = *client_handle; - (*client_handle)->mhi_dev_ctxt = mhi_dev_ctxt; - (*client_handle)->user_data = user_data; - (*client_handle)->magic = MHI_HANDLE_MAGIC; - (*client_handle)->chan_info.chan_nr = chan; + (*client_handle)->dev_id = mhi_dev_ctxt->core.dev_id; + (*client_handle)->domain = mhi_dev_ctxt->core.domain; + (*client_handle)->bus = mhi_dev_ctxt->core.bus; + (*client_handle)->slot = mhi_dev_ctxt->core.slot; + client_config = (*client_handle)->client_config; + client_config->mhi_dev_ctxt = mhi_dev_ctxt; + client_config->user_data = client_info->user_data; + client_config->magic = MHI_HANDLE_MAGIC; + client_config->chan_info.chan_nr = chan; if (NULL != client_info) - (*client_handle)->client_info = *client_info; + client_config->client_info = *client_info; if (MHI_CLIENT_IP_HW_0_OUT == chan) - (*client_handle)->intmod_t = 10; + client_config->intmod_t = 10; if (MHI_CLIENT_IP_HW_0_IN == chan) - (*client_handle)->intmod_t = 10; + client_config->intmod_t = 10; + + get_chan_props(mhi_dev_ctxt, chan, &client_config->chan_info); + ret = enable_bb_ctxt(mhi_dev_ctxt, &mhi_dev_ctxt->chan_bb_list[chan], + client_config->chan_info.max_desc, chan, + client_config->client_info.max_payload); + if (ret) { + kfree(mhi_dev_ctxt->client_handle_list[chan]->client_config); + kfree(mhi_dev_ctxt->client_handle_list[chan]); + mhi_dev_ctxt->client_handle_list[chan] = NULL; + return -ENOMEM; + } - if (mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_AMSS) { - mhi_log(MHI_MSG_INFO, - "Exec env is AMSS notifing client now chan: 0x%x\n", - chan); + if (mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_AMSS && + mhi_dev_ctxt->flags.mhi_initialized) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Exec env is AMSS notify client now chan:%u\n", chan); mhi_notify_client(*client_handle, MHI_CB_MHI_ENABLED); } - mhi_log(MHI_MSG_VERBOSE, - "Successfuly registered chan 0x%x\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Successfuly registered chan:%u\n", chan); return 0; } EXPORT_SYMBOL(mhi_register_channel); @@ -469,46 +564,54 @@ void mhi_close_channel(struct mhi_client_handle *client_handle) union mhi_cmd_pkt cmd_pkt; struct mhi_ring *chan_ring; enum MHI_EVENT_CCS ev_code; + struct mhi_client_config *client_config = + client_handle->client_config; - if (!client_handle || - client_handle->magic != MHI_HANDLE_MAGIC || - !client_handle->chan_status) + if (client_config->magic != MHI_HANDLE_MAGIC || + !client_config->chan_status) return; - mhi_dev_ctxt = client_handle->mhi_dev_ctxt; - chan = client_handle->chan_info.chan_nr; + mhi_dev_ctxt = client_config->mhi_dev_ctxt; + chan = client_config->chan_info.chan_nr; cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; - mhi_log(MHI_MSG_INFO, "Client attempting to close chan 0x%x\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Client attempting to close chan 0x%x\n", chan); + chan_ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; mutex_lock(&cfg->chan_lock); /* No more processing events for this channel */ spin_lock_irq(&chan_ring->ring_lock); + if (chan_ring->ch_state != MHI_CHAN_STATE_ENABLED) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Chan %d is not enabled, cur state:0x%x\n", + chan, chan_ring->ch_state); + spin_unlock_irq(&chan_ring->ring_lock); + mutex_unlock(&cfg->chan_lock); + return; + } chan_ring->ch_state = MHI_CHAN_STATE_DISABLED; spin_unlock_irq(&chan_ring->ring_lock); init_completion(&cfg->cmd_complete); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); WARN_ON(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE); - mhi_assert_device_wake(mhi_dev_ctxt, false); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); - ret_val = mhi_send_cmd(client_handle->mhi_dev_ctxt, - MHI_COMMAND_RESET_CHAN, - chan); + mhi_dev_ctxt->runtime_get(mhi_dev_ctxt); + ret_val = mhi_send_cmd(mhi_dev_ctxt, + MHI_COMMAND_RESET_CHAN, chan); if (ret_val) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to send reset cmd for chan %d ret %d\n", - chan, - ret_val); + chan, ret_val); goto error_completion; } ret_val = wait_for_completion_timeout(&cfg->cmd_complete, msecs_to_jiffies(MHI_MAX_CMD_TIMEOUT)); if (!ret_val) { - mhi_log(MHI_MSG_ERROR, - "Failed to receive cmd completion for %d\n", - chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to receive cmd completion for %d\n", chan); goto error_completion; } @@ -519,28 +622,36 @@ void mhi_close_channel(struct mhi_client_handle *client_handle) ev_code = MHI_EV_READ_CODE(EV_TRB_CODE, ((union mhi_event_pkt *)&cmd_event_pkt)); if (ev_code != MHI_EVENT_CC_SUCCESS) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Error to receive event completion ev_cod:0x%x\n", ev_code); - goto error_completion; } +error_completion: ret_val = reset_chan_cmd(mhi_dev_ctxt, &cmd_pkt); if (ret_val) - mhi_log(MHI_MSG_ERROR, - "Error resetting cmd ret:%d\n", - ret_val); - -error_completion: + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error resetting cmd ret:%d\n", ret_val); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info->pcie_device->dev); - mhi_log(MHI_MSG_INFO, "Freeing ring for chan 0x%x\n", chan); - free_tre_ring(client_handle); - mhi_log(MHI_MSG_INFO, "Chan 0x%x confirmed closed.\n", chan); - client_handle->chan_status = 0; + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "resetting bb_ring for chan 0x%x\n", chan); + mhi_dev_ctxt->chan_bb_list[chan].rp = + mhi_dev_ctxt->chan_bb_list[chan].base; + mhi_dev_ctxt->chan_bb_list[chan].wp = + mhi_dev_ctxt->chan_bb_list[chan].base; + mhi_dev_ctxt->chan_bb_list[chan].ack_rp = + mhi_dev_ctxt->chan_bb_list[chan].base; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Freeing ring for chan 0x%x\n", chan); + free_tre_ring(mhi_dev_ctxt, chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Chan 0x%x confirmed closed.\n", chan); + client_config->chan_status = 0; mutex_unlock(&cfg->chan_lock); } EXPORT_SYMBOL(mhi_close_channel); @@ -596,6 +707,7 @@ static inline int mhi_queue_tre(struct mhi_device_ctxt } return 0; } + static int create_bb(struct mhi_device_ctxt *mhi_dev_ctxt, int chan, void *buf, size_t buf_len, enum dma_data_direction dir, struct mhi_buf_info **bb) @@ -606,7 +718,8 @@ static int create_bb(struct mhi_device_ctxt *mhi_dev_ctxt, int r; uintptr_t bb_index, ctxt_index_wp, ctxt_index_rp; - mhi_log(MHI_MSG_RAW, "Entered chan %d\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, + "Entered chan %d\n", chan); get_element_index(bb_ctxt, bb_ctxt->wp, &bb_index); get_element_index(&mhi_dev_ctxt->mhi_local_chan_ctxt[chan], mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp, @@ -615,9 +728,9 @@ static int create_bb(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_dev_ctxt->mhi_local_chan_ctxt[chan].rp, &ctxt_index_rp); BUG_ON(bb_index != ctxt_index_wp); - mhi_log(MHI_MSG_VERBOSE, - "Chan RP index %ld Chan WP index %ld, chan %d\n", - ctxt_index_rp, ctxt_index_wp, chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Chan RP index %ld Chan WP index %ld, chan %d\n", + ctxt_index_rp, ctxt_index_wp, chan); r = ctxt_add_element(bb_ctxt, (void **)&bb_info); if (r) return r; @@ -626,88 +739,76 @@ static int create_bb(struct mhi_device_ctxt *mhi_dev_ctxt, bb_info->client_buf = buf; bb_info->dir = dir; bb_info->bb_p_addr = dma_map_single( - &mhi_dev_ctxt->dev_info->plat_dev->dev, + &mhi_dev_ctxt->plat_dev->dev, bb_info->client_buf, bb_info->buf_len, bb_info->dir); + bb_info->bb_active = 0; if (!VALID_BUF(bb_info->bb_p_addr, bb_info->buf_len, mhi_dev_ctxt)) { - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Buffer outside DMA range 0x%lx, size 0x%zx\n", - (uintptr_t)bb_info->bb_p_addr, buf_len); - dma_unmap_single(&mhi_dev_ctxt->dev_info->plat_dev->dev, + (uintptr_t)bb_info->bb_p_addr, buf_len); + dma_unmap_single(&mhi_dev_ctxt->plat_dev->dev, bb_info->bb_p_addr, bb_info->buf_len, bb_info->dir); - mhi_log(MHI_MSG_RAW, "Allocating BB, chan %d\n", chan); - bb_info->bb_v_addr = dma_alloc_coherent( - &mhi_dev_ctxt->dev_info->pcie_device->dev, - bb_info->buf_len, - &bb_info->bb_p_addr, - GFP_ATOMIC); - if (!bb_info->bb_v_addr) - return -ENOMEM; - mhi_dev_ctxt->counters.bb_used[chan]++; - if (dir == DMA_TO_DEVICE) { - mhi_log(MHI_MSG_INFO, "Copying client buf into BB.\n"); - memcpy(bb_info->bb_v_addr, buf, bb_info->buf_len); - /* Flush out data to bounce buffer */ - wmb(); - } - bb_info->bb_active = 1; + + if (likely((mhi_dev_ctxt->flags.bb_required && + bb_info->pre_alloc_len >= bb_info->buf_len))) { + bb_info->bb_p_addr = bb_info->pre_alloc_p_addr; + bb_info->bb_v_addr = bb_info->pre_alloc_v_addr; + mhi_dev_ctxt->counters.bb_used[chan]++; + if (dir == DMA_TO_DEVICE) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Copying client buf into BB.\n"); + memcpy(bb_info->bb_v_addr, buf, + bb_info->buf_len); + } + bb_info->bb_active = 1; + } else + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "No BB allocated\n"); } *bb = bb_info; - mhi_log(MHI_MSG_RAW, "Exited chan %d\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Exited chan %d\n", chan); return 0; } +static void disable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, + struct mhi_ring *bb_ctxt) +{ + if (mhi_dev_ctxt->flags.bb_required) { + struct mhi_buf_info *bb = + (struct mhi_buf_info *)bb_ctxt->base; + int nr_el = bb_ctxt->len / bb_ctxt->el_size; + int i = 0; + + for (i = 0; i < nr_el; i++, bb++) + dma_pool_free(bb_ctxt->dma_pool, bb->pre_alloc_v_addr, + bb->pre_alloc_p_addr); + dma_pool_destroy(bb_ctxt->dma_pool); + bb_ctxt->dma_pool = NULL; + } + + kfree(bb_ctxt->base); + bb_ctxt->base = NULL; +} + static void free_bounce_buffer(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_buf_info *bb) { - mhi_log(MHI_MSG_RAW, "Entered\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Entered\n"); if (!bb->bb_active) /* This buffer was maped directly to device */ - dma_unmap_single(&mhi_dev_ctxt->dev_info->plat_dev->dev, + dma_unmap_single(&mhi_dev_ctxt->plat_dev->dev, bb->bb_p_addr, bb->buf_len, bb->dir); - else - /* This buffer was bounced */ - dma_free_coherent(&mhi_dev_ctxt->dev_info->pcie_device->dev, - bb->buf_len, - bb->bb_v_addr, - bb->bb_p_addr); - bb->bb_active = 0; - mhi_log(MHI_MSG_RAW, "Exited\n"); -} - -void reset_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, - struct mhi_ring *bb_ctxt) -{ - int r = 0; - struct mhi_buf_info *bb = NULL; - mhi_log(MHI_MSG_VERBOSE, "Entered\n"); - /* - Assumption: No events are expected during or after - this operation is occurring for this channel. - If a bounce buffer was allocated, the coherent memory is - expected to be already freed. - If the user's bounce buffer was mapped, it is expected to be - already unmapped. - Failure of any of the above conditions will result in - a memory leak or subtle memory corruption. - */ - while (!r) { - r = ctxt_del_element(bb_ctxt, (void **)&bb); - if (bb) - free_bounce_buffer(mhi_dev_ctxt, bb); - } - bb_ctxt->ack_rp = bb_ctxt->base; - bb_ctxt->rp = bb_ctxt->base; - bb_ctxt->wp = bb_ctxt->base; - mhi_log(MHI_MSG_VERBOSE, "Exited\n"); + bb->bb_active = 0; + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Exited\n"); } static int mhi_queue_dma_xfer( - struct mhi_client_handle *client_handle, + struct mhi_client_config *client_config, dma_addr_t buf, size_t buf_len, enum MHI_FLAGS mhi_flags) { union mhi_xfer_pkt *pkt_loc; @@ -715,17 +816,17 @@ static int mhi_queue_dma_xfer( enum MHI_CLIENT_CHANNEL chan; struct mhi_device_ctxt *mhi_dev_ctxt; - mhi_dev_ctxt = client_handle->mhi_dev_ctxt; + mhi_dev_ctxt = client_config->mhi_dev_ctxt; MHI_ASSERT(VALID_BUF(buf, buf_len, mhi_dev_ctxt), "Client buffer is of invalid length\n"); - chan = client_handle->chan_info.chan_nr; + chan = client_config->chan_info.chan_nr; pkt_loc = mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp; pkt_loc->data_tx_pkt.buffer_ptr = buf; pkt_loc->type.info = mhi_flags; trace_mhi_tre(pkt_loc, chan, 0); - if (likely(0 != client_handle->intmod_t)) + if (likely(client_config->intmod_t)) MHI_TRB_SET_INFO(TX_TRB_BEI, pkt_loc, 1); else MHI_TRB_SET_INFO(TX_TRB_BEI, pkt_loc, 0); @@ -736,21 +837,21 @@ static int mhi_queue_dma_xfer( /* Ensure writes to descriptor are flushed */ wmb(); - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Channel %d Has buf size of %zd and buf addr %lx, flags 0x%x\n", - chan, buf_len, (uintptr_t)buf, mhi_flags); + chan, buf_len, (uintptr_t)buf, mhi_flags); /* Add the TRB to the correct transfer ring */ ret_val = ctxt_add_element(&mhi_dev_ctxt->mhi_local_chan_ctxt[chan], (void *)&pkt_loc); if (unlikely(0 != ret_val)) { - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Failed to insert trb in xfer ring\n"); return ret_val; } if (MHI_OUT == - GET_CHAN_PROPS(CHAN_DIR, client_handle->chan_info.flags)) + GET_CHAN_PROPS(CHAN_DIR, client_config->chan_info.flags)) atomic_inc(&mhi_dev_ctxt->counters.outbound_acks); return ret_val; @@ -765,56 +866,55 @@ int mhi_queue_xfer(struct mhi_client_handle *client_handle, struct mhi_device_ctxt *mhi_dev_ctxt; u32 chan; unsigned long flags; + struct mhi_client_config *client_config; if (!client_handle || !buf || !buf_len) return -EINVAL; - mhi_dev_ctxt = client_handle->mhi_dev_ctxt; - chan = client_handle->chan_info.chan_nr; + client_config = client_handle->client_config; + mhi_dev_ctxt = client_config->mhi_dev_ctxt; + chan = client_config->chan_info.chan_nr; read_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE) { read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "MHI is not in active state\n"); return -EINVAL; } - - pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); - mhi_assert_device_wake(mhi_dev_ctxt, false); + mhi_dev_ctxt->runtime_get(mhi_dev_ctxt); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); - if (MHI_OUT == GET_CHAN_PROPS(CHAN_DIR, client_handle->chan_info.flags)) + if (GET_CHAN_PROPS(CHAN_DIR, client_config->chan_info.flags) == MHI_OUT) dma_dir = DMA_TO_DEVICE; else dma_dir = DMA_FROM_DEVICE; - r = create_bb(client_handle->mhi_dev_ctxt, - client_handle->chan_info.chan_nr, - buf, buf_len, dma_dir, &bb); + r = create_bb(client_config->mhi_dev_ctxt, + client_config->chan_info.chan_nr, + buf, + buf_len, + dma_dir, + &bb); if (r) { - mhi_log(MHI_MSG_VERBOSE, - "Failed to create BB, chan %d ret %d\n", - chan, - r); - pm_runtime_mark_last_busy(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info-> - pcie_device->dev); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Failed to create BB, chan %d ret %d\n", chan, r); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); read_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); return r; } - mhi_log(MHI_MSG_VERBOSE, - "Queueing to HW: Client Buf 0x%p, size 0x%zx, DMA %llx, chan %d\n", - buf, buf_len, (u64)bb->bb_p_addr, - client_handle->chan_info.chan_nr); - r = mhi_queue_dma_xfer(client_handle, - bb->bb_p_addr, - bb->buf_len, - mhi_flags); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Queueing to HW: Client Buf 0x%p, size 0x%zx, DMA %llx, chan %d\n", + buf, buf_len, (u64)bb->bb_p_addr, + client_config->chan_info.chan_nr); + r = mhi_queue_dma_xfer(client_config, + bb->bb_p_addr, + bb->buf_len, + mhi_flags); /* * Assumption: If create_bounce_buffer did not fail, we do not @@ -826,11 +926,8 @@ int mhi_queue_xfer(struct mhi_client_handle *client_handle, read_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); mhi_queue_tre(mhi_dev_ctxt, chan, MHI_RING_TYPE_XFER_RING); if (dma_dir == DMA_FROM_DEVICE) { - pm_runtime_mark_last_busy(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - pm_runtime_put_noidle(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); } read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); return 0; @@ -848,13 +945,12 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_local_cmd_ctxt[PRIMARY_CMD_RING]; if (chan >= MHI_MAX_CHANNELS || cmd >= MHI_COMMAND_MAX_NR) { - mhi_log(MHI_MSG_ERROR, - "Invalid channel id, received id: 0x%x", - chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid channel id, received id: 0x%x", chan); return -EINVAL; } - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered, MHI state %s dev_exec_env %d chan %d cmd %d\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), mhi_dev_ctxt->dev_exec_env, chan, cmd); @@ -868,14 +964,16 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, ring_el_type = MHI_PKT_TYPE_START_CHAN_CMD; break; default: - mhi_log(MHI_MSG_ERROR, "Bad command received\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Bad command received\n"); return -EINVAL; } spin_lock_irqsave(&mhi_ring->ring_lock, flags); ret_val = ctxt_add_element(mhi_ring, (void *)&cmd_pkt); if (ret_val) { - mhi_log(MHI_MSG_ERROR, "Failed to insert element\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to insert element\n"); spin_unlock_irqrestore(&mhi_ring->ring_lock, flags); return ret_val; } @@ -886,13 +984,10 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_queue_tre(mhi_dev_ctxt, 0, MHI_RING_TYPE_CMD_RING); read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags2); spin_unlock_irqrestore(&mhi_ring->ring_lock, flags); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Sent command 0x%x for chan %d\n", cmd, chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited ret %d.\n", ret_val); - mhi_log(MHI_MSG_VERBOSE, - "Sent command 0x%x for chan %d\n", - cmd, - chan); - - mhi_log(MHI_MSG_INFO, "Exited ret %d.\n", ret_val); return ret_val; } @@ -904,7 +999,7 @@ static void parse_inbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_buf_info *bb; - mhi_log(MHI_MSG_INFO, "Entered\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); bb = bb_ctxt->rp; bb->filled_size = bounced_data_size; @@ -915,7 +1010,7 @@ static void parse_inbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, if (bb->bb_active) { /* This is coherent memory, no cache management is needed */ memcpy(bb->client_buf, bb->bb_v_addr, bb->filled_size); - mhi_log(MHI_MSG_RAW, + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Bounce from BB:0x%p to Client Buf: 0x%p Len 0x%zx\n", bb->client_buf, bb->bb_v_addr, bb->filled_size); } @@ -929,7 +1024,7 @@ static void parse_inbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, * rp, since it can be moved async by mhi_poll_inbound */ free_bounce_buffer(mhi_dev_ctxt, bb); - mhi_log(MHI_MSG_INFO, "Exited\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); } static void parse_outbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, @@ -940,7 +1035,7 @@ static void parse_outbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_buf_info *bb; bb = bb_ctxt->rp; - mhi_log(MHI_MSG_RAW, "Entered\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Entered\n"); BUG_ON(bb->dir != DMA_TO_DEVICE); bb->filled_size = bounced_data_size; BUG_ON(bb->filled_size != bb->buf_len); @@ -948,7 +1043,7 @@ static void parse_outbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, result->bytes_xferd = bb->filled_size; result->transaction_status = 0; free_bounce_buffer(mhi_dev_ctxt, bb); - mhi_log(MHI_MSG_RAW, "Exited\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Exited\n"); } static int parse_outbound(struct mhi_device_ctxt *mhi_dev_ctxt, @@ -957,71 +1052,75 @@ static int parse_outbound(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_result *result = NULL; int ret_val = 0; struct mhi_client_handle *client_handle = NULL; + struct mhi_client_config *client_config; struct mhi_ring *local_chan_ctxt = NULL; struct mhi_cb_info cb_info; struct mhi_ring *bb_ctxt = &mhi_dev_ctxt->chan_bb_list[chan]; local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; client_handle = mhi_dev_ctxt->client_handle_list[chan]; + client_config = client_handle->client_config; /* If ring is empty */ MHI_ASSERT(!unlikely(mhi_dev_ctxt->mhi_local_chan_ctxt[chan].rp == mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp), "Empty Event Ring\n"); parse_outbound_bb(mhi_dev_ctxt, bb_ctxt, - &client_handle->result, xfer_len); + &client_config->result, xfer_len); - mhi_log(MHI_MSG_RAW, "Removing BB from head, chan %d\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, + "Removing BB from head, chan %d\n", chan); atomic_dec(&mhi_dev_ctxt->counters.outbound_acks); - mhi_deassert_device_wake(mhi_dev_ctxt); - pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info->pcie_device->dev); - pm_runtime_mark_last_busy(&mhi_dev_ctxt->dev_info->pcie_device->dev); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); ret_val = ctxt_del_element(&mhi_dev_ctxt->mhi_local_chan_ctxt[chan], NULL); BUG_ON(ret_val); ret_val = ctxt_del_element(bb_ctxt, NULL); BUG_ON(ret_val); - if (NULL != client_handle) { - result = &mhi_dev_ctxt->client_handle_list[chan]->result; - if (NULL != (&client_handle->client_info.mhi_client_cb)) { - client_handle->result.user_data = - client_handle->user_data; - cb_info.cb_reason = MHI_CB_XFER; - cb_info.result = &client_handle->result; - cb_info.chan = chan; - client_handle->client_info.mhi_client_cb(&cb_info); - } + + result = &client_config->result; + if (NULL != (&client_config->client_info.mhi_client_cb)) { + client_config->result.user_data = + client_config->user_data; + cb_info.cb_reason = MHI_CB_XFER; + cb_info.result = result; + cb_info.chan = chan; + client_config->client_info.mhi_client_cb(&cb_info); } - mhi_log(MHI_MSG_RAW, + + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, "Processed outbound ack chan %d Pending acks %d.\n", chan, atomic_read(&mhi_dev_ctxt->counters.outbound_acks)); return 0; } static int parse_inbound(struct mhi_device_ctxt *mhi_dev_ctxt, - u32 chan, union mhi_xfer_pkt *local_ev_trb_loc, u16 xfer_len) + u32 chan, union mhi_xfer_pkt *local_ev_trb_loc, + u16 xfer_len, unsigned ev_ring) { struct mhi_client_handle *client_handle; + struct mhi_client_config *client_config; struct mhi_ring *local_chan_ctxt; struct mhi_result *result; struct mhi_cb_info cb_info; struct mhi_ring *bb_ctxt = &mhi_dev_ctxt->chan_bb_list[chan]; + bool ev_managed = GET_EV_PROPS(EV_MANAGED, + mhi_dev_ctxt->ev_ring_props[ev_ring].flags); int r; uintptr_t bb_index, ctxt_index_rp, ctxt_index_wp; client_handle = mhi_dev_ctxt->client_handle_list[chan]; + client_config = client_handle->client_config; local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; MHI_ASSERT(!unlikely(mhi_dev_ctxt->mhi_local_chan_ctxt[chan].rp == mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp), "Empty Event Ring\n"); - if (NULL != mhi_dev_ctxt->client_handle_list[chan]) - result = &mhi_dev_ctxt->client_handle_list[chan]->result; - - parse_inbound_bb(mhi_dev_ctxt, bb_ctxt, - &client_handle->result, xfer_len); + result = &client_config->result; + parse_inbound_bb(mhi_dev_ctxt, bb_ctxt, result, xfer_len); - if (unlikely(IS_SOFTWARE_CHANNEL(chan))) { + if (ev_managed) { MHI_TX_TRB_SET_LEN(TX_TRB_LEN, local_ev_trb_loc, xfer_len); r = ctxt_del_element(local_chan_ctxt, NULL); BUG_ON(r); @@ -1034,19 +1133,19 @@ static int parse_inbound(struct mhi_device_ctxt *mhi_dev_ctxt, get_element_index(&mhi_dev_ctxt->mhi_local_chan_ctxt[chan], mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp, &ctxt_index_wp); - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Chan RP index %ld Chan WP index %ld chan %d\n", ctxt_index_rp, ctxt_index_wp, chan); BUG_ON(bb_index != ctxt_index_rp); - if (NULL != client_handle->client_info.mhi_client_cb) { - client_handle->result.user_data = - client_handle->user_data; + if (client_config->client_info.mhi_client_cb) { + client_config->result.user_data = + client_config->user_data; cb_info.cb_reason = MHI_CB_XFER; - cb_info.result = &client_handle->result; + cb_info.result = &client_config->result; cb_info.chan = chan; - client_handle->client_info.mhi_client_cb(&cb_info); + client_config->client_info.mhi_client_cb(&cb_info); } else { - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "No client registered chan %d\n", chan); } } else { @@ -1067,7 +1166,7 @@ static int parse_inbound(struct mhi_device_ctxt *mhi_dev_ctxt, &mhi_dev_ctxt->mhi_local_chan_ctxt[chan], mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp, &ctxt_index_wp); - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Chan RP index %ld Chan WP index %ld chan %d\n", ctxt_index_rp, ctxt_index_wp, chan); BUG_ON(bb_index != ctxt_index_rp); @@ -1088,27 +1187,32 @@ static int validate_xfer_el_addr(struct mhi_chan_ctxt *ring, -ERANGE : 0; } -static void print_tre(int chan, struct mhi_ring *ring, struct mhi_tx_pkt *tre) +static void print_tre(struct mhi_device_ctxt *mhi_dev_ctxt, + int chan, + struct mhi_ring *ring, + struct mhi_tx_pkt *tre) { uintptr_t el_index; get_element_index(ring, tre, &el_index); - mhi_log(MHI_MSG_ERROR, "Printing TRE 0x%p index %lx for channel %d:\n", - tre, el_index, chan); - mhi_log(MHI_MSG_ERROR, "Buffer Pointer 0x%llx, len 0x%x, info 0x%x\n", - tre->buffer_ptr, tre->buf_len, tre->info); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Printing TRE 0x%p index %lx for channel %d:\n", + tre, el_index, chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Buffer Pointer 0x%llx, len 0x%x, info 0x%x\n", + tre->buffer_ptr, tre->buf_len, tre->info); } -int parse_xfer_event(struct mhi_device_ctxt *ctxt, +int parse_xfer_event(struct mhi_device_ctxt *mhi_dev_ctxt, union mhi_event_pkt *event, u32 event_id) { - struct mhi_device_ctxt *mhi_dev_ctxt = (struct mhi_device_ctxt *)ctxt; struct mhi_result *result; u32 chan = MHI_MAX_CHANNELS; u16 xfer_len; uintptr_t phy_ev_trb_loc; union mhi_xfer_pkt *local_ev_trb_loc; struct mhi_client_handle *client_handle; + struct mhi_client_config *client_config; union mhi_xfer_pkt *local_trb_loc; struct mhi_chan_ctxt *chan_ctxt; u32 nr_trb_to_parse; @@ -1121,11 +1225,11 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; ev_code = MHI_EV_READ_CODE(EV_TRB_CODE, event); client_handle = mhi_dev_ctxt->client_handle_list[chan]; - client_handle->pkt_count++; - result = &client_handle->result; - mhi_log(MHI_MSG_VERBOSE, - "Event Received, chan %d, cc_code %d\n", - chan, ev_code); + client_config = client_handle->client_config; + client_config->pkt_count++; + result = &client_config->result; + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Event Received, chan %d, cc_code %d\n", chan, ev_code); if (ev_code == MHI_EVENT_CC_OVERFLOW) result->transaction_status = -EOVERFLOW; else @@ -1158,10 +1262,9 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, local_ev_trb_loc, &nr_trb_to_parse); if (unlikely(ret_val)) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to get nr available trbs ret: %d.\n", ret_val); - panic("critical error"); return ret_val; } do { @@ -1177,14 +1280,14 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, local_trb_loc); if (!VALID_BUF(trb_data_loc, xfer_len, mhi_dev_ctxt)) { - mhi_log(MHI_MSG_CRITICAL, - "Bad buffer ptr: %lx.\n", - (uintptr_t)trb_data_loc); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Bad buf ptr: %llx.\n", trb_data_loc); return -EINVAL; } if (local_chan_ctxt->dir == MHI_IN) { parse_inbound(mhi_dev_ctxt, chan, - local_ev_trb_loc, xfer_len); + local_ev_trb_loc, xfer_len, + event_id); } else { parse_outbound(mhi_dev_ctxt, chan, local_ev_trb_loc, xfer_len); @@ -1192,7 +1295,7 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, mhi_dev_ctxt->counters.chan_pkts_xferd[chan]++; if (local_trb_loc == (union mhi_xfer_pkt *)local_chan_ctxt->rp) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done. Processed until: %lx.\n", (uintptr_t)trb_data_loc); break; @@ -1208,7 +1311,8 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, { u64 db_value = 0; - mhi_log(MHI_MSG_INFO, "DB_MODE/OOB Detected chan %d.\n", chan); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "DB_MODE/OOB Detected chan %d.\n", chan); local_chan_ctxt->db_mode.db_mode = 1; if (local_chan_ctxt->wp != local_chan_ctxt->rp) { @@ -1219,9 +1323,6 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, mhi_dev_ctxt->mmio_info.chan_db_addr, chan, db_value); } - client_handle = mhi_dev_ctxt->client_handle_list[chan]; - if (client_handle) - result->transaction_status = -ENOTCONN; break; } case MHI_EVENT_CC_BAD_TRE: @@ -1229,15 +1330,16 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, local_ev_trb_loc = (void *)mhi_p2v_addr(mhi_dev_ctxt, MHI_RING_TYPE_EVENT_RING, event_id, phy_ev_trb_loc); - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Received BAD TRE event for ring %d, pointer 0x%p\n", chan, local_ev_trb_loc); - print_tre(chan, &mhi_dev_ctxt->mhi_local_chan_ctxt[chan], + print_tre(mhi_dev_ctxt, chan, + &mhi_dev_ctxt->mhi_local_chan_ctxt[chan], (struct mhi_tx_pkt *)local_ev_trb_loc); BUG(); break; default: - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Unknown TX completion.\n"); break; @@ -1261,12 +1363,14 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt, ret_val = ctxt_del_element(ring, &removed_element); if (ret_val) { - mhi_log(MHI_MSG_ERROR, "Could not remove element from ring\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Could not remove element from ring\n"); return ret_val; } ret_val = ctxt_add_element(ring, &added_element); if (ret_val) { - mhi_log(MHI_MSG_ERROR, "Could not add element to ring\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Could not add element to ring\n"); return ret_val; } @@ -1296,9 +1400,7 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_ring *ev_ring; struct mhi_chan_ctxt *chan_ctxt; struct mhi_event_ctxt *ev_ctxt = NULL; - struct mhi_client_handle *client_handle = NULL; int pending_el = 0, i; - struct mhi_ring *bb_ctxt; unsigned long flags; union mhi_event_pkt *local_rp = NULL; union mhi_event_pkt *device_rp = NULL; @@ -1306,20 +1408,19 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan); if (!VALID_CHAN_NR(chan)) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Bad channel number for CCE\n"); return -EINVAL; } - bb_ctxt = &mhi_dev_ctxt->chan_bb_list[chan]; - client_handle = mhi_dev_ctxt->client_handle_list[chan]; local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; ev_ring = &mhi_dev_ctxt-> mhi_local_event_ctxt[chan_ctxt->mhi_event_ring_index]; ev_ctxt = &mhi_dev_ctxt-> dev_space.ring_ctxt.ec_list[chan_ctxt->mhi_event_ring_index]; - mhi_log(MHI_MSG_INFO, "Processed cmd reset event\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Processed cmd reset event\n"); /* Clear all stale events related to Channel */ spin_lock_irqsave(&ev_ring->ring_lock, flags); @@ -1357,21 +1458,18 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, local_chan_ctxt->rp, local_chan_ctxt->wp, &pending_el); - mhi_log(MHI_MSG_INFO, "Decrementing chan %d out acks by %d.\n", - chan, pending_el); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Decrementing chan %d out acks by %d.\n", chan, pending_el); atomic_sub(pending_el, &mhi_dev_ctxt->counters.outbound_acks); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); for (i = 0; i < pending_el; i++) - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); for (i = 0; i < pending_el; i++) { - pm_runtime_put_noidle(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - pm_runtime_mark_last_busy(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); } /* Reset the local channel context */ @@ -1384,10 +1482,7 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, chan_ctxt->mhi_trb_read_ptr = chan_ctxt->mhi_trb_ring_base_addr; chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr; - mhi_log(MHI_MSG_INFO, "Cleaning up BB list\n"); - reset_bb_ctxt(mhi_dev_ctxt, bb_ctxt); - - mhi_log(MHI_MSG_INFO, "Reset complete.\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Reset complete.\n"); return ret_val; } @@ -1418,15 +1513,17 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle, struct mhi_chan_cfg *cfg; struct mhi_ring *bb_ctxt = NULL; struct mhi_buf_info *bb = NULL; + struct mhi_client_config *client_config; int chan = 0, r = 0; - if (!client_handle || !result || !client_handle->mhi_dev_ctxt) + if (!client_handle || !result) return -EINVAL; + client_config = client_handle->client_config; + mhi_dev_ctxt = client_config->mhi_dev_ctxt; - mhi_log(MHI_MSG_VERBOSE, "Entered\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Entered\n"); - mhi_dev_ctxt = client_handle->mhi_dev_ctxt; - chan = client_handle->chan_info.chan_nr; + chan = client_config->chan_info.chan_nr; local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; bb_ctxt = &mhi_dev_ctxt->chan_bb_list[chan]; @@ -1437,7 +1534,7 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle, result->flags = pending_trb->info; bb = bb_ctxt->ack_rp; if (bb->bb_active) { - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Bounce buffer active chan %d, copying data\n", chan); } @@ -1458,7 +1555,7 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle, r = -ENODATA; } mutex_unlock(&cfg->chan_lock); - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exited Result: Buf addr: 0x%p Bytes xfed 0x%zx chan %d\n", result->buf_addr, result->bytes_xferd, chan); return r; @@ -1488,11 +1585,11 @@ int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt) while (mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr, MHIREGLEN) == 0xFFFFFFFF && j <= MHI_MAX_LINK_RETRIES) { - mhi_log(MHI_MSG_CRITICAL, - "Could not access device retry %d\n", j); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Could not access device retry %d\n", j); msleep(MHI_LINK_STABILITY_WAIT_MS); if (MHI_MAX_LINK_RETRIES == j) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Could not access device, FAILING!\n"); return -ETIME; } @@ -1503,9 +1600,12 @@ int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt) int mhi_get_max_desc(struct mhi_client_handle *client_handle) { + struct mhi_client_config *client_config; + if (!client_handle) return -EINVAL; - return client_handle->chan_info.max_desc - 1; + client_config = client_handle->client_config; + return client_config->chan_info.max_desc - 1; } EXPORT_SYMBOL(mhi_get_max_desc); @@ -1514,6 +1614,27 @@ int mhi_get_epid(struct mhi_client_handle *client_handle) return MHI_EPID; } +void mhi_master_mode_runtime_get(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + pm_runtime_get(&mhi_dev_ctxt->pcie_device->dev); +} + +void mhi_master_mode_runtime_put(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + pm_runtime_mark_last_busy(&mhi_dev_ctxt->pcie_device->dev); + pm_runtime_put_noidle(&mhi_dev_ctxt->pcie_device->dev); +} + +void mhi_slave_mode_runtime_get(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + mhi_dev_ctxt->bus_master_rt_get(mhi_dev_ctxt->pcie_device); +} + +void mhi_slave_mode_runtime_put(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + mhi_dev_ctxt->bus_master_rt_put(mhi_dev_ctxt->pcie_device); +} + /* * mhi_assert_device_wake - Set WAKE_DB register * force_set - if true, will set bit regardless of counts @@ -1572,16 +1693,17 @@ void mhi_deassert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt) int mhi_set_lpm(struct mhi_client_handle *client_handle, bool enable_lpm) { - struct mhi_device_ctxt *mhi_dev_ctxt = client_handle->mhi_dev_ctxt; + struct mhi_client_config *client_config = client_handle->client_config; + struct mhi_device_ctxt *mhi_dev_ctxt = client_config->mhi_dev_ctxt; unsigned long flags; read_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); /* Disable low power mode by asserting Wake */ if (enable_lpm == false) - mhi_assert_device_wake(mhi_dev_ctxt, false); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); else - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); @@ -1592,26 +1714,147 @@ EXPORT_SYMBOL(mhi_set_lpm); int mhi_set_bus_request(struct mhi_device_ctxt *mhi_dev_ctxt, int index) { - mhi_log(MHI_MSG_INFO, "Setting bus request to index %d\n", index); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Setting bus request to index %d\n", index); return msm_bus_scale_client_update_request(mhi_dev_ctxt->bus_client, index); } -int mhi_deregister_channel(struct mhi_client_handle - *client_handle) { +int mhi_deregister_channel(struct mhi_client_handle *client_handle) +{ int ret_val = 0; int chan; + struct mhi_client_config *client_config; + struct mhi_device_ctxt *mhi_dev_ctxt; - if (!client_handle || client_handle->magic != MHI_HANDLE_MAGIC) + if (!client_handle) return -EINVAL; - chan = client_handle->chan_info.chan_nr; - client_handle->magic = 0; - client_handle->mhi_dev_ctxt->client_handle_list[chan] = NULL; + + client_config = client_handle->client_config; + mhi_dev_ctxt = client_config->mhi_dev_ctxt; + chan = client_config->chan_info.chan_nr; + client_config->magic = 0; + mhi_dev_ctxt->client_handle_list[chan] = NULL; + disable_bb_ctxt(mhi_dev_ctxt, &mhi_dev_ctxt->chan_bb_list[chan]); + kfree(client_config); kfree(client_handle); return ret_val; } EXPORT_SYMBOL(mhi_deregister_channel); +int mhi_register_device(struct mhi_device *mhi_device, + const char *node_name, + unsigned long user_data) +{ + const struct device_node *of_node; + struct mhi_device_ctxt *mhi_dev_ctxt = NULL, *itr; + struct pcie_core_info *core_info; + struct pci_dev *pci_dev = mhi_device->pci_dev; + u32 domain = pci_domain_nr(pci_dev->bus); + u32 bus = pci_dev->bus->number; + u32 dev_id = pci_dev->device; + u32 slot = PCI_SLOT(pci_dev->devfn); + int ret, i; + + of_node = of_parse_phandle(mhi_device->dev->of_node, node_name, 0); + if (!of_node) + return -EINVAL; + + if (!mhi_device_drv) + return -EPROBE_DEFER; + + /* Traverse thru the list */ + mutex_lock(&mhi_device_drv->lock); + list_for_each_entry(itr, &mhi_device_drv->head, node) { + struct platform_device *pdev = itr->plat_dev; + struct pcie_core_info *core = &itr->core; + + if (pdev->dev.of_node == of_node && + core->domain == domain && + core->bus == bus && + core->dev_id == dev_id && + core->slot == slot) { + mhi_dev_ctxt = itr; + break; + } + } + mutex_unlock(&mhi_device_drv->lock); + + /* perhaps we've not probed yet */ + if (!mhi_dev_ctxt) + return -EPROBE_DEFER; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Registering Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n", + domain, bus, dev_id, slot); + + /* Set up pcie dev info */ + mhi_dev_ctxt->pcie_device = pci_dev; + mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE; + INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition); + INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker); + mutex_init(&mhi_dev_ctxt->pm_lock); + rwlock_init(&mhi_dev_ctxt->pm_xfer_lock); + spin_lock_init(&mhi_dev_ctxt->dev_wake_lock); + init_completion(&mhi_dev_ctxt->cmd_complete); + mhi_dev_ctxt->flags.link_up = 1; + core_info = &mhi_dev_ctxt->core; + core_info->manufact_id = pci_dev->vendor; + core_info->pci_master = false; + + /* Go thru resources and set up */ + for (i = 0; i < ARRAY_SIZE(mhi_device->resources); i++) { + const struct resource *res = &mhi_device->resources[i]; + + switch (resource_type(res)) { + case IORESOURCE_MEM: + /* bus master already mapped it */ + core_info->bar0_base = (void __iomem *)res->start; + core_info->bar0_end = (void __iomem *)res->end; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "bar mapped to:0x%llx - 0x%llx (virtual)\n", + res->start, res->end); + break; + case IORESOURCE_IRQ: + core_info->irq_base = (u32)res->start; + core_info->max_nr_msis = (u32)resource_size(res); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "irq mapped to: %u size:%u\n", + core_info->irq_base, + core_info->max_nr_msis); + break; + }; + } + + if (!core_info->bar0_base || !core_info->irq_base) + return -EINVAL; + + mhi_dev_ctxt->bus_master_rt_get = mhi_device->pm_runtime_get; + mhi_dev_ctxt->bus_master_rt_put = mhi_device->pm_runtime_noidle; + if (!mhi_dev_ctxt->bus_master_rt_get || + !mhi_dev_ctxt->bus_master_rt_put) + return -EINVAL; + + ret = mhi_ctxt_init(mhi_dev_ctxt); + if (ret) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "MHI Initialization failed, ret %d\n", ret); + return ret; + } + mhi_init_debugfs(mhi_dev_ctxt); + + /* setup shadow pm functions */ + mhi_dev_ctxt->assert_wake = mhi_assert_device_wake; + mhi_dev_ctxt->deassert_wake = mhi_deassert_device_wake; + mhi_dev_ctxt->runtime_get = mhi_slave_mode_runtime_get; + mhi_dev_ctxt->runtime_put = mhi_slave_mode_runtime_put; + mhi_device->mhi_dev_ctxt = mhi_dev_ctxt; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n"); + + return 0; +} +EXPORT_SYMBOL(mhi_register_device); + void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr, uintptr_t chan, @@ -1627,9 +1870,9 @@ void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt, ring_ctxt = &mhi_dev_ctxt-> mhi_local_event_ctxt[chan]; - mhi_log(MHI_MSG_VERBOSE, - "db.set addr: %p io_offset 0x%lx val:0x%x\n", - io_addr, chan, val); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "db.set addr: %p io_offset 0x%lx val:0x%x\n", + io_addr, chan, val); mhi_update_ctxt(mhi_dev_ctxt, io_addr, chan, val); @@ -1637,10 +1880,9 @@ void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_write_db(mhi_dev_ctxt, io_addr, chan, val); ring_ctxt->db_mode.db_mode = 0; } else { - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Not ringing xfer db, chan %ld, brstmode %d db_mode %d\n", - chan, - ring_ctxt->db_mode.brstmode, + chan, ring_ctxt->db_mode.brstmode, ring_ctxt->db_mode.db_mode); } } @@ -1650,10 +1892,9 @@ void mhi_process_db_brstmode_disable(struct mhi_device_ctxt *mhi_dev_ctxt, uintptr_t chan, u32 val) { - mhi_log(MHI_MSG_VERBOSE, - "db.set addr: %p io_offset 0x%lx val:0x%x\n", - io_addr, chan, val); - + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "db.set addr: %p io_offset 0x%lx val:0x%x\n", + io_addr, chan, val); mhi_update_ctxt(mhi_dev_ctxt, io_addr, chan, val); mhi_write_db(mhi_dev_ctxt, io_addr, chan, val); } @@ -1663,9 +1904,9 @@ void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, uintptr_t chan, u32 val) { - mhi_log(MHI_MSG_VERBOSE, - "db.set addr: %p io_offset 0x%lx val:0x%x\n", - io_addr, chan, val); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "db.set addr: %p io_offset 0x%lx val:0x%x\n", + io_addr, chan, val); mhi_update_ctxt(mhi_dev_ctxt, io_addr, chan, val); @@ -1678,7 +1919,7 @@ void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_write_db(mhi_dev_ctxt, io_addr, chan, val); chan_ctxt->db_mode.db_mode = 0; } else { - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Not ringing xfer db, chan %ld, brstmode %d db_mode %d\n", chan, chan_ctxt->db_mode.brstmode, chan_ctxt->db_mode.db_mode); @@ -1714,10 +1955,9 @@ void mhi_reg_write(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr, uintptr_t io_offset, u32 val) { - mhi_log(MHI_MSG_RAW, "d.s 0x%p off: 0x%lx 0x%x\n", - io_addr, io_offset, val); + mhi_log(mhi_dev_ctxt, MHI_MSG_RAW, + "d.s 0x%p off: 0x%lx 0x%x\n", io_addr, io_offset, val); iowrite32(val, io_addr + io_offset); - /* Flush write to device */ wmb(); } diff --git a/drivers/platform/msm/mhi/mhi_mmio_ops.c b/drivers/platform/msm/mhi/mhi_mmio_ops.c index b4447378683e..a991a2e68b34 100644 --- a/drivers/platform/msm/mhi/mhi_mmio_ops.c +++ b/drivers/platform/msm/mhi/mhi_mmio_ops.c @@ -29,93 +29,79 @@ int mhi_test_for_device_reset(struct mhi_device_ctxt *mhi_dev_ctxt) { u32 pcie_word_val = 0; - u32 expiry_counter; unsigned long flags; rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; + unsigned long timeout; - mhi_log(MHI_MSG_INFO, "Waiting for MMIO RESET bit to be cleared.\n"); - read_lock_irqsave(pm_xfer_lock, flags); - if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { - read_unlock_irqrestore(pm_xfer_lock, flags); - return -EIO; - } - pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr, - MHISTATUS); - MHI_READ_FIELD(pcie_word_val, - MHICTRL_RESET_MASK, - MHICTRL_RESET_SHIFT); - read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); - if (pcie_word_val == 0xFFFFFFFF) - return -ENOTCONN; - - while (MHI_STATE_RESET != pcie_word_val && expiry_counter < 100) { - expiry_counter++; - mhi_log(MHI_MSG_ERROR, - "Device is not RESET, sleeping and retrying.\n"); - msleep(MHI_READY_STATUS_TIMEOUT_MS); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Waiting for MMIO RESET bit to be cleared.\n"); + + timeout = jiffies + + msecs_to_jiffies(mhi_dev_ctxt->poll_reset_timeout_ms); + while (time_before(jiffies, timeout)) { read_lock_irqsave(pm_xfer_lock, flags); if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { read_unlock_irqrestore(pm_xfer_lock, flags); return -EIO; } pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr, - MHICTRL); + MHICTRL); + read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); + if (pcie_word_val == 0xFFFFFFFF) + return -ENOTCONN; MHI_READ_FIELD(pcie_word_val, - MHICTRL_RESET_MASK, - MHICTRL_RESET_SHIFT); - read_unlock_irqrestore(pm_xfer_lock, flags); - } + MHICTRL_RESET_MASK, + MHICTRL_RESET_SHIFT); - if (MHI_STATE_READY != pcie_word_val) - return -ENOTCONN; - return 0; + if (!pcie_word_val) + return 0; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI still in Reset sleeping\n"); + msleep(MHI_THREAD_SLEEP_TIMEOUT_MS); + } + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Timeout waiting for reset to be cleared\n"); + return -ETIMEDOUT; } int mhi_test_for_device_ready(struct mhi_device_ctxt *mhi_dev_ctxt) { u32 pcie_word_val = 0; - u32 expiry_counter; unsigned long flags; rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; + unsigned long timeout; - mhi_log(MHI_MSG_INFO, "Waiting for MMIO Ready bit to be set\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Waiting for MMIO Ready bit to be set\n"); - read_lock_irqsave(pm_xfer_lock, flags); - if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { - read_unlock_irqrestore(pm_xfer_lock, flags); - return -EIO; - } - /* Read MMIO and poll for READY bit to be set */ - pcie_word_val = mhi_reg_read( - mhi_dev_ctxt->mmio_info.mmio_addr, MHISTATUS); - MHI_READ_FIELD(pcie_word_val, - MHISTATUS_READY_MASK, - MHISTATUS_READY_SHIFT); - read_unlock_irqrestore(pm_xfer_lock, flags); - - if (pcie_word_val == 0xFFFFFFFF) - return -ENOTCONN; - expiry_counter = 0; - while (MHI_STATE_READY != pcie_word_val && expiry_counter < 50) { - expiry_counter++; - mhi_log(MHI_MSG_ERROR, - "Device is not ready, sleeping and retrying.\n"); - msleep(MHI_READY_STATUS_TIMEOUT_MS); + timeout = jiffies + + msecs_to_jiffies(mhi_dev_ctxt->poll_reset_timeout_ms); + while (time_before(jiffies, timeout)) { + /* Read MMIO and poll for READY bit to be set */ read_lock_irqsave(pm_xfer_lock, flags); if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { read_unlock_irqrestore(pm_xfer_lock, flags); return -EIO; } + pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr, MHISTATUS); - MHI_READ_FIELD(pcie_word_val, - MHISTATUS_READY_MASK, MHISTATUS_READY_SHIFT); read_unlock_irqrestore(pm_xfer_lock, flags); + if (pcie_word_val == 0xFFFFFFFF) + return -ENOTCONN; + MHI_READ_FIELD(pcie_word_val, + MHISTATUS_READY_MASK, + MHISTATUS_READY_SHIFT); + if (pcie_word_val == MHI_STATE_READY) + return 0; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Device is not ready, sleeping and retrying.\n"); + msleep(MHI_THREAD_SLEEP_TIMEOUT_MS); } - - if (pcie_word_val != MHI_STATE_READY) - return -ETIMEDOUT; - return 0; + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Device timed out waiting for ready\n"); + return -ETIMEDOUT; } int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) @@ -125,28 +111,26 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) u32 i = 0; int ret_val; - mhi_log(MHI_MSG_INFO, "~~~ Initializing MMIO ~~~\n"); - mhi_dev_ctxt->mmio_info.mmio_addr = mhi_dev_ctxt->dev_props->bar0_base; - - mhi_log(MHI_MSG_INFO, "Bar 0 address is at: 0x%p\n", - mhi_dev_ctxt->mmio_info.mmio_addr); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "~~~ Initializing MMIO ~~~\n"); + mhi_dev_ctxt->mmio_info.mmio_addr = mhi_dev_ctxt->core.bar0_base; mhi_dev_ctxt->mmio_info.mmio_len = mhi_reg_read( mhi_dev_ctxt->mmio_info.mmio_addr, MHIREGLEN); if (0 == mhi_dev_ctxt->mmio_info.mmio_len) { - mhi_log(MHI_MSG_ERROR, "Received mmio length as zero\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Received mmio length as zero\n"); return -EIO; } - mhi_log(MHI_MSG_INFO, "Testing MHI Ver\n"); - mhi_dev_ctxt->dev_props->mhi_ver = mhi_reg_read( + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Testing MHI Ver\n"); + mhi_dev_ctxt->core.mhi_ver = mhi_reg_read( mhi_dev_ctxt->mmio_info.mmio_addr, MHIVER); - if (MHI_VERSION != mhi_dev_ctxt->dev_props->mhi_ver) { - mhi_log(MHI_MSG_CRITICAL, - "Bad MMIO version, 0x%x\n", - mhi_dev_ctxt->dev_props->mhi_ver); + if (mhi_dev_ctxt->core.mhi_ver != MHI_VERSION) { + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Bad MMIO version, 0x%x\n", mhi_dev_ctxt->core.mhi_ver); return ret_val; } @@ -159,9 +143,10 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) else chan_ctxt->chstate = MHI_CHAN_STATE_DISABLED; } - mhi_log(MHI_MSG_INFO, - "Read back MMIO Ready bit successfully. Moving on..\n"); - mhi_log(MHI_MSG_INFO, "Reading channel doorbell offset\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Read back MMIO Ready bit successfully. Moving on..\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Reading channel doorbell offset\n"); mhi_dev_ctxt->mmio_info.chan_db_addr = mhi_dev_ctxt->mmio_info.mmio_addr; @@ -173,13 +158,15 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) CHDBOFF, CHDBOFF_CHDBOFF_MASK, CHDBOFF_CHDBOFF_SHIFT); - mhi_log(MHI_MSG_INFO, "Reading event doorbell offset\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Reading event doorbell offset\n"); mhi_dev_ctxt->mmio_info.event_db_addr += mhi_reg_read_field( mhi_dev_ctxt->mmio_info.mmio_addr, ERDBOFF, ERDBOFF_ERDBOFF_MASK, ERDBOFF_ERDBOFF_SHIFT); - mhi_log(MHI_MSG_INFO, "Setting all MMIO values.\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Setting all MMIO values.\n"); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr, MHICFG, @@ -290,7 +277,7 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_MASK, MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_SHIFT, pcie_word_val); - mhi_log(MHI_MSG_INFO, "Done..\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done..\n"); return 0; } diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c index 2f44601e225e..d7a4f7aa93ef 100644 --- a/drivers/platform/msm/mhi/mhi_pm.c +++ b/drivers/platform/msm/mhi/mhi_pm.c @@ -20,14 +20,17 @@ #include "mhi_sys.h" #include "mhi.h" #include "mhi_hwio.h" +#include "mhi_bhi.h" /* Write only sysfs attributes */ static DEVICE_ATTR(MHI_M0, S_IWUSR, NULL, sysfs_init_m0); +static DEVICE_ATTR(MHI_M3, S_IWUSR, NULL, sysfs_init_m3); /* Read only sysfs attributes */ static struct attribute *mhi_attributes[] = { &dev_attr_MHI_M0.attr, + &dev_attr_MHI_M3.attr, NULL, }; @@ -38,9 +41,9 @@ static struct attribute_group mhi_attribute_group = { int mhi_pci_suspend(struct device *dev) { int r = 0; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); - mhi_log(MHI_MSG_INFO, "Entered\n"); - + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); /* if rpm status still active then force suspend */ if (!pm_runtime_status_suspended(dev)) { r = mhi_runtime_suspend(dev); @@ -51,86 +54,134 @@ int mhi_pci_suspend(struct device *dev) pm_runtime_set_suspended(dev); pm_runtime_disable(dev); - mhi_log(MHI_MSG_INFO, "Exit\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit\n"); return r; } -int mhi_runtime_suspend(struct device *dev) +static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, + bool force_m3) { int r = 0; - struct mhi_device_ctxt *mhi_dev_ctxt = dev->platform_data; - mutex_lock(&mhi_dev_ctxt->pm_lock); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - - mhi_log(MHI_MSG_INFO, "Entered with State:0x%x %s\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered with State:0x%x %s\n", mhi_dev_ctxt->mhi_pm_state, TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); /* Link is already disabled */ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE || mhi_dev_ctxt->mhi_pm_state == MHI_PM_M3) { - mhi_log(MHI_MSG_INFO, "Already in active state, exiting\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Already in M3 State\n"); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mutex_unlock(&mhi_dev_ctxt->pm_lock); return 0; } - if (unlikely(atomic_read(&mhi_dev_ctxt->counters.device_wake))) { - mhi_log(MHI_MSG_INFO, "Busy, Aborting Runtime Suspend\n"); + if (unlikely(atomic_read(&mhi_dev_ctxt->counters.device_wake) && + force_m3 == false)){ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Busy, Aborting M3\n"); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mutex_unlock(&mhi_dev_ctxt->pm_lock); return -EBUSY; } - mhi_assert_device_wake(mhi_dev_ctxt, false); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || mhi_dev_ctxt->mhi_state == MHI_STATE_M1, msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); if (!r) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to get M0||M1 event, timeout, current state:%s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); - r = -EIO; - goto rpm_suspend_exit; + return -EIO; } - mhi_log(MHI_MSG_INFO, "Allowing M3 State\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Allowing M3 State\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_ENTER; mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M3); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_log(MHI_MSG_INFO, - "Waiting for M3 completion.\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n"); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event, mhi_dev_ctxt->mhi_state == MHI_STATE_M3, msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT)); if (!r) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to get M3 event, timeout, current state:%s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); - r = -EIO; - goto rpm_suspend_exit; + return -EIO; } + return 0; +} + +static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + int r; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered with State:0x%x %s\n", + mhi_dev_ctxt->mhi_pm_state, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); + + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_EXIT; + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + + /* Set and wait for M0 Event */ + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, + mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || + mhi_dev_ctxt->mhi_state == MHI_STATE_M1, + msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); + if (!r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to get M0 event, timeout\n"); + r = -EIO; + } else + r = 0; + + return r; +} + +int mhi_runtime_suspend(struct device *dev) +{ + int r = 0; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n"); + + mutex_lock(&mhi_dev_ctxt->pm_lock); + r = mhi_pm_initiate_m3(mhi_dev_ctxt, false); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "abort due to ret:%d\n", r); + mutex_unlock(&mhi_dev_ctxt->pm_lock); + return r; + } r = mhi_turn_off_pcie_link(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to Turn off link ret:%d\n", r); } -rpm_suspend_exit: - mhi_log(MHI_MSG_INFO, "Exited\n"); mutex_unlock(&mhi_dev_ctxt->pm_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited with ret:%d\n", r); + return r; } int mhi_runtime_idle(struct device *dev) { - mhi_log(MHI_MSG_INFO, "Entered returning -EBUSY\n"); + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered returning -EBUSY\n"); /* * RPM framework during runtime resume always calls @@ -150,7 +201,7 @@ int mhi_runtime_idle(struct device *dev) int mhi_runtime_resume(struct device *dev) { int r = 0; - struct mhi_device_ctxt *mhi_dev_ctxt = dev->platform_data; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); mutex_lock(&mhi_dev_ctxt->pm_lock); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); @@ -159,45 +210,24 @@ int mhi_runtime_resume(struct device *dev) /* turn on link */ r = mhi_turn_on_pcie_link(mhi_dev_ctxt); - if (r) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to resume link\n"); - goto rpm_resume_exit; - } - - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_EXIT; - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - - /* Set and wait for M0 Event */ - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0); - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || - mhi_dev_ctxt->mhi_state == MHI_STATE_M1, - msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); - if (!r) { - mhi_log(MHI_MSG_ERROR, - "Failed to get M0 event, timeout\n"); - r = -EIO; + if (r) goto rpm_resume_exit; - } - r = 0; /* no errors */ + r = mhi_pm_initiate_m0(mhi_dev_ctxt); rpm_resume_exit: mutex_unlock(&mhi_dev_ctxt->pm_lock); - mhi_log(MHI_MSG_INFO, "Exited with :%d\n", r); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited with :%d\n", r); return r; } int mhi_pci_resume(struct device *dev) { int r = 0; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); r = mhi_runtime_resume(dev); if (r) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to resume link\n"); } else { pm_runtime_set_active(dev); @@ -207,6 +237,97 @@ int mhi_pci_resume(struct device *dev) return r; } +static int mhi_pm_slave_mode_power_on(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + int ret_val; + u32 timeout = mhi_dev_ctxt->poll_reset_timeout_ms; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); + mutex_lock(&mhi_dev_ctxt->pm_lock); + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->mhi_pm_state = MHI_PM_POR; + ret_val = set_mhi_base_state(mhi_dev_ctxt); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + + if (ret_val) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error Setting MHI Base State %d\n", ret_val); + goto unlock_pm_lock; + } + + if (mhi_dev_ctxt->base_state != STATE_TRANSITION_BHI) { + ret_val = -EIO; + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid Base State, cur_state:%s\n", + state_transition_str(mhi_dev_ctxt->base_state)); + goto unlock_pm_lock; + } + + reinit_completion(&mhi_dev_ctxt->cmd_complete); + init_mhi_base_state(mhi_dev_ctxt); + + /* + * Keep wake in Active until AMSS, @ AMSS we will + * decrement counts + */ + read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); + read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + + ret_val = wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete, + msecs_to_jiffies(timeout)); + if (!ret_val || mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS) + ret_val = -EIO; + else + ret_val = 0; + + if (ret_val) { + read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); + read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + } + +unlock_pm_lock: + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit with ret:%d\n", ret_val); + mutex_unlock(&mhi_dev_ctxt->pm_lock); + return ret_val; +} + +static int mhi_pm_slave_mode_suspend(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + int r; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); + mutex_lock(&mhi_dev_ctxt->pm_lock); + + r = mhi_pm_initiate_m3(mhi_dev_ctxt, false); + if (r) + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "abort due to ret:%d\n", r); + mutex_unlock(&mhi_dev_ctxt->pm_lock); + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit with ret:%d\n", r); + + return r; +} + +static int mhi_pm_slave_mode_resume(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + int r; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); + mutex_lock(&mhi_dev_ctxt->pm_lock); + + r = mhi_pm_initiate_m0(mhi_dev_ctxt); + if (r) + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "M3 exit failed ret:%d\n", r); + mutex_unlock(&mhi_dev_ctxt->pm_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit with ret:%d\n", r); + + return r; +} + int mhi_init_pm_sysfs(struct device *dev) { return sysfs_create_group(&dev->kobj, &mhi_attribute_group); @@ -220,12 +341,29 @@ void mhi_rem_pm_sysfs(struct device *dev) ssize_t sysfs_init_m0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct mhi_device_ctxt *mhi_dev_ctxt = - &mhi_devices.device_list[0].mhi_ctxt; + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); + + pm_runtime_get(&mhi_dev_ctxt->pcie_device->dev); + pm_runtime_mark_last_busy(&mhi_dev_ctxt->pcie_device->dev); + pm_runtime_put_noidle(&mhi_dev_ctxt->pcie_device->dev); + + return count; +} + +ssize_t sysfs_init_m3(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mhi_device_ctxt *mhi_dev_ctxt = dev_get_drvdata(dev); + + if (atomic_read(&mhi_dev_ctxt->counters.device_wake) == 0) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Schedule RPM suspend"); + pm_runtime_mark_last_busy(&mhi_dev_ctxt-> + pcie_device->dev); + pm_request_autosuspend(&mhi_dev_ctxt-> + pcie_device->dev); + } - pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); - pm_runtime_mark_last_busy(&mhi_dev_ctxt->dev_info->pcie_device->dev); - pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info->pcie_device->dev); return count; } @@ -234,45 +372,45 @@ int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt) struct pci_dev *pcie_dev; int r = 0; - mhi_log(MHI_MSG_INFO, "Entered...\n"); - pcie_dev = mhi_dev_ctxt->dev_info->pcie_device; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered...\n"); + pcie_dev = mhi_dev_ctxt->pcie_device; if (0 == mhi_dev_ctxt->flags.link_up) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Link already marked as down, nothing to do\n"); goto exit; } r = pci_save_state(pcie_dev); if (r) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to save pcie state ret: %d\n", - r); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to save pcie state ret: %d\n", r); } - mhi_dev_ctxt->dev_props->pcie_state = pci_store_saved_state(pcie_dev); + mhi_dev_ctxt->core.pcie_state = pci_store_saved_state(pcie_dev); pci_disable_device(pcie_dev); r = pci_set_power_state(pcie_dev, PCI_D3hot); if (r) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to set pcie power state to D3 hot ret: %d\n", - r); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to set pcie power state to D3hot ret:%d\n", r); } r = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcie_dev->bus->number, pcie_dev, - NULL, - 0); + NULL, + 0); if (r) - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Failed to suspend pcie bus ret 0x%x\n", r); r = mhi_set_bus_request(mhi_dev_ctxt, 0); if (r) - mhi_log(MHI_MSG_INFO, "Failed to set bus freq ret %d\n", r); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to set bus freq ret %d\n", r); mhi_dev_ctxt->flags.link_up = 0; exit: - mhi_log(MHI_MSG_INFO, "Exited...\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited...\n"); + return 0; } @@ -281,17 +419,16 @@ int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt) int r = 0; struct pci_dev *pcie_dev; - pcie_dev = mhi_dev_ctxt->dev_info->pcie_device; + pcie_dev = mhi_dev_ctxt->pcie_device; - mhi_log(MHI_MSG_INFO, "Entered...\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered...\n"); if (mhi_dev_ctxt->flags.link_up) goto exit; r = mhi_set_bus_request(mhi_dev_ctxt, 1); if (r) - mhi_log(MHI_MSG_CRITICAL, - "Could not set bus frequency ret: %d\n", - r); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Could not set bus frequency ret: %d\n", r); r = msm_pcie_pm_control(MSM_PCIE_RESUME, pcie_dev->bus->number, @@ -299,24 +436,50 @@ int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt) NULL, 0); if (r) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to resume pcie bus ret %d\n", r); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to resume pcie bus ret %d\n", r); goto exit; } r = pci_enable_device(pcie_dev); if (r) - mhi_log(MHI_MSG_CRITICAL, - "Failed to enable device ret:%d\n", - r); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to enable device ret:%d\n", r); pci_load_and_free_saved_state(pcie_dev, - &mhi_dev_ctxt->dev_props->pcie_state); + &mhi_dev_ctxt->core.pcie_state); pci_restore_state(pcie_dev); pci_set_master(pcie_dev); mhi_dev_ctxt->flags.link_up = 1; exit: - mhi_log(MHI_MSG_INFO, "Exited...\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited...\n"); return r; } + +int mhi_pm_control_device(struct mhi_device *mhi_device, + enum mhi_dev_ctrl ctrl) +{ + struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->mhi_dev_ctxt; + + if (!mhi_dev_ctxt) + return -EINVAL; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered with cmd:%d\n", ctrl); + + switch (ctrl) { + case MHI_DEV_CTRL_INIT: + return bhi_probe(mhi_dev_ctxt); + case MHI_DEV_CTRL_POWER_ON: + return mhi_pm_slave_mode_power_on(mhi_dev_ctxt); + case MHI_DEV_CTRL_SUSPEND: + return mhi_pm_slave_mode_suspend(mhi_dev_ctxt); + case MHI_DEV_CTRL_RESUME: + return mhi_pm_slave_mode_resume(mhi_dev_ctxt); + default: + break; + } + return -EINVAL; +} +EXPORT_SYMBOL(mhi_pm_control_device); diff --git a/drivers/platform/msm/mhi/mhi_ring_ops.c b/drivers/platform/msm/mhi/mhi_ring_ops.c index 07d0098a1b61..e15055f7db9c 100644 --- a/drivers/platform/msm/mhi/mhi_ring_ops.c +++ b/drivers/platform/msm/mhi/mhi_ring_ops.c @@ -21,7 +21,6 @@ static int add_element(struct mhi_ring *ring, void **rp, if (NULL == ring || 0 == ring->el_size || NULL == ring->base || 0 == ring->len) { - mhi_log(MHI_MSG_ERROR, "Bad input parameters, quitting.\n"); return -EINVAL; } @@ -39,8 +38,6 @@ static int add_element(struct mhi_ring *ring, void **rp, if (ring->overwrite_en) { ctxt_del_element(ring, NULL); } else { - mhi_log(MHI_MSG_INFO, "Ring 0x%lX is full\n", - (uintptr_t)ring->base); return -ENOSPC; } } @@ -92,8 +89,6 @@ int delete_element(struct mhi_ring *ring, void **rp, if (r) return r; if (d_wp == d_rp) { - mhi_log(MHI_MSG_VERBOSE, "Ring 0x%lx is empty\n", - (uintptr_t)ring->base); if (NULL != assigned_addr) *assigned_addr = NULL; return -ENODATA; @@ -113,23 +108,26 @@ int delete_element(struct mhi_ring *ring, void **rp, int mhi_get_free_desc(struct mhi_client_handle *client_handle) { u32 chan; + struct mhi_client_config *client_config; struct mhi_device_ctxt *ctxt; int bb_ring, ch_ring; - if (!client_handle || MHI_HANDLE_MAGIC != client_handle->magic || - !client_handle->mhi_dev_ctxt) + if (!client_handle) return -EINVAL; - ctxt = client_handle->mhi_dev_ctxt; - chan = client_handle->chan_info.chan_nr; + client_config = client_handle->client_config; + ctxt = client_config->mhi_dev_ctxt; + chan = client_config->chan_info.chan_nr; - bb_ring = get_nr_avail_ring_elements(&ctxt->chan_bb_list[chan]); - ch_ring = get_nr_avail_ring_elements(&ctxt->mhi_local_chan_ctxt[chan]); + bb_ring = get_nr_avail_ring_elements(ctxt, &ctxt->chan_bb_list[chan]); + ch_ring = get_nr_avail_ring_elements(ctxt, + &ctxt->mhi_local_chan_ctxt[chan]); return min(bb_ring, ch_ring); } EXPORT_SYMBOL(mhi_get_free_desc); -int get_nr_avail_ring_elements(struct mhi_ring *ring) +int get_nr_avail_ring_elements(struct mhi_device_ctxt *mhi_dev_ctxt, + struct mhi_ring *ring) { u32 nr_el = 0; uintptr_t ring_size = 0; @@ -138,7 +136,7 @@ int get_nr_avail_ring_elements(struct mhi_ring *ring) ring_size = ring->len / ring->el_size; ret_val = get_nr_enclosed_el(ring, ring->rp, ring->wp, &nr_el); if (ret_val != 0) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to get enclosed el ret %d.\n", ret_val); return 0; } @@ -155,19 +153,14 @@ int get_nr_enclosed_el(struct mhi_ring *ring, void *rp, if (NULL == ring || 0 == ring->el_size || NULL == ring->base || 0 == ring->len) { - mhi_log(MHI_MSG_ERROR, "Bad input parameters, quitting.\n"); return -EINVAL; } r = get_element_index(ring, rp, &index_rp); - if (r) { - mhi_log(MHI_MSG_CRITICAL, "Bad element index rp 0x%p.\n", rp); + if (r) return r; - } r = get_element_index(ring, wp, &index_wp); - if (r) { - mhi_log(MHI_MSG_CRITICAL, "Bad element index wp 0x%p.\n", wp); + if (r) return r; - } ring_size = ring->len / ring->el_size; if (index_rp < index_wp) diff --git a/drivers/platform/msm/mhi/mhi_ssr.c b/drivers/platform/msm/mhi/mhi_ssr.c index defd6f4fd137..22481dede21a 100644 --- a/drivers/platform/msm/mhi/mhi_ssr.c +++ b/drivers/platform/msm/mhi/mhi_ssr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,40 +24,35 @@ static int mhi_ssr_notify_cb(struct notifier_block *nb, unsigned long action, void *data) { - + struct mhi_device_ctxt *mhi_dev_ctxt = + container_of(nb, struct mhi_device_ctxt, mhi_ssr_nb); switch (action) { case SUBSYS_BEFORE_POWERUP: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received Subsystem event BEFORE_POWERUP\n"); break; case SUBSYS_AFTER_POWERUP: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received Subsystem event AFTER_POWERUP\n"); break; case SUBSYS_POWERUP_FAILURE: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received Subsystem event POWERUP_FAILURE\n"); break; case SUBSYS_BEFORE_SHUTDOWN: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received Subsystem event BEFORE_SHUTDOWN\n"); - mhi_log(MHI_MSG_INFO, - "Not notifying clients\n"); break; case SUBSYS_AFTER_SHUTDOWN: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received Subsystem event AFTER_SHUTDOWN\n"); - mhi_log(MHI_MSG_INFO, - "Not notifying clients\n"); break; case SUBSYS_RAMDUMP_NOTIFICATION: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received Subsystem event RAMDUMP\n"); - mhi_log(MHI_MSG_INFO, - "Not notifying clients\n"); break; default: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received ESOC notifcation %d, NOT handling\n", (int)action); break; @@ -65,36 +60,30 @@ static int mhi_ssr_notify_cb(struct notifier_block *nb, return NOTIFY_OK; } -static struct notifier_block mhi_ssr_nb = { - .notifier_call = mhi_ssr_notify_cb, -}; - int mhi_esoc_register(struct mhi_device_ctxt *mhi_dev_ctxt) { int ret_val = 0; struct device_node *np; - struct pci_driver *mhi_driver; - struct device *dev = &mhi_dev_ctxt->dev_info->pcie_device->dev; + struct device *dev = &mhi_dev_ctxt->pcie_device->dev; - mhi_driver = mhi_dev_ctxt->dev_info->mhi_pcie_driver; np = dev->of_node; mhi_dev_ctxt->esoc_handle = devm_register_esoc_client(dev, "mdm"); - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Of table of pcie struct device property is dev->of_node %p\n", np); if (IS_ERR_OR_NULL(mhi_dev_ctxt->esoc_handle)) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to register for SSR, ret %lx\n", (uintptr_t)mhi_dev_ctxt->esoc_handle); return -EIO; } - + mhi_dev_ctxt->mhi_ssr_nb.notifier_call = mhi_ssr_notify_cb; mhi_dev_ctxt->esoc_ssr_handle = subsys_notif_register_notifier( mhi_dev_ctxt->esoc_handle->name, - &mhi_ssr_nb); + &mhi_dev_ctxt->mhi_ssr_nb); if (IS_ERR_OR_NULL(mhi_dev_ctxt->esoc_ssr_handle)) { ret_val = PTR_RET(mhi_dev_ctxt->esoc_ssr_handle); - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Can't find esoc desc ret 0x%lx\n", (uintptr_t)mhi_dev_ctxt->esoc_ssr_handle); } @@ -107,18 +96,25 @@ void mhi_notify_client(struct mhi_client_handle *client_handle, { struct mhi_cb_info cb_info = {0}; struct mhi_result result = {0}; + struct mhi_client_config *client_config; cb_info.result = NULL; cb_info.cb_reason = reason; - if (NULL != client_handle && - NULL != client_handle->client_info.mhi_client_cb) { - result.user_data = client_handle->user_data; - cb_info.chan = client_handle->chan_info.chan_nr; + if (client_handle == NULL) + return; + + client_config = client_handle->client_config; + + if (client_config->client_info.mhi_client_cb) { + result.user_data = client_config->user_data; + cb_info.chan = client_config->chan_info.chan_nr; cb_info.result = &result; - mhi_log(MHI_MSG_INFO, "Calling back for chan %d, reason %d\n", - cb_info.chan, reason); - client_handle->client_info.mhi_client_cb(&cb_info); + mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO, + "Calling back for chan %d, reason %d\n", + cb_info.chan, + reason); + client_config->client_info.mhi_client_cb(&cb_info); } } @@ -136,16 +132,22 @@ void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt, } } -int set_mhi_base_state(struct mhi_pcie_dev_info *mhi_pcie_dev) +int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt) { u32 pcie_word_val = 0; int r = 0; - struct mhi_device_ctxt *mhi_dev_ctxt = &mhi_pcie_dev->mhi_ctxt; - mhi_pcie_dev->bhi_ctxt.bhi_base = mhi_pcie_dev->core.bar0_base; - pcie_word_val = mhi_reg_read(mhi_pcie_dev->bhi_ctxt.bhi_base, BHIOFF); - mhi_pcie_dev->bhi_ctxt.bhi_base += pcie_word_val; - pcie_word_val = mhi_reg_read(mhi_pcie_dev->bhi_ctxt.bhi_base, + mhi_dev_ctxt->bhi_ctxt.bhi_base = mhi_dev_ctxt->core.bar0_base; + pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, BHIOFF); + + /* confirm it's a valid reading */ + if (unlikely(pcie_word_val == U32_MAX)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid BHI Offset:0x%x\n", pcie_word_val); + return -EIO; + } + mhi_dev_ctxt->bhi_ctxt.bhi_base += pcie_word_val; + pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, BHI_EXECENV); mhi_dev_ctxt->dev_exec_env = pcie_word_val; if (pcie_word_val == MHI_EXEC_ENV_AMSS) { @@ -153,55 +155,50 @@ int set_mhi_base_state(struct mhi_pcie_dev_info *mhi_pcie_dev) } else if (pcie_word_val == MHI_EXEC_ENV_PBL) { mhi_dev_ctxt->base_state = STATE_TRANSITION_BHI; } else { - mhi_log(MHI_MSG_ERROR, "Invalid EXEC_ENV: 0x%x\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid EXEC_ENV: 0x%x\n", pcie_word_val); r = -EIO; } - mhi_log(MHI_MSG_INFO, "EXEC_ENV: %d Base state %d\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "EXEC_ENV: %d Base state %d\n", pcie_word_val, mhi_dev_ctxt->base_state); return r; } void mhi_link_state_cb(struct msm_pcie_notify *notify) { - - struct mhi_pcie_dev_info *mhi_pcie_dev; struct mhi_device_ctxt *mhi_dev_ctxt = NULL; - if (NULL == notify || NULL == notify->data) { - mhi_log(MHI_MSG_CRITICAL, - "Incomplete handle received\n"); + if (!notify || !notify->data) { + pr_err("%s: incomplete handle received\n", __func__); return; } - mhi_pcie_dev = notify->data; - mhi_dev_ctxt = &mhi_pcie_dev->mhi_ctxt; + mhi_dev_ctxt = notify->data; switch (notify->event) { case MSM_PCIE_EVENT_LINKDOWN: - mhi_log(MHI_MSG_INFO, "Received MSM_PCIE_EVENT_LINKDOWN\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Received MSM_PCIE_EVENT_LINKDOWN\n"); break; case MSM_PCIE_EVENT_LINKUP: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received MSM_PCIE_EVENT_LINKUP\n"); - mhi_pcie_dev->link_up_cntr++; + mhi_dev_ctxt->counters.link_up_cntr++; break; case MSM_PCIE_EVENT_WAKEUP: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received MSM_PCIE_EVENT_WAKE\n"); __pm_stay_awake(&mhi_dev_ctxt->w_lock); __pm_relax(&mhi_dev_ctxt->w_lock); if (mhi_dev_ctxt->flags.mhi_initialized) { - pm_runtime_get(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - pm_runtime_mark_last_busy(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - pm_runtime_put_noidle(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); + mhi_dev_ctxt->runtime_get(mhi_dev_ctxt); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); } break; default: - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Received bad link event\n"); return; } @@ -213,9 +210,9 @@ int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt) r = mhi_init_state_transition(mhi_dev_ctxt, mhi_dev_ctxt->base_state); if (r) { - mhi_log(MHI_MSG_CRITICAL, - "Failed to start state change event, to %d\n", - mhi_dev_ctxt->base_state); + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to start state change event, to %d\n", + mhi_dev_ctxt->base_state); } return r; } diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c index 1021a56d1b3d..a4da6c21b50d 100644 --- a/drivers/platform/msm/mhi/mhi_states.c +++ b/drivers/platform/msm/mhi/mhi_states.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,24 +19,24 @@ const char *state_transition_str(enum STATE_TRANSITION state) { - static const char * const mhi_states_transition_str[] = { - "RESET", - "READY", - "M0", - "M1", - "M2", - "M3", - "BHI", - "SBL", - "AMSS", - "LINK_DOWN", - "WAKE" + static const char * const + mhi_states_transition_str[STATE_TRANSITION_MAX] = { + [STATE_TRANSITION_RESET] = "RESET", + [STATE_TRANSITION_READY] = "READY", + [STATE_TRANSITION_M0] = "M0", + [STATE_TRANSITION_M1] = "M1", + [STATE_TRANSITION_M2] = "M2", + [STATE_TRANSITION_M3] = "M3", + [STATE_TRANSITION_BHI] = "BHI", + [STATE_TRANSITION_SBL] = "SBL", + [STATE_TRANSITION_AMSS] = "AMSS", + [STATE_TRANSITION_LINK_DOWN] = "LINK_DOWN", + [STATE_TRANSITION_WAKE] = "WAKE", + [STATE_TRANSITION_BHIE] = "BHIE", + [STATE_TRANSITION_SYS_ERR] = "SYS_ERR", }; - if (state == STATE_TRANSITION_SYS_ERR) - return "SYS_ERR"; - - return (state <= STATE_TRANSITION_WAKE) ? + return (state < STATE_TRANSITION_MAX) ? mhi_states_transition_str[state] : "Invalid"; } @@ -94,7 +94,7 @@ static void ring_all_chan_dbs(struct mhi_device_ctxt *mhi_dev_ctxt, u32 i = 0; struct mhi_ring *local_ctxt = NULL; - mhi_log(MHI_MSG_VERBOSE, "Ringing chan dbs\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Ringing chan dbs\n"); for (i = 0; i < MHI_MAX_CHANNELS; ++i) if (VALID_CHAN_NR(i)) { local_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[i]; @@ -115,7 +115,7 @@ static void ring_all_cmd_dbs(struct mhi_device_ctxt *mhi_dev_ctxt) u64 rp = 0; struct mhi_ring *local_ctxt = NULL; - mhi_log(MHI_MSG_VERBOSE, "Ringing chan dbs\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Ringing chan dbs\n"); local_ctxt = &mhi_dev_ctxt->mhi_local_cmd_ctxt[PRIMARY_CMD_RING]; rp = mhi_v2p_addr(mhi_dev_ctxt, MHI_RING_TYPE_CMD_RING, @@ -158,12 +158,23 @@ static void ring_all_ev_dbs(struct mhi_device_ctxt *mhi_dev_ctxt) } } -static int process_m0_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) +static int process_bhie_transition(struct mhi_device_ctxt *mhi_dev_ctxt, + enum STATE_TRANSITION cur_work_item) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); + mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_BHIE; + wake_up(mhi_dev_ctxt->mhi_ev_wq.bhi_event); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); + + return 0; +} - mhi_log(MHI_MSG_INFO, "Entered With State %s\n", +int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + unsigned long flags; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered With State %s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); switch (mhi_dev_ctxt->mhi_state) { @@ -177,12 +188,12 @@ static int process_m0_transition( break; } - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); mhi_dev_ctxt->mhi_state = MHI_STATE_M0; mhi_dev_ctxt->mhi_pm_state = MHI_PM_M0; - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_assert_device_wake(mhi_dev_ctxt, true); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, true); if (mhi_dev_ctxt->flags.mhi_initialized) { ring_all_ev_dbs(mhi_dev_ctxt); @@ -190,10 +201,11 @@ static int process_m0_transition( ring_all_cmd_dbs(mhi_dev_ctxt); } - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); wake_up(mhi_dev_ctxt->mhi_ev_wq.m0_event); - mhi_log(MHI_MSG_INFO, "Exited\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); + return 0; } @@ -207,7 +219,7 @@ void process_m1_transition(struct work_struct *work) mutex_lock(&mhi_dev_ctxt->pm_lock); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Processing M1 state transition from state %s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); @@ -218,7 +230,8 @@ void process_m1_transition(struct work_struct *work) return; } - mhi_log(MHI_MSG_INFO, "Transitioning to M2 Transition\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Transitioning to M2 Transition\n"); mhi_dev_ctxt->mhi_pm_state = MHI_PM_M1_M2_TRANSITION; mhi_dev_ctxt->counters.m1_m2++; mhi_dev_ctxt->mhi_state = MHI_STATE_M2; @@ -230,34 +243,32 @@ void process_m1_transition(struct work_struct *work) /* During DEBOUNCE Time We could be receiving M0 Event */ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_M1_M2_TRANSITION) { - mhi_log(MHI_MSG_INFO, "Entered M2 State\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered M2 State\n"); mhi_dev_ctxt->mhi_pm_state = MHI_PM_M2; } write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); if (unlikely(atomic_read(&mhi_dev_ctxt->counters.device_wake))) { - mhi_log(MHI_MSG_INFO, "Exiting M2 Immediately, count:%d\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Exiting M2 Immediately, count:%d\n", atomic_read(&mhi_dev_ctxt->counters.device_wake)); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_assert_device_wake(mhi_dev_ctxt, true); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, true); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - } else { - mhi_log(MHI_MSG_INFO, "Schedule RPM suspend"); - pm_runtime_mark_last_busy(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); - pm_request_autosuspend(&mhi_dev_ctxt-> - dev_info->pcie_device->dev); + } else if (mhi_dev_ctxt->core.pci_master) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Schedule RPM suspend"); + pm_runtime_mark_last_busy(&mhi_dev_ctxt->pcie_device->dev); + pm_request_autosuspend(&mhi_dev_ctxt->pcie_device->dev); } mutex_unlock(&mhi_dev_ctxt->pm_lock); } -static int process_m3_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) +int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt) { - - mhi_log(MHI_MSG_INFO, + unsigned long flags; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered with State %s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); @@ -272,45 +283,24 @@ static int process_m3_transition( break; } - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); mhi_dev_ctxt->mhi_state = MHI_STATE_M3; mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3; - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event); return 0; } -static int process_link_down_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) -{ - mhi_log(MHI_MSG_INFO, - "Entered with State %s\n", - TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); - return -EIO; -} - -static int process_wake_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) -{ - mhi_log(MHI_MSG_INFO, - "Entered with State %s\n", - TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); - return -EIO; - -} - static int process_bhi_transition( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION cur_work_item) { - mhi_log(MHI_MSG_INFO, "Entered\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->mhi_state = MHI_STATE_BHI; write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event); - mhi_log(MHI_MSG_INFO, "Exited\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); return 0; } @@ -320,11 +310,12 @@ static int process_ready_transition( { int r = 0; - mhi_log(MHI_MSG_INFO, "Processing READY state transition\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Processing READY state transition\n"); r = mhi_reset_all_thread_queues(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to reset thread queues\n"); return r; } @@ -335,7 +326,7 @@ static int process_ready_transition( write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); /* Initialize MMIO */ if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failure during MMIO initialization\n"); return r; } @@ -344,13 +335,12 @@ static int process_ready_transition( cur_work_item); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); if (r) { - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failure during event ring init\n"); return r; } write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_dev_ctxt->flags.stop_threads = 0; mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRL, MHICTRL_MHISTATE_MASK, @@ -379,7 +369,8 @@ static int process_reset_transition( enum STATE_TRANSITION cur_work_item) { int r = 0, i = 0; - mhi_log(MHI_MSG_INFO, "Processing RESET state transition\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Processing RESET state transition\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->mhi_state = MHI_STATE_RESET; write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); @@ -387,11 +378,12 @@ static int process_reset_transition( mhi_dev_ctxt->counters.mhi_reset_cntr++; r = mhi_test_for_device_reset(mhi_dev_ctxt); if (r) - mhi_log(MHI_MSG_INFO, "Device not RESET ret %d\n", r); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Device not RESET ret %d\n", r); r = mhi_test_for_device_ready(mhi_dev_ctxt); if (r) { - mhi_log(MHI_MSG_ERROR, "timed out waiting for ready ret:%d\n", - r); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "timed out waiting for ready ret:%d\n", r); return r; } @@ -417,22 +409,12 @@ static int process_reset_transition( r = mhi_init_state_transition(mhi_dev_ctxt, STATE_TRANSITION_READY); if (0 != r) - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to initiate %s state trans\n", state_transition_str(STATE_TRANSITION_READY)); return r; } -static int process_syserr_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) -{ - mhi_log(MHI_MSG_INFO, - "Entered with State %s\n", - TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); - return -EIO; -} - static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_EXEC_ENV exec_env) { @@ -443,7 +425,8 @@ static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt, cb_info.cb_reason = MHI_CB_MHI_ENABLED; - mhi_log(MHI_MSG_INFO, "Enabling Clients, exec env %d.\n", exec_env); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Enabling Clients, exec env %d.\n", exec_env); for (i = 0; i < MHI_MAX_CHANNELS; ++i) { if (!VALID_CHAN_NR(i)) continue; @@ -455,14 +438,15 @@ static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_notify_client(client_handle, MHI_CB_MHI_ENABLED); } - mhi_log(MHI_MSG_INFO, "Done.\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done.\n"); } static int process_sbl_transition( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION cur_work_item) { - mhi_log(MHI_MSG_INFO, "Enabled\n"); + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enabled\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_SBL; write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); @@ -476,7 +460,8 @@ static int process_amss_transition( { int r = 0; - mhi_log(MHI_MSG_INFO, "Processing AMSS state transition\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Processing AMSS state transition\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_AMSS; write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); @@ -486,41 +471,40 @@ static int process_amss_transition( cur_work_item); mhi_dev_ctxt->flags.mhi_initialized = 1; if (r) { - mhi_log(MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to set local chan state ret %d\n", r); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); return r; } - read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - ring_all_chan_dbs(mhi_dev_ctxt, true); - read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_log(MHI_MSG_INFO, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Notifying clients that MHI is enabled\n"); enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env); } else { - mhi_log(MHI_MSG_INFO, "MHI is initialized\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI is initialized\n"); } - read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - ring_all_ev_dbs(mhi_dev_ctxt); - read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); + complete(&mhi_dev_ctxt->cmd_complete); /* * runtime_allow will decrement usage_count, counts were * incremented by pci fw pci_pm_init() or by * mhi shutdown/ssr apis. */ - mhi_log(MHI_MSG_INFO, "Allow runtime suspend\n"); + if (mhi_dev_ctxt->core.pci_master) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Allow runtime suspend\n"); - pm_runtime_mark_last_busy(&mhi_dev_ctxt->dev_info->pcie_device->dev); - pm_runtime_allow(&mhi_dev_ctxt->dev_info->pcie_device->dev); + pm_runtime_mark_last_busy(&mhi_dev_ctxt->pcie_device->dev); + pm_runtime_allow(&mhi_dev_ctxt->pcie_device->dev); + } /* During probe we incremented, releasing that count */ read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_deassert_device_wake(mhi_dev_ctxt); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); - mhi_log(MHI_MSG_INFO, "Exited\n"); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); return 0; } @@ -530,7 +514,8 @@ static int process_stt_work_item( { int r = 0; - mhi_log(MHI_MSG_INFO, "Transitioning to %s\n", + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Transitioning to %s\n", state_transition_str(cur_work_item)); trace_mhi_state(cur_work_item); switch (cur_work_item) { @@ -549,25 +534,11 @@ static int process_stt_work_item( case STATE_TRANSITION_AMSS: r = process_amss_transition(mhi_dev_ctxt, cur_work_item); break; - case STATE_TRANSITION_M0: - r = process_m0_transition(mhi_dev_ctxt, cur_work_item); - break; - case STATE_TRANSITION_M3: - r = process_m3_transition(mhi_dev_ctxt, cur_work_item); - break; - case STATE_TRANSITION_SYS_ERR: - r = process_syserr_transition(mhi_dev_ctxt, - cur_work_item); - break; - case STATE_TRANSITION_LINK_DOWN: - r = process_link_down_transition(mhi_dev_ctxt, - cur_work_item); - break; - case STATE_TRANSITION_WAKE: - r = process_wake_transition(mhi_dev_ctxt, cur_work_item); + case STATE_TRANSITION_BHIE: + r = process_bhie_transition(mhi_dev_ctxt, cur_work_item); break; default: - mhi_log(MHI_MSG_ERROR, + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Unrecongized state: %s\n", state_transition_str(cur_work_item)); break; @@ -575,46 +546,26 @@ static int process_stt_work_item( return r; } -int mhi_state_change_thread(void *ctxt) +void mhi_state_change_worker(struct work_struct *work) { int r = 0; - unsigned long flags = 0; - struct mhi_device_ctxt *mhi_dev_ctxt = (struct mhi_device_ctxt *)ctxt; + struct mhi_device_ctxt *mhi_dev_ctxt = container_of(work, + struct mhi_device_ctxt, + st_thread_worker); enum STATE_TRANSITION cur_work_item; struct mhi_state_work_queue *work_q = &mhi_dev_ctxt->state_change_work_item_list; struct mhi_ring *state_change_q = &work_q->q_info; - if (NULL == mhi_dev_ctxt) { - mhi_log(MHI_MSG_ERROR, "Got bad context, quitting\n"); - return -EIO; - } - for (;;) { - r = wait_event_interruptible( - *mhi_dev_ctxt->mhi_ev_wq.state_change_event, - ((work_q->q_info.rp != work_q->q_info.wp) && - !mhi_dev_ctxt->flags.st_thread_stopped)); - if (r) { - mhi_log(MHI_MSG_INFO, - "Caught signal %d, quitting\n", r); - return 0; - } - - if (mhi_dev_ctxt->flags.kill_threads) { - mhi_log(MHI_MSG_INFO, - "Caught exit signal, quitting\n"); - return 0; - } - mhi_dev_ctxt->flags.st_thread_stopped = 0; - spin_lock_irqsave(work_q->q_lock, flags); + while (work_q->q_info.rp != work_q->q_info.wp) { + spin_lock_irq(work_q->q_lock); cur_work_item = *(enum STATE_TRANSITION *)(state_change_q->rp); r = ctxt_del_element(&work_q->q_info, NULL); MHI_ASSERT(r == 0, "Failed to delete element from STT workqueue\n"); - spin_unlock_irqrestore(work_q->q_lock, flags); + spin_unlock_irq(work_q->q_lock); r = process_stt_work_item(mhi_dev_ctxt, cur_work_item); } - return 0; } /** @@ -638,16 +589,17 @@ int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt, &mhi_dev_ctxt->state_change_work_item_list; spin_lock_irqsave(work_q->q_lock, flags); - nr_avail_work_items = get_nr_avail_ring_elements(stt_ring); + nr_avail_work_items = + get_nr_avail_ring_elements(mhi_dev_ctxt, stt_ring); BUG_ON(nr_avail_work_items <= 0); - mhi_log(MHI_MSG_VERBOSE, + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Processing state transition %s\n", state_transition_str(new_state)); *(enum STATE_TRANSITION *)stt_ring->wp = new_state; r = ctxt_add_element(stt_ring, (void **)&cur_work_item); BUG_ON(r); spin_unlock_irqrestore(work_q->q_lock, flags); - wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.state_change_event); + schedule_work(&mhi_dev_ctxt->st_thread_worker); return r; } diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c index c5c025b8585a..3389de2f95b3 100644 --- a/drivers/platform/msm/mhi/mhi_sys.c +++ b/drivers/platform/msm/mhi/mhi_sys.c @@ -51,13 +51,13 @@ static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, { int amnt_copied = 0; struct mhi_chan_ctxt *chan_ctxt; - struct mhi_device_ctxt *mhi_dev_ctxt = - &mhi_devices.device_list[0].mhi_ctxt; + struct mhi_device_ctxt *mhi_dev_ctxt = fp->private_data; uintptr_t v_wp_index; uintptr_t v_rp_index; int valid_chan = 0; struct mhi_chan_ctxt *cc_list; struct mhi_client_handle *client_handle; + struct mhi_client_config *client_config; int pkts_queued; if (NULL == mhi_dev_ctxt) @@ -76,6 +76,7 @@ static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, continue; } client_handle = mhi_dev_ctxt->client_handle_list[*offp]; + client_config = client_handle->client_config; valid_chan = 1; } @@ -87,8 +88,9 @@ static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, mhi_dev_ctxt->mhi_local_chan_ctxt[*offp].wp, &v_wp_index); - pkts_queued = client_handle->chan_info.max_desc - - get_nr_avail_ring_elements(&mhi_dev_ctxt-> + pkts_queued = client_config->chan_info.max_desc - + get_nr_avail_ring_elements(mhi_dev_ctxt, + &mhi_dev_ctxt-> mhi_local_chan_ctxt[*offp]) - 1; amnt_copied = scnprintf(mhi_dev_ctxt->chan_info, @@ -115,7 +117,7 @@ static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, "pkts_queued", pkts_queued, "/", - client_handle->chan_info.max_desc, + client_config->chan_info.max_desc, "bb_used:", mhi_dev_ctxt->counters.bb_used[*offp]); @@ -128,9 +130,16 @@ static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, return -ENOMEM; } +int mhi_dbgfs_open(struct inode *inode, struct file *fp) +{ + fp->private_data = inode->i_private; + return 0; +} + static const struct file_operations mhi_dbgfs_chan_fops = { .read = mhi_dbgfs_chan_read, .write = NULL, + .open = mhi_dbgfs_open, }; static ssize_t mhi_dbgfs_ev_read(struct file *fp, char __user *buf, @@ -143,8 +152,7 @@ static ssize_t mhi_dbgfs_ev_read(struct file *fp, char __user *buf, uintptr_t v_rp_index; uintptr_t device_p_rp_index; - struct mhi_device_ctxt *mhi_dev_ctxt = - &mhi_devices.device_list[0].mhi_ctxt; + struct mhi_device_ctxt *mhi_dev_ctxt = fp->private_data; if (NULL == mhi_dev_ctxt) return -EIO; *offp = (u32)(*offp) % mhi_dev_ctxt->mmio_info.nr_event_rings; @@ -209,31 +217,15 @@ static ssize_t mhi_dbgfs_ev_read(struct file *fp, char __user *buf, static const struct file_operations mhi_dbgfs_ev_fops = { .read = mhi_dbgfs_ev_read, .write = NULL, -}; - -static ssize_t mhi_dbgfs_trigger_msi(struct file *fp, const char __user *buf, - size_t count, loff_t *offp) -{ - u32 msi_nr = 0; - void *irq_ctxt = &((mhi_devices.device_list[0]).pcie_device->dev); - - if (copy_from_user(&msi_nr, buf, sizeof(msi_nr))) - return -ENOMEM; - mhi_msi_handlr(msi_nr, irq_ctxt); - return 0; -} - -static const struct file_operations mhi_dbgfs_trigger_msi_fops = { - .read = NULL, - .write = mhi_dbgfs_trigger_msi, + .open = mhi_dbgfs_open, }; static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf, size_t count, loff_t *offp) { int amnt_copied = 0; - struct mhi_device_ctxt *mhi_dev_ctxt = - &mhi_devices.device_list[0].mhi_ctxt; + struct mhi_device_ctxt *mhi_dev_ctxt = fp->private_data; + if (NULL == mhi_dev_ctxt) return -EIO; msleep(100); @@ -260,7 +252,7 @@ static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf, "device_wake:", atomic_read(&mhi_dev_ctxt->counters.device_wake), "usage_count:", - atomic_read(&mhi_dev_ctxt->dev_info->pcie_device->dev. + atomic_read(&mhi_dev_ctxt->pcie_device->dev. power.usage_count), "outbound_acks:", atomic_read(&mhi_dev_ctxt->counters.outbound_acks)); @@ -275,63 +267,61 @@ static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf, static const struct file_operations mhi_dbgfs_state_fops = { .read = mhi_dbgfs_state_read, .write = NULL, + .open = mhi_dbgfs_open, }; int mhi_init_debugfs(struct mhi_device_ctxt *mhi_dev_ctxt) { struct dentry *mhi_chan_stats; struct dentry *mhi_state_stats; - struct dentry *mhi_msi_trigger; struct dentry *mhi_ev_stats; - - mhi_dev_ctxt->mhi_parent_folder = - debugfs_create_dir("mhi", NULL); - if (mhi_dev_ctxt->mhi_parent_folder == NULL) { - mhi_log(MHI_MSG_INFO, "Failed to create debugfs parent dir.\n"); + const struct pcie_core_info *core = &mhi_dev_ctxt->core; + char node_name[32]; + + snprintf(node_name, + sizeof(node_name), + "%04x_%02u.%02u.%02u", + core->dev_id, core->domain, core->bus, core->slot); + + mhi_dev_ctxt->child = + debugfs_create_dir(node_name, mhi_dev_ctxt->parent); + if (mhi_dev_ctxt->child == NULL) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to create debugfs parent dir.\n"); return -EIO; } mhi_chan_stats = debugfs_create_file("mhi_chan_stats", 0444, - mhi_dev_ctxt->mhi_parent_folder, + mhi_dev_ctxt->child, mhi_dev_ctxt, &mhi_dbgfs_chan_fops); if (mhi_chan_stats == NULL) return -ENOMEM; mhi_ev_stats = debugfs_create_file("mhi_ev_stats", 0444, - mhi_dev_ctxt->mhi_parent_folder, + mhi_dev_ctxt->child, mhi_dev_ctxt, &mhi_dbgfs_ev_fops); if (mhi_ev_stats == NULL) goto clean_chan; mhi_state_stats = debugfs_create_file("mhi_state_stats", 0444, - mhi_dev_ctxt->mhi_parent_folder, + mhi_dev_ctxt->child, mhi_dev_ctxt, &mhi_dbgfs_state_fops); if (mhi_state_stats == NULL) goto clean_ev_stats; - mhi_msi_trigger = debugfs_create_file("mhi_msi_trigger", - 0444, - mhi_dev_ctxt->mhi_parent_folder, - mhi_dev_ctxt, - &mhi_dbgfs_trigger_msi_fops); - if (mhi_msi_trigger == NULL) - goto clean_state; mhi_dev_ctxt->chan_info = kmalloc(MHI_LOG_SIZE, GFP_KERNEL); if (mhi_dev_ctxt->chan_info == NULL) - goto clean_all; + goto clean_ev_stats; return 0; -clean_all: - debugfs_remove(mhi_msi_trigger); -clean_state: - debugfs_remove(mhi_state_stats); + clean_ev_stats: debugfs_remove(mhi_ev_stats); clean_chan: debugfs_remove(mhi_chan_stats); - debugfs_remove(mhi_dev_ctxt->mhi_parent_folder); + debugfs_remove(mhi_dev_ctxt->child); return -ENOMEM; } diff --git a/drivers/platform/msm/mhi/mhi_sys.h b/drivers/platform/msm/mhi/mhi_sys.h index a948a2354de7..712647dc9f7c 100644 --- a/drivers/platform/msm/mhi/mhi_sys.h +++ b/drivers/platform/msm/mhi/mhi_sys.h @@ -38,12 +38,13 @@ extern void *mhi_ipc_log; } \ } while (0) -#define mhi_log(_msg_lvl, _msg, ...) do { \ +#define mhi_log(mhi_dev_ctxt, _msg_lvl, _msg, ...) do { \ if ((_msg_lvl) >= mhi_msg_lvl) \ pr_alert("[%s] " _msg, __func__, ##__VA_ARGS__);\ - if (mhi_ipc_log && ((_msg_lvl) >= mhi_ipc_log_lvl)) \ - ipc_log_string(mhi_ipc_log, \ - "[%s] " _msg, __func__, ##__VA_ARGS__); \ + if (mhi_dev_ctxt->mhi_ipc_log && \ + ((_msg_lvl) >= mhi_ipc_log_lvl)) \ + ipc_log_string(mhi_dev_ctxt->mhi_ipc_log, \ + "[%s] " _msg, __func__, ##__VA_ARGS__); \ } while (0) extern const char * const mhi_states_str[MHI_STATE_LIMIT]; diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index 96c4671f994f..0e28ebdd8fea 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,8 +31,6 @@ #define MHI_DEV_NODE_NAME_LEN 13 #define MHI_SOFTWARE_CLIENT_LIMIT 23 -#define TRE_TYPICAL_SIZE 0x1000 -#define TRE_MAX_SIZE 0xFFFF #define MHI_UCI_IPC_LOG_PAGES (25) #define MAX_NR_TRBS_PER_CHAN 10 @@ -129,9 +127,8 @@ struct uci_client { struct mhi_uci_ctxt_t { struct list_head node; - struct platform_dev *pdev; + struct platform_device *pdev; struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT]; - struct mhi_client_info_t client_info; dev_t dev_t; struct mutex ctrl_mutex; struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT]; @@ -332,8 +329,8 @@ static int mhi_uci_send_packet(struct mhi_client_handle **client_handle, return 0; for (i = 0; i < nr_avail_trbs; ++i) { - data_to_insert_now = min(data_left_to_insert, - TRE_MAX_SIZE); + data_to_insert_now = min_t(size_t, data_left_to_insert, + uci_handle->out_attr.max_packet_size); if (is_uspace_buf) { data_loc = kmalloc(data_to_insert_now, GFP_KERNEL); if (NULL == data_loc) { @@ -1172,6 +1169,9 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info) uci_handle = cb_info->result->user_data; switch (cb_info->cb_reason) { case MHI_CB_MHI_ENABLED: + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, + "MHI enabled CB received.\n"); atomic_set(&uci_handle->mhi_disabled, 0); break; case MHI_CB_MHI_DISABLED: @@ -1202,9 +1202,11 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info) } } -static int mhi_register_client(struct uci_client *mhi_client) +static int mhi_register_client(struct uci_client *mhi_client, + struct device *dev) { int ret_val = 0; + struct mhi_client_info_t client_info; uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO, @@ -1222,11 +1224,13 @@ static int mhi_register_client(struct uci_client *mhi_client) UCI_DBG_INFO, "Registering chan %d\n", mhi_client->out_chan); - ret_val = mhi_register_channel(&mhi_client->out_handle, - mhi_client->out_chan, - 0, - &mhi_client->uci_ctxt->client_info, - mhi_client); + client_info.dev = dev; + client_info.node_name = "qcom,mhi"; + client_info.user_data = mhi_client; + client_info.mhi_client_cb = uci_xfer_cb; + client_info.chan = mhi_client->out_chan; + client_info.max_payload = mhi_client->out_attr.max_packet_size; + ret_val = mhi_register_channel(&mhi_client->out_handle, &client_info); if (0 != ret_val) uci_log(mhi_client->uci_ipc_log, UCI_DBG_ERROR, @@ -1238,11 +1242,9 @@ static int mhi_register_client(struct uci_client *mhi_client) UCI_DBG_INFO, "Registering chan %d\n", mhi_client->in_chan); - ret_val = mhi_register_channel(&mhi_client->in_handle, - mhi_client->in_chan, - 0, - &mhi_client->uci_ctxt->client_info, - mhi_client); + client_info.max_payload = mhi_client->in_attr.max_packet_size; + client_info.chan = mhi_client->in_chan; + ret_val = mhi_register_channel(&mhi_client->in_handle, &client_info); if (0 != ret_val) uci_log(mhi_client->uci_ipc_log, UCI_DBG_ERROR, @@ -1266,13 +1268,16 @@ static int mhi_uci_probe(struct platform_device *pdev) struct mhi_uci_ctxt_t *uci_ctxt; int ret_val; int i; - char node_name[16]; + char node_name[32]; uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, "Entered with pdev:%p\n", pdev); + if (mhi_is_device_ready(&pdev->dev, "qcom,mhi") == false) + return -EPROBE_DEFER; + if (pdev->dev.of_node == NULL) return -ENODEV; @@ -1286,7 +1291,7 @@ static int mhi_uci_probe(struct platform_device *pdev) if (!uci_ctxt) return -ENOMEM; - uci_ctxt->client_info.mhi_client_cb = uci_xfer_cb; + uci_ctxt->pdev = pdev; mutex_init(&uci_ctxt->ctrl_mutex); uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, @@ -1309,7 +1314,8 @@ static int mhi_uci_probe(struct platform_device *pdev) uci_client->uci_ctxt = uci_ctxt; if (uci_client->in_attr.uci_ownership) { - ret_val = mhi_register_client(uci_client); + ret_val = mhi_register_client(uci_client, + &pdev->dev); if (ret_val) { uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_CRITICAL, @@ -1319,7 +1325,13 @@ static int mhi_uci_probe(struct platform_device *pdev) return -EIO; } - snprintf(node_name, sizeof(node_name), "mhi-uci%d", + snprintf(node_name, + sizeof(node_name), + "mhi_uci_%04x_%02u.%02u.%02u_%d", + uci_client->out_handle->dev_id, + uci_client->out_handle->domain, + uci_client->out_handle->bus, + uci_client->out_handle->slot, uci_client->out_attr.chan_id); uci_client->uci_ipc_log = ipc_log_context_create (MHI_UCI_IPC_LOG_PAGES, @@ -1364,11 +1376,16 @@ static int mhi_uci_probe(struct platform_device *pdev) } uci_client->dev = device_create(mhi_uci_drv_ctxt.mhi_uci_class, - NULL, - uci_ctxt->dev_t + i, - NULL, - DEVICE_NAME "_pipe_%d", - uci_client->out_chan); + NULL, + uci_ctxt->dev_t + i, + NULL, + DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d", + uci_client->out_handle->dev_id, + uci_client->out_handle->domain, + uci_client->out_handle->bus, + uci_client->out_handle->slot, + "_pipe_", + uci_client->out_chan); if (IS_ERR(uci_client->dev)) { uci_log(uci_client->uci_ipc_log, UCI_DBG_ERROR, diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c index e1a92fb23912..c07e9f083204 100644 --- a/drivers/power/supply/qcom/pmic-voter.c +++ b/drivers/power/supply/qcom/pmic-voter.c @@ -188,6 +188,38 @@ void unlock_votable(struct votable *votable) } /** + * is_client_vote_enabled() - + * is_client_vote_enabled_locked() - + * The unlocked and locked variants of getting whether a client's + vote is enabled. + * @votable: the votable object + * @client_str: client of interest + * + * Returns: + * True if the client's vote is enabled; false otherwise. + */ +bool is_client_vote_enabled_locked(struct votable *votable, + const char *client_str) +{ + int client_id = get_client_id(votable, client_str); + + if (client_id < 0) + return false; + + return votable->votes[client_id].enabled; +} + +bool is_client_vote_enabled(struct votable *votable, const char *client_str) +{ + bool enabled; + + lock_votable(votable); + enabled = is_client_vote_enabled_locked(votable, client_str); + unlock_votable(votable); + return enabled; +} + +/** * get_client_vote() - * get_client_vote_locked() - * The unlocked and locked variants of getting a client's voted diff --git a/drivers/power/supply/qcom/pmic-voter.h b/drivers/power/supply/qcom/pmic-voter.h index 031b9a010a42..f202bf704055 100644 --- a/drivers/power/supply/qcom/pmic-voter.h +++ b/drivers/power/supply/qcom/pmic-voter.h @@ -24,6 +24,9 @@ enum votable_type { NUM_VOTABLE_TYPES, }; +bool is_client_vote_enabled(struct votable *votable, const char *client_str); +bool is_client_vote_enabled_locked(struct votable *votable, + const char *client_str); int get_client_vote(struct votable *votable, const char *client_str); int get_client_vote_locked(struct votable *votable, const char *client_str); int get_effective_result(struct votable *votable); diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 39afc235fbc3..5dcd4c36675a 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1696,6 +1696,9 @@ static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc) if (!chip->dt.auto_recharge_soc) return 0; + if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY) + return 0; + fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word, @@ -1712,46 +1715,55 @@ static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc) static int fg_adjust_recharge_soc(struct fg_chip *chip) { int rc, msoc, recharge_soc, new_recharge_soc = 0; + bool recharge_soc_status; if (!chip->dt.auto_recharge_soc) return 0; recharge_soc = chip->dt.recharge_soc_thr; + recharge_soc_status = chip->recharge_soc_adjusted; /* * If the input is present and charging had been terminated, adjust * the recharge SOC threshold based on the monotonic SOC at which * the charge termination had happened. */ - if (is_input_present(chip) && !chip->recharge_soc_adjusted - && chip->charge_done) { - /* Get raw monotonic SOC for calculation */ - rc = fg_get_msoc(chip, &msoc); - if (rc < 0) { - pr_err("Error in getting msoc, rc=%d\n", rc); - return rc; - } + if (is_input_present(chip)) { + if (chip->charge_done) { + if (!chip->recharge_soc_adjusted) { + /* Get raw monotonic SOC for calculation */ + rc = fg_get_msoc(chip, &msoc); + if (rc < 0) { + pr_err("Error in getting msoc, rc=%d\n", + rc); + return rc; + } - /* Adjust the recharge_soc threshold */ - new_recharge_soc = msoc - (FULL_CAPACITY - recharge_soc); - } else if (chip->recharge_soc_adjusted && (!is_input_present(chip) - || chip->health == POWER_SUPPLY_HEALTH_GOOD)) { + /* Adjust the recharge_soc threshold */ + new_recharge_soc = msoc - (FULL_CAPACITY - + recharge_soc); + chip->recharge_soc_adjusted = true; + } else { + /* adjusted already, do nothing */ + return 0; + } + } else { + /* Charging, do nothing */ + return 0; + } + } else { /* Restore the default value */ new_recharge_soc = recharge_soc; + chip->recharge_soc_adjusted = false; } - if (new_recharge_soc > 0 && new_recharge_soc < FULL_CAPACITY) { - rc = fg_set_recharge_soc(chip, new_recharge_soc); - if (rc) { - pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc); - return rc; - } - - chip->recharge_soc_adjusted = (new_recharge_soc != - recharge_soc); - fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", - new_recharge_soc); + rc = fg_set_recharge_soc(chip, new_recharge_soc); + if (rc < 0) { + chip->recharge_soc_adjusted = recharge_soc_status; + pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc); + return rc; } + fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc); return 0; } diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 4f126854728f..7d2e00dc934b 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -161,39 +161,14 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua) int smblib_icl_override(struct smb_charger *chg, bool override) { int rc; - bool override_status; - u8 stat; - u16 reg; - - switch (chg->smb_version) { - case PMI8998_SUBTYPE: - reg = APSD_RESULT_STATUS_REG; - break; - case PM660_SUBTYPE: - reg = AICL_STATUS_REG; - break; - default: - smblib_dbg(chg, PR_MISC, "Unknown chip version=%x\n", - chg->smb_version); - return -EINVAL; - } - rc = smblib_read(chg, reg, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read reg=%x rc=%d\n", reg, rc); - return rc; - } - override_status = (bool)(stat & ICL_OVERRIDE_LATCH_BIT); + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, + ICL_OVERRIDE_AFTER_APSD_BIT, + override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0); + if (rc < 0) + smblib_err(chg, "Couldn't override ICL rc=%d\n", rc); - if (override != override_status) { - rc = smblib_masked_write(chg, CMD_APSD_REG, - ICL_OVERRIDE_BIT, ICL_OVERRIDE_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't override ICL rc=%d\n", rc); - return rc; - } - } - return 0; + return rc; } /******************** @@ -727,21 +702,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) rc); } -static bool smblib_sysok_reason_usbin(struct smb_charger *chg) -{ - int rc; - u8 stat; - - rc = smblib_read(chg, SYSOK_REASON_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't get SYSOK_REASON_STATUS rc=%d\n", rc); - /* assuming 'not usbin' in case of read failure */ - return false; - } - - return stat & SYSOK_REASON_USBIN_BIT; -} - void smblib_suspend_on_debug_battery(struct smb_charger *chg) { int rc; @@ -1098,16 +1058,6 @@ static int smblib_apsd_disable_vote_callback(struct votable *votable, int rc; if (apsd_disable) { - /* Don't run APSD on CC debounce when APSD is disabled */ - rc = smblib_masked_write(chg, TYPE_C_CFG_REG, - APSD_START_ON_CC_BIT, - 0); - if (rc < 0) { - smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", - rc); - return rc; - } - rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, AUTO_SRC_DETECT_BIT, 0); @@ -1123,15 +1073,6 @@ static int smblib_apsd_disable_vote_callback(struct votable *votable, smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc); return rc; } - - rc = smblib_masked_write(chg, TYPE_C_CFG_REG, - APSD_START_ON_CC_BIT, - APSD_START_ON_CC_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", - rc); - return rc; - } } return 0; @@ -2510,10 +2451,6 @@ int smblib_set_prop_usb_voltage_max(struct smb_charger *chg, } chg->voltage_max_uv = max_uv; - rc = smblib_rerun_aicl(chg); - if (rc < 0) - smblib_err(chg, "Couldn't re-run AICL rc=%d\n", rc); - return rc; } @@ -2568,6 +2505,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } + /* since PD was found the cable must be non-legacy */ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + /* clear USB ICL vote for DCP_VOTER */ rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); if (rc < 0) @@ -2685,12 +2625,6 @@ int smblib_reg_block_restore(struct smb_charger *chg, static struct reg_info cc2_detach_settings[] = { { - .reg = TYPE_C_CFG_REG, - .mask = APSD_START_ON_CC_BIT, - .val = 0, - .desc = "TYPE_C_CFG_REG", - }, - { .reg = TYPE_C_CFG_2_REG, .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT, .val = TYPE_C_UFP_MODE_BIT, @@ -3406,6 +3340,37 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) +{ + switch (pst) { + case POWER_SUPPLY_TYPE_USB: + /* + * USB_PSY will vote to increase the current to 500/900mA once + * enumeration is done. Ensure that USB_PSY has at least voted + * for 100mA before releasing the LEGACY_UNKNOWN vote + */ + if (!is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + break; + case POWER_SUPPLY_TYPE_USB_CDP: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); + break; + case POWER_SUPPLY_TYPE_USB_DCP: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); + break; + case POWER_SUPPLY_TYPE_USB_HVDCP: + case POWER_SUPPLY_TYPE_USB_HVDCP_3: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000); + break; + default: + smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000); + break; + } +} + #define HVDCP_DET_MS 2500 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { @@ -3415,6 +3380,10 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) return; apsd_result = smblib_update_usb_type(chg); + + if (!chg->pd_active) + smblib_force_legacy_icl(chg, apsd_result->pst); + switch (apsd_result->bit) { case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: @@ -3495,6 +3464,9 @@ static void typec_source_removal(struct smb_charger *chg) { int rc; + /* reset legacy unknown vote */ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + /* reset both usbin current and voltage votes */ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); @@ -3548,6 +3520,15 @@ static void typec_source_removal(struct smb_charger *chg) static void typec_source_insertion(struct smb_charger *chg) { + /* + * at any time we want LEGACY_UNKNOWN, PD, or USB_PSY to be voting for + * ICL, so vote LEGACY_UNKNOWN here if none of the above three have + * casted their votes + */ + if (!is_client_vote_enabled(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER) + && !is_client_vote_enabled(chg->usb_icl_votable, PD_VOTER) + && !is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER)) + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); } static void typec_sink_insertion(struct smb_charger *chg) @@ -3568,10 +3549,10 @@ static void typec_sink_removal(struct smb_charger *chg) static void smblib_handle_typec_removal(struct smb_charger *chg) { + int rc; + vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0); - vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER, true, 0); - vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0); vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0); /* reset votes from vbus_cc_short */ @@ -3590,10 +3571,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) chg->pulse_cnt = 0; chg->usb_icl_delta_ua = 0; - chg->usb_ever_removed = true; + /* enable APSD CC trigger for next insertion */ + rc = smblib_masked_write(chg, TYPE_C_CFG_REG, + APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc); smblib_update_usb_type(chg); - typec_source_removal(chg); typec_sink_removal(chg); } @@ -3601,12 +3585,16 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) static void smblib_handle_typec_insertion(struct smb_charger *chg, bool sink_attached, bool legacy_cable) { - int rp; - bool vbus_cc_short = false; - bool valid_legacy_cable; + int rp, rc; vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0); + /* disable APSD CC trigger since CC is attached */ + rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0); + if (rc < 0) + smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", + rc); + if (sink_attached) { typec_source_removal(chg); typec_sink_insertion(chg); @@ -3615,25 +3603,18 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg, typec_sink_removal(chg); } - valid_legacy_cable = legacy_cable && - (chg->usb_ever_removed || !smblib_sysok_reason_usbin(chg)); - vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER, - valid_legacy_cable, 0); - - if (valid_legacy_cable) { - rp = smblib_get_prop_ufp_mode(chg); - if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH - || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) { - vbus_cc_short = true; - smblib_err(chg, "Disabling PD and HVDCP, VBUS-CC shorted, rp = %d found\n", - rp); - } + rp = smblib_get_prop_ufp_mode(chg); + if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH + || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) { + smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n"); + /* HVDCP is not going to be enabled; enable parallel */ + vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0); + vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, + true, 0); + } else { + vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, + false, 0); } - - vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, - vbus_cc_short, 0); - vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER, - vbus_cc_short, 0); } static void smblib_handle_typec_debounce_done(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 22ef78fd9641..de236164e6b2 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -47,7 +47,6 @@ enum print_reason { #define PD_DISALLOWED_INDIRECT_VOTER "PD_DISALLOWED_INDIRECT_VOTER" #define PD_HARD_RESET_VOTER "PD_HARD_RESET_VOTER" #define VBUS_CC_SHORT_VOTER "VBUS_CC_SHORT_VOTER" -#define LEGACY_CABLE_VOTER "LEGACY_CABLE_VOTER" #define PD_INACTIVE_VOTER "PD_INACTIVE_VOTER" #define BOOST_BACK_VOTER "BOOST_BACK_VOTER" #define HVDCP_INDIRECT_VOTER "HVDCP_INDIRECT_VOTER" @@ -58,6 +57,7 @@ enum print_reason { #define CTM_VOTER "CTM_VOTER" #define SW_QC3_VOTER "SW_QC3_VOTER" #define AICL_RERUN_VOTER "AICL_RERUN_VOTER" +#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER" #define VCONN_MAX_ATTEMPTS 3 #define OTG_MAX_ATTEMPTS 3 @@ -316,7 +316,6 @@ struct smb_charger { /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; - bool usb_ever_removed; int icl_reduction_ua; diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index 54b6b38d134b..f7c13390d477 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -628,6 +628,7 @@ enum { #define USBIN_LOAD_CFG_REG (USBIN_BASE + 0x65) #define USBIN_OV_CH_LOAD_OPTION_BIT BIT(7) +#define ICL_OVERRIDE_AFTER_APSD_BIT BIT(4) #define USBIN_ICL_OPTIONS_REG (USBIN_BASE + 0x66) #define CFG_USB3P0_SEL_BIT BIT(2) 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/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 14cf10b92122..2dc4208cbc51 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -213,6 +213,7 @@ struct edge_info { bool tx_blocked_signal_sent; struct kthread_work kwork; struct kthread_worker kworker; + struct work_struct wakeup_work; struct task_struct *task; struct tasklet_struct tasklet; struct srcu_struct use_ref; @@ -826,7 +827,6 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) int i; bool granted; unsigned long flags; - bool trigger_wakeup = false; int rcu_id; uint16_t rcid; uint32_t name_len; @@ -851,22 +851,10 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) srcu_read_unlock(&einfo->use_ref, rcu_id); return; } - if (!atomic_ctx) { - if (einfo->tx_resume_needed && fifo_write_avail(einfo)) { - einfo->tx_resume_needed = false; - einfo->xprt_if.glink_core_if_ptr->tx_resume( - &einfo->xprt_if); - } - spin_lock_irqsave(&einfo->write_lock, flags); - if (waitqueue_active(&einfo->tx_blocked_queue)) { - einfo->tx_blocked_signal_sent = false; - trigger_wakeup = true; - } - spin_unlock_irqrestore(&einfo->write_lock, flags); - if (trigger_wakeup) - wake_up_all(&einfo->tx_blocked_queue); - } + if ((atomic_ctx) && ((einfo->tx_resume_needed) || + (waitqueue_active(&einfo->tx_blocked_queue)))) /* tx waiting ?*/ + schedule_work(&einfo->wakeup_work); /* * Access to the fifo needs to be synchronized, however only the calls @@ -1174,6 +1162,39 @@ static void rx_worker_atomic(unsigned long param) } /** + * tx_wakeup_worker() - worker function to wakeup tx blocked thread + * @work: kwork associated with the edge to process commands on. + */ +static void tx_wakeup_worker(struct work_struct *work) +{ + struct edge_info *einfo; + bool trigger_wakeup = false; + unsigned long flags; + int rcu_id; + + einfo = container_of(work, struct edge_info, wakeup_work); + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + if (einfo->tx_resume_needed && fifo_write_avail(einfo)) { + einfo->tx_resume_needed = false; + einfo->xprt_if.glink_core_if_ptr->tx_resume( + &einfo->xprt_if); + } + spin_lock_irqsave(&einfo->write_lock, flags); + if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/ + einfo->tx_blocked_signal_sent = false; + trigger_wakeup = true; + } + spin_unlock_irqrestore(&einfo->write_lock, flags); + if (trigger_wakeup) + wake_up_all(&einfo->tx_blocked_queue); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** * rx_worker() - worker function to process received commands * @work: kwork associated with the edge to process commands on. */ @@ -2275,6 +2296,7 @@ static int glink_smem_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); + INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; @@ -2374,6 +2396,7 @@ request_irq_fail: reg_xprt_fail: smem_alloc_fail: flush_kthread_worker(&einfo->kworker); + flush_work(&einfo->wakeup_work); kthread_stop(einfo->task); einfo->task = NULL; tasklet_kill(&einfo->tasklet); @@ -2462,6 +2485,7 @@ static int glink_rpm_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); + INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->intentless = true; einfo->read_from_fifo = memcpy32_fromio; @@ -2622,6 +2646,7 @@ request_irq_fail: reg_xprt_fail: toc_init_fail: flush_kthread_worker(&einfo->kworker); + flush_work(&einfo->wakeup_work); kthread_stop(einfo->task); einfo->task = NULL; tasklet_kill(&einfo->tasklet); @@ -2753,6 +2778,7 @@ static int glink_mailbox_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); + INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; @@ -2873,6 +2899,7 @@ request_irq_fail: reg_xprt_fail: smem_alloc_fail: flush_kthread_worker(&einfo->kworker); + flush_work(&einfo->wakeup_work); kthread_stop(einfo->task); einfo->task = NULL; tasklet_kill(&einfo->tasklet); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 2fcd1a4c636c..75b96fd609c8 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -104,13 +104,16 @@ module_param(qmi_timeout, ulong, 0600); #ifdef CONFIG_ICNSS_DEBUG #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ - icnss_pr_err("ASSERT at line %d\n", \ - __LINE__); \ + icnss_pr_err("ASSERT at line %d\n", __LINE__); \ BUG_ON(1); \ } \ } while (0) + +bool ignore_qmi_timeout; +#define ICNSS_QMI_ASSERT() ICNSS_ASSERT(ignore_qmi_timeout) #else #define ICNSS_ASSERT(_condition) do { } while (0) +#define ICNSS_QMI_ASSERT() do { } while (0) #endif enum icnss_debug_quirks { @@ -322,8 +325,9 @@ static struct icnss_priv { u32 pwr_pin_result; u32 phy_io_pin_result; u32 rf_pin_result; + uint32_t nr_mem_region; struct icnss_mem_region_info - icnss_mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01]; + mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01]; struct dentry *root_dentry; spinlock_t on_off_lock; struct icnss_stats stats; @@ -349,6 +353,15 @@ static struct icnss_priv { bool bypass_s1_smmu; } *penv; +#ifdef CONFIG_ICNSS_DEBUG +static void icnss_ignore_qmi_timeout(bool ignore) +{ + ignore_qmi_timeout = ignore; +} +#else +static void icnss_ignore_qmi_timeout(bool ignore) { } +#endif + static void icnss_pm_stay_awake(struct icnss_priv *priv) { if (atomic_inc_return(&priv->pm_count) != 1) @@ -952,7 +965,7 @@ int icnss_power_off(struct device *dev) } EXPORT_SYMBOL(icnss_power_off); -static int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index) +static int icnss_map_msa_permissions(struct icnss_mem_region_info *mem_region) { int ret = 0; phys_addr_t addr; @@ -965,10 +978,10 @@ static int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index) int source_nelems = sizeof(source_vmlist)/sizeof(u32); int dest_nelems = 0; - addr = priv->icnss_mem_region[index].reg_addr; - size = priv->icnss_mem_region[index].size; + addr = mem_region->reg_addr; + size = mem_region->size; - if (!priv->icnss_mem_region[index].secure_flag) { + if (!mem_region->secure_flag) { dest_vmids[2] = VMID_WLAN_CE; dest_nelems = 3; } else { @@ -978,19 +991,20 @@ static int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index) ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) { - icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", - index, &addr, size, ret); + icnss_pr_err("Hyperviser map failed for PA=%pa size=%u err=%d\n", + &addr, size, ret); goto out; } - icnss_pr_dbg("Hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", - index, source_vmlist[0], dest_nelems, - dest_vmids[0], dest_vmids[1], dest_vmids[2]); + + icnss_pr_dbg("Hypervisor map for source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", + source_vmlist[0], dest_nelems, dest_vmids[0], + dest_vmids[1], dest_vmids[2]); out: return ret; } -static int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index) +static int icnss_unmap_msa_permissions(struct icnss_mem_region_info *mem_region) { int ret = 0; phys_addr_t addr; @@ -1001,9 +1015,10 @@ static int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index) int source_nelems = 0; int dest_nelems = sizeof(dest_vmids)/sizeof(u32); - addr = priv->icnss_mem_region[index].reg_addr; - size = priv->icnss_mem_region[index].size; - if (!priv->icnss_mem_region[index].secure_flag) { + addr = mem_region->reg_addr; + size = mem_region->size; + + if (!mem_region->secure_flag) { source_vmlist[2] = VMID_WLAN_CE; source_nelems = 3; } else { @@ -1014,14 +1029,13 @@ static int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index) ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) { - icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", - index, &addr, size, ret); + icnss_pr_err("Hyperviser unmap failed for PA=%pa size=%u err=%d\n", + &addr, size, ret); goto out; } - icnss_pr_dbg("hypervisor unmap for region %u, source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n", - index, source_nelems, - source_vmlist[0], source_vmlist[1], source_vmlist[2], - dest_vmids[0]); + icnss_pr_dbg("Hypervisor unmap for source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n", + source_nelems, source_vmlist[0], source_vmlist[1], + source_vmlist[2], dest_vmids[0]); out: return ret; } @@ -1029,34 +1043,37 @@ out: static int icnss_setup_msa_permissions(struct icnss_priv *priv) { int ret; + int i; if (test_bit(ICNSS_MSA0_ASSIGNED, &priv->state)) return 0; - ret = icnss_map_msa_permissions(priv, 0); - if (ret) - return ret; + for (i = 0; i < priv->nr_mem_region; i++) { - ret = icnss_map_msa_permissions(priv, 1); - if (ret) - goto err_map_msa; + ret = icnss_map_msa_permissions(&priv->mem_region[i]); + if (ret) + goto err_unmap; + } set_bit(ICNSS_MSA0_ASSIGNED, &priv->state); - return ret; + return 0; -err_map_msa: - icnss_unmap_msa_permissions(priv, 0); +err_unmap: + for (i--; i >= 0; i--) + icnss_unmap_msa_permissions(&priv->mem_region[i]); return ret; } static void icnss_remove_msa_permissions(struct icnss_priv *priv) { + int i; + if (!test_bit(ICNSS_MSA0_ASSIGNED, &priv->state)) return; - icnss_unmap_msa_permissions(priv, 0); - icnss_unmap_msa_permissions(priv, 1); + for (i = 0; i < priv->nr_mem_region; i++) + icnss_unmap_msa_permissions(&priv->mem_region[i]); clear_bit(ICNSS_MSA0_ASSIGNED, &priv->state); } @@ -1107,7 +1124,7 @@ static int wlfw_msa_mem_info_send_sync_msg(void) icnss_pr_dbg("Receive mem_region_info_len: %d\n", resp.mem_region_info_len); - if (resp.mem_region_info_len > 2) { + if (resp.mem_region_info_len > QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01) { icnss_pr_err("Invalid memory region length received: %d\n", resp.mem_region_info_len); ret = -EINVAL; @@ -1115,24 +1132,25 @@ static int wlfw_msa_mem_info_send_sync_msg(void) } penv->stats.msa_info_resp++; + penv->nr_mem_region = resp.mem_region_info_len; for (i = 0; i < resp.mem_region_info_len; i++) { - penv->icnss_mem_region[i].reg_addr = + penv->mem_region[i].reg_addr = resp.mem_region_info[i].region_addr; - penv->icnss_mem_region[i].size = + penv->mem_region[i].size = resp.mem_region_info[i].size; - penv->icnss_mem_region[i].secure_flag = + penv->mem_region[i].secure_flag = resp.mem_region_info[i].secure_flag; icnss_pr_dbg("Memory Region: %d Addr: 0x%llx Size: 0x%x Flag: 0x%08x\n", - i, penv->icnss_mem_region[i].reg_addr, - penv->icnss_mem_region[i].size, - penv->icnss_mem_region[i].secure_flag); + i, penv->mem_region[i].reg_addr, + penv->mem_region[i].size, + penv->mem_region[i].secure_flag); } return 0; out: penv->stats.msa_info_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1180,7 +1198,7 @@ static int wlfw_msa_ready_send_sync_msg(void) out: penv->stats.msa_ready_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1243,7 +1261,7 @@ static int wlfw_ind_register_send_sync_msg(void) out: penv->stats.ind_register_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1312,7 +1330,7 @@ static int wlfw_cap_send_sync_msg(void) out: penv->stats.cap_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1373,7 +1391,7 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) out: penv->stats.mode_req_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1423,7 +1441,7 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) out: penv->stats.cfg_req_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1476,7 +1494,7 @@ static int wlfw_ini_send_sync_msg(uint8_t fw_log_mode) out: penv->stats.ini_req_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1642,7 +1660,7 @@ static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv) out: priv->stats.rejuvenate_ack_err++; - ICNSS_ASSERT(false); + ICNSS_QMI_ASSERT(); return ret; } @@ -1774,6 +1792,8 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, case QMI_WLFW_REJUVENATE_IND_V01: icnss_pr_dbg("Received Rejuvenate Indication msg_id 0x%x, state: 0x%lx\n", msg_id, penv->state); + + icnss_ignore_qmi_timeout(true); event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return; @@ -2142,7 +2162,7 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data = data; if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) - return 0; + goto out; if (test_bit(ICNSS_PD_RESTART, &priv->state)) { icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n", @@ -2159,6 +2179,8 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, out: kfree(data); + icnss_ignore_qmi_timeout(false); + return ret; } @@ -2300,9 +2322,11 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (test_bit(ICNSS_PDR_ENABLED, &priv->state)) return NOTIFY_OK; - icnss_pr_info("Modem went down, state: %lx, crashed: %d\n", + icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n", priv->state, notif->crashed); + icnss_ignore_qmi_timeout(true); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) @@ -2409,6 +2433,8 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, } event_post: + icnss_ignore_qmi_timeout(true); + icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); done: diff --git a/drivers/soc/qcom/ipc_router_mhi_xprt.c b/drivers/soc/qcom/ipc_router_mhi_xprt.c index 9a0624804c21..f9d967fd0af6 100644 --- a/drivers/soc/qcom/ipc_router_mhi_xprt.c +++ b/drivers/soc/qcom/ipc_router_mhi_xprt.c @@ -792,20 +792,14 @@ static int ipc_router_mhi_driver_register( { int rc_status; - rc_status = mhi_register_channel(&mhi_xprtp->ch_hndl.out_handle, - mhi_xprtp->ch_hndl.out_chan_id, 0, - &mhi_xprtp->ch_hndl.out_clnt_info, - (void *)mhi_xprtp); + rc_status = mhi_register_channel(&mhi_xprtp->ch_hndl.out_handle, NULL); if (rc_status) { IPC_RTR_ERR("%s: Error %d registering out_chan for %s\n", __func__, rc_status, mhi_xprtp->xprt_name); return -EFAULT; } - rc_status = mhi_register_channel(&mhi_xprtp->ch_hndl.in_handle, - mhi_xprtp->ch_hndl.in_chan_id, 0, - &mhi_xprtp->ch_hndl.in_clnt_info, - (void *)mhi_xprtp); + rc_status = mhi_register_channel(&mhi_xprtp->ch_hndl.in_handle, NULL); if (rc_status) { mhi_deregister_channel(mhi_xprtp->ch_hndl.out_handle); IPC_RTR_ERR("%s: Error %d registering in_chan for %s\n", diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index d6853e4bea72..0e7bf13c192b 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -101,6 +101,7 @@ struct elem_info qmi_response_type_v01_ei[] = { .ei_array = NULL, }, }; +EXPORT_SYMBOL(qmi_response_type_v01_ei); struct elem_info qmi_error_resp_type_v01_ei[] = { { diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c index 90c7585d480c..4307937d9f6d 100644 --- a/drivers/soc/qcom/secure_buffer.c +++ b/drivers/soc/qcom/secure_buffer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google, Inc - * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-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 @@ -379,6 +379,7 @@ int hyp_assign_phys(phys_addr_t addr, u64 size, u32 *source_vm_list, sg_free_table(&table); return ret; } +EXPORT_SYMBOL(hyp_assign_phys); const char *msm_secure_vmid_to_string(int secure_vmid) { 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/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index b132cff14f01..15ff4e149d75 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -30,6 +30,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/smp.h> +#include <linux/sysrq.h> #include <linux/timer.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -401,7 +402,7 @@ static void fiq_debugger_work(struct work_struct *work) cmd += 6; while (*cmd == ' ') cmd++; - if (cmd != '\0') + if ((cmd != '\0') && sysrq_on()) kernel_restart(cmd); else kernel_restart(NULL); @@ -431,29 +432,39 @@ static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd) static void fiq_debugger_help(struct fiq_debugger_state *state) { fiq_debugger_printf(&state->output, - "FIQ Debugger commands:\n" - " pc PC status\n" - " regs Register dump\n" - " allregs Extended Register dump\n" - " bt Stack trace\n" - " reboot [<c>] Reboot with command <c>\n" - " reset [<c>] Hard reset with command <c>\n" - " irqs Interupt status\n" - " kmsg Kernel log\n" - " version Kernel version\n"); - fiq_debugger_printf(&state->output, - " sleep Allow sleep while in FIQ\n" - " nosleep Disable sleep while in FIQ\n" - " console Switch terminal to console\n" - " cpu Current CPU\n" - " cpu <number> Switch to CPU<number>\n"); + "FIQ Debugger commands:\n"); + if (sysrq_on()) { + fiq_debugger_printf(&state->output, + " pc PC status\n" + " regs Register dump\n" + " allregs Extended Register dump\n" + " bt Stack trace\n"); + fiq_debugger_printf(&state->output, + " reboot [<c>] Reboot with command <c>\n" + " reset [<c>] Hard reset with command <c>\n" + " irqs Interrupt status\n" + " kmsg Kernel log\n" + " version Kernel version\n"); + fiq_debugger_printf(&state->output, + " cpu Current CPU\n" + " cpu <number> Switch to CPU<number>\n" + " sysrq sysrq options\n" + " sysrq <param> Execute sysrq with <param>\n"); + } else { + fiq_debugger_printf(&state->output, + " reboot Reboot\n" + " reset Hard reset\n" + " irqs Interrupt status\n"); + } fiq_debugger_printf(&state->output, - " ps Process list\n" - " sysrq sysrq options\n" - " sysrq <param> Execute sysrq with <param>\n"); + " sleep Allow sleep while in FIQ\n" + " nosleep Disable sleep while in FIQ\n" + " console Switch terminal to console\n" + " ps Process list\n"); #ifdef CONFIG_KGDB - fiq_debugger_printf(&state->output, - " kgdb Enter kernel debugger\n"); + if (fiq_kgdb_enable) { + fiq_debugger_printf(&state->output, + " kgdb Enter kernel debugger\n"); #endif } @@ -485,18 +496,23 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { - fiq_debugger_dump_pc(&state->output, regs); + if (sysrq_on()) + fiq_debugger_dump_pc(&state->output, regs); } else if (!strcmp(cmd, "regs")) { - fiq_debugger_dump_regs(&state->output, regs); + if (sysrq_on()) + fiq_debugger_dump_regs(&state->output, regs); } else if (!strcmp(cmd, "allregs")) { - fiq_debugger_dump_allregs(&state->output, regs); + if (sysrq_on()) + fiq_debugger_dump_allregs(&state->output, regs); } else if (!strcmp(cmd, "bt")) { - fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp); + if (sysrq_on()) + fiq_debugger_dump_stacktrace(&state->output, regs, + 100, svc_sp); } else if (!strncmp(cmd, "reset", 5)) { cmd += 5; while (*cmd == ' ') cmd++; - if (*cmd) { + if (*cmd && sysrq_on()) { char tmp_cmd[32]; strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd)); machine_restart(tmp_cmd); @@ -506,9 +522,12 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, } else if (!strcmp(cmd, "irqs")) { fiq_debugger_dump_irqs(state); } else if (!strcmp(cmd, "kmsg")) { - fiq_debugger_dump_kernel_log(state); + if (sysrq_on()) + fiq_debugger_dump_kernel_log(state); } else if (!strcmp(cmd, "version")) { - fiq_debugger_printf(&state->output, "%s\n", linux_banner); + if (sysrq_on()) + fiq_debugger_printf(&state->output, "%s\n", + linux_banner); } else if (!strcmp(cmd, "sleep")) { state->no_sleep = false; fiq_debugger_printf(&state->output, "enabling sleep\n"); @@ -520,14 +539,17 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, fiq_debugger_uart_flush(state); state->console_enable = true; } else if (!strcmp(cmd, "cpu")) { - fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); - } else if (!strncmp(cmd, "cpu ", 4)) { + if (sysrq_on()) + fiq_debugger_printf(&state->output, "cpu %d\n", + state->current_cpu); + } else if (!strncmp(cmd, "cpu ", 4) && sysrq_on()) { unsigned long cpu = 0; if (kstrtoul(cmd + 4, 10, &cpu) == 0) fiq_debugger_switch_cpu(state, cpu); else fiq_debugger_printf(&state->output, "invalid cpu\n"); - fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(&state->output, "cpu %d\n", + state->current_cpu); } else { if (state->debug_busy) { fiq_debugger_printf(&state->output, diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 81bda878a7ec..b7fe42582e89 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -807,7 +807,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) struct ion_handle *handle = rb_entry(n, struct ion_handle, node); - seq_printf(s, "%16.16s: %16zx : %16d : %12p", + seq_printf(s, "%16.16s: %16zx : %16d : %12pK", handle->buffer->heap->name, handle->buffer->size, atomic_read(&handle->ref.refcount), diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c index cff5b6e3fc63..efe80c24d270 100644 --- a/drivers/thermal/msm_lmh_dcvs.c +++ b/drivers/thermal/msm_lmh_dcvs.c @@ -114,9 +114,9 @@ static void msm_lmh_dcvs_get_max_freq(uint32_t cpu, uint32_t *max_freq) static uint32_t msm_lmh_mitigation_notify(struct msm_lmh_dcvs_hw *hw) { - uint32_t max_limit = 0, val = 0; + uint32_t val = 0; struct device *cpu_dev = NULL; - unsigned long freq_val; + unsigned long freq_val, max_limit = 0; struct dev_pm_opp *opp_entry; val = readl_relaxed(hw->osm_hw_reg); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index e5139402e7f8..cde24aca6dea 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -55,10 +55,11 @@ static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; -static bool sysrq_on(void) +bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; } +EXPORT_SYMBOL(sysrq_on); /* * A value of 1 means 'all', other nonzero values are an op mask: diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7a279db521ca..82fe26822582 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -388,8 +388,10 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, } return -ETIMEDOUT; } - - udelay(1); + if ((cmd & DWC3_DEPCMD_SETTRANSFRESOURCE)) + udelay(20); + else + udelay(1); } while (1); } diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index ac17d0aa46ae..45c39d3c4225 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -153,6 +153,7 @@ static unsigned int rndis_qc_bitrate(struct usb_gadget *g) /* interface descriptor: */ +/* interface descriptor: Supports "Wireless" RNDIS; auto-detected by Windows*/ static struct usb_interface_descriptor rndis_qc_control_intf = { .bLength = sizeof(rndis_qc_control_intf), .bDescriptorType = USB_DT_INTERFACE, @@ -160,9 +161,9 @@ static struct usb_interface_descriptor rndis_qc_control_intf = { /* .bInterfaceNumber = DYNAMIC */ /* status endpoint is optional; this could be patched later */ .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, + .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x03, /* .iInterface = DYNAMIC */ }; @@ -214,15 +215,16 @@ static struct usb_interface_descriptor rndis_qc_data_intf = { }; +/* Supports "Wireless" RNDIS; auto-detected by Windows */ static struct usb_interface_assoc_descriptor rndis_qc_iad_descriptor = { .bLength = sizeof(rndis_qc_iad_descriptor), .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bFirstInterface = 0, /* XXX, hardcoded */ .bInterfaceCount = 2, /* control + data */ - .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bFunctionProtocol = USB_CDC_PROTO_NONE, + .bFunctionClass = USB_CLASS_WIRELESS_CONTROLLER, + .bFunctionSubClass = 0x01, + .bFunctionProtocol = 0x03, /* .iFunction = DYNAMIC */ }; 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 153c733fdf43..bd5e8862f6d0 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -4022,8 +4022,6 @@ static int mdss_dp_probe(struct platform_device *pdev) pr_debug("done\n"); - dp_send_events(dp_drv, EV_USBPD_DISCOVER_MODES); - return 0; probe_err: diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 5f1dde279732..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: 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_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 36a866685f21..3d5d046c536a 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 { @@ -650,6 +661,7 @@ struct mdss_mdp_img_data { struct dma_buf *srcp_dma_buf; struct dma_buf_attachment *srcp_attachment; struct sg_table *srcp_table; + struct ion_handle *ihandle; }; enum mdss_mdp_data_state { @@ -691,6 +703,8 @@ struct pp_hist_col_info { char __iomem *base; u32 intr_shift; u32 disp_num; + u32 expect_sum; + u32 next_sum; struct mdss_mdp_ctl *ctl; }; @@ -953,6 +967,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 e33e174780e7..bd70535e79f9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4496,11 +4496,15 @@ end: */ static void mdss_mdp_pipe_reset(struct mdss_mdp_mixer *mixer, bool is_recovery) { - unsigned long pipe_map = mixer->pipe_mapped; + unsigned long pipe_map; u32 bit = 0; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); bool sw_rst_avail = mdss_mdp_pipe_is_sw_reset_available(mdata); + if (!mixer) + return; + + pipe_map = mixer->pipe_mapped; pr_debug("pipe_map=0x%lx\n", pipe_map); for_each_set_bit_from(bit, &pipe_map, MAX_PIPES_PER_LM) { struct mdss_mdp_pipe *pipe; @@ -5716,6 +5720,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) { @@ -5884,6 +5897,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) { @@ -6032,6 +6054,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 533239c99345..8470dc33dc3f 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); @@ -1790,7 +1790,7 @@ static void mdss_mdp_fetch_end_config(struct mdss_mdp_video_ctx *ctx, static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx, struct mdss_mdp_ctl *ctl) { - int fetch_start, fetch_enable, v_total, h_total; + int fetch_start = 0, fetch_enable, v_total, h_total; struct mdss_data_type *mdata; struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; @@ -1799,6 +1799,15 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx, pinfo->prg_fet = mdss_mdp_get_prefetch_lines(pinfo); if (!pinfo->prg_fet) { pr_debug("programmable fetch is not needed/supported\n"); + + fetch_enable = mdp_video_read(ctx, MDSS_MDP_REG_INTF_CONFIG); + fetch_enable &= ~BIT(31); + + mdp_video_write(ctx, MDSS_MDP_REG_INTF_CONFIG, fetch_enable); + mdp_video_write(ctx, MDSS_MDP_REG_INTF_PROG_FETCH_START, + fetch_start); + + MDSS_XLOG(ctx->intf_num, fetch_enable, fetch_start); return; } @@ -2348,6 +2357,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..fce667a2126d 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; @@ -2261,6 +2264,78 @@ static int __validate_multirect(struct msm_fb_data_type *mfd, return 0; } +static int __check_source_split(struct mdp_input_layer *layer_list, + struct mdss_mdp_pipe **pipe_list, u32 index, + u32 left_lm_w, struct mdss_mdp_pipe **left_blend_pipe) +{ + int i = index - 1; + struct mdp_input_layer *curr, *prev; + struct mdp_rect *left, *right; + bool match = false; + struct mdss_mdp_pipe *left_pipe = NULL; + + /* + * check if current layer is at same z_order as any of the + * previous layers, and fail if any or both are async layers, + * as async layers should have unique z_order. + * + * If it has same z_order and qualifies as a right blend, + * pass a pointer to the pipe representing previous overlay or + * in other terms left blend layer. + * + * Following logic of selecting left_blend has an inherent + * assumption that layer list is sorted on dst_x within a + * same z_order. Otherwise it will fail based on z_order checks. + */ + curr = &layer_list[index]; + + while (i >= 0) { + if (layer_list[i].z_order == curr->z_order) { + pr_debug("z=%d found match @ %d of %d\n", + curr->z_order, i, index); + match = true; + break; + } + i--; + } + + if (match) { + left_pipe = pipe_list[i]; + prev = &layer_list[i]; + left = &prev->dst_rect; + right = &curr->dst_rect; + + if ((curr->flags & MDP_LAYER_ASYNC) + || (prev->flags & MDP_LAYER_ASYNC)) { + curr->error_code = -EINVAL; + pr_err("async curr should have unique z_order\n"); + return curr->error_code; + } + + /* + * check if curr is right blend by checking it's + * directly to the right. + */ + if (((left->x + left->w) == right->x) && + (left->y == right->y) && (left->h == right->h)) { + *left_blend_pipe = left_pipe; + MDSS_XLOG(curr->z_order, i, index); + } + + /* + * if the curr is right at the left lm boundary and + * src split is not required then right blend is not + * required as it will lie only on the left mixer + */ + if (!__layer_needs_src_split(prev) && + ((left->x + left->w) == left_lm_w)) + *left_blend_pipe = NULL; + } + + return 0; +} + + /* * __validate_layers() - validate input layers * @mfd: Framebuffer data structure for display @@ -2291,13 +2366,14 @@ static int __validate_layers(struct msm_fb_data_type *mfd, struct mdss_data_type *mdata = mfd_to_mdata(mfd); struct mdss_mdp_mixer *mixer = NULL; - struct mdp_input_layer *layer, *prev_layer, *layer_list; + struct mdp_input_layer *layer, *layer_list; struct mdss_mdp_validate_info_t *validate_info_list = NULL; bool is_single_layer = false, force_validate; enum layer_pipe_q pipe_q_type; enum layer_zorder_used zorder_used[MDSS_MDP_MAX_STAGE] = {0}; enum mdss_mdp_pipe_rect rect_num; struct mdp_destination_scaler_data *ds_data; + struct mdss_mdp_pipe *pipe_list[MAX_LAYER_COUNT] = {0}; ret = mutex_lock_interruptible(&mdp5_data->ov_lock); if (ret) @@ -2369,49 +2445,10 @@ static int __validate_layers(struct msm_fb_data_type *mfd, dst_x = layer->dst_rect.x; left_blend_pipe = NULL; - prev_layer = (i > 0) ? &layer_list[i - 1] : NULL; - /* - * check if current layer is at same z_order as - * previous one, and fail if any or both are async layers, - * as async layers should have unique z_order. - * - * If it has same z_order and qualifies as a right blend, - * pass a pointer to the pipe representing previous overlay or - * in other terms left blend layer. - * - * Following logic of selecting left_blend has an inherent - * assumption that layer list is sorted on dst_x within a - * same z_order. Otherwise it will fail based on z_order checks. - */ - if (prev_layer && (prev_layer->z_order == layer->z_order)) { - struct mdp_rect *left = &prev_layer->dst_rect; - struct mdp_rect *right = &layer->dst_rect; - - if ((layer->flags & MDP_LAYER_ASYNC) - || (prev_layer->flags & MDP_LAYER_ASYNC)) { - ret = -EINVAL; - layer->error_code = ret; - pr_err("async layer should have unique z_order\n"); - goto validate_exit; - } - - /* - * check if layer is right blend by checking it's - * directly to the right. - */ - if (((left->x + left->w) == right->x) && - (left->y == right->y) && (left->h == right->h)) - left_blend_pipe = pipe; - - /* - * if the layer is right at the left lm boundary and - * src split is not required then right blend is not - * required as it will lie only on the left mixer - */ - if (!__layer_needs_src_split(prev_layer) && - ((left->x + left->w) == left_lm_w)) - left_blend_pipe = NULL; - } + if ((i > 0) && + __check_source_split(layer_list, pipe_list, i, left_lm_w, + &left_blend_pipe)) + goto validate_exit; if (!is_split_lm(mfd) || __layer_needs_src_split(layer)) z = LAYER_ZORDER_BOTH; @@ -2456,6 +2493,8 @@ static int __validate_layers(struct msm_fb_data_type *mfd, else left_plist[left_cnt++] = pipe; + pipe_list[i] = pipe; + if (layer->flags & MDP_LAYER_PP) { memcpy(&pipe->pp_cfg, layer->pp_info, sizeof(struct mdp_overlay_pp_params)); @@ -2548,6 +2587,8 @@ static int __validate_layers(struct msm_fb_data_type *mfd, else left_plist[left_cnt++] = pipe; + pipe_list[i] = pipe; + pr_debug("id:0x%x flags:0x%x dst_x:%d\n", layer->pipe_ndx, layer->flags, layer->dst_rect.x); layer->z_order -= MDSS_MDP_STAGE_0; 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_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 1fe8fe6f7be8..f10d4fb60f52 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -2146,6 +2146,7 @@ static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix, unsigned long flag; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); u32 intr_mask; + u32 expected_sum = 0; if (!mdata) return -EPERM; @@ -2156,6 +2157,7 @@ static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix, block_type = DSPP; op_flags = BIT(16); hist_info = &mdss_pp_res->dspp_hist[mix->num]; + expected_sum = mix->width * mix->height; base = mdss_mdp_get_dspp_addr_off(PP_BLOCK(block)); if (IS_ERR(base)) { ret = -EPERM; @@ -2207,6 +2209,15 @@ static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix, else if (hist_info->col_en) *op |= op_flags; + if (hist_info->col_en) { + if (!hist_info->expect_sum) { + hist_info->expect_sum = expected_sum; + } else if (hist_info->expect_sum != expected_sum) { + hist_info->expect_sum = 0; + hist_info->next_sum = expected_sum; + } + } + spin_unlock_irqrestore(&hist_info->hist_lock, flag); mutex_unlock(&hist_info->hist_mutex); error: @@ -5276,8 +5287,7 @@ exit: static int pp_hist_collect(struct mdp_histogram_data *hist, struct pp_hist_col_info *hist_info, - char __iomem *ctl_base, u32 expect_sum, - u32 block) + char __iomem *ctl_base, u32 block) { int ret = 0; int sum = 0; @@ -5318,11 +5328,16 @@ static int pp_hist_collect(struct mdp_histogram_data *hist, if (sum < 0) { pr_err("failed to get the hist data, sum = %d\n", sum); ret = sum; - } else if (expect_sum && sum != expect_sum) { + } else if (hist_info->expect_sum && sum != hist_info->expect_sum) { pr_err_ratelimited("hist error: bin sum incorrect! (%d/%d)\n", - sum, expect_sum); + sum, hist_info->expect_sum); ret = -EINVAL; } + + if (hist_info->next_sum) { + hist_info->expect_sum = hist_info->next_sum; + hist_info->next_sum = 0; + } hist_collect_exit: mutex_unlock(&hist_info->hist_mutex); return ret; @@ -5387,8 +5402,7 @@ int mdss_mdp_hist_collect(struct mdp_histogram_data *hist) mdata->mixer_intf[dspp_num].height); if (ret) temp_ret = ret; - ret = pp_hist_collect(hist, hists[i], ctl_base, - exp_sum, DSPP); + ret = pp_hist_collect(hist, hists[i], ctl_base, DSPP); if (ret) pr_err_ratelimited("hist error: dspp[%d] collect %d\n", dspp_num, ret); @@ -5487,7 +5501,7 @@ int mdss_mdp_hist_collect(struct mdp_histogram_data *hist) if (ret) temp_ret = ret; ret = pp_hist_collect(hist, hist_info, ctl_base, - exp_sum, SSPP_VIG); + SSPP_VIG); if (ret) pr_debug("hist error: pipe[%d] collect: %d\n", pipe->num, ret); diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index c14840ffd08d..d0bf61679f61 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.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 @@ -974,7 +974,9 @@ static int mdss_mdp_put_img(struct mdss_mdp_img_data *data, bool rotator, * be filled due to map call which will be unmapped above. * */ - pr_debug("skip memory unmapping for secure display/camera content\n"); + if (data->ihandle) + ion_free(iclient, data->ihandle); + pr_debug("free memory handle for secure display/camera content\n"); } else { return -ENOMEM; } @@ -1053,19 +1055,18 @@ static int mdss_mdp_get_img(struct msmfb_data *img, ret = 0; goto done; } else { - struct ion_handle *ihandle = NULL; struct sg_table *sg_ptr = NULL; + data->ihandle = ion_import_dma_buf(iclient, + img->memory_id); + if (IS_ERR_OR_NULL(data->ihandle)) { + ret = -EINVAL; + pr_err("ion import buffer failed\n"); + data->ihandle = NULL; + goto done; + } do { - ihandle = ion_import_dma_buf(iclient, - img->memory_id); - if (IS_ERR_OR_NULL(ihandle)) { - ret = -EINVAL; - pr_err("ion import buffer failed\n"); - break; - } - - sg_ptr = ion_sg_table(iclient, ihandle); + sg_ptr = ion_sg_table(iclient, data->ihandle); if (sg_ptr == NULL) { pr_err("ion sg table get failed\n"); ret = -EINVAL; @@ -1091,8 +1092,6 @@ static int mdss_mdp_get_img(struct msmfb_data *img, ret = 0; } while (0); - if (!IS_ERR_OR_NULL(ihandle)) - ion_free(iclient, ihandle); return ret; } } 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/linux/diagchar.h b/include/linux/diagchar.h index 0ae23ddbc528..04a22505edd7 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.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 @@ -144,10 +144,10 @@ the appropriate macros. */ /* This needs to be modified manually now, when we add a new RANGE of SSIDs to the msg_mask_tbl */ #define MSG_MASK_TBL_CNT 25 -#define APPS_EVENT_LAST_ID 0x0B2A +#define APPS_EVENT_LAST_ID 0x0B3F #define MSG_SSID_0 0 -#define MSG_SSID_0_LAST 120 +#define MSG_SSID_0_LAST 121 #define MSG_SSID_1 500 #define MSG_SSID_1_LAST 506 #define MSG_SSID_2 1000 @@ -159,7 +159,7 @@ the appropriate macros. */ #define MSG_SSID_5 4000 #define MSG_SSID_5_LAST 4010 #define MSG_SSID_6 4500 -#define MSG_SSID_6_LAST 4573 +#define MSG_SSID_6_LAST 4583 #define MSG_SSID_7 4600 #define MSG_SSID_7_LAST 4615 #define MSG_SSID_8 5000 @@ -183,7 +183,7 @@ the appropriate macros. */ #define MSG_SSID_17 9000 #define MSG_SSID_17_LAST 9008 #define MSG_SSID_18 9500 -#define MSG_SSID_18_LAST 9510 +#define MSG_SSID_18_LAST 9521 #define MSG_SSID_19 10200 #define MSG_SSID_19_LAST 10210 #define MSG_SSID_20 10251 @@ -338,7 +338,8 @@ static const uint32_t msg_bld_masks_0[] = { MSG_LVL_MED, MSG_LVL_HIGH, MSG_LVL_LOW, - MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL + MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL, + MSG_LVL_HIGH }; static const uint32_t msg_bld_masks_1[] = { @@ -858,7 +859,7 @@ static const uint32_t msg_bld_masks_23[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1A02, /* EQUIP ID 1 */ + 0x1A11, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h index f8ba31ea7573..b9fd610f92da 100644 --- a/include/linux/msm_mhi.h +++ b/include/linux/msm_mhi.h @@ -12,12 +12,14 @@ #ifndef MSM_MHI_H #define MSM_MHI_H #include <linux/types.h> - -struct mhi_client_handle; +#include <linux/device.h> #define MHI_DMA_MASK 0xFFFFFFFFFFULL #define MHI_MAX_MTU 0xFFFF +struct mhi_client_config; +struct mhi_device_ctxt; + enum MHI_CLIENT_CHANNEL { MHI_CLIENT_LOOPBACK_OUT = 0, MHI_CLIENT_LOOPBACK_IN = 1, @@ -70,11 +72,11 @@ enum MHI_CLIENT_CHANNEL { }; enum MHI_CB_REASON { - MHI_CB_XFER = 0x0, - MHI_CB_MHI_DISABLED = 0x4, - MHI_CB_MHI_ENABLED = 0x8, - MHI_CB_CHAN_RESET_COMPLETE = 0x10, - MHI_CB_reserved = 0x80000000, + MHI_CB_XFER, + MHI_CB_MHI_DISABLED, + MHI_CB_MHI_ENABLED, + MHI_CB_MHI_SHUTDOWN, + MHI_CB_SYS_ERROR, }; enum MHI_FLAGS { @@ -99,10 +101,90 @@ struct mhi_cb_info { }; struct mhi_client_info_t { + enum MHI_CLIENT_CHANNEL chan; + const struct device *dev; + const char *node_name; void (*mhi_client_cb)(struct mhi_cb_info *); + bool pre_allocate; + size_t max_payload; + void *user_data; +}; + +struct mhi_client_handle { + u32 dev_id; + u32 domain; + u32 bus; + u32 slot; + struct mhi_client_config *client_config; +}; + +struct __packed bhi_vec_entry { + u64 phys_addr; + u64 size; +}; + +/** + * struct mhi_device - IO resources for MHI + * @dev: device node points to of_node + * @pdev: pci device node + * @resource: bar memory space and IRQ resources + * @pm_runtime_get: fp for bus masters rpm pm_runtime_get + * @pm_runtime_noidle: fp for bus masters rpm pm_runtime_noidle + * @mhi_dev_ctxt: private data for host + */ +struct mhi_device { + struct device *dev; + struct pci_dev *pci_dev; + struct resource resources[2]; + int (*pm_runtime_get)(struct pci_dev *pci_dev); + void (*pm_runtime_noidle)(struct pci_dev *pci_dev); + struct mhi_device_ctxt *mhi_dev_ctxt; +}; + +enum mhi_dev_ctrl { + MHI_DEV_CTRL_INIT, + MHI_DEV_CTRL_DE_INIT, + MHI_DEV_CTRL_SUSPEND, + MHI_DEV_CTRL_RESUME, + MHI_DEV_CTRL_POWER_OFF, + MHI_DEV_CTRL_POWER_ON, + MHI_DEV_CTRL_RAM_DUMP, + MHI_DEV_CTRL_NOTIFY_LINK_ERROR, }; /** + * mhi_is_device_ready - Check if MHI is ready to register clients + * + * @dev: device node that points to DT node + * @node_name: device tree node that links MHI node + * + * @Return true if ready + */ +bool mhi_is_device_ready(const struct device * const dev, + const char *node_name); + +/** + * mhi_resgister_device - register hardware resources with MHI + * + * @mhi_device: resources to be used + * @node_name: DT node name + * @userdata: cb data for client + * @Return 0 on success + */ +int mhi_register_device(struct mhi_device *mhi_device, + const char *node_name, + unsigned long user_data); + +/** + * mhi_pm_control_device - power management control api + * @mhi_device: registered device structure + * @ctrl: specific command + * @Return 0 on success + */ +int mhi_pm_control_device(struct mhi_device *mhi_device, + enum mhi_dev_ctrl ctrl); + +/** * mhi_deregister_channel - de-register callbacks from MHI * * @client_handle: Handle populated by MHI, opaque to client @@ -116,21 +198,13 @@ int mhi_deregister_channel(struct mhi_client_handle *client_handle); * any MHI operations * * @client_handle: Handle populated by MHI, opaque to client - * @chan: Channel provided by client to which the handle - * maps to. - * @device_index: MHI device for which client wishes to register, if - * there are multiple devices supporting MHI. Client - * should specify 0 for the first device 1 for second etc. - * @info: Client provided callbacks which MHI will invoke on events - * @user_data: Client provided context to be returned to client upon - * callback invocation. - * Not thread safe, caller must ensure concurrency protection. + * @client_info: Channel\device information provided by client to + * which the handle maps to. * * @Return errno */ int mhi_register_channel(struct mhi_client_handle **client_handle, - enum MHI_CLIENT_CHANNEL chan, s32 device_index, - struct mhi_client_info_t *client_info, void *user_data); + struct mhi_client_info_t *client_info); /** * mhi_open_channel - Client must call this function to open a channel diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 387fa7d05c98..d802692acb53 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -42,6 +42,7 @@ struct sysrq_key_op { * are available -- else NULL's). */ +bool sysrq_on(void); void handle_sysrq(int key); void __handle_sysrq(int key, bool check_mask); int register_sysrq_key(int key, struct sysrq_key_op *op); diff --git a/include/soc/qcom/secure_buffer.h b/include/soc/qcom/secure_buffer.h index 59971c08ed74..b5e71387a6fc 100644 --- a/include/soc/qcom/secure_buffer.h +++ b/include/soc/qcom/secure_buffer.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 @@ -53,7 +53,7 @@ int hyp_assign_table(struct sg_table *table, u32 *source_vm_list, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems); -int hyp_assign_phys(phys_addr_t addr, u64 size, +extern int hyp_assign_phys(phys_addr_t addr, u64 size, u32 *source_vmlist, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems); bool msm_secure_v2_is_supported(void); 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/eventpoll.h b/include/uapi/linux/eventpoll.h index bc81fb2e1f0e..47d6342b1c48 100644 --- a/include/uapi/linux/eventpoll.h +++ b/include/uapi/linux/eventpoll.h @@ -56,6 +56,7 @@ #define EPOLL_PACKED #endif +#ifdef __KERNEL__ struct epoll_event { __u32 events; __u64 data; @@ -73,4 +74,5 @@ static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev) epev->events &= ~EPOLLWAKEUP; } #endif +#endif /* __KERNEL__ */ #endif /* _UAPI_LINUX_EVENTPOLL_H */ 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/media/msmb_camera.h b/include/uapi/media/msmb_camera.h index 071331ef6882..df9807e72e47 100644 --- a/include/uapi/media/msmb_camera.h +++ b/include/uapi/media/msmb_camera.h @@ -51,7 +51,7 @@ #define MSM_CAMERA_SUBDEV_IR_LED 17 #define MSM_CAMERA_SUBDEV_IR_CUT 18 #define MSM_CAMERA_SUBDEV_EXT 19 - +#define MSM_CAMERA_SUBDEV_TOF 20 #define MSM_MAX_CAMERA_SENSORS 5 /* The below macro is defined to put an upper limit on maximum diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index 21fcb3401298..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 { diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index 1e3accddd103..983159cc0646 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "core_ctl: " fmt + #include <linux/init.h> #include <linux/notifier.h> #include <linux/cpu.h> @@ -50,7 +52,6 @@ struct cluster_data { }; struct cpu_data { - bool online; bool is_busy; unsigned int busy; unsigned int cpu; @@ -242,22 +243,6 @@ static ssize_t show_is_big_cluster(const struct cluster_data *state, char *buf) return snprintf(buf, PAGE_SIZE, "%u\n", state->is_big_cluster); } -static ssize_t show_cpus(const struct cluster_data *state, char *buf) -{ - struct cpu_data *c; - ssize_t count = 0; - unsigned long flags; - - spin_lock_irqsave(&state_lock, flags); - list_for_each_entry(c, &state->lru, sib) { - count += snprintf(buf + count, PAGE_SIZE - count, - "CPU%u (%s)\n", c->cpu, - c->online ? "Online" : "Offline"); - } - spin_unlock_irqrestore(&state_lock, flags); - return count; -} - static ssize_t show_need_cpus(const struct cluster_data *state, char *buf) { return snprintf(buf, PAGE_SIZE, "%u\n", state->need_cpus); @@ -286,10 +271,11 @@ static ssize_t show_global_state(const struct cluster_data *state, char *buf) count += snprintf(buf + count, PAGE_SIZE - count, "\tCPU: %u\n", c->cpu); count += snprintf(buf + count, PAGE_SIZE - count, - "\tOnline: %u\n", c->online); + "\tOnline: %u\n", + cpu_online(c->cpu)); count += snprintf(buf + count, PAGE_SIZE - count, - "\tActive: %u\n", - !cpu_isolated(c->cpu)); + "\tIsolated: %u\n", + cpu_isolated(c->cpu)); count += snprintf(buf + count, PAGE_SIZE - count, "\tFirst CPU: %u\n", cluster->first_cpu); @@ -376,7 +362,6 @@ core_ctl_attr_rw(busy_up_thres); core_ctl_attr_rw(busy_down_thres); core_ctl_attr_rw(task_thres); core_ctl_attr_rw(is_big_cluster); -core_ctl_attr_ro(cpus); core_ctl_attr_ro(need_cpus); core_ctl_attr_ro(active_cpus); core_ctl_attr_ro(global_state); @@ -390,7 +375,6 @@ static struct attribute *default_attrs[] = { &busy_down_thres.attr, &task_thres.attr, &is_big_cluster.attr, - &cpus.attr, &need_cpus.attr, &active_cpus.attr, &global_state.attr, @@ -534,7 +518,7 @@ static unsigned int get_active_cpu_count(const struct cluster_data *cluster) static bool is_active(const struct cpu_data *state) { - return state->online && !cpu_isolated(state->cpu); + return cpu_online(state->cpu) && !cpu_isolated(state->cpu); } static bool adjustment_possible(const struct cluster_data *cluster, @@ -815,7 +799,7 @@ static void __try_to_unisolate(struct cluster_data *cluster, if (!c->isolated_by_us) continue; - if ((c->online && !cpu_isolated(c->cpu)) || + if ((cpu_online(c->cpu) && !cpu_isolated(c->cpu)) || (!force && c->not_preferred)) continue; if (cluster->active_cpus == need) @@ -904,19 +888,7 @@ static int __ref cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; switch (action & ~CPU_TASKS_FROZEN) { - case CPU_UP_PREPARE: - - /* If online state of CPU somehow got out of sync, fix it. */ - if (state->online) { - state->online = false; - cluster->active_cpus = get_active_cpu_count(cluster); - pr_warn("CPU%d offline when state is online\n", cpu); - } - break; - case CPU_ONLINE: - - state->online = true; cluster->active_cpus = get_active_cpu_count(cluster); /* @@ -941,15 +913,6 @@ static int __ref cpu_callback(struct notifier_block *nfb, /* Move a CPU to the end of the LRU when it goes offline. */ move_cpu_lru(state); - /* Fall through */ - - case CPU_UP_CANCELED: - - /* If online state of CPU somehow got out of sync, fix it. */ - if (!state->online) - pr_warn("CPU%d online when state is offline\n", cpu); - - state->online = false; state->busy = 0; cluster->active_cpus = get_active_cpu_count(cluster); break; @@ -1028,8 +991,6 @@ static int cluster_init(const struct cpumask *mask) state = &per_cpu(cpu_state, cpu); state->cluster = cluster; state->cpu = cpu; - if (cpu_online(cpu)) - state->online = true; list_add_tail(&state->sib, &cluster->lru); } cluster->active_cpus = get_active_cpu_count(cluster); diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index 928284d1e0e3..04440262fe7a 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -4047,6 +4047,7 @@ 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; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int ret; sdm660_cdc = dev_get_drvdata(codec->dev); @@ -4155,6 +4156,9 @@ static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *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; } @@ -4230,24 +4234,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_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; diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index ed54016e1919..1b56ef4d5fbe 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", @@ -1166,6 +1166,7 @@ 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 *msm_dig_cdc = dev_get_drvdata(codec->dev); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int i, ret; msm_dig_cdc->codec = codec; @@ -1197,6 +1198,15 @@ static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec) } 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; } @@ -1973,9 +1983,27 @@ static struct regmap *msm_digital_get_regmap(struct device *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, @@ -2058,6 +2086,52 @@ 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; + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev); + + if (!registered_digcodec || !msm_dig_cdc) { + pr_debug("%s:digcodec not initialized, return\n", __func__); + return 0; + } + pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card); + if (!pdata) { + pr_debug("%s:card not initialized, return\n", __func__); + return 0; + } + 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 +2142,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 b401a4082cbb..f0e7a9cf9228 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h @@ -47,6 +47,7 @@ struct msm_dig_priv { 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/codecs/wcd934x/wcd934x-mbhc.h b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h index 0b27f3f62b02..27b96799be2b 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h +++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.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 @@ -35,6 +35,7 @@ struct wcd934x_mbhc { bool is_hph_recover; }; +#ifdef CONFIG_SND_SOC_WCD934X_MBHC extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec, struct fw_info *fw_data); @@ -46,6 +47,40 @@ extern int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc, struct snd_soc_codec *codec); extern int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, uint32_t *zl, uint32_t *zr); +#else +static inline int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, + struct snd_soc_codec *codec, + struct fw_info *fw_data) +{ + return 0; +} +static inline void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec) +{ +} +static inline int tavil_mbhc_hs_detect(struct snd_soc_codec *codec, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void tavil_mbhc_deinit(struct snd_soc_codec *codec) +{ +} +static inline int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc, + struct snd_soc_codec *codec) +{ + return 0; +} +static inline int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + #endif /* __WCD934X_MBHC_H__ */ 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/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, |
