summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt104
-rw-r--r--Documentation/devicetree/bindings/media/video/msm-cpp.txt8
-rw-r--r--Documentation/devicetree/bindings/media/video/msm-vfe.txt15
-rw-r--r--Documentation/devicetree/bindings/mhi/msm_mhi.txt175
-rw-r--r--Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt20
-rw-r--r--Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt70
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi124
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi51
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi52
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk-hdk.dtsi15
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi24
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-camera.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts28
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-audio.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-camera.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-coresight.dtsi160
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi19
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mtp.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts31
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dts21
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dtsi18
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi5
-rw-r--r--arch/arm64/boot/Makefile2
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig1
-rw-r--r--arch/arm64/configs/msmcortex_defconfig1
-rw-r--r--drivers/base/core.c8
-rw-r--r--drivers/base/power/main.c12
-rw-r--r--drivers/bluetooth/btfm_slim_codec.c60
-rw-r--r--drivers/bluetooth/btfm_slim_wcn3990.c69
-rw-r--r--drivers/char/adsprpc.c6
-rw-r--r--drivers/char/diag/diagfwd_mhi.c3
-rw-r--r--drivers/clk/clk.c6
-rw-r--r--drivers/clk/clk.h2
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/clk-branch.c3
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c2
-rw-r--r--drivers/clk/qcom/clk-debug.c277
-rw-r--r--drivers/clk/qcom/clk-debug.h120
-rw-r--r--drivers/clk/qcom/clk-dummy.c5
-rw-r--r--drivers/clk/qcom/clk-rcg.h3
-rw-r--r--drivers/clk/qcom/clk-rcg2.c70
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c3
-rw-r--r--drivers/clk/qcom/common.c239
-rw-r--r--drivers/clk/qcom/common.h100
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c7
-rw-r--r--drivers/clk/qcom/mmcc-sdm660.c6
-rw-r--r--drivers/firmware/qcom/tz_log.c40
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c2
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/vl53L0/Makefile4
-rw-r--r--drivers/input/touchscreen/Kconfig12
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/gt9xx/Kconfig51
-rw-r--r--drivers/input/touchscreen/gt9xx/Makefile8
-rw-r--r--drivers/input/touchscreen/gt9xx/goodix_tool.c600
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx.c2564
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx.h220
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx_update.c1530
-rw-r--r--drivers/iommu/io-pgtable-arm.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c46
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c78
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c10
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c14
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c62
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h5
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c12
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_util.c15
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c1
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c2
-rw-r--r--drivers/misc/qpnp-misc.c2
-rw-r--r--drivers/mmc/card/block.c8
-rw-r--r--drivers/net/ethernet/msm/msm_rmnet_mhi.c153
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c44
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c13
-rw-r--r--drivers/platform/msm/gsi/gsi.c5
-rw-r--r--drivers/platform/msm/gsi/gsi_reg.h5
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_dp.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c3
-rw-r--r--drivers/platform/msm/mhi/mhi.h175
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.c496
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.h42
-rw-r--r--drivers/platform/msm/mhi/mhi_event.c105
-rw-r--r--drivers/platform/msm/mhi/mhi_iface.c478
-rw-r--r--drivers/platform/msm/mhi/mhi_init.c245
-rw-r--r--drivers/platform/msm/mhi/mhi_isr.c247
-rw-r--r--drivers/platform/msm/mhi/mhi_macros.h9
-rw-r--r--drivers/platform/msm/mhi/mhi_main.c1056
-rw-r--r--drivers/platform/msm/mhi/mhi_mmio_ops.c139
-rw-r--r--drivers/platform/msm/mhi/mhi_pm.c337
-rw-r--r--drivers/platform/msm/mhi/mhi_ring_ops.c33
-rw-r--r--drivers/platform/msm/mhi/mhi_ssr.c123
-rw-r--r--drivers/platform/msm/mhi/mhi_states.c266
-rw-r--r--drivers/platform/msm/mhi/mhi_sys.c88
-rw-r--r--drivers/platform/msm/mhi/mhi_sys.h9
-rw-r--r--drivers/platform/msm/mhi_uci/mhi_uci.c71
-rw-r--r--drivers/power/supply/qcom/pmic-voter.c32
-rw-r--r--drivers/power/supply/qcom/pmic-voter.h3
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c58
-rw-r--r--drivers/power/supply/qcom/smb-lib.c181
-rw-r--r--drivers/power/supply/qcom/smb-lib.h3
-rw-r--r--drivers/power/supply/qcom/smb-reg.h1
-rw-r--r--drivers/regulator/core.c3
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c59
-rw-r--r--drivers/soc/qcom/icnss.c126
-rw-r--r--drivers/soc/qcom/ipc_router_mhi_xprt.c10
-rw-r--r--drivers/soc/qcom/qmi_interface.c3
-rw-r--r--drivers/soc/qcom/secure_buffer.c3
-rw-r--r--drivers/soc/qcom/service-locator.c11
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger.c86
-rw-r--r--drivers/staging/android/ion/ion.c2
-rw-r--r--drivers/thermal/msm_lmh_dcvs.c4
-rw-r--r--drivers/tty/sysrq.c3
-rw-r--r--drivers/usb/dwc3/gadget.c6
-rw-r--r--drivers/usb/gadget/function/f_qc_rndis.c14
-rw-r--r--drivers/usb/host/xhci-plat.c12
-rw-r--r--drivers/video/fbdev/msm/mdss_compat_utils.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_compat_utils.h7
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c21
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h16
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c35
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c65
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c26
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c133
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c106
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c28
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h8
-rw-r--r--include/linux/diagchar.h15
-rw-r--r--include/linux/msm_mhi.h110
-rw-r--r--include/linux/sysrq.h1
-rw-r--r--include/soc/qcom/secure_buffer.h4
-rw-r--r--include/uapi/drm/msm_drm.h8
-rw-r--r--include/uapi/linux/eventpoll.h2
-rw-r--r--include/uapi/linux/msm_mdp_ext.h10
-rw-r--r--include/uapi/media/msmb_camera.h2
-rw-r--r--include/uapi/media/msmb_isp.h3
-rw-r--r--kernel/sched/core_ctl.c55
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c18
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c79
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h1
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.h37
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c60
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c10
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,
- &reg_val, IFD);
+ reg = CHRK_SB_SLAVE_HW_REV_MSB;
+ ret = btfm_slim_read(btfmslim, reg, 1, &reg_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,
- &reg_val, IFD);
+ reg = CHRK_SB_SLAVE_HW_REV_LSB;
+ ret = btfm_slim_read(btfmslim, reg, 1, &reg_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, &reg_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,
- &reg_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, &reg_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, &reg_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, &reg_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, &regval);
+
+ /* Wait for timer to become ready. */
+ while ((regval & XO_DIV4_CNT_DONE) != 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, &regval);
+ }
+
+ /* Run measurement and wait for completion. */
+ regmap_write(regmap, ctl_reg, (CNT_EN|ticks));
+
+ regmap_read(regmap, status_reg, &regval);
+
+ while ((regval & XO_DIV4_CNT_DONE) == 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, &regval);
+ }
+
+ /* Return measured ticks. */
+ regmap_read(regmap, status_reg, &regval);
+ 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, &regval);
+
+ /* 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, &regval);
+
+ /* 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, &regval);
-
- /* Wait for timer to become ready. */
- while ((regval & BIT(25)) != 0) {
- cpu_relax();
- regmap_read(regmap, status_reg, &regval);
- }
-
- /* Run measurement and wait for completion. */
- regmap_write(regmap, ctl_reg, (BIT(20)|ticks));
- regmap_read(regmap, ctl_reg, &regval);
-
- regmap_read(regmap, status_reg, &regval);
-
- while ((regval & BIT(25)) == 0) {
- cpu_relax();
- regmap_read(regmap, status_reg, &regval);
- }
-
- /* Return measured ticks. */
- regmap_read(regmap, status_reg, &regval);
- 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, &regval);
-
- /* 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, &regval);
-
- /* 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(&gt_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(&gt_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(&gt_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(&gt_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(&gt_client->dev, "copy_from_user failed");
- ret = -EFAULT;
- goto exit;
- }
-
- dev_dbg(&gt_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(&gt_client->dev,
- "flag val:0x%02x, flag rel:0x%02x,\n", cmd_head.flag_val,
- cmd_head.flag_relation);
- dev_dbg(&gt_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(&gt_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(&gt_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(&gt_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(&gt_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(&gt_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(&gt_client->dev, "copy_from_user failed");
- ret = -EFAULT;
- goto exit;
- }
-
- if (cmd_head.data_len > sizeof(ic_type)) {
- dev_err(&gt_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(&gt_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(&gt_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(&gt_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(&gt_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(&gt_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(&gt_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, &gtp_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, &gtp_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, &gtp_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,
- &gtp_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(&gtp_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,
- &gtp_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(&gtp_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, &param) < 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, &param->paddr,