diff options
353 files changed, 10311 insertions, 17193 deletions
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt deleted file mode 100644 index 8ec9f78346d8..000000000000 --- a/Documentation/devicetree/bindings/display/msm/sde.txt +++ /dev/null @@ -1,55 +0,0 @@ -Qualcomm Technologies, Inc. SDE KMS - -Snapdragon Display Engine implements Linux DRM/KMS APIs to drive user -interface to different panel interfaces. SDE driver is the core of -display subsystem which manage all data paths to different panel interfaces. - -Required properties -- compatible: Must be "qcom,sde-kms" -- reg: Offset and length of the register set for the device. -- reg-names : Names to refer to register sets related to this device -- clocks: List of Phandles for clock device nodes - needed by the device. -- clock-names: List of clock names needed by the device. -- mmagic-supply: Phandle for mmagic mdss supply regulator device node. -- vdd-supply: Phandle for vdd regulator device node. -- interrupt-parent: Must be core interrupt controller. -- interrupts: Interrupt associated with MDSS. -- interrupt-controller: Mark the device node as an interrupt controller. -- #interrupt-cells: Should be one. The first cell is interrupt number. -- iommus: Specifies the SID's used by this context bank. - -Please refer to ../../interrupt-controller/interrupts.txt for a general -description of interrupt bindings. - -Example: - mdss_mdp: qcom,mdss_mdp@900000 { - compatible = "qcom,sde-kms"; - reg = <0x00900000 0x90000>, - <0x009b0000 0x1040>, - <0x009b8000 0x1040>; - reg-names = "mdp_phys", - "vbif_phys", - "vbif_nrt_phys"; - clocks = <&clock_mmss clk_mdss_ahb_clk>, - <&clock_mmss clk_mdss_axi_clk>, - <&clock_mmss clk_mdp_clk_src>, - <&clock_mmss clk_mdss_mdp_vote_clk>, - <&clock_mmss clk_smmu_mdp_axi_clk>, - <&clock_mmss clk_mmagic_mdss_axi_clk>, - <&clock_mmss clk_mdss_vsync_clk>; - clock-names = "iface_clk", - "bus_clk", - "core_clk_src", - "core_clk", - "iommu_clk", - "mmagic_clk", - "vsync_clk"; - mmagic-supply = <&gdsc_mmagic_mdss>; - vdd-supply = <&gdsc_mdss>; - interrupt-parent = <&intc>; - interrupts = <0 83 0>; - interrupt-controller; - #interrupt-cells = <1>; - iommus = <&mdp_smmu 0>; - }; diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 52ffbe5c7207..b676efe97b8b 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -61,6 +61,30 @@ Required properties: transmitted byte 5, 6: 16 bits length in network byte order byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-on: This is used to enable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-off: This is used to disable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload - qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are sent after displaying an image. @@ -648,6 +672,9 @@ Example: qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp-mode-on = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-lp-mode-off = [22 01 00 00 00 00 00]; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt index 5d9a703c4823..b9d4ebfb79e3 100644 --- a/Documentation/devicetree/bindings/fb/mdss-pll.txt +++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt @@ -15,7 +15,8 @@ Required properties: "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", "qcom,mdss_dsi_pll_8998", "qcom,mdss_dp_pll_8998", - "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dsi_pll_sdm660" + "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dsi_pll_sdm660", + "qcom,mdss_dp_pll_sdm660" - cell-index: Specifies the controller used - reg: offset and length of the register set for the device. - reg-names : names to refer to register sets related to this device diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index d00a5c1ce502..9e512d1ea763 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -139,8 +139,8 @@ conditions. time. This should be a list of 2-tuples of the format: <offset reg_value>. -- qcom,bus-master-id : The master ID of the bus, if a bus vote is needed. - See include/dt-bindings/msm/msm-bus-ids.h. +Optional bus bindings as defined in +Documentation/devicetree/bindings/arm/msm/msm_bus.txt may also be present. Example: diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index 80f2d8f43e35..ed784f7f58a5 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -81,6 +81,8 @@ memory allocation over a PCIe bridge - qcom,ipa-polling-iteration: IPA Polling Iteration Count,default is 40. - qcom,ipa-tz-unlock-reg: Register start addresses and ranges which need to be unlocked by TZ. +- qcom,ipa-uc-monitor-holb: Boolean context flag to indicate whether + monitoring of holb via IPA uc is required. IPA pipe sub nodes (A2 static pipes configurations): diff --git a/Documentation/devicetree/bindings/qdsp/msm-cdsp-loader.txt b/Documentation/devicetree/bindings/qdsp/msm-cdsp-loader.txt new file mode 100644 index 000000000000..33adc661448a --- /dev/null +++ b/Documentation/devicetree/bindings/qdsp/msm-cdsp-loader.txt @@ -0,0 +1,16 @@ +Qualcomm Technologies, Inc. CDSP Loader Driver + +msm-cdsp-loader driver implements the mechanism that allows to load CDSP firmware images. + +Required properties: + + - compatible: This must be "qcom,msm-cdsp-loader". + - qcom,proc-img-to-load: CDSP firmware name, must be "cdsp". + +Example: + The following for sdm660. + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt index 3e22f178aa82..d08ca957c954 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt @@ -203,10 +203,11 @@ IBB subnode required properties: - qcom,qpnp-ibb-init-lcd-voltage: The default output voltage when IBB regulator is configured in lcd mode. +IBB subnode optional properties: + - qcom,qpnp-ibb-discharge-resistor: The discharge resistor in Kilo Ohms which controls the soft start time. Supported values are 300, 64, 32 and 16. -IBB subnode optional properties: - qcom,qpnp-ibb-slew-rate: The time (in us) taken by the regulator to change voltage value in one step. This property is not diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index fa6ee8969946..47fad8aa4a1a 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -19,6 +19,7 @@ Required properties : and reset lines used by this controller. - reset-names: reset signal name strings sorted in the same order as the resets property. +- qcom,core-clk-rate: clock frequency to be set for USB master clock. Optional properties : - reg: Additional registers @@ -54,7 +55,8 @@ Optional properties : - qcom,disable-dev-mode-pm: If present, it disables PM runtime functionality for device mode. - qcom,disable-host-mode-pm: If present, it disables XHCI PM runtime functionality when USB host mode is used. -- qcom,core-clk-rate: If present, indicates clock frequency to be set for USB master clock. +- qcom,core-clk-rate-hs: If present, indicates min core clock frequency required to support + hs speed. - extcon: phandles to external connector devices. First phandle should point to external connector, which provide "USB" cable events, the second should point to external connector device, which provide "USB-HOST" diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 2c5137a6fef6..6475fa234065 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -850,14 +850,13 @@ via the /proc/sys interface: Each write syscall must fully contain the sysctl value to be written, and multiple writes on the same sysctl file descriptor will rewrite the sysctl value, regardless of file position. - 0 - (default) Same behavior as above, but warn about processes that - perform writes to a sysctl file descriptor when the file position - is not 0. - 1 - Respect file position when writing sysctl strings. Multiple writes - will append to the sysctl value buffer. Anything past the max length - of the sysctl value buffer will be ignored. Writes to numeric sysctl - entries must always be at file position 0 and the value must be - fully contained in the buffer sent in the write syscall. + 0 - Same behavior as above, but warn about processes that perform writes + to a sysctl file descriptor when the file position is not 0. + 1 - (default) Respect file position when writing sysctl strings. Multiple + writes will append to the sysctl value buffer. Anything past the max + length of the sysctl value buffer will be ignored. Writes to numeric + sysctl entries must always be at file position 0 and the value must + be fully contained in the buffer sent in the write syscall. ============================================================== diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts index 03fa038d9413..bc18fb54400f 100644 --- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts +++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts @@ -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 @@ -46,3 +46,31 @@ }; }; }; + +&mdss_dsi { + status = "disabled"; +}; + +&sdhc_2 { + vdd-supply = <&pm8998_l21>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8998_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_cd_on_mediabox>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_cd_off_mediabox>; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + cd-gpios = <&tlmm 86 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi index 7bd844ae6770..6d91e72851ec 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-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 @@ -57,6 +57,60 @@ 05 01 00 00 b4 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-lp-mode-on = [39 00 00 00 05 00 03 f0 5a 5a + 39 00 00 00 05 00 03 f1 5a 5a + 39 00 00 00 05 00 03 fc 5a 5a + 39 00 00 00 05 00 02 b0 17 + 39 00 00 00 05 00 02 cb 10 + 39 00 00 00 05 00 02 b0 2d + 39 00 00 00 05 00 02 cb cd + 39 00 00 00 05 00 02 b0 0e + 39 00 00 00 05 00 02 cb 02 + 39 00 00 00 05 00 02 b0 0f + 39 00 00 00 05 00 02 cb 09 + 39 00 00 00 05 00 02 b0 02 + 39 00 00 00 05 00 02 f2 c9 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f2 c0 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f4 aa + 39 00 00 00 05 00 02 b0 08 + 39 00 00 00 05 00 02 b1 30 + 39 00 00 00 05 00 02 b0 09 + 39 00 00 00 05 00 02 b1 0a + 39 00 00 00 05 00 02 b0 0d + 39 00 00 00 05 00 02 b1 10 + 39 00 00 00 05 00 02 b0 00 + 39 00 00 00 05 00 02 f7 03 + 39 00 00 00 05 00 02 fe 30 + 39 01 00 00 05 00 02 fe b0]; + qcom,mdss-dsi-lp-mode-off = [39 00 00 00 05 00 03 f0 5a 5a + 39 00 00 00 05 00 03 f1 5a 5a + 39 00 00 00 05 00 03 fc 5a 5a + 39 00 00 00 05 00 02 b0 2d + 39 00 00 00 05 00 02 cb 4d + 39 00 00 00 05 00 02 b0 17 + 39 00 00 00 05 00 02 cb 04 + 39 00 00 00 05 00 02 b0 0e + 39 00 00 00 05 00 02 cb 06 + 39 00 00 00 05 00 02 b0 0f + 39 00 00 00 05 00 02 cb 05 + 39 00 00 00 05 00 02 b0 02 + 39 00 00 00 05 00 02 f2 b8 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f2 80 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f4 8a + 39 00 00 00 05 00 02 b0 08 + 39 00 00 00 05 00 02 b1 10 + 39 00 00 00 05 00 02 b0 09 + 39 00 00 00 05 00 02 b1 0a + 39 00 00 00 05 00 02 b0 0d + 39 00 00 00 05 00 02 b1 80 + 39 00 00 00 05 00 02 b0 00 + 39 00 00 00 05 00 02 f7 03 + 39 00 00 00 05 00 02 fe 30 + 39 01 00 00 05 00 02 fe b0]; qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-lane-map = "lane_map_0123"; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi index 76f7c498d2cd..c7cecbca3929 100644 --- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.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 @@ -11,36 +11,36 @@ */ qcom,ascent_3450mah { - /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Nov28th2016 */ + /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Jan6th2017 */ qcom,max-voltage-uv = <4350000>; qcom,fg-cc-cv-threshold-mv = <4340>; qcom,fastchg-current-ma = <3450>; qcom,batt-id-kohm = <60>; qcom,battery-beta = <3435>; - qcom,battery-type = "ascent_3450mah_averaged_masterslave_nov28th2016"; - qcom,checksum = <0x2232>; - qcom,gui-version = "PMI8998GUI - 2.0.0.52"; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_jan6th2017"; + qcom,checksum = <0x96AC>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; qcom,fg-profile-data = [ 9C 1F 85 05 82 0A 73 FC - 2B 1D 6A EA - F2 03 63 0C - C8 17 F3 22 + 2B 1D 72 EA + EE 03 66 0C + C8 17 F4 22 E0 45 1F 52 5C 00 00 00 10 00 00 00 00 00 4A C4 C7 BC 48 C2 0F 00 08 00 - 92 00 5D ED - 8D FD B1 F3 - 27 00 A6 12 - 77 F4 0F 3B + E1 DA 5D ED + 8D FD B2 F3 + 96 E2 A7 12 + 7E F4 0E 3B 24 06 09 20 27 00 14 00 83 1F EE 05 1F 0A 45 FD - 6B 1D 52 E5 + 6B 1D 53 E5 EC 0B 31 14 44 18 49 23 18 45 A6 53 @@ -50,9 +50,9 @@ qcom,ascent_3450mah { B7 C3 0F BC 0F 00 00 00 92 00 5D ED - E3 06 81 F3 + E3 06 E0 00 75 FD 9C 03 - 43 DB B3 22 + 47 DB B3 22 CB 33 CC FF 07 10 00 00 99 0D 99 45 diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi index d196a8074d8a..03801ee90589 100644 --- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.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 @@ -11,37 +11,37 @@ */ qcom,itech_3000mah { - /* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jul20th2016*/ + /* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jan10th2017*/ qcom,max-voltage-uv = <4350000>; qcom,fg-cc-cv-threshold-mv = <4340>; qcom,fastchg-current-ma = <3000>; qcom,batt-id-kohm = <100>; - qcom,battery-beta = <3450>; - qcom,battery-type = "itech_b00826lf_3000mah_ver1660"; - qcom,checksum = <0xE06B>; - qcom,gui-version = "PMI8998GUI - 0.0.0.82"; + qcom,battery-beta = <3435>; + qcom,battery-type = "itech_b00826lf_3000mah_ver1660_jan10th2017"; + qcom,checksum = <0xFB8F>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; qcom,fg-profile-data = [ A4 1F 6E 05 - 9C 0A 16 06 - 32 1D 24 E5 - 61 0B 1B 15 + 9C 0A 2B FC + 32 1D 23 E5 + 60 0B 1B 15 AD 17 8C 22 - EB 3C 87 4A + EA 3C 89 4A 5B 00 00 00 12 00 00 00 00 00 62 C2 0C CD D8 C2 - 19 00 0C 00 - 7E 00 C7 EC - E3 05 5D FA - 97 F5 12 12 - C2 05 90 3B - 22 09 40 40 - 07 00 05 00 - 7D 1F DE 05 - 3F 0A 73 06 - 72 1D E2 F5 - 6F 12 BF 1D + 19 00 08 00 + 85 EA C7 EC + E2 05 2F 01 + 9B F5 12 12 + 5E 05 88 3B + 22 06 09 20 + 27 00 14 00 + 7D 1F DD 05 + 3F 0A E5 FC + 72 1D E3 F5 + 6F 12 C0 1D 88 18 FB 22 8D 45 C6 52 54 00 00 00 @@ -51,12 +51,12 @@ qcom,itech_3000mah { 14 00 00 00 7E 00 C7 EC 60 06 BB 00 - B3 FC 61 03 - 6A 06 78 1B - B3 33 08 33 + 59 06 61 03 + D9 FC 75 1B + B3 33 CC FF 07 10 00 00 3E 0B 99 45 - 14 00 19 00 + 14 00 40 00 AE 01 0A FA FF 00 00 00 00 00 00 00 diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi index e023a7700437..8cbb29aac927 100644 --- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.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 @@ -11,34 +11,36 @@ */ qcom,qrd_msm8998_skuk_3000mah { + /* QRD8997_ST1031GA_3000mAh_averaged_MasterSlave_Jan10th2017 */ qcom,max-voltage-uv = <4400000>; qcom,fastchg-current-ma = <3000>; qcom,batt-id-kohm = <68>; qcom,battery-beta = <3380>; - qcom,battery-type = "qrd_msm8998_skuk_300mah"; - qcom,checksum = <0x0F19>; + qcom,battery-type = "qrd8997_st1031ga_3000mah"; + qcom,checksum = <0xD299>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; qcom,fg-profile-data = [ - 6F 1F B2 05 - 6E 0A A3 FC - 8C 1D DB FD - C2 12 AE 1D - 7E 18 00 23 - 8D 45 B4 52 + 70 1F B1 05 + 6F 0A A1 FC + 8C 1D D7 FD + C4 12 AC 1D + 7E 18 01 23 + 8C 45 B6 52 55 00 00 00 0F 00 00 00 00 00 92 C5 95 CD A0 CA - 1F 00 0C 00 - 56 F2 C3 EC - 7B 06 27 F3 + 1F 00 08 00 + 9F E3 C3 EC + F7 FC 25 F3 02 01 FF 12 - 1C DA 21 3A - 1C 09 40 40 - 07 00 05 00 + 29 DC 1D 3A + 1C 06 09 20 + 27 00 14 00 AC 1F B4 05 57 0A EF FC - 6A 1D 2E 00 - 12 0B BA 14 + 6A 1D E9 E2 + 11 0B BB 14 40 19 DC 22 79 45 03 53 53 00 00 00 @@ -48,12 +50,12 @@ qcom,qrd_msm8998_skuk_3000mah { 1C 00 00 00 56 F2 C3 EC A6 06 A2 F2 - 96 06 C7 01 - 8B EA CF 1A - BA 33 08 33 + 9A 06 CC 01 + 8C EA CF 1A + BA 33 CC FF 07 10 00 00 3A 0C 66 46 - 1C 00 19 00 + 1C 00 40 00 98 01 0A FA FF 00 00 00 00 00 00 00 diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi index 0ba86e81887f..ecfff13f9355 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,9 +29,14 @@ <GIC_SPI 367 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 368 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 369 IRQ_TYPE_EDGE_RISING>; - clocks = <&clock_gcc clk_aggre1_noc_clk>; - clock-names = "smmu_aggre1_noc_clk"; - #clock-cells = <1>; + qcom,msm-bus,name = "smmu-bus-client-anoc1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + /* aggre1_noc_clk */ + qcom,msm-bus,vectors-KBps = + <84 10062 0 0>, + <84 10062 0 1000>; }; anoc2_smmu: arm,smmu-anoc2@16c0000 { @@ -52,9 +57,14 @@ <GIC_SPI 463 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 464 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 465 IRQ_TYPE_EDGE_RISING>; - clocks = <&clock_gcc clk_aggre2_noc_clk>; - clock-names = "smmu_aggre2_noc_clk"; - #clock-cells = <1>; + qcom,msm-bus,name = "smmu-bus-client-anoc2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + /* aggre2_noc_clk */ + qcom,msm-bus,vectors-KBps = + <117 10065 0 0>, + <117 10065 0 1000>; }; lpass_q6_smmu: arm,smmu-lpass_q6@5100000 { @@ -116,15 +126,20 @@ <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>; vdd-supply = <&gdsc_bimc_smmu>; clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, - <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, <&clock_mmss clk_mmss_bimc_smmu_axi_clk>; clock-names = "mmss_mnoc_ahb_clk", - "mmssnoc_axi_clk", "mmss_bimc_smmu_ahb_clk", "mmss_bimc_smmu_axi_clk"; #clock-cells = <1>; - qcom,bus-master-id = <MSM_BUS_MNOC_BIMC_MAS>; + qcom,msm-bus,name = "smmu-bus-client-mmss"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + /* ahb_clk_src, mmssnoc_axi_clk */ + qcom,msm-bus,vectors-KBps = + <102 722 0 0>, <29 512 0 0>, + <102 722 0 1000>, <29 512 0 1000>; }; kgsl_smmu: arm,smmu-kgsl@5040000 { diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi index e4903a821bc1..bc960093fcea 100644 --- a/arch/arm/boot/dts/qcom/msm-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi @@ -827,6 +827,7 @@ qcom,msm-mclk-freq = <9600000>; qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-micbias2-ext-cap; qcom,msm-hs-micbias-type = "external"; qcom,us-euro-gpios = <&us_euro_gpio>; qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>; @@ -928,7 +929,6 @@ }; clock_audio: audio_ext_clk { - status = "disabled"; compatible = "qcom,audio-ref-clk"; qcom,audio-ref-clk-gpio = <&pm660_gpios 3 0>; clock-names = "osr_clk"; diff --git a/arch/arm/boot/dts/qcom/msm-pm660a.dtsi b/arch/arm/boot/dts/qcom/msm-pm660a.dtsi index c43aa5425aae..bfe1b5aa831b 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660a.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660a.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 @@ -19,3 +19,11 @@ &pm660l_lcdb { status = "disabled"; }; + +&pm660a_oledb { + status = "okay"; +}; + +&pm660a_labibb { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index 3ac4c851f5ba..cdb3662a1a56 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -404,5 +404,60 @@ regulator-max-microvolt = <6000000>; }; }; + + pm660a_oledb: qpnp-oledb@e000 { + compatible = "qcom,qpnp-oledb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe000 0x100>; + + label = "oledb"; + regulator-name = "regulator-oledb"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <8100000>; + + qcom,swire-control; + qcom,ext-pin-control; + status = "disabled"; + }; + + pm660a_labibb: qpnp-labibb-regulator { + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; + qcom,swire-control; + status = "disabled"; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6300000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-init-voltage = <4000000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6100000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-init-voltage = <4600000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index b1880c076e1c..be47b6483288 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -534,7 +534,6 @@ qcom,qpnp-ibb-soft-start = <1000>; - qcom,qpnp-ibb-discharge-resistor = <32>; qcom,qpnp-ibb-lab-pwrup-delay = <8000>; qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; qcom,qpnp-ibb-en-discharge; diff --git a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi index 9a497a473a56..45ab53ccc2c2 100644 --- a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-gpu.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 @@ -98,6 +98,7 @@ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; qcom,msm-bus,num-cases = <13>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi index 9bab7c037d40..bfe29ff56413 100644 --- a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.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 @@ -31,6 +31,7 @@ #include "dsi-panel-sim-dualmipi-video.dtsi" #include "dsi-panel-sim-dualmipi-cmd.dtsi" #include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -196,3 +197,9 @@ qcom,mdss-dsi-t-clk-post = <0x07>; qcom,mdss-dsi-t-clk-pre = <0x2a>; }; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-panel-timings = [00 1c 06 06 0b 11 06 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x34>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi index c1d550a4bbff..a0e56f630eb7 100644 --- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-mtp.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 @@ -564,3 +564,7 @@ #include "fg-gen3-batterydata-demo-6000mah.dtsi" }; }; + +&pmi8998_fg { + qcom,battery-data = <&mtp_batterydata>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index ce3604f4dc3b..19b227f1b60f 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -3143,5 +3143,31 @@ }; }; }; + + sdc2_cd_on_mediabox: sdc2_cd_on_mediabox { + mux { + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_off_mediabox: sdc2_cd_off_mediabox { + mux { + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi index 150194a0e86f..af533bbfbc83 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd.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 @@ -510,13 +510,17 @@ }; /{ - mtp_batterydata: qcom,battery-data { + qrd_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-itech-3000mah.dtsi" #include "fg-gen3-batterydata-ascent-3450mah.dtsi" }; }; +&pmi8998_fg { + qcom,battery-data = <&qrd_batterydata>; +}; + &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dts index d48516381e29..180cc9128f53 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dts +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dts @@ -146,6 +146,50 @@ qcom,battery-data = <&qrd_batterydata>; }; +&mdss_dsi { + hw-config = "split_dsi"; + vdda-1p2-supply = <&pm660_l1>; + vdda-0p9-supply = <&pm660l_l1>; + + qcom,ctrl-supply-entries { + qcom,ctrl-supply-entry@0 { + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1250000>; + }; + }; + + qcom,phy-supply-entries { + qcom,phy-supply-entry@0 { + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <925000>; + }; + }; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + wqhd-vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + wqhd-vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + &pm660l_wled { qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dtsi index 5a882c7eb27f..c92872648709 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.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 @@ -123,3 +123,53 @@ synaptics,button-map = <139 172 158>; }; }; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_fb0 { + qcom,mdss-mixer-swap; +}; + +&mdss_dsi { + hw-config = "split_dsi"; + vdda-1p2-supply = <&pm660_l1>; + vdda-0p9-supply = <&pm660l_l1>; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + wqhd-vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + wqhd-vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&labibb { + status = "ok"; + qcom,qpnp-labibb-mode = "lcd"; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index cfdbf98af76e..30679791006b 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -1286,8 +1286,7 @@ compatible = "qcom,glink_ssr"; label = "modem"; qcom,edge = "mpss"; - qcom,notify-edges = <&glink_lpass>, <&glink_dsps>, <&glink_rpm>, - <&glink_spss>; + qcom,notify-edges = <&glink_lpass>, <&glink_dsps>, <&glink_rpm>; qcom,xprt = "smem"; }; @@ -1295,8 +1294,7 @@ compatible = "qcom,glink_ssr"; label = "adsp"; qcom,edge = "lpass"; - qcom,notify-edges = <&glink_mpss>, <&glink_dsps>, <&glink_rpm>, - <&glink_spss>; + qcom,notify-edges = <&glink_mpss>, <&glink_dsps>, <&glink_rpm>; qcom,xprt = "smem"; }; @@ -1304,8 +1302,7 @@ compatible = "qcom,glink_ssr"; label = "slpi"; qcom,edge = "dsps"; - qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, <&glink_rpm>, - <&glink_spss>; + qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, <&glink_rpm>; qcom,xprt = "smem"; }; @@ -1739,6 +1736,7 @@ "utmi_clk", "sleep_clk", "xo"; qcom,core-clk-rate = <120000000>; + qcom,core-clk-rate-hs = <60000000>; resets = <&clock_gcc USB_30_BCR>; reset-names = "core_reset"; @@ -2243,7 +2241,7 @@ }; sensor_information22: qcom,sensor-information-22 { qcom,sensor-type = "alarm"; - qcom,sensor-name = "pm8994_tz"; + qcom,sensor-name = "pm8998_tz"; qcom,scaling-factor = <1000>; }; sensor_information23: qcom,sensor-information-23 { diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi index c22926510f94..e2344063ce16 100644 --- a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi @@ -11,6 +11,7 @@ */ #include "sdm660-pinctrl.dtsi" +#include "sdm660-camera-sensor-cdp.dtsi" / { }; @@ -26,3 +27,52 @@ &pm660_charger { qcom,batteryless-platform; }; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <110 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi index b4b22d31402e..7a4e36ddda9e 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi @@ -11,6 +11,7 @@ */ #include "sdm660-pinctrl.dtsi" +#include "sdm660-camera-sensor-mtp.dtsi" / { mtp_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; @@ -35,3 +36,52 @@ &pm660_fg { qcom,battery-data = <&mtp_batterydata>; }; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <110 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-rumi.dts b/arch/arm/boot/dts/qcom/sdm630-rumi.dts index ddf954f9f6ff..2ea1af4da90c 100644 --- a/arch/arm/boot/dts/qcom/sdm630-rumi.dts +++ b/arch/arm/boot/dts/qcom/sdm630-rumi.dts @@ -86,3 +86,52 @@ compatible = "qcom,dummycc"; clock-output-names = "debug_clocks"; }; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <110 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 5002a11652ae..dbff3394ce76 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -26,6 +26,8 @@ aliases { serial0 = &uartblsp1dm1; + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 for SD card */ }; chosen { @@ -908,6 +910,13 @@ }; }; + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + }; + qcom,rmnet-ipa { compatible = "qcom,rmnet-ipa"; qcom,rmnet-ipa-ssr; @@ -1101,7 +1110,6 @@ compatible = "qcom,rpm-glink"; qcom,glink-edge = "rpm"; rpm-channel-name = "rpm_requests"; - rpm-standalone; }; qcom,ipc_router { @@ -1387,6 +1395,7 @@ #include "msm-gdsc-660.dtsi" #include "sdm660-common.dtsi" #include "msm-arm-smmu-630.dtsi" +#include "sdm660-camera.dtsi" &gdsc_usb30 { status = "ok"; diff --git a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi index 766642dced6a..6f9a6f9ee946 100644 --- a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi @@ -167,8 +167,8 @@ cdc_pdm_gpios: cdc_pdm_pinctrl { compatible = "qcom,msm-cdc-pinctrl"; pinctrl-names = "aud_active", "aud_sleep"; - pinctrl-0 = <&cdc_pdm_gpios_active>; - pinctrl-1 = <&cdc_pdm_gpios_sleep>; + pinctrl-0 = <&cdc_pdm_gpios_active &cdc_pdm_2_gpios_active>; + pinctrl-1 = <&cdc_pdm_gpios_sleep &cdc_pdm_2_gpios_sleep>; qcom,lpi-gpios; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-blsp.dtsi b/arch/arm/boot/dts/qcom/sdm660-blsp.dtsi index 023c34d65680..555d9a285102 100644 --- a/arch/arm/boot/dts/qcom/sdm660-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-blsp.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 @@ -518,9 +518,10 @@ clocks = <&clock_gcc GCC_BLSP2_UART1_APPS_CLK>, <&clock_gcc GCC_BLSP2_AHB_CLK>; pinctrl-names = "sleep", "default"; - pinctrl-0 = <&blsp2_uart1_sleep>; - pinctrl-1 = <&blsp2_uart1_active>; - + pinctrl-0 = <&blsp2_uart1_tx_sleep>, + <&blsp2_uart1_rxcts_sleep>, <&blsp2_uart1_rfr_sleep>; + pinctrl-1 = <&blsp2_uart1_tx_active>, + <&blsp2_uart1_rxcts_active>, <&blsp2_uart1_rfr_active>; qcom,msm-bus,name = "buart3"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; diff --git a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi index 93c615639be9..68ff96829d4f 100644 --- a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-bus.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 @@ -34,7 +34,6 @@ label = "fab-a2noc"; qcom,fab-dev; qcom,base-name = "a2noc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; qcom,qos-off = <4096>; qcom,base-offset = <16384>; @@ -44,16 +43,16 @@ qcom,node-qos-clks { clock-names = "clk-ipa-clk", - "clk-sdcc1-ahb-no-rate", - "clk-sdcc2-ahb-no-rate", - "clk-blsp1-ahb-no-rate", - "clk-blsp2-ahb-no-rate"; + "clk-ufs-axi-clk", + "clk-aggre2-ufs-axi-no-rate", + "clk-aggre2-usb3-axi-cfg-no-rate", + "clk-cfg-noc-usb2-axi-no-rate"; clocks = <&clock_rpmcc RPM_IPA_CLK>, - <&clock_gcc GCC_SDCC1_AHB_CLK>, - <&clock_gcc GCC_SDCC2_AHB_CLK>, - <&clock_gcc GCC_BLSP1_AHB_CLK>, - <&clock_gcc GCC_BLSP2_AHB_CLK>; + <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&clock_gcc GCC_CFG_NOC_USB2_AXI_CLK>; }; }; @@ -63,7 +62,6 @@ qcom,fab-dev; qcom,base-name = "bimc-base"; qcom,bus-type = <2>; - qcom,bypass-qos-prg; qcom,util-fact = <153>; clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpmcc BIMC_MSMBUS_CLK>, @@ -75,7 +73,6 @@ label = "fab-cnoc"; qcom,fab-dev; qcom,base-name = "cnoc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpmcc CNOC_MSMBUS_CLK>, @@ -87,7 +84,6 @@ label = "fab-gnoc"; qcom,virt-dev; qcom,base-name = "gnoc-base"; - qcom,bypass-qos-prg; }; fab_mnoc: fab-mnoc { @@ -95,7 +91,6 @@ label = "fab-mnoc"; qcom,fab-dev; qcom,base-name = "mnoc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; qcom,qos-off = <4096>; qcom,base-offset = <20480>; @@ -103,27 +98,13 @@ clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>, <&clock_rpmcc MMSSNOC_AXI_A_CLK>; - clk-camss-ahb-no-rate-supply = - <&gdsc_camss_top>; - clk-video-ahb-no-rate-supply = - <&gdsc_venus>; - clk-video-axi-no-rate-supply = - <&gdsc_venus>; qcom,node-qos-clks { clock-names = "clk-mmssnoc-axi-no-rate", - "clk-noc-cfg-ahb-no-rate", - "clk-mnoc-ahb-no-rate", - "clk-camss-ahb-no-rate", - "clk-video-ahb-no-rate", - "clk-video-axi-no-rate"; + "clk-mmss-noc-cfg-ahb-no-rate"; clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>, - <&clock_gcc GCC_MMSS_NOC_CFG_AHB_CLK>, - <&clock_mmss MMSS_MNOC_AHB_CLK>, - <&clock_mmss MMSS_CAMSS_AHB_CLK>, - <&clock_mmss MMSS_VIDEO_AHB_CLK>, - <&clock_mmss MMSS_VIDEO_AXI_CLK>; + <&clock_gcc GCC_MMSS_NOC_CFG_AHB_CLK>; }; }; @@ -132,7 +113,6 @@ label = "fab-snoc"; qcom,fab-dev; qcom,base-name = "snoc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; qcom,qos-off = <4096>; qcom,base-offset = <24576>; @@ -146,7 +126,6 @@ label = "fab-mnoc-ahb"; qcom,fab-dev; qcom,base-name = "mmnoc-ahb-base"; - qcom,bypass-qos-prg; qcom,setrate-only-clk; qcom,bus-type = <1>; clock-names = "bus_clk", "bus_a_clk"; @@ -483,18 +462,6 @@ qcom,bus-dev = <&fab_mnoc>; qcom,vrail-comp = <50>; qcom,mas-rpm-id = <ICBID_MASTER_MDP0>; - clk-mdss-axi-no-rate-supply = - <&gdsc_mdss>; - clk-mdss-ahb-no-rate-supply = - <&gdsc_mdss>; - qcom,node-qos-clks { - clock-names = - "clk-mdss-ahb-no-rate", - "clk-mdss-axi-no-rate"; - clocks = - <&clock_mmss MMSS_MDSS_AHB_CLK>, - <&clock_mmss MMSS_MDSS_AXI_CLK>; - }; }; mas_mdp_p1: mas-mdp-p1 { diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi index ae8da056d12b..f44d59e021d2 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi @@ -21,7 +21,7 @@ status = "ok"; }; - cam_avdd_gpio_regulator:fixed_regulator@1 { + cam_avdd_gpio_regulator:cam_avdd_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_vadd_gpio_regulator"; regulator-min-microvolt = <2800000>; @@ -31,17 +31,7 @@ vin-supply = <&pm660l_bob>; }; - cam_dvdd_gpio_regulator:fixed_regulator@1 { - compatible = "regulator-fixed"; - regulator-name = "cam_vadd_gpio_regulator"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - enable-active-high; - gpio = <&pm660l_gpios 4>; - vin-supply = <&pm660_s5>; - }; - - cam_vaf_gpio_regulator:fixed_regulator@2 { + cam_vaf_gpio_regulator:cam_vaf_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_vaf_gpio_regulator"; regulator-min-microvolt = <2800000>; @@ -182,11 +172,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1750000 0 0>; - qcom,cam-vreg-max-voltage = <1980000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -194,12 +184,15 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>; + <&tlmm 46 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0"; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET0", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -216,11 +209,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1750000 0 0>; - qcom,cam-vreg-max-voltage = <1980000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -228,15 +221,18 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>; + <&tlmm 48 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; + "CAM_RESET1", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + qcom,cci-master = <1>; status = "ok"; clocks = <&clock_mmss MCLK2_CLK_SRC>, <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; @@ -287,18 +283,18 @@ reg = <0x0>; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 0 0>; - qcom,cam-vreg-max-voltage = <1950000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -306,12 +302,15 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>; + <&tlmm 46 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET0"; + "CAM_RESET0", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -328,16 +327,16 @@ reg = <0x1>; qcom,csiphy-sd-index = <1>; qcom,csid-sd-index = <1>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,actuator-src = <&actuator1>; qcom,eeprom-src = <&eeprom1>; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 0 0>; - qcom,cam-vreg-max-voltage = <1950000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -345,15 +344,18 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>; + <&tlmm 48 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; + "CAM_RESET1", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + qcom,cci-master = <1>; status = "ok"; clocks = <&clock_mmss MCLK2_CLK_SRC>, <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi index 150c759496bf..de2a44640972 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi @@ -24,8 +24,9 @@ qcom,csiphy@c824000 { cell-index = <0>; compatible = "qcom,csiphy-v3.5", "qcom,csiphy"; - reg = <0xc824000 0x1000>; - reg-names = "csiphy"; + reg = <0xc824000 0x1000>, + <0xca00120 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; interrupts = <0 78 0>; interrupt-names = "csiphy"; gdscr-supply = <&gdsc_camss_top>; @@ -61,8 +62,9 @@ qcom,csiphy@c825000 { cell-index = <1>; compatible = "qcom,csiphy-v3.5", "qcom,csiphy"; - reg = <0xc825000 0x1000>; - reg-names = "csiphy"; + reg = <0xc825000 0x1000>, + <0xca00124 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; interrupts = <0 79 0>; interrupt-names = "csiphy"; gdscr-supply = <&gdsc_camss_top>; @@ -98,8 +100,9 @@ qcom,csiphy@c826000 { cell-index = <2>; compatible = "qcom,csiphy-v3.5", "qcom,csiphy"; - reg = <0xc826000 0x1000>; - reg-names = "csiphy"; + reg = <0xc826000 0x1000>, + <0xca00128 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; interrupts = <0 80 0>; interrupt-names = "csiphy"; gdscr-supply = <&gdsc_camss_top>; diff --git a/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi index 729e55ec9d6c..676e970a7e73 100644 --- a/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi @@ -109,6 +109,22 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_dual_nt35597_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 128 720 128 1440 128>; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm660l_l4>; diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi index f9915fbf3f58..a5e66f38df3c 100644 --- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi @@ -321,4 +321,98 @@ reg = <0xa8f8000 0x300>; qcom,reset-ep-after-lpm-resume; }; + + sdhc_1: sdhci@c0c4000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>; + reg-names = "hc_mem", "cmdq_mem"; + + interrupts = <0 110 0>, <0 112 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <26 81>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cmdq-latency-us = <26 81>, <26 81>; + qcom,pm-qos-legacy-latency-us = <26 81>, <26 81>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */ + <78 512 1046 3200>, /* 400 KB/s*/ + <78 512 52286 160000>, /* 20 MB/s */ + <78 512 65360 200000>, /* 25 MB/s */ + <78 512 130718 400000>, /* 50 MB/s */ + <78 512 130718 400000>, /* 100 MB/s */ + <78 512 261438 800000>, /* 200 MB/s */ + <78 512 261438 800000>, /* 400 MB/s */ + <78 512 1338562 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,ice-clk-rates = <300000000 150000000>; + + status = "disabled"; + }; + + sdhc_2: sdhci@c084000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0xc084000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 125 0>, <0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */ + <81 512 1046 3200>, /* 400 KB/s */ + <81 512 52286 160000>, /* 20 MB/s */ + <81 512 65360 200000>, /* 25 MB/s */ + <81 512 130718 400000>, /* 50 MB/s */ + <81 512 261438 800000>, /* 100 MB/s */ + <81 512 261438 800000>, /* 200 MB/s */ + <81 512 1338562 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <26 81>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-legacy-latency-us = <26 81>, <26 81>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index d347f033b12d..1e62a2423e38 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -32,21 +32,26 @@ * subsystem is inactive */ qcom,active-only; + /* + * IB votes in MBPS, derived using below formula + * IB = (DDR frequency * DDR bus width in Bytes * Dual rate) + * Note: IB vote is per DDR channel vote + */ qcom,bw-tbl = < 0 /* off */ >, - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5161 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; msm_gpu: qcom,kgsl-3d0@5000000 { @@ -85,26 +90,27 @@ /* Bus Scale Settings */ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; - qcom,bus-width = <16>; + /* GPU to BIMC bus width, VBIF data transfer in 1 cycle */ + qcom,bus-width = <32>; qcom,msm-bus,name = "grp3d"; qcom,msm-bus,num-cases = <14>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <26 512 0 0>, - <26 512 0 800000>, /* 1 bus=100 */ - <26 512 0 1200000>, /* 2 bus=150 */ - <26 512 0 1600000>, /* 3 bus=200 */ - <26 512 0 2400000>, /* 4 bus=300 */ - <26 512 0 3296000>, /* 5 bus=412 */ - <26 512 0 4376000>, /* 6 bus=547 */ - <26 512 0 5448000>, /* 7 bus=681 */ - <26 512 0 6144000>, /* 8 bus=768 */ - <26 512 0 8136000>, /* 9 bus=1017 */ - <26 512 0 10368000>, /* 10 bus=1296 */ - <26 512 0 10824000>, /* 11 bus=1353 */ - <26 512 0 12440000>, /* 12 bus=1555 */ - <26 512 0 14432000>; /* 13 bus=1804 */ + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 600000>, /* 2 bus=150 */ + <26 512 0 800000>, /* 3 bus=200 */ + <26 512 0 1200000>, /* 4 bus=300 */ + <26 512 0 1648000>, /* 5 bus=412 */ + <26 512 0 2188000>, /* 6 bus=547 */ + <26 512 0 2724000>, /* 7 bus=681 */ + <26 512 0 3072000>, /* 8 bus=768 */ + <26 512 0 4068000>, /* 9 bus=1017 */ + <26 512 0 5184000>, /* 10 bus=1296 */ + <26 512 0 5412000>, /* 11 bus=1353 */ + <26 512 0 6220000>, /* 12 bus=1555 */ + <26 512 0 7216000>; /* 13 bus=1804 */ /* GDSC regulator names */ regulator-names = "vddcx", "vdd"; @@ -161,8 +167,8 @@ qcom,gpu-pwrlevel@0 { reg = <0>; qcom,gpu-freq = <750000000>; - qcom,bus-freq = <12>; - qcom,bus-min = <11>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; qcom,bus-max = <13>; }; @@ -171,7 +177,7 @@ reg = <1>; qcom,gpu-freq = <700000000>; qcom,bus-freq = <11>; - qcom,bus-min = <10>; + qcom,bus-min = <11>; qcom,bus-max = <13>; }; @@ -179,7 +185,7 @@ qcom,gpu-pwrlevel@2 { reg = <2>; qcom,gpu-freq = <647000000>; - qcom,bus-freq = <10>; + qcom,bus-freq = <11>; qcom,bus-min = <10>; qcom,bus-max = <12>; }; @@ -188,9 +194,9 @@ qcom,gpu-pwrlevel@3 { reg = <3>; qcom,gpu-freq = <588000000>; - qcom,bus-freq = <9>; + qcom,bus-freq = <10>; qcom,bus-min = <9>; - qcom,bus-max = <11>; + qcom,bus-max = <12>; }; /* SVS_L1 */ @@ -198,7 +204,7 @@ reg = <4>; qcom,gpu-freq = <465000000>; qcom,bus-freq = <9>; - qcom,bus-min = <7>; + qcom,bus-min = <8>; qcom,bus-max = <11>; }; @@ -206,8 +212,8 @@ qcom,gpu-pwrlevel@5 { reg = <5>; qcom,gpu-freq = <370000000>; - qcom,bus-freq = <7>; - qcom,bus-min = <5>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; qcom,bus-max = <9>; }; @@ -225,7 +231,7 @@ reg = <7>; qcom,gpu-freq = <160000000>; qcom,bus-freq = <3>; - qcom,bus-min = <2>; + qcom,bus-min = <3>; qcom,bus-max = <5>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts index c5d4504fd97e..6755385313b1 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts @@ -24,9 +24,3 @@ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; - -&int_codec { - status = "okay"; - qcom,msm-hs-micbias-type = "internal"; - qcom,msm-micbias2-ext-cap; -}; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts index 9d5453240ef9..39da13e7565b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts @@ -27,5 +27,4 @@ &int_codec { qcom,model = "sdm660-snd-card-mtp"; - status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts index 6990c299d4e2..caf8af514237 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts @@ -24,9 +24,3 @@ qcom,board-id = <1 1>; qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; }; - -&int_codec { - status = "okay"; - qcom,msm-hs-micbias-type = "internal"; - qcom,msm-micbias2-ext-cap; -}; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-rcm.dts index 03b0e029a569..462362211f5b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-rcm.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-rcm.dts @@ -24,9 +24,3 @@ qcom,board-id = <21 1>; qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; }; - -&int_codec { - status = "okay"; - qcom,msm-hs-micbias-type = "internal"; - qcom,msm-micbias2-ext-cap; -}; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-rcm.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-rcm.dts index fc79dc9a36ee..8d95f8c422f9 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-rcm.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-rcm.dts @@ -24,9 +24,3 @@ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; - -&int_codec { - status = "okay"; - qcom,msm-hs-micbias-type = "internal"; - qcom,msm-micbias2-ext-cap; -}; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec.dtsi b/arch/arm/boot/dts/qcom/sdm660-internal-codec.dtsi index 512918966f6d..5f36e76c910d 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec.dtsi @@ -70,6 +70,10 @@ status = "disabled"; }; +&int_codec { + status = "okay"; +}; + &pmic_analog_codec { status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-lpi.dtsi b/arch/arm/boot/dts/qcom/sdm660-lpi.dtsi index 195128f3ad43..1fcf0993c4b3 100644 --- a/arch/arm/boot/dts/qcom/sdm660-lpi.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-lpi.dtsi @@ -157,51 +157,55 @@ cdc_dmic12_gpios_active: dmic12_gpios_active { mux { - pins = "gpio26", "gpio27"; + pins = "gpio26", "gpio28"; function = "func1"; }; config { - pins = "gpio26", "gpio27"; + pins = "gpio26", "gpio28"; drive-strength = <8>; + output-high; }; }; cdc_dmic12_gpios_sleep: dmic12_gpios_sleep { mux { - pins = "gpio26", "gpio27"; + pins = "gpio26", "gpio28"; function = "func1"; }; config { - pins = "gpio26", "gpio27"; + pins = "gpio26", "gpio28"; drive-strength = <2>; bias-disable; + output-low; }; }; cdc_dmic34_gpios_active: dmic34_gpios_active { mux { - pins = "gpio28", "gpio29"; + pins = "gpio27", "gpio29"; function = "func1"; }; config { - pins = "gpio28", "gpio29"; + pins = "gpio27", "gpio29"; drive-strength = <8>; + input-enable; }; }; cdc_dmic34_gpios_sleep: dmic34_gpios_sleep { mux { - pins = "gpio28", "gpio29"; + pins = "gpio27", "gpio29"; function = "func1"; }; config { - pins = "gpio28", "gpio29"; + pins = "gpio27", "gpio29"; drive-strength = <2>; - bias-disable; + pull-down; + input-enable; }; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index f4290d1aef0b..a25343981ace 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -18,6 +18,8 @@ #include "dsi-panel-sharp-dualmipi-wqxga-video.dtsi" #include "dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi" #include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -121,3 +123,19 @@ 20 12 05 06 03 13 04 a0]; qcom,config-select = <&dsi_nt35597_truly_dsc_cmd_config2>; }; + +&dsi_dual_nt35597_video { + 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 18 07 08 04 03 04 a0]; +}; + +&dsi_dual_nt35597_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 18 07 08 04 03 04 a0]; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi index ec14815a4be6..1e7f5ea6efc5 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss.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 @@ -245,6 +245,9 @@ mdss_fb0: qcom,mdss_fb_primary { cell-index = <0>; compatible = "qcom,mdss-fb"; + qcom,cont-splash-memory { + linux,contiguous-region = <&cont_splash_mem>; + }; }; mdss_fb1: qcom,mdss_fb_wfd { @@ -367,6 +370,7 @@ "byte_clk_rcg", "pixel_clk_rcg", "byte_intf_clk"; + qcom,null-insertion-enabled; qcom,platform-strength-ctrl = [ff 06 ff 06 ff 06 @@ -407,6 +411,7 @@ "byte_clk_rcg", "pixel_clk_rcg", "byte_intf_clk"; + qcom,null-insertion-enabled; qcom,platform-strength-ctrl = [ff 06 ff 06 ff 06 diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 0c933807cdd8..2c207873aa0b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -1190,29 +1190,83 @@ }; }; - blsp2_uart1_active: blsp2_uart1_active { - mux { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - function = "blsp_uart5"; + blsp2_uart1: blsp2_uart1 { + blsp2_uart1_tx_active: blsp2_uart1_tx_active { + mux { + pins = "gpio16"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - drive-strength = <2>; - bias-disable; + blsp2_uart1_tx_sleep: blsp2_uart1_tx_sleep { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; }; - }; - blsp2_uart1_sleep: blsp2_uart1_sleep { - mux { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - function = "gpio"; + blsp2_uart1_rxcts_active: blsp2_uart1_rxcts_active { + mux { + pins = "gpio17", "gpio18"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio16", "gpio17", "gpio18", "gpio19"; - drive-strength = <2>; - bias-disable; + blsp2_uart1_rxcts_sleep: blsp2_uart1_rxcts_sleep { + mux { + pins = "gpio17", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp2_uart1_rfr_active: blsp2_uart1_rfr_active { + mux { + pins = "gpio19"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_rfr_sleep: blsp2_uart1_rfr_sleep { + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-no-pull; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index c09ab4c50692..57e547085cf9 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -108,6 +108,18 @@ &soc { }; +&pm660_gpios { + /* GPIO 11 for home key */ + gpio@ca00 { + status = "ok"; + qcom,mode = <0>; + qcom,pull = <0>; + qcom,vin-sel = <0>; + qcom,src-sel = <0>; + qcom,out-strength = <1>; + }; +}; + &pm660l_gpios { /* GPIO 7 for VOL_UP */ gpio@c600 { @@ -166,6 +178,16 @@ gpio-key,wakeup; debounce-interval = <15>; }; + + home { + label = "home"; + gpios = <&pm660_gpios 11 0x1>; + linux,input-type = <1>; + linux,code = <102>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; hbtp { diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 42db8c60f681..cd87a20e9780 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -343,6 +343,11 @@ size = <0 0x2000000>; linux,cma-default; }; + + cont_splash_mem: splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x02400000>; + label = "cont_splash_mem"; + }; }; bluetooth: bt_wcn3990 { @@ -436,7 +441,6 @@ interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; - qcom,not-wakeup; /* Needed until Full-boot-chain enabled */ status = "ok"; }; @@ -1011,19 +1015,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; bwmon: qcom,cpu-bwmon { @@ -1042,19 +1046,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; memlat_cpu0: qcom,memlat-cpu0 { @@ -1063,19 +1067,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; memlat_cpu4: qcom,memlat-cpu4 { @@ -1084,19 +1088,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; devfreq_memlat_0: qcom,arm-memlat-mon-0 { @@ -1104,9 +1108,9 @@ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; qcom,target-dev = <&memlat_cpu0>; qcom,core-dev-table = - < 633600 1525 >, - < 1401600 4173 >, - < 1881600 7759 >; + < 633600 762 >, + < 1401600 2086 >, + < 1881600 3879 >; }; devfreq_memlat_4: qcom,arm-memlat-mon-4 { @@ -1114,25 +1118,25 @@ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; qcom,target-dev = <&memlat_cpu4>; qcom,core-dev-table = - < 1113600 1525 >, - < 1401600 7759 >, - < 2150400 11863 >, - < 2457600 13763 >; + < 1113600 762 >, + < 1401600 3879 >, + < 2150400 5931 >, + < 2457600 6881 >; }; devfreq_cpufreq: devfreq-cpufreq { mincpubw-cpufreq { target-dev = <&mincpubw>; cpu-to-dev-map-0 = - < 633600 1525 >, - < 1401600 3143 >, - < 1881600 5859 >; + < 633600 762 >, + < 1401600 1571 >, + < 1881600 2929 >; cpu-to-dev-map-4 = - < 1113600 1525 >, - < 1401600 4173 >, - < 1747200 5859 >, - < 2150400 7759 >, - < 2457600 13763 >; + < 1113600 762 >, + < 1401600 2086 >, + < 1747200 2929 >, + < 2150400 3879 >, + < 2457600 6881 >; }; }; @@ -1276,8 +1280,10 @@ 100000000 200000000 400000000 4294967295>; clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, - <&clock_gcc GCC_SDCC1_APPS_CLK>; - clock-names = "iface_clk", "core_clk"; + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + qcom,ice-clk-rates = <300000000 150000000>; status = "disabled"; }; @@ -1406,6 +1412,10 @@ qcom,mpu-enabled; }; + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; qcom,msm-adsprpc-mem { compatible = "qcom,msm-adsprpc-mem-region"; diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index fec429d7bd0c..2cfe647855c3 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -293,12 +293,13 @@ CONFIG_PINCTRL_SDM660=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y -CONFIG_QPNP_FG_GEN3=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y CONFIG_MSM_BCL_CTL=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y -CONFIG_QPNP_QNOVO=y CONFIG_APSS_CORE_EA=y CONFIG_MSM_APM=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y @@ -477,7 +478,6 @@ CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y -CONFIG_QCOM_TADC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index a2584f6831e2..b8df922b52fc 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -362,6 +362,7 @@ CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -372,6 +373,8 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_CAMERA=y CONFIG_MSM_CAMERA_DEBUG=y CONFIG_MSM_SDE_ROTATOR=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y @@ -582,8 +585,6 @@ CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PAGE_EXTENSION=y -CONFIG_LOCKUP_DETECTOR=y -CONFIG_WQ_WATCHDOG=y CONFIG_PANIC_TIMEOUT=5 # CONFIG_SCHED_DEBUG is not set CONFIG_PANIC_ON_SCHED_BUG=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index 7ba3f7b4362f..fd5340a45aa2 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -361,6 +361,7 @@ CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -374,6 +375,8 @@ CONFIG_MSM_VIDC_V4L2=m CONFIG_MSM_VIDC_GOVERNORS=m CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index df5ce357294c..27b445e30a49 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -360,6 +360,7 @@ CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -400,6 +401,8 @@ CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_ARMCLCD=y @@ -546,6 +549,7 @@ CONFIG_ICNSS=y CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index c959f1864256..9dac8be9d37d 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -8,7 +8,6 @@ CONFIG_RCU_EXPERT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 -CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y @@ -16,7 +15,6 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y CONFIG_SCHED_HMP_CSTATE_AWARE=y @@ -24,6 +22,7 @@ CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_XZ is not set @@ -362,6 +361,7 @@ CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -402,6 +402,8 @@ CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y @@ -467,6 +469,7 @@ CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 @@ -565,6 +568,7 @@ CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 9bcc0ad84917..cab1821db191 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -104,6 +104,7 @@ str x20, [sp, #S_ORIG_ADDR_LIMIT] mov x20, #TASK_SIZE_64 str x20, [tsk, #TI_ADDR_LIMIT] + ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO) .endif /* \el == 0 */ mrs x22, elr_el1 mrs x23, spsr_el1 @@ -139,6 +140,8 @@ /* Restore the task's original addr_limit. */ ldr x20, [sp, #S_ORIG_ADDR_LIMIT] str x20, [tsk, #TI_ADDR_LIMIT] + + /* No need to restore UAO, it will be restored from SPSR_EL1 */ .endif ldp x21, x22, [sp, #S_PC] // load ELR, SPSR diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 68cd3bb8eb89..eacaee18645b 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -291,7 +291,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, } if (permission_fault(esr) && (addr < USER_DS)) { - if (get_fs() == KERNEL_DS) + /* regs->orig_addr_limit may be 0 if we entered from EL0 */ + if (regs->orig_addr_limit == KERNEL_DS) die("Accessing user space memory with fs=KERNEL_DS", regs, esr); if (!search_exception_tables(regs->pc)) diff --git a/block/Kconfig b/block/Kconfig index 161491d0a879..39e956942b9d 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -33,7 +33,7 @@ config LBDAF This option is required to support the full capacity of large (2TB+) block devices, including RAID, disk, Network Block Device, Logical Volume Manager (LVM) and loopback. - + This option also enables support for single files larger than 2TB. @@ -111,6 +111,13 @@ config BLK_CMDLINE_PARSER See Documentation/block/cmdline-partition.txt for more information. +config BLOCK_PERF_FRAMEWORK + bool "Enable Block device performance measurement framework" + default n + ---help--- + Enabling this option allows you to measure the performance at the + block layer. + menu "Partition Types" source "block/partitions/Kconfig" diff --git a/block/bio.c b/block/bio.c index b9829b6504c8..02c4d9bf1590 100644 --- a/block/bio.c +++ b/block/bio.c @@ -31,6 +31,8 @@ #include <trace/events/block.h> +#include "blk.h" + /* * Test patch to inline a certain number of bi_io_vec's inside the bio * itself, to shrink a bio data allocation from two mempool calls to one @@ -1765,8 +1767,10 @@ void bio_endio(struct bio *bio) bio_put(bio); bio = parent; } else { - if (bio->bi_end_io) + if (bio->bi_end_io) { + blk_update_perf_stats(bio); bio->bi_end_io(bio); + } bio = NULL; } } diff --git a/block/blk-core.c b/block/blk-core.c index 450da06fa27e..4162327d8804 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -11,6 +11,12 @@ /* * This handles all read/write requests to block devices */ + +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +#define DRIVER_NAME "Block" +#define pr_fmt(fmt) DRIVER_NAME ": %s: " fmt, __func__ +#endif + #include <linux/kernel.h> #include <linux/module.h> #include <linux/backing-dev.h> @@ -34,6 +40,12 @@ #include <linux/pm_runtime.h> #include <linux/blk-cgroup.h> +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +#include <linux/ktime.h> +#include <linux/spinlock.h> +#include <linux/debugfs.h> +#endif + #define CREATE_TRACE_POINTS #include <trace/events/block.h> @@ -2111,6 +2123,456 @@ static inline struct task_struct *get_dirty_task(struct bio *bio) } #endif +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +#define BLK_PERF_SIZE (1024 * 15) +#define BLK_PERF_HIST_SIZE (sizeof(u32) * BLK_PERF_SIZE) + +struct blk_perf_stats { + u32 *read_hist; + u32 *write_hist; + u32 *flush_hist; + int buffers_alloced; + ktime_t max_read_time; + ktime_t max_write_time; + ktime_t max_flush_time; + ktime_t min_write_time; + ktime_t min_read_time; + ktime_t min_flush_time; + ktime_t total_write_time; + ktime_t total_read_time; + u64 total_read_size; + u64 total_write_size; + spinlock_t lock; + int is_enabled; +}; + +static struct blk_perf_stats blk_perf; +static struct dentry *blk_perf_debug_dir; + +static int alloc_histogram_buffers(void) +{ + int ret = 0; + + if (!blk_perf.read_hist) + blk_perf.read_hist = kzalloc(BLK_PERF_HIST_SIZE, GFP_KERNEL); + + if (!blk_perf.write_hist) + blk_perf.write_hist = kzalloc(BLK_PERF_HIST_SIZE, GFP_KERNEL); + + if (!blk_perf.flush_hist) + blk_perf.flush_hist = kzalloc(BLK_PERF_HIST_SIZE, GFP_KERNEL); + + if (!blk_perf.read_hist || !blk_perf.write_hist || !blk_perf.flush_hist) + ret = -ENOMEM; + + if (!ret) + blk_perf.buffers_alloced = 1; + return ret; +} + +static void clear_histogram_buffers(void) +{ + if (!blk_perf.buffers_alloced) + return; + memset(blk_perf.read_hist, 0, BLK_PERF_HIST_SIZE); + memset(blk_perf.write_hist, 0, BLK_PERF_HIST_SIZE); + memset(blk_perf.flush_hist, 0, BLK_PERF_HIST_SIZE); +} + +static int enable_perf(void *data, u64 val) +{ + int ret; + + if (!blk_perf.buffers_alloced) + ret = alloc_histogram_buffers(); + + if (ret) + return ret; + + spin_lock(&blk_perf.lock); + blk_perf.is_enabled = val; + spin_unlock(&blk_perf.lock); + return 0; +} + +static int is_perf_enabled(void *data, u64 *val) +{ + spin_lock(&blk_perf.lock); + *val = blk_perf.is_enabled; + spin_unlock(&blk_perf.lock); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(enable_perf_fops, is_perf_enabled, enable_perf, + "%llu\n"); + +static char *blk_debug_buffer; +static u32 blk_debug_data_size; +static DEFINE_MUTEX(blk_perf_debug_buffer_mutex); + +static ssize_t blk_perf_read(struct file *file, char __user *buf, + size_t count, loff_t *file_pos) +{ + ssize_t ret = 0; + + mutex_lock(&blk_perf_debug_buffer_mutex); + ret = simple_read_from_buffer(buf, count, file_pos, blk_debug_buffer, + blk_debug_data_size); + mutex_unlock(&blk_perf_debug_buffer_mutex); + + return ret; +} + +static int blk_debug_buffer_alloc(u32 buffer_size) +{ + int ret = 0; + + mutex_lock(&blk_perf_debug_buffer_mutex); + if (blk_debug_buffer != NULL) { + pr_err("blk_debug_buffer is in use\n"); + ret = -EBUSY; + goto end; + } + blk_debug_buffer = kzalloc(buffer_size, GFP_KERNEL); + if (!blk_debug_buffer) + ret = -ENOMEM; +end: + mutex_unlock(&blk_perf_debug_buffer_mutex); + return ret; +} + +static int blk_perf_close(struct inode *inode, struct file *file) +{ + mutex_lock(&blk_perf_debug_buffer_mutex); + blk_debug_data_size = 0; + kfree(blk_debug_buffer); + blk_debug_buffer = NULL; + mutex_unlock(&blk_perf_debug_buffer_mutex); + return 0; +} + +static u32 fill_basic_perf_info(char *buffer, u32 buffer_size) +{ + u32 size = 0; + + size += scnprintf(buffer + size, buffer_size - size, "\n"); + + spin_lock(&blk_perf.lock); + size += scnprintf(buffer + size, buffer_size - size, + "max_read_time_ms: %llu\n", + ktime_to_ms(blk_perf.max_read_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "min_read_time_ms: %llu\n", + ktime_to_ms(blk_perf.min_read_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_read_time_ms: %llu\n", + ktime_to_ms(blk_perf.total_read_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_read_size: %llu\n\n", + blk_perf.total_read_size); + + size += scnprintf(buffer + size, buffer_size - size, + "max_write_time_ms: %llu\n", + ktime_to_ms(blk_perf.max_write_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "min_write_time_ms: %llu\n", + ktime_to_ms(blk_perf.min_write_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_write_time_ms: %llu\n", + ktime_to_ms(blk_perf.total_write_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_write_size: %llu\n\n", + blk_perf.total_write_size); + + size += scnprintf(buffer + size, buffer_size - size, + "max_flush_time_ms: %llu\n", + ktime_to_ms(blk_perf.max_flush_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "min_flush_time_ms: %llu\n\n", + ktime_to_ms(blk_perf.min_flush_time)); + + spin_unlock(&blk_perf.lock); + + return size; +} + +static int basic_perf_open(struct inode *inode, struct file *file) +{ + u32 buffer_size; + int ret; + + buffer_size = BLK_PERF_HIST_SIZE; + ret = blk_debug_buffer_alloc(buffer_size); + if (ret) + return ret; + + mutex_lock(&blk_perf_debug_buffer_mutex); + blk_debug_data_size = fill_basic_perf_info(blk_debug_buffer, + buffer_size); + mutex_unlock(&blk_perf_debug_buffer_mutex); + return 0; +} + + +static const struct file_operations basic_perf_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = basic_perf_open, +}; + +static int hist_open_helper(void *hist_buf) +{ + int ret; + + if (!blk_perf.buffers_alloced) + return -EINVAL; + + ret = blk_debug_buffer_alloc(BLK_PERF_HIST_SIZE); + if (ret) + return ret; + + spin_lock(&blk_perf.lock); + memcpy(blk_debug_buffer, hist_buf, BLK_PERF_HIST_SIZE); + spin_unlock(&blk_perf.lock); + + mutex_lock(&blk_perf_debug_buffer_mutex); + blk_debug_data_size = BLK_PERF_HIST_SIZE; + mutex_unlock(&blk_perf_debug_buffer_mutex); + return 0; +} + +static int write_hist_open(struct inode *inode, struct file *file) +{ + return hist_open_helper(blk_perf.write_hist); +} + +static const struct file_operations write_hist_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = write_hist_open, +}; + + +static int read_hist_open(struct inode *inode, struct file *file) +{ + return hist_open_helper(blk_perf.read_hist); +} + +static const struct file_operations read_hist_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = read_hist_open, +}; + +static int flush_hist_open(struct inode *inode, struct file *file) +{ + return hist_open_helper(blk_perf.flush_hist); +} + +static const struct file_operations flush_hist_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = flush_hist_open, +}; + +static void clear_perf_stats_helper(void) +{ + spin_lock(&blk_perf.lock); + blk_perf.max_write_time = ktime_set(0, 0); + blk_perf.max_read_time = ktime_set(0, 0); + blk_perf.max_flush_time = ktime_set(0, 0); + blk_perf.min_write_time = ktime_set(KTIME_MAX, 0); + blk_perf.min_read_time = ktime_set(KTIME_MAX, 0); + blk_perf.min_flush_time = ktime_set(KTIME_MAX, 0); + blk_perf.total_write_time = ktime_set(0, 0); + blk_perf.total_read_time = ktime_set(0, 0); + blk_perf.total_read_size = 0; + blk_perf.total_write_size = 0; + blk_perf.is_enabled = 0; + clear_histogram_buffers(); + spin_unlock(&blk_perf.lock); +} + +static int clear_perf_stats(void *data, u64 val) +{ + clear_perf_stats_helper(); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clear_perf_stats_fops, NULL, clear_perf_stats, + "%llu\n"); + +static void blk_debugfs_init(void) +{ + struct dentry *f_ent; + + blk_perf_debug_dir = debugfs_create_dir("block_perf", NULL); + if (IS_ERR(blk_perf_debug_dir)) { + pr_err("Failed to create block_perf debug_fs directory\n"); + return; + } + + f_ent = debugfs_create_file("basic_perf", 0400, blk_perf_debug_dir, + NULL, &basic_perf_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs basic_perf file\n"); + return; + } + + f_ent = debugfs_create_file("write_hist", 0400, blk_perf_debug_dir, + NULL, &write_hist_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs write_hist file\n"); + return; + } + + f_ent = debugfs_create_file("read_hist", 0400, blk_perf_debug_dir, + NULL, &read_hist_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs read_hist file\n"); + return; + } + + f_ent = debugfs_create_file("flush_hist", 0400, blk_perf_debug_dir, + NULL, &flush_hist_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs flush_hist file\n"); + return; + } + + f_ent = debugfs_create_file("enable_perf", 0600, blk_perf_debug_dir, + NULL, &enable_perf_fops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs enable_perf file\n"); + return; + } + + f_ent = debugfs_create_file("clear_perf_stats", 0200, + blk_perf_debug_dir, NULL, + &clear_perf_stats_fops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs clear_perf_stats file\n"); + return; + } +} + +static void blk_init_perf(void) +{ + blk_debugfs_init(); + spin_lock_init(&blk_perf.lock); + + clear_perf_stats_helper(); +} + + +static void set_submit_info(struct bio *bio, unsigned int count) +{ + ktime_t submit_time; + + if (unlikely(blk_perf.is_enabled)) { + submit_time = ktime_get(); + bio->submit_time.tv64 = submit_time.tv64; + bio->blk_sector_count = count; + return; + } + + bio->submit_time.tv64 = 0; + bio->blk_sector_count = 0; +} + +void blk_update_perf_read_write_stats(ktime_t bio_process_time, int is_write, + int count) +{ + u32 bio_process_time_ms; + + bio_process_time_ms = ktime_to_ms(bio_process_time); + if (bio_process_time_ms >= BLK_PERF_SIZE) + bio_process_time_ms = BLK_PERF_SIZE - 1; + + if (is_write) { + if (ktime_after(bio_process_time, blk_perf.max_write_time)) + blk_perf.max_write_time = bio_process_time; + + if (ktime_before(bio_process_time, blk_perf.min_write_time)) + blk_perf.min_write_time = bio_process_time; + blk_perf.total_write_time = + ktime_add(blk_perf.total_write_time, bio_process_time); + blk_perf.total_write_size += count; + blk_perf.write_hist[bio_process_time_ms] += count; + + } else { + if (ktime_after(bio_process_time, blk_perf.max_read_time)) + blk_perf.max_read_time = bio_process_time; + + if (ktime_before(bio_process_time, blk_perf.min_read_time)) + blk_perf.min_read_time = bio_process_time; + blk_perf.total_read_time = + ktime_add(blk_perf.total_read_time, bio_process_time); + blk_perf.total_read_size += count; + blk_perf.read_hist[bio_process_time_ms] += count; + } +} +void blk_update_perf_stats(struct bio *bio) +{ + ktime_t bio_process_time; + u32 bio_process_time_ms; + u32 count; + + spin_lock(&blk_perf.lock); + if (likely(!blk_perf.is_enabled)) + goto end; + if (!bio->submit_time.tv64) + goto end; + bio_process_time = ktime_sub(ktime_get(), bio->submit_time); + + count = bio->blk_sector_count; + + if (count) { + int is_write = 0; + + if (bio->bi_rw & WRITE || + unlikely(bio->bi_rw & REQ_WRITE_SAME)) + is_write = 1; + + blk_update_perf_read_write_stats(bio_process_time, is_write, + count); + } else { + + bio_process_time_ms = ktime_to_ms(bio_process_time); + if (bio_process_time_ms >= BLK_PERF_SIZE) + bio_process_time_ms = BLK_PERF_SIZE - 1; + + if (ktime_after(bio_process_time, blk_perf.max_flush_time)) + blk_perf.max_flush_time = bio_process_time; + + if (ktime_before(bio_process_time, blk_perf.min_flush_time)) + blk_perf.min_flush_time = bio_process_time; + + blk_perf.flush_hist[bio_process_time_ms] += 1; + } +end: + spin_unlock(&blk_perf.lock); + +} +#else +static inline void set_submit_info(struct bio *bio, unsigned int count) +{ + (void) bio; + (void) count; +} + +static inline void blk_init_perf(void) +{ +} +#endif /* #ifdef CONFIG_BLOCK_PERF_FRAMEWORK */ + /** * submit_bio - submit a bio to the block device layer for I/O * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) @@ -2123,6 +2585,7 @@ static inline struct task_struct *get_dirty_task(struct bio *bio) */ blk_qc_t submit_bio(int rw, struct bio *bio) { + unsigned int count = 0; bio->bi_rw |= rw; /* @@ -2130,8 +2593,6 @@ blk_qc_t submit_bio(int rw, struct bio *bio) * go through the normal accounting stuff before submission. */ if (bio_has_data(bio)) { - unsigned int count; - if (unlikely(rw & REQ_WRITE_SAME)) count = bdev_logical_block_size(bio->bi_bdev) >> 9; else @@ -2158,6 +2619,7 @@ blk_qc_t submit_bio(int rw, struct bio *bio) } } + set_submit_info(bio, count); return generic_make_request(bio); } EXPORT_SYMBOL(submit_bio); @@ -3578,7 +4040,7 @@ int __init blk_dev_init(void) blk_requestq_cachep = kmem_cache_create("blkdev_queue", sizeof(struct request_queue), 0, SLAB_PANIC, NULL); - + blk_init_perf(); return 0; } diff --git a/block/blk.h b/block/blk.h index ce2287639ab3..6ceebbd61afd 100644 --- a/block/blk.h +++ b/block/blk.h @@ -112,6 +112,15 @@ void blk_account_io_start(struct request *req, bool new_io); void blk_account_io_completion(struct request *req, unsigned int bytes); void blk_account_io_done(struct request *req); +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +void blk_update_perf_stats(struct bio *bio); +#else +static inline void blk_update_perf_stats(struct bio *bio) +{ + (void) bio; +} +#endif + /* * Internal atomic flags for request handling */ diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 8e3bff9c7fe9..ebbe31fee7ae 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -607,7 +607,7 @@ source "drivers/char/xillybus/Kconfig" config MSM_ADSPRPC tristate "QTI ADSP RPC driver" - depends on MSM_SMD + depends on MSM_GLINK help Provides a communication mechanism that allows for clients to make remote method invocations across processor boundary to diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 03429b18825b..95dca75efde9 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -25,7 +25,6 @@ #include <linux/hash.h> #include <linux/msm_ion.h> #include <soc/qcom/secure_buffer.h> -#include <soc/qcom/smd.h> #include <soc/qcom/glink.h> #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/subsystem_restart.h> @@ -48,6 +47,7 @@ #include "adsprpc_compat.h" #include "adsprpc_shared.h" #include <soc/qcom/ramdump.h> +#include <linux/debugfs.h> #define TZ_PIL_PROTECT_MEM_SUBSYS_ID 0x0C #define TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID 0x0D @@ -55,6 +55,7 @@ #define ADSP_MMAP_HEAP_ADDR 4 #define FASTRPC_ENOSUCH 39 #define VMID_SSC_Q6 5 +#define DEBUGFS_SIZE 1024 #define RPC_TIMEOUT (5 * HZ) #define BALIGN 128 @@ -90,6 +91,8 @@ static int fastrpc_glink_open(int cid); static void fastrpc_glink_close(void *chan, int cid); +static struct dentry *debugfs_root; +static struct dentry *debugfs_global_file; static inline uint64_t buf_page_start(uint64_t buf) { @@ -207,7 +210,6 @@ struct fastrpc_channel_ctx { struct completion work; struct notifier_block nb; struct kref kref; - int channel; int sesscount; int ssrcount; void *handle; @@ -231,7 +233,6 @@ struct fastrpc_apps { spinlock_t hlock; struct ion_client *client; struct device *dev; - bool glink; }; struct fastrpc_mmap { @@ -283,6 +284,7 @@ struct fastrpc_file { int pd; struct fastrpc_apps *apps; struct fastrpc_perf perf; + struct dentry *debugfs_file; }; static struct fastrpc_apps gfa; @@ -291,21 +293,18 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { { .name = "adsprpc-smd", .subsys = "adsp", - .channel = SMD_APPS_QDSP, .link.link_info.edge = "lpass", .link.link_info.transport = "smem", }, { .name = "mdsprpc-smd", .subsys = "modem", - .channel = SMD_APPS_MODEM, .link.link_info.edge = "mpss", .link.link_info.transport = "smem", }, { .name = "sdsprpc-smd", .subsys = "slpi", - .channel = SMD_APPS_DSPS, .link.link_info.edge = "dsps", .link.link_info.transport = "smem", .vmid = VMID_SSC_Q6, @@ -1348,7 +1347,7 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, struct smq_msg *msg = &ctx->msg; struct fastrpc_file *fl = ctx->fl; struct fastrpc_channel_ctx *channel_ctx = &fl->apps->channel[fl->cid]; - int err = 0, len; + int err = 0; VERIFY(err, 0 != channel_ctx->chan); if (err) @@ -1363,64 +1362,21 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, msg->invoke.page.addr = ctx->buf ? ctx->buf->phys : 0; msg->invoke.page.size = buf_page_size(ctx->used); - if (fl->apps->glink) { - if (fl->ssrcount != channel_ctx->ssrcount) { - err = -ECONNRESET; - goto bail; - } - VERIFY(err, channel_ctx->link.port_state == - FASTRPC_LINK_CONNECTED); - if (err) - goto bail; - err = glink_tx(channel_ctx->chan, - (void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg), - GLINK_TX_REQ_INTENT); - } else { - spin_lock(&fl->apps->hlock); - len = smd_write((smd_channel_t *) - channel_ctx->chan, - msg, sizeof(*msg)); - spin_unlock(&fl->apps->hlock); - VERIFY(err, len == sizeof(*msg)); + if (fl->ssrcount != channel_ctx->ssrcount) { + err = -ECONNRESET; + goto bail; } + VERIFY(err, channel_ctx->link.port_state == + FASTRPC_LINK_CONNECTED); + if (err) + goto bail; + err = glink_tx(channel_ctx->chan, + (void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg), + GLINK_TX_REQ_INTENT); bail: return err; } -static void fastrpc_smd_read_handler(int cid) -{ - struct fastrpc_apps *me = &gfa; - struct smq_invoke_rsp rsp = {0}; - int ret = 0; - - do { - ret = smd_read_from_cb(me->channel[cid].chan, &rsp, - sizeof(rsp)); - if (ret != sizeof(rsp)) - break; - rsp.ctx = rsp.ctx & ~1; - context_notify_user(uint64_to_ptr(rsp.ctx), rsp.retval); - } while (ret == sizeof(rsp)); -} - -static void smd_event_handler(void *priv, unsigned event) -{ - struct fastrpc_apps *me = &gfa; - int cid = (int)(uintptr_t)priv; - - switch (event) { - case SMD_EVENT_OPEN: - complete(&me->channel[cid].work); - break; - case SMD_EVENT_CLOSE: - fastrpc_notify_drivers(me, cid); - break; - case SMD_EVENT_DATA: - fastrpc_smd_read_handler(cid); - break; - } -} - static void fastrpc_init(struct fastrpc_apps *me) { int i; @@ -1883,11 +1839,7 @@ static void fastrpc_channel_close(struct kref *kref) ctx = container_of(kref, struct fastrpc_channel_ctx, kref); cid = ctx - &gcinfo[0]; - if (!me->glink) { - smd_close(ctx->chan); - } else { - fastrpc_glink_close(ctx->chan, cid); - } + fastrpc_glink_close(ctx->chan, cid); ctx->chan = 0; mutex_unlock(&me->smd_mutex); pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name, @@ -2042,6 +1994,8 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; if (fl) { + if (fl->debugfs_file != NULL) + debugfs_remove(fl->debugfs_file); fastrpc_file_free(fl); file->private_data = 0; } @@ -2158,9 +2112,124 @@ bail: return err; } +static int fastrpc_debugfs_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, + size_t count, loff_t *position) +{ + struct fastrpc_file *fl = filp->private_data; + struct hlist_node *n; + struct fastrpc_buf *buf = 0; + struct fastrpc_mmap *map = 0; + struct smq_invoke_ctx *ictx = 0; + struct fastrpc_channel_ctx *chan; + struct fastrpc_session_ctx *sess; + unsigned int len = 0; + int i, j, ret = 0; + char *fileinfo = NULL; + + fileinfo = kzalloc(DEBUGFS_SIZE, GFP_KERNEL); + if (!fileinfo) + goto bail; + if (fl == NULL) { + for (i = 0; i < NUM_CHANNELS; i++) { + chan = &gcinfo[i]; + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, "%s\n\n", + chan->name); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, "%s %d\n", + "sesscount:", chan->sesscount); + for (j = 0; j < chan->sesscount; j++) { + sess = &chan->session[j]; + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, + "%s%d\n\n", "SESSION", j); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, + "%s %d\n", "sid:", + sess->smmu.cb); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, + "%s %d\n", "SECURE:", + sess->smmu.secure); + } + } + } else { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "PROCESS_ID:", fl->tgid); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "CHANNEL_ID:", fl->cid); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "SSRCOUNT:", fl->ssrcount); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s\n", + "LIST OF BUFS:"); + spin_lock(&fl->hlock); + hlist_for_each_entry_safe(buf, n, &fl->bufs, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %p %s %llx\n", "buf:", + buf, "buf->virt:", buf->virt, + "buf->phys:", buf->phys); + } + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "\n%s\n", + "LIST OF MAPS:"); + hlist_for_each_entry_safe(map, n, &fl->maps, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %lx %s %llx\n", + "map:", map, + "map->va:", map->va, + "map->phys:", map->phys); + } + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "\n%s\n", + "LIST OF PENDING SMQCONTEXTS:"); + hlist_for_each_entry_safe(ictx, n, &fl->clst.pending, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %u %s %u %s %u\n", + "smqcontext:", ictx, + "sc:", ictx->sc, + "tid:", ictx->pid, + "handle", ictx->rpra->h); + } + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "\n%s\n", + "LIST OF INTERRUPTED SMQCONTEXTS:"); + hlist_for_each_entry_safe(ictx, n, &fl->clst.interrupted, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %u %s %u %s %u\n", + "smqcontext:", ictx, + "sc:", ictx->sc, + "tid:", ictx->pid, + "handle", ictx->rpra->h); + } + spin_unlock(&fl->hlock); + } + if (len > DEBUGFS_SIZE) + len = DEBUGFS_SIZE; + ret = simple_read_from_buffer(buffer, count, position, fileinfo, len); + kfree(fileinfo); +bail: + return ret; +} + +static const struct file_operations debugfs_fops = { + .open = fastrpc_debugfs_open, + .read = fastrpc_debugfs_read, +}; + static int fastrpc_device_open(struct inode *inode, struct file *filp) { int cid = MINOR(inode->i_rdev); + struct dentry *debugfs_file; int err = 0; struct fastrpc_apps *me = &gfa; struct fastrpc_file *fl = 0; @@ -2173,6 +2242,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) mutex_lock(&me->smd_mutex); + debugfs_file = debugfs_create_file(current->comm, 0644, debugfs_root, + fl, &debugfs_fops); context_list_ctor(&fl->clst); spin_lock_init(&fl->hlock); INIT_HLIST_HEAD(&fl->maps); @@ -2181,6 +2252,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->tgid = current->tgid; fl->apps = me; fl->cid = cid; + if (debugfs_file != NULL) + fl->debugfs_file = debugfs_file; memset(&fl->perf, 0, sizeof(fl->perf)); VERIFY(err, !fastrpc_session_alloc_locked(&me->channel[cid], 0, @@ -2191,16 +2264,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->ssrcount = me->channel[cid].ssrcount; if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || (me->channel[cid].chan == 0)) { - if (me->glink) { - fastrpc_glink_register(cid, me); - VERIFY(err, 0 == fastrpc_glink_open(cid)); - } else { - VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID, - gcinfo[cid].channel, - (smd_channel_t **)&me->channel[cid].chan, - (void *)(uintptr_t)cid, - smd_event_handler)); - } + fastrpc_glink_register(cid, me); + VERIFY(err, 0 == fastrpc_glink_open(cid)); if (err) goto bail; @@ -2387,11 +2452,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, mutex_lock(&me->smd_mutex); ctx->ssrcount++; if (ctx->chan) { - if (me->glink) { - fastrpc_glink_close(ctx->chan, cid); - } else { - smd_close(ctx->chan); - } + fastrpc_glink_close(ctx->chan, cid); ctx->chan = 0; pr_info("'restart notifier: closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); @@ -2496,6 +2557,8 @@ static int fastrpc_cb_probe(struct device *dev) sess->dev = dev; sess->smmu.enabled = 1; chan->sesscount++; + debugfs_global_file = debugfs_create_file("global", 0644, debugfs_root, + NULL, &debugfs_fops); bail: return err; } @@ -2610,8 +2673,6 @@ static int fastrpc_probe(struct platform_device *pdev) return 0; } - me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink"); - VERIFY(err, !of_platform_populate(pdev->dev.of_node, fastrpc_match_table, NULL, &pdev->dev)); @@ -2706,6 +2767,7 @@ static int __init fastrpc_device_init(void) VERIFY(err, !IS_ERR_OR_NULL(me->client)); if (err) goto device_create_bail; + debugfs_root = debugfs_create_dir("adsprpc", NULL); return 0; device_create_bail: for (i = 0; i < NUM_CHANNELS; i++) { @@ -2744,6 +2806,7 @@ static void __exit fastrpc_device_exit(void) cdev_del(&me->cdev); unregister_chrdev_region(me->dev_no, NUM_CHANNELS); ion_client_destroy(me->client); + debugfs_remove_recursive(debugfs_root); } late_initcall(fastrpc_device_init); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 409d2724042c..9d235b7abc58 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/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 @@ -514,7 +514,7 @@ struct diagchar_dev { struct list_head cmd_reg_list; struct mutex cmd_reg_mutex; uint32_t cmd_reg_count; - struct mutex diagfwd_channel_mutex; + struct mutex diagfwd_channel_mutex[NUM_PERIPHERALS]; /* Sizes that reflect memory pool sizes */ unsigned int poolsize; unsigned int poolsize_hdlc; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index f8b08527d633..facdb0f40e44 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -3371,7 +3371,7 @@ static int diagchar_cleanup(void) static int __init diagchar_init(void) { dev_t dev; - int error, ret; + int error, ret, i; pr_debug("diagfwd initializing ..\n"); ret = 0; @@ -3418,7 +3418,8 @@ static int __init diagchar_init(void) mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); mutex_init(&apps_data_mutex); - mutex_init(&driver->diagfwd_channel_mutex); + for (i = 0; i < NUM_PERIPHERALS; i++) + mutex_init(&driver->diagfwd_channel_mutex[i]); init_waitqueue_head(&driver->wait_q); INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn); INIT_WORK(&(driver->update_user_clients), diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index c1f954cdb080..3f9f7a999fdf 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.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 @@ -655,7 +655,7 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) return; } - mutex_lock(&driver->diagfwd_channel_mutex); + mutex_lock(&driver->diagfwd_channel_mutex[peripheral]); fwd_info = &early_init_info[transport][peripheral]; if (fwd_info->p_ops && fwd_info->p_ops->close) fwd_info->p_ops->close(fwd_info->ctxt); @@ -679,7 +679,7 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) diagfwd_late_open(dest_info); diagfwd_cntl_open(dest_info); init_fn(peripheral); - mutex_unlock(&driver->diagfwd_channel_mutex); + mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]); diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]); diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]); } diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index 888949816dfe..22a60cdff7e7 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -1088,9 +1088,9 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) (info->data_ready > 0) || (!info->hdl) || (atomic_read(&info->diag_state) == 0)); if (err) { - mutex_lock(&driver->diagfwd_channel_mutex); + mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]); diagfwd_channel_read_done(info->fwd_ctxt, buf, 0); - mutex_unlock(&driver->diagfwd_channel_mutex); + mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]); return -ERESTARTSYS; } @@ -1102,9 +1102,9 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s closing read thread. diag state is closed\n", info->name); - mutex_lock(&driver->diagfwd_channel_mutex); + mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]); diagfwd_channel_read_done(info->fwd_ctxt, buf, 0); - mutex_unlock(&driver->diagfwd_channel_mutex); + mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]); return 0; } @@ -1171,10 +1171,10 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) if (total_recd > 0) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s read total bytes: %d\n", info->name, total_recd); - mutex_lock(&driver->diagfwd_channel_mutex); + mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]); err = diagfwd_channel_read_done(info->fwd_ctxt, buf, total_recd); - mutex_unlock(&driver->diagfwd_channel_mutex); + mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]); if (err) goto fail; } else { @@ -1187,9 +1187,9 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) return 0; fail: - mutex_lock(&driver->diagfwd_channel_mutex); + mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]); diagfwd_channel_read_done(info->fwd_ctxt, buf, 0); - mutex_unlock(&driver->diagfwd_channel_mutex); + mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]); return -EIO; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 6493b59dac01..4f1ba98a2b2c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org> - * 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 as @@ -2534,7 +2534,46 @@ do { \ pr_info(fmt, ##__VA_ARGS__); \ } while (0) -int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) +/* + * clock_debug_print_enabled_debug_suspend() - Print names of enabled clocks + * during suspend. + */ +static void clock_debug_print_enabled_debug_suspend(struct seq_file *s) +{ + struct clk_core *core; + int cnt = 0; + + if (!mutex_trylock(&clk_debug_lock)) + return; + + clock_debug_output(s, 0, "Enabled clocks:\n"); + + hlist_for_each_entry(core, &clk_debug_list, debug_node) { + if (!core || !core->prepare_count) + continue; + + if (core->vdd_class) + clock_debug_output(s, 0, " %s:%u:%u [%ld, %d]", + core->name, core->prepare_count, + core->enable_count, core->rate, + clk_find_vdd_level(core, core->rate)); + + else + clock_debug_output(s, 0, " %s:%u:%u [%ld]", + core->name, core->prepare_count, + core->enable_count, core->rate); + cnt++; + } + + mutex_unlock(&clk_debug_lock); + + if (cnt) + clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt); + else + clock_debug_output(s, 0, "No clocks enabled.\n"); +} + +static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) { char *start = ""; struct clk *clk; @@ -2910,7 +2949,7 @@ void clock_debug_print_enabled(void) if (likely(!debug_suspend)) return; - clock_debug_print_enabled_clocks(NULL); + clock_debug_print_enabled_debug_suspend(NULL); } EXPORT_SYMBOL_GPL(clock_debug_print_enabled); diff --git a/drivers/clk/msm/clock-debug.c b/drivers/clk/msm/clock-debug.c index 00a86ba55171..0fe93ede17cc 100644 --- a/drivers/clk/msm/clock-debug.c +++ b/drivers/clk/msm/clock-debug.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2014, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-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 @@ -77,6 +78,7 @@ static int clock_debug_measure_get(void *data, u64 *val) else is_hw_gated = 0; + mutex_lock(&clock->prepare_lock); ret = clk_set_parent(measure, clock); if (!ret) { /* @@ -107,6 +109,7 @@ static int clock_debug_measure_get(void *data, u64 *val) */ meas_rate = clk_get_rate(clock); sw_rate = clk_get_rate(measure->parent); + mutex_unlock(&clock->prepare_lock); if (sw_rate && meas_rate >= (sw_rate * 2)) *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); diff --git a/drivers/clk/msm/clock-gcc-8998.c b/drivers/clk/msm/clock-gcc-8998.c index 87cf6cc5631e..8b7efbd093b5 100644 --- a/drivers/clk/msm/clock-gcc-8998.c +++ b/drivers/clk/msm/clock-gcc-8998.c @@ -263,6 +263,7 @@ static struct rcg_clk hmss_ahb_clk_src = { static struct clk_freq_tbl ftbl_usb30_master_clk_src[] = { F( 19200000, cxo_clk_src, 1, 0, 0), + F( 60000000, gpll0_out_main, 10, 0, 0), F( 120000000, gpll0_out_main, 5, 0, 0), F( 150000000, gpll0_out_main, 4, 0, 0), F_END diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c index 2a112aad1fa3..eb543010c17b 100644 --- a/drivers/clk/msm/clock-mmss-8998.c +++ b/drivers/clk/msm/clock-mmss-8998.c @@ -527,6 +527,7 @@ static struct clk_freq_tbl ftbl_csiphy_clk_src[] = { static struct clk_freq_tbl ftbl_csiphy_clk_src_vq[] = { F_MM( 164570000, mmpll10_pll_out, 3.5, 0, 0), F_MM( 256000000, mmpll4_pll_out, 3, 0, 0), + F_MM( 274290000, mmpll7_pll_out, 3.5, 0, 0), F_MM( 300000000, mmsscc_gpll0, 2, 0, 0), F_MM( 384000000, mmpll4_pll_out, 2, 0, 0), F_END diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 096e16db02fe..bfaf4482d668 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -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 @@ -275,6 +275,8 @@ static int clk_branch2_hw_ctl_determine_rate(struct clk_hw *hw, struct clk_hw *clkp; clkp = __clk_get_hw(clk_get_parent(hw->clk)); + if (!clkp) + return -EINVAL; req->best_parent_hw = clkp; req->best_parent_rate = clk_round_rate(clkp->clk, req->rate); diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 5ed0dba189f7..6d13adf7a6ee 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -1512,7 +1512,7 @@ static int clk_osm_setup_hw_table(struct clk_osm *c) { struct osm_entry *entry = c->osm_table; int i; - u32 freq_val, volt_val, override_val, spare_val; + u32 freq_val = 0, volt_val = 0, override_val = 0, spare_val = 0; u32 table_entry_offset, last_spare, last_virtual_corner = 0; for (i = 0; i < OSM_TABLE_SIZE; i++) { @@ -2472,14 +2472,19 @@ static u64 clk_osm_get_cpu_cycle_counter(int cpu) static void populate_opp_table(struct platform_device *pdev) { int cpu; + struct device *cpu_dev; for_each_possible_cpu(cpu) { if (logical_cpu_to_clk(cpu) == pwrcl_clk.hw.clk) { - WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)), + cpu_dev = get_cpu_device(cpu); + if (cpu_dev) + WARN(add_opp(&pwrcl_clk, cpu_dev), "Failed to add OPP levels for power cluster\n"); } if (logical_cpu_to_clk(cpu) == perfcl_clk.hw.clk) { - WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)), + cpu_dev = get_cpu_device(cpu); + if (cpu_dev) + WARN(add_opp(&perfcl_clk, cpu_dev), "Failed to add OPP levels for perf cluster\n"); } } @@ -2543,7 +2548,7 @@ static ssize_t debugfs_trace_method_set(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct clk_osm *c = file->private_data; + struct clk_osm *c; u32 val; if (IS_ERR(file) || file == NULL) { @@ -2551,6 +2556,8 @@ static ssize_t debugfs_trace_method_set(struct file *file, return -EINVAL; } + c = file->private_data; + if (!c) { pr_err("invalid clk_osm handle\n"); return -EINVAL; @@ -2593,7 +2600,7 @@ static ssize_t debugfs_trace_method_set(struct file *file, static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct clk_osm *c = file->private_data; + struct clk_osm *c; int len, rc; if (IS_ERR(file) || file == NULL) { @@ -2601,6 +2608,8 @@ static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf, return -EINVAL; } + c = file->private_data; + if (!c) { pr_err("invalid clk_osm handle\n"); return -EINVAL; @@ -3023,7 +3032,7 @@ static unsigned long perfcl_boot_rate = 1747200000; static int clk_cpu_osm_driver_probe(struct platform_device *pdev) { - int rc, cpu, i; + int rc = 0, cpu, i; int speedbin = 0, pvs_ver = 0; u32 pte_efuse; int num_clks = ARRAY_SIZE(osm_qcom_clk_hws); diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index 076ff3565ef4..d8ae85b65a47 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -818,7 +818,7 @@ static struct clk_rcg2 hmss_rbcpr_clk_src = { .parent_names = gcc_parent_names_ao_1, .num_parents = 3, .ops = &clk_rcg2_ops, - VDD_DIG_FMAX_MAP2( + VDD_DIG_FMAX_MAP2_AO( LOWER, 19200000, NOMINAL, 50000000), }, diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile index 6a0a1de1e942..733b91b993d6 100644 --- a/drivers/clk/qcom/mdss/Makefile +++ b/drivers/clk/qcom/mdss/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll-util.o obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll.o obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm.o obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm-util.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-14nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-14nm-util.o diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c new file mode 100644 index 000000000000..0965d5590a28 --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c @@ -0,0 +1,624 @@ +/* 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 + * 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. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/usb/usbpd.h> + +#include "mdss-pll.h" +#include "mdss-dp-pll.h" +#include "mdss-dp-pll-14nm.h" + +int dp_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val) +{ + struct mdss_pll_resources *dp_res = context; + int rc; + u32 auxclk_div; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP PLL resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= ~0x03; /* bits 0 to 1 */ + + if (val == 0) /* mux parent index = 0 */ + auxclk_div |= 1; + else if (val == 1) /* mux parent index = 1 */ + auxclk_div |= 2; + + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_VCO_DIV, auxclk_div); + /* Make sure the PHY registers writes are done */ + wmb(); + pr_debug("%s: mux=%d auxclk_div=%x\n", __func__, val, auxclk_div); + + mdss_pll_resource_enable(dp_res, false); + + return 0; +} + +int dp_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val) +{ + int rc; + u32 auxclk_div = 0; + struct mdss_pll_resources *dp_res = context; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable dp_res resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= 0x03; + + if (auxclk_div == 1) /* Default divider */ + *val = 0; + else if (auxclk_div == 2) + *val = 1; + + mdss_pll_resource_enable(dp_res, false); + + pr_debug("%s: auxclk_div=%d, val=%d\n", __func__, auxclk_div, *val); + + return 0; +} + +static int dp_vco_pll_init_db_14nm(struct dp_pll_db *pdb, + unsigned long rate) +{ + struct mdss_pll_resources *dp_res = pdb->pll; + u32 spare_value = 0; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + pdb->lane_cnt = spare_value & 0x0F; + pdb->orientation = (spare_value & 0xF0) >> 4; + + pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + __func__, spare_value, pdb->lane_cnt, pdb->orientation); + + switch (rate) { + case DP_VCO_HSCLK_RATE_1620MHZDIV1000: + pdb->hsclk_sel = 0x2c; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0xbf; + pdb->lock_cmp2_mode0 = 0x21; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + break; + case DP_VCO_HSCLK_RATE_2700MHZDIV1000: + pdb->hsclk_sel = 0x24; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x3f; + pdb->lock_cmp2_mode0 = 0x38; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + break; + case DP_VCO_HSCLK_RATE_5400MHZDIV1000: + pdb->hsclk_sel = 0x20; + pdb->dec_start_mode0 = 0x8c; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x00; + pdb->div_frac_start3_mode0 = 0x0a; + pdb->lock_cmp1_mode0 = 0x7f; + pdb->lock_cmp2_mode0 = 0x70; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x2; + break; + default: + return -EINVAL; + } + return 0; +} + +int dp_config_vco_rate_14nm(struct dp_pll_vco_clk *vco, + unsigned long rate) +{ + u32 res = 0; + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + + res = dp_vco_pll_init_db_14nm(pdb, rate); + if (res) { + pr_err("VCO Init DB failed\n"); + return res; + } + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_PD_CTL, 0x2d); + else + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_PD_CTL, 0x35); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_PD_CTL, 0x3d); + } + + /* Make sure the PHY register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SVS_MODE_CLK_SEL, 0x01); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SYSCLK_EN_SEL, 0x37); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CLK_SELECT, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SYS_CLK_CTRL, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CLK_ENABLE1, 0x0e); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_BG_CTRL, 0x0f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CLK_SELECT, 0x30); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_PLL_IVCO, 0x0f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_PLL_CCTRL_MODE0, 0x28); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_PLL_RCTRL_MODE0, 0x16); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CP_CTRL_MODE0, 0x0b); + + /* Parameters dependent on vco clock frequency */ + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP3_MODE0, pdb->lock_cmp3_mode0); + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_MAP, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_BG_TIMER, 0x08); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CORECLK_DIV, 0x05); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_CTRL, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE1_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE2_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_CTRL, 0x00); + wmb(); /* make sure write happens */ + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CORE_CLK_EN, 0x0f); + wmb(); /* make sure write happens */ + + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xc8); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xd8); + wmb(); /* make sure write happens */ + + /* TX Lane configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX0_TX1_LANE_CTL, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX2_TX3_LANE_CTL, 0x05); + + /* TX-0 register configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_EMP_POST1_LVL, 0x23); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_DRV_LVL, 0x3f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_BAND, 0x4); + + /* TX-1 register configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL, 0x23); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_DRV_LVL, 0x3f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_BAND, 0x4); + wmb(); /* make sure write happens */ + + /* PHY VCO divider programming */ + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_VCO_DIV, pdb->phy_vco_div); + wmb(); /* make sure write happens */ + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CMN_CONFIG, 0x02); + wmb(); /* make sure write happens */ + + return res; +} + +static bool dp_14nm_pll_lock_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool pll_locked; + + /* poll for PLL lock status */ + if (readl_poll_timeout_atomic((dp_res->pll_base + + QSERDES_COM_C_READY_STATUS), + status, + ((status & BIT(0)) > 0), + DP_PLL_POLL_SLEEP_US, + DP_PLL_POLL_TIMEOUT_US)) { + pr_err("%s: C_READY status is not high. Status=%x\n", + __func__, status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +static bool dp_14nm_phy_rdy_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool phy_ready = true; + + /* poll for PHY ready status */ + if (readl_poll_timeout_atomic((dp_res->phy_base + + DP_PHY_STATUS), + status, + ((status & (BIT(1) | BIT(0))) > 0), + DP_PHY_POLL_SLEEP_US, + DP_PHY_POLL_TIMEOUT_US)) { + pr_err("%s: Phy_ready is not high. Status=%x\n", + __func__, status); + phy_ready = false; + } + + return phy_ready; +} + +static int dp_pll_enable_14nm(struct clk_hw *hw) +{ + int rc = 0; + u32 bias_en, drvr_en; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09); + wmb(); /* Make sure the PHY register writes are done */ + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_RESETSM_CNTRL, 0x20); + wmb(); /* Make sure the PLL register writes are done */ + + udelay(900); /* hw recommended delay for full PU */ + + if (!dp_14nm_pll_lock_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + wmb(); /* Make sure the PHY register writes are done */ + + udelay(10); /* hw recommended delay */ + + if (!dp_14nm_phy_rdy_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + pr_debug("%s: PLL is locked\n", __func__); + + if (pdb->lane_cnt == 1) { + bias_en = 0x3e; + drvr_en = 0x13; + } else { + bias_en = 0x3f; + drvr_en = 0x10; + } + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC1) { + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); + } + } else { + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); + } + + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_POL_INV, 0x0a); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_POL_INV, 0x0a); + + /* + * Switch DP Mainlink clock (cc_dpphy_link_clk) from DP + * controller side with final frequency + */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x18); + wmb(); /* Make sure the PHY register writes are done */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + wmb(); /* Make sure the PHY register writes are done */ + +lock_err: + return rc; +} + +static int dp_pll_disable_14nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + /* Assert DP PHY power down */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2); + /* + * Make sure all the register writes to disable PLL are + * completed before doing any other operation + */ + wmb(); + + return rc; +} + + +int dp_vco_prepare_14nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + DEV_DBG("rate=%ld\n", vco->rate); + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll resources\n"); + goto error; + } + + if ((dp_res->vco_cached_rate != 0) + && (dp_res->vco_cached_rate == vco->rate)) { + rc = vco->hw.init->ops->set_rate(hw, + dp_res->vco_cached_rate, dp_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, dp_res->index); + mdss_pll_resource_enable(dp_res, false); + goto error; + } + } + + rc = dp_pll_enable_14nm(hw); + if (rc) { + mdss_pll_resource_enable(dp_res, false); + pr_err("ndx=%d failed to enable dp pll\n", + dp_res->index); + goto error; + } + + mdss_pll_resource_enable(dp_res, false); +error: + return rc; +} + +void dp_vco_unprepare_14nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + if (!dp_res) { + DEV_ERR("Invalid input parameter\n"); + return; + } + + if (!dp_res->pll_on && + mdss_pll_resource_enable(dp_res, true)) { + DEV_ERR("pll resource can't be enabled\n"); + return; + } + dp_res->vco_cached_rate = vco->rate; + dp_pll_disable_14nm(hw); + + dp_res->handoff_resources = false; + mdss_pll_resource_enable(dp_res, false); + dp_res->pll_on = false; +} + +int dp_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + int rc; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + DEV_ERR("pll resource can't be enabled\n"); + return rc; + } + + DEV_DBG("DP lane CLK rate=%ld\n", rate); + + rc = dp_config_vco_rate_14nm(vco, rate); + if (rc) + DEV_ERR("%s: Failed to set clk rate\n", __func__); + + mdss_pll_resource_enable(dp_res, false); + + vco->rate = rate; + + return 0; +} + +unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + int rc; + u32 div, hsclk_div, link2xclk_div = 0; + u64 vco_rate; + struct mdss_pll_resources *dp_res = vco->priv; + + if (is_gdsc_disabled(dp_res)) + return 0; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index); + return rc; + } + + div = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL); + div &= 0x0f; + + if (div == 12) + hsclk_div = 5; /* Default */ + else if (div == 4) + hsclk_div = 3; + else if (div == 0) + hsclk_div = 2; + else { + pr_debug("unknown divider. forcing to default\n"); + hsclk_div = 5; + } + + div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_MODE); + + if (div & 0xd8) + pr_err("%s: DP PAR Rate not correct\n", __func__); + + if ((div & 0x3) == 1) + link2xclk_div = 10; + else if ((div & 0x3) == 0) + link2xclk_div = 5; + else + pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div); + + if (link2xclk_div == 10) { + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + } else { + if (hsclk_div == 5) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 3) + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + } + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(dp_res, false); + + return (unsigned long)vco_rate; +} + +long dp_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + + if (rate <= vco->min_rate) + rrate = vco->min_rate; + else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else + rrate = vco->max_rate; + + pr_debug("%s: rrate=%ld\n", __func__, rrate); + + *parent_rate = rrate; + return rrate; +} + diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c new file mode 100644 index 000000000000..ffe8286cfaaa --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c @@ -0,0 +1,234 @@ +/* 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 + * 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. + * + */ + +/* +*************************************************************************** +******** Display Port PLL driver block diagram for branch clocks ********** +*************************************************************************** + + +--------------------------+ + | DP_VCO_CLK | + | | + | +-------------------+ | + | | (DP PLL/VCO) | | + | +---------+---------+ | + | v | + | +----------+-----------+ | + | | hsclk_divsel_clk_src | | + | +----------+-----------+ | + +--------------------------+ + | + v + +------------<------------|------------>-------------+ + | | | ++----------v----------+ +----------v----------+ +----------v----------+ +| dp_link_2x_clk | | vco_divided_clk_src | | vco_divided_clk_src | +| divsel_five | | | | | +v----------+----------v | divsel_two | | divsel_four | + | +----------+----------+ +----------+----------+ + | | | + v v v + | +---------------------+ | + Input to MMSSCC block | | (aux_clk_ops) | | + for link clk, crypto clk +--> vco_divided_clk <-+ + and interface clock | _src_mux | + +----------+----------+ + | + v + Input to MMSSCC block + for DP pixel clock + +****************************************************************************** +*/ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include "mdss-pll.h" +#include "mdss-dp-pll.h" +#include "mdss-dp-pll-14nm.h" + +static struct dp_pll_db dp_pdb; + +static struct regmap_config dp_pll_14nm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x910, +}; + +static struct regmap_bus dp_pixel_mux_regmap_ops = { + .reg_write = dp_mux_set_parent_14nm, + .reg_read = dp_mux_get_parent_14nm, +}; + +/* Op structures */ +static struct clk_ops dp_14nm_vco_clk_ops = { + .recalc_rate = dp_vco_recalc_rate_14nm, + .set_rate = dp_vco_set_rate_14nm, + .round_rate = dp_vco_round_rate_14nm, + .prepare = dp_vco_prepare_14nm, + .unprepare = dp_vco_unprepare_14nm, +}; + +static struct dp_pll_vco_clk dp_vco_clk = { + .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000, + .max_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000, + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_clk", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &dp_14nm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor dp_link_2x_clk_divsel_five = { + .div = 5, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_link_2x_clk_divsel_five", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dp_vco_divided_clk_src_mux = { + .reg = 0x64, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divided_clk_src_mux", + .parent_names = + (const char *[]){"dp_vco_divsel_two_clk_src", + "dp_vco_divsel_four_clk_src"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + }, + }, +}; + +static struct clk_hw *mdss_dp_pllcc_14nm[] = { + [DP_VCO_CLK] = &dp_vco_clk.hw, + [DP_LINK_2X_CLK_DIVSEL_FIVE] = &dp_link_2x_clk_divsel_five.hw, + [DP_VCO_DIVSEL_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw, + [DP_VCO_DIVSEL_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw, + [DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_vco_divided_clk_src_mux.clkr.hw, +}; + +int dp_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i = 0; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dp_pllcc_14nm); + + if (!pdev || !pdev->dev.of_node) { + pr_err("Invalid input parameters\n"); + return -EINVAL; + } + + if (!pll_res || !pll_res->pll_base || !pll_res->phy_base) { + DEV_ERR("%s: Invalid input parameters\n", __func__); + return -EINVAL; + } + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) { + devm_kfree(&pdev->dev, clk_data); + return -ENOMEM; + } + clk_data->clk_num = num_clks; + + pll_res->priv = &dp_pdb; + dp_pdb.pll = pll_res; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops, + pll_res, &dp_pll_14nm_cfg); + dp_vco_divided_clk_src_mux.clkr.regmap = regmap; + + dp_vco_clk.priv = pll_res; + + for (i = DP_VCO_CLK; i <= DP_VCO_DIVIDED_CLK_SRC_MUX; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dp_pllcc_14nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DP: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (rc) { + DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc); + rc = -EPROBE_DEFER; + } else { + DEV_DBG("%s SUCCESS\n", __func__); + } + return 0; +clk_reg_fail: + devm_kfree(&pdev->dev, clk_data->clks); + devm_kfree(&pdev->dev, clk_data); + return rc; +} diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h new file mode 100644 index 000000000000..08dee8909da4 --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h @@ -0,0 +1,193 @@ +/* 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 + * 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 __MDSS_DP_PLL_14NM_H +#define __MDSS_DP_PLL_14NM_H + +#define DP_PHY_REVISION_ID0 0x0000 +#define DP_PHY_REVISION_ID1 0x0004 +#define DP_PHY_REVISION_ID2 0x0008 +#define DP_PHY_REVISION_ID3 0x000C + +#define DP_PHY_CFG 0x0010 +#define DP_PHY_CFG_1 0x0014 +#define DP_PHY_PD_CTL 0x0018 +#define DP_PHY_MODE 0x001C + +#define DP_PHY_AUX_CFG0 0x0020 +#define DP_PHY_AUX_CFG1 0x0024 +#define DP_PHY_AUX_CFG2 0x0028 +#define DP_PHY_AUX_CFG3 0x002C +#define DP_PHY_AUX_CFG4 0x0030 +#define DP_PHY_AUX_CFG5 0x0034 +#define DP_PHY_AUX_CFG6 0x0038 +#define DP_PHY_AUX_CFG7 0x003C +#define DP_PHY_AUX_CFG8 0x0040 +#define DP_PHY_AUX_CFG9 0x0044 +#define DP_PHY_AUX_INTERRUPT_MASK 0x0048 +#define DP_PHY_AUX_INTERRUPT_CLEAR 0x004C +#define DP_PHY_AUX_BIST_CFG 0x0050 + +#define DP_PHY_VCO_DIV 0x0068 +#define DP_PHY_TX0_TX1_LANE_CTL 0x006C + +#define DP_PHY_TX2_TX3_LANE_CTL 0x0088 +#define DP_PHY_SPARE0 0x00AC +#define DP_PHY_STATUS 0x00C0 + +/* Tx registers */ +#define QSERDES_TX0_OFFSET 0x0400 +#define QSERDES_TX1_OFFSET 0x0800 + +#define TXn_BIST_MODE_LANENO 0x0000 +#define TXn_CLKBUF_ENABLE 0x0008 +#define TXn_TX_EMP_POST1_LVL 0x000C + +#define TXn_TX_DRV_LVL 0x001C + +#define TXn_RESET_TSYNC_EN 0x0024 +#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028 +#define TXn_TX_BAND 0x002C +#define TXn_SLEW_CNTL 0x0030 +#define TXn_INTERFACE_SELECT 0x0034 + +#define TXn_RES_CODE_LANE_TX 0x003C +#define TXn_RES_CODE_LANE_RX 0x0040 +#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044 +#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048 + +#define TXn_DEBUG_BUS_SEL 0x0058 +#define TXn_TRANSCEIVER_BIAS_EN 0x005C +#define TXn_HIGHZ_DRVR_EN 0x0060 +#define TXn_TX_POL_INV 0x0064 +#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068 + +#define TXn_LANE_MODE_1 0x008C + +#define TXn_TRAN_DRVR_EMP_EN 0x00C0 +#define TXn_TX_INTERFACE_MODE 0x00C4 + +#define TXn_VMODE_CTRL1 0x00F0 + + +/* PLL register offset */ +#define QSERDES_COM_ATB_SEL1 0x0000 +#define QSERDES_COM_ATB_SEL2 0x0004 +#define QSERDES_COM_FREQ_UPDATE 0x0008 +#define QSERDES_COM_BG_TIMER 0x000C +#define QSERDES_COM_SSC_EN_CENTER 0x0010 +#define QSERDES_COM_SSC_ADJ_PER1 0x0014 +#define QSERDES_COM_SSC_ADJ_PER2 0x0018 +#define QSERDES_COM_SSC_PER1 0x001C +#define QSERDES_COM_SSC_PER2 0x0020 +#define QSERDES_COM_SSC_STEP_SIZE1 0x0024 +#define QSERDES_COM_SSC_STEP_SIZE2 0x0028 +#define QSERDES_COM_POST_DIV 0x002C +#define QSERDES_COM_POST_DIV_MUX 0x0030 +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034 +#define QSERDES_COM_CLK_ENABLE1 0x0038 +#define QSERDES_COM_SYS_CLK_CTRL 0x003C +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040 +#define QSERDES_COM_PLL_EN 0x0044 +#define QSERDES_COM_PLL_IVCO 0x0048 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x004C +#define QSERDES_COM_LOCK_CMP2_MODE0 0x0050 +#define QSERDES_COM_LOCK_CMP3_MODE0 0x0054 + +#define QSERDES_COM_CP_CTRL_MODE0 0x0078 +#define QSERDES_COM_CP_CTRL_MODE1 0x007C +#define QSERDES_COM_PLL_RCTRL_MODE0 0x0084 +#define QSERDES_COM_PLL_CCTRL_MODE0 0x0090 +#define QSERDES_COM_PLL_CNTRL 0x009C + +#define QSERDES_COM_SYSCLK_EN_SEL 0x00AC +#define QSERDES_COM_CML_SYSCLK_SEL 0x00B0 +#define QSERDES_COM_RESETSM_CNTRL 0x00B4 +#define QSERDES_COM_RESETSM_CNTRL2 0x00B8 +#define QSERDES_COM_LOCK_CMP_EN 0x00C8 +#define QSERDES_COM_LOCK_CMP_CFG 0x00CC + + +#define QSERDES_COM_DEC_START_MODE0 0x00D0 +#define QSERDES_COM_DEC_START_MODE1 0x00D4 +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00DC +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00E0 +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00E4 + +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x0108 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x010C +#define QSERDES_COM_VCO_TUNE_CTRL 0x0124 +#define QSERDES_COM_VCO_TUNE_MAP 0x0128 +#define QSERDES_COM_VCO_TUNE1_MODE0 0x012C +#define QSERDES_COM_VCO_TUNE2_MODE0 0x0130 + +#define QSERDES_COM_CMN_STATUS 0x015C +#define QSERDES_COM_RESET_SM_STATUS 0x0160 + +#define QSERDES_COM_BG_CTRL 0x0170 +#define QSERDES_COM_CLK_SELECT 0x0174 +#define QSERDES_COM_HSCLK_SEL 0x0178 +#define QSERDES_COM_CORECLK_DIV 0x0184 +#define QSERDES_COM_SW_RESET 0x0188 +#define QSERDES_COM_CORE_CLK_EN 0x018C +#define QSERDES_COM_C_READY_STATUS 0x0190 +#define QSERDES_COM_CMN_CONFIG 0x0194 +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x019C + +#define DP_PLL_POLL_SLEEP_US 500 +#define DP_PLL_POLL_TIMEOUT_US 10000 + +#define DP_PHY_POLL_SLEEP_US 500 +#define DP_PHY_POLL_TIMEOUT_US 10000 + +#define DP_VCO_RATE_8100MHZDIV1000 8100000UL +#define DP_VCO_RATE_10800MHZDIV1000 10800000UL + +#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL +#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL +#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL + +struct dp_pll_db { + struct mdss_pll_resources *pll; + + /* lane and orientation settings */ + u8 lane_cnt; + u8 orientation; + + /* COM PHY settings */ + u32 hsclk_sel; + u32 dec_start_mode0; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp3_mode0; + + /* PHY vco divider */ + u32 phy_vco_div; +}; + +int dp_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate); +long dp_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int dp_vco_prepare_14nm(struct clk_hw *hw); +void dp_vco_unprepare_14nm(struct clk_hw *hw); +int dp_mux_set_parent_14nm(void *context, + unsigned int reg, unsigned int val); +int dp_mux_get_parent_14nm(void *context, + unsigned int reg, unsigned int *val); +#endif /* __MDSS_DP_PLL_14NM_H */ diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll.h b/drivers/clk/qcom/mdss/mdss-dp-pll.h new file mode 100644 index 000000000000..a05e27af456e --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll.h @@ -0,0 +1,35 @@ +/* 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 + * 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 __MDSS_DP_PLL_H +#define __MDSS_DP_PLL_H + +struct dp_pll_vco_clk { + struct clk_hw hw; + unsigned long rate; /* current vco rate */ + u64 min_rate; /* min vco rate */ + u64 max_rate; /* max vco rate */ + void *priv; +}; + +static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw) +{ + return container_of(hw, struct dp_pll_vco_clk, hw); +} + +int dp_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + + +#endif /* __MDSS_DP_PLL_H */ + diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index f356be38a25c..2f3a020a761a 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,6 +22,7 @@ #include "mdss-pll.h" #include "mdss-dsi-pll.h" +#include "mdss-dp-pll.h" int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable) { @@ -141,6 +142,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, pll_res->pll_interface_type = MDSS_DSI_PLL_8998; } else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_8998")) { pll_res->pll_interface_type = MDSS_DP_PLL_8998; + } else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_sdm660")) { + pll_res->target_id = MDSS_PLL_TARGET_SDM660; + pll_res->pll_interface_type = MDSS_DP_PLL_SDM660; } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996")) { pll_res->pll_interface_type = MDSS_HDMI_PLL_8996; } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) { @@ -178,6 +182,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev, case MDSS_DSI_PLL_8996: rc = dsi_pll_clock_register_14nm(pdev, pll_res); break; + case MDSS_DP_PLL_SDM660: + rc = dp_pll_clock_register_14nm(pdev, pll_res); + break; case MDSS_UNKNOWN_PLL: default: rc = -EINVAL; @@ -383,6 +390,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dp_pll_8998"}, {.compatible = "qcom,mdss_hdmi_pll_8998"}, {.compatible = "qcom,mdss_dsi_pll_sdm660"}, + {.compatible = "qcom,mdss_dp_pll_sdm660"}, {} }; diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index e0e62a0f379b..9cf785d43504 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.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 @@ -41,6 +41,7 @@ enum { MDSS_DSI_PLL_8996, MDSS_DSI_PLL_8998, MDSS_DP_PLL_8998, + MDSS_DP_PLL_SDM660, MDSS_HDMI_PLL_8996, MDSS_HDMI_PLL_8996_V2, MDSS_HDMI_PLL_8996_V3, diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index 0226bf49b3b0..934779f16107 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -207,8 +207,8 @@ static const struct parent_map mmcc_parent_map_6[] = { static const char * const mmcc_parent_names_6[] = { "xo", - "dp_phy_pll_link_clk", - "dp_phy_pll_vco_div", + "dp_link_2x_clk_divsel_five", + "dp_vco_divided_clk_src_mux", "core_bi_pll_test_se", }; @@ -882,9 +882,9 @@ static struct clk_rcg2 dp_aux_clk_src = { }; static const struct freq_tbl ftbl_dp_crypto_clk_src[] = { - F(101250000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0), - F(168750000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0), - F(337500000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0), + F(101250, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0), + F(168750, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0), + F(337500, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0), { } }; @@ -900,9 +900,9 @@ static struct clk_rcg2 dp_crypto_clk_src = { .num_parents = 4, .ops = &clk_rcg2_ops, VDD_DIG_FMAX_MAP3( - LOWER, 101250000, - LOW, 168750000, - NOMINAL, 337500000), + LOWER, 101250, + LOW, 168750, + NOMINAL, 337500), }, }; @@ -930,9 +930,9 @@ static struct clk_rcg2 dp_gtc_clk_src = { }; static const struct freq_tbl ftbl_dp_link_clk_src[] = { - F(162000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), - F(270000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), - F(540000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(162000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(270000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(540000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), { } }; @@ -949,9 +949,9 @@ static struct clk_rcg2 dp_link_clk_src = { .ops = &clk_rcg2_ops, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, VDD_DIG_FMAX_MAP3( - LOWER, 162000000, - LOW, 270000000, - NOMINAL, 540000000), + LOWER, 162000, + LOW, 270000, + NOMINAL, 540000), }, }; @@ -966,9 +966,9 @@ static struct clk_rcg2 dp_pixel_clk_src = { .num_parents = 4, .ops = &clk_dp_ops, VDD_DIG_FMAX_MAP3( - LOWER, 148380000, - LOW, 296740000, - NOMINAL, 593470000), + LOWER, 148380, + LOW, 296740, + NOMINAL, 593470), }, }; diff --git a/drivers/clk/qcom/vdd-level-660.h b/drivers/clk/qcom/vdd-level-660.h index f98a96033ea9..53317fe6d294 100644 --- a/drivers/clk/qcom/vdd-level-660.h +++ b/drivers/clk/qcom/vdd-level-660.h @@ -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 @@ -95,6 +95,14 @@ }, \ .num_rate_max = VDD_DIG_NUM +#define VDD_DIG_FMAX_MAP2_AO(l1, f1, l2, f2) \ + .vdd_class = &vdd_dig_ao, \ + .rate_max = (unsigned long[VDD_DIG_NUM]) { \ + [VDD_DIG_##l1] = (f1), \ + [VDD_DIG_##l2] = (f2), \ + }, \ + .num_rate_max = VDD_DIG_NUM + #define VDD_DIG_FMAX_MAP3_AO(l1, f1, l2, f2, l3, f3) \ .vdd_class = &vdd_dig_ao, \ .rate_max = (unsigned long[VDD_DIG_NUM]) { \ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 6ec828805428..e4d9aef1dda4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1258,6 +1258,9 @@ static int cpufreq_online(unsigned int cpu) for_each_cpu(j, policy->related_cpus) per_cpu(cpufreq_cpu_data, j) = policy; write_unlock_irqrestore(&cpufreq_driver_lock, flags); + } else { + policy->min = policy->user_policy.min; + policy->max = policy->user_policy.max; } if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 433e4783d1d1..a629c621648c 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1,6 +1,6 @@ /* Qualcomm CE device driver. * - * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1381,7 +1381,7 @@ static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req, /* if not using HW key make sure key * length is valid */ - if ((req->mode == QCEDEV_AES_MODE_XTS)) { + if (req->mode == QCEDEV_AES_MODE_XTS) { if ((req->encklen != QCEDEV_AES_KEY_128*2) && (req->encklen != QCEDEV_AES_KEY_256*2)) { pr_err("%s: unsupported key size: %d\n", @@ -1445,6 +1445,15 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, pr_err("%s: Invalid byte offset\n", __func__); goto error; } + total = req->byteoffset; + for (i = 0; i < req->entries; i++) { + if (total > U32_MAX - req->vbuf.src[i].len) { + pr_err("%s:Integer overflow on total src len\n", + __func__); + goto error; + } + total += req->vbuf.src[i].len; + } } if (req->data_len < req->byteoffset) { @@ -1480,7 +1489,7 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, } } /* Check for sum of all dst length is equal to data_len */ - for (i = 0; i < req->entries; i++) { + for (i = 0, total = 0; i < req->entries; i++) { if (req->vbuf.dst[i].len >= U32_MAX - total) { pr_err("%s: Integer overflow on total req dst vbuf length\n", __func__); diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 7f29f3644fb6..84d3ec98e6b9 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -3,7 +3,7 @@ config DRM_MSM tristate "MSM DRM" depends on DRM depends on ARCH_QCOM || (ARM && COMPILE_TEST) - depends on OF + depends on OF && COMMON_CLK select REGULATOR select DRM_KMS_HELPER select DRM_PANEL diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 05b6ca9b5c55..1c90290be716 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -38,14 +38,6 @@ msm-y := \ mdp/mdp5/mdp5_kms.o \ mdp/mdp5/mdp5_plane.o \ mdp/mdp5/mdp5_smp.o \ - sde/sde_crtc.o \ - sde/sde_encoder.o \ - sde/sde_encoder_phys_vid.o \ - sde/sde_encoder_phys_cmd.o \ - sde/sde_irq.o \ - sde/sde_kms_utils.o \ - sde/sde_kms.o \ - sde/sde_plane.o \ msm_atomic.o \ msm_drv.o \ msm_fb.o \ @@ -54,7 +46,6 @@ msm-y := \ msm_gem_submit.o \ msm_gpu.o \ msm_iommu.o \ - msm_smmu.o \ msm_perf.o \ msm_rd.o \ msm_ringbuffer.o @@ -78,18 +69,3 @@ msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o endif obj-$(CONFIG_DRM_MSM) += msm.o - -obj-$(CONFIG_DRM_MSM) += sde/sde_hw_catalog.o \ - sde/sde_hw_catalog_8996.o \ - sde/sde_hw_cdm.o \ - sde/sde_hw_dspp.o \ - sde/sde_hw_intf.o \ - sde/sde_hw_lm.o \ - sde/sde_hw_mdp_ctl.o \ - sde/sde_hw_mdp_util.o \ - sde/sde_hw_sspp.o \ - sde/sde_hw_wb.o \ - sde/sde_hw_pingpong.o \ - sde/sde_hw_mdp_top.o \ - sde/sde_hw_interrupts.o \ - sde/sde_mdp_formats.o diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c deleted file mode 100644 index 114998fb8fc5..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "msm-dsi-catalog:[%s] " fmt, __func__ -#include <linux/errno.h> - -#include "dsi_catalog.h" - -/** - * dsi_catalog_14_init() - catalog init for dsi controller v1.4 - */ -static void dsi_catalog_14_init(struct dsi_ctrl_hw *ctrl) -{ - ctrl->ops.host_setup = dsi_ctrl_hw_14_host_setup; - ctrl->ops.setup_lane_map = dsi_ctrl_hw_14_setup_lane_map; - ctrl->ops.video_engine_en = dsi_ctrl_hw_14_video_engine_en; - ctrl->ops.video_engine_setup = dsi_ctrl_hw_14_video_engine_setup; - ctrl->ops.set_video_timing = dsi_ctrl_hw_14_set_video_timing; - ctrl->ops.cmd_engine_setup = dsi_ctrl_hw_14_cmd_engine_setup; - ctrl->ops.ctrl_en = dsi_ctrl_hw_14_ctrl_en; - ctrl->ops.cmd_engine_en = dsi_ctrl_hw_14_cmd_engine_en; - ctrl->ops.phy_sw_reset = dsi_ctrl_hw_14_phy_sw_reset; - ctrl->ops.soft_reset = dsi_ctrl_hw_14_soft_reset; - ctrl->ops.kickoff_command = dsi_ctrl_hw_14_kickoff_command; - ctrl->ops.kickoff_fifo_command = dsi_ctrl_hw_14_kickoff_fifo_command; - ctrl->ops.reset_cmd_fifo = dsi_ctrl_hw_14_reset_cmd_fifo; - ctrl->ops.trigger_command_dma = dsi_ctrl_hw_14_trigger_command_dma; - ctrl->ops.ulps_request = dsi_ctrl_hw_14_ulps_request; - ctrl->ops.ulps_exit = dsi_ctrl_hw_14_ulps_exit; - ctrl->ops.clear_ulps_request = dsi_ctrl_hw_14_clear_ulps_request; - ctrl->ops.get_lanes_in_ulps = dsi_ctrl_hw_14_get_lanes_in_ulps; - ctrl->ops.clamp_enable = dsi_ctrl_hw_14_clamp_enable; - ctrl->ops.clamp_disable = dsi_ctrl_hw_14_clamp_disable; - ctrl->ops.get_interrupt_status = dsi_ctrl_hw_14_get_interrupt_status; - ctrl->ops.get_error_status = dsi_ctrl_hw_14_get_error_status; - ctrl->ops.clear_error_status = dsi_ctrl_hw_14_clear_error_status; - ctrl->ops.clear_interrupt_status = - dsi_ctrl_hw_14_clear_interrupt_status; - ctrl->ops.enable_status_interrupts = - dsi_ctrl_hw_14_enable_status_interrupts; - ctrl->ops.enable_error_interrupts = - dsi_ctrl_hw_14_enable_error_interrupts; - ctrl->ops.video_test_pattern_setup = - dsi_ctrl_hw_14_video_test_pattern_setup; - ctrl->ops.cmd_test_pattern_setup = - dsi_ctrl_hw_14_cmd_test_pattern_setup; - ctrl->ops.test_pattern_enable = dsi_ctrl_hw_14_test_pattern_enable; - ctrl->ops.trigger_cmd_test_pattern = - dsi_ctrl_hw_14_trigger_cmd_test_pattern; -} - -/** - * dsi_catalog_20_init() - catalog init for dsi controller v2.0 - */ -static void dsi_catalog_20_init(struct dsi_ctrl_hw *ctrl) -{ - set_bit(DSI_CTRL_CPHY, ctrl->feature_map); -} - -/** - * dsi_catalog_ctrl_setup() - return catalog info for dsi controller - * @ctrl: Pointer to DSI controller hw object. - * @version: DSI controller version. - * @index: DSI controller instance ID. - * - * This function setups the catalog information in the dsi_ctrl_hw object. - * - * return: error code for failure and 0 for success. - */ -int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_ctrl_version version, - u32 index) -{ - int rc = 0; - - if (version == DSI_CTRL_VERSION_UNKNOWN || - version >= DSI_CTRL_VERSION_MAX) { - pr_err("Unsupported version: %d\n", version); - return -ENOTSUPP; - } - - ctrl->index = index; - set_bit(DSI_CTRL_VIDEO_TPG, ctrl->feature_map); - set_bit(DSI_CTRL_CMD_TPG, ctrl->feature_map); - set_bit(DSI_CTRL_VARIABLE_REFRESH_RATE, ctrl->feature_map); - set_bit(DSI_CTRL_DYNAMIC_REFRESH, ctrl->feature_map); - set_bit(DSI_CTRL_DESKEW_CALIB, ctrl->feature_map); - set_bit(DSI_CTRL_DPHY, ctrl->feature_map); - - switch (version) { - case DSI_CTRL_VERSION_1_4: - dsi_catalog_14_init(ctrl); - break; - case DSI_CTRL_VERSION_2_0: - dsi_catalog_20_init(ctrl); - break; - default: - return -ENOTSUPP; - } - - return rc; -} - -/** - * dsi_catalog_phy_4_0_init() - catalog init for DSI PHY v4.0 - */ -static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy) -{ - phy->ops.regulator_enable = dsi_phy_hw_v4_0_regulator_enable; - phy->ops.regulator_disable = dsi_phy_hw_v4_0_regulator_disable; - phy->ops.enable = dsi_phy_hw_v4_0_enable; - phy->ops.disable = dsi_phy_hw_v4_0_disable; - phy->ops.calculate_timing_params = - dsi_phy_hw_v4_0_calculate_timing_params; -} - -/** - * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware - * @ctrl: Pointer to DSI PHY hw object. - * @version: DSI PHY version. - * @index: DSI PHY instance ID. - * - * This function setups the catalog information in the dsi_phy_hw object. - * - * return: error code for failure and 0 for success. - */ -int dsi_catalog_phy_setup(struct dsi_phy_hw *phy, - enum dsi_phy_version version, - u32 index) -{ - int rc = 0; - - if (version == DSI_PHY_VERSION_UNKNOWN || - version >= DSI_PHY_VERSION_MAX) { - pr_err("Unsupported version: %d\n", version); - return -ENOTSUPP; - } - - phy->index = index; - set_bit(DSI_PHY_DPHY, phy->feature_map); - - switch (version) { - case DSI_PHY_VERSION_4_0: - dsi_catalog_phy_4_0_init(phy); - break; - case DSI_PHY_VERSION_1_0: - case DSI_PHY_VERSION_2_0: - case DSI_PHY_VERSION_3_0: - default: - return -ENOTSUPP; - } - - return rc; -} - - diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h deleted file mode 100644 index e4b33c259540..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DSI_CATALOG_H_ -#define _DSI_CATALOG_H_ - -#include "dsi_ctrl_hw.h" -#include "dsi_phy_hw.h" - -/** - * dsi_catalog_ctrl_setup() - return catalog info for dsi controller - * @ctrl: Pointer to DSI controller hw object. - * @version: DSI controller version. - * @index: DSI controller instance ID. - * - * This function setups the catalog information in the dsi_ctrl_hw object. - * - * return: error code for failure and 0 for success. - */ -int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_ctrl_version version, - u32 index); - -/** - * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware - * @ctrl: Pointer to DSI PHY hw object. - * @version: DSI PHY version. - * @index: DSI PHY instance ID. - * - * This function setups the catalog information in the dsi_phy_hw object. - * - * return: error code for failure and 0 for success. - */ -int dsi_catalog_phy_setup(struct dsi_phy_hw *phy, - enum dsi_phy_version version, - u32 index); - -/* Definitions for 4.0 PHY hardware driver */ -void dsi_phy_hw_v4_0_regulator_enable(struct dsi_phy_hw *phy, - struct dsi_phy_per_lane_cfgs *cfg); -void dsi_phy_hw_v4_0_regulator_disable(struct dsi_phy_hw *phy); -void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); -void dsi_phy_hw_v4_0_disable(struct dsi_phy_hw *phy); -int dsi_phy_hw_v4_0_calculate_timing_params(struct dsi_phy_hw *phy, - struct dsi_mode_info *mode, - struct dsi_host_common_cfg *cfg, - struct dsi_phy_per_lane_cfgs - *timing); - -/* Definitions for 1.4 controller hardware driver */ -void dsi_ctrl_hw_14_host_setup(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *config); -void dsi_ctrl_hw_14_video_engine_en(struct dsi_ctrl_hw *ctrl, bool on); -void dsi_ctrl_hw_14_video_engine_setup(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *common_cfg, - struct dsi_video_engine_cfg *cfg); -void dsi_ctrl_hw_14_set_video_timing(struct dsi_ctrl_hw *ctrl, - struct dsi_mode_info *mode); - -void dsi_ctrl_hw_14_cmd_engine_setup(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *common_cfg, - struct dsi_cmd_engine_cfg *cfg); - -void dsi_ctrl_hw_14_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on); -void dsi_ctrl_hw_14_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on); - -void dsi_ctrl_hw_14_phy_sw_reset(struct dsi_ctrl_hw *ctrl); -void dsi_ctrl_hw_14_soft_reset(struct dsi_ctrl_hw *ctrl); - -void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl, - struct dsi_lane_mapping *lane_map); -void dsi_ctrl_hw_14_kickoff_command(struct dsi_ctrl_hw *ctrl, - struct dsi_ctrl_cmd_dma_info *cmd, - u32 flags); - -void dsi_ctrl_hw_14_kickoff_fifo_command(struct dsi_ctrl_hw *ctrl, - struct dsi_ctrl_cmd_dma_fifo_info *cmd, - u32 flags); -void dsi_ctrl_hw_14_reset_cmd_fifo(struct dsi_ctrl_hw *ctrl); -void dsi_ctrl_hw_14_trigger_command_dma(struct dsi_ctrl_hw *ctrl); - -void dsi_ctrl_hw_14_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes); -void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes); -void dsi_ctrl_hw_14_clear_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes); -u32 dsi_ctrl_hw_14_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl); - -void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl, - u32 lanes, - bool enable_ulps); - -void dsi_ctrl_hw_14_clamp_disable(struct dsi_ctrl_hw *ctrl, - u32 lanes, - bool disable_ulps); -u32 dsi_ctrl_hw_14_get_interrupt_status(struct dsi_ctrl_hw *ctrl); -void dsi_ctrl_hw_14_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints); -void dsi_ctrl_hw_14_enable_status_interrupts(struct dsi_ctrl_hw *ctrl, - u32 ints); - -u64 dsi_ctrl_hw_14_get_error_status(struct dsi_ctrl_hw *ctrl); -void dsi_ctrl_hw_14_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors); -void dsi_ctrl_hw_14_enable_error_interrupts(struct dsi_ctrl_hw *ctrl, - u64 errors); - -void dsi_ctrl_hw_14_video_test_pattern_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_test_pattern type, - u32 init_val); -void dsi_ctrl_hw_14_cmd_test_pattern_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_test_pattern type, - u32 init_val, - u32 stream_id); -void dsi_ctrl_hw_14_test_pattern_enable(struct dsi_ctrl_hw *ctrl, bool enable); -void dsi_ctrl_hw_14_trigger_cmd_test_pattern(struct dsi_ctrl_hw *ctrl, - u32 stream_id); -#endif /* _DSI_CATALOG_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h deleted file mode 100644 index b5ddfbb4ef72..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DSI_CTRL_HW_H_ -#define _DSI_CTRL_HW_H_ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/bitops.h> -#include <linux/bitmap.h> - -#include "dsi_defs.h" - -/** - * Modifier flag for command transmission. If this flag is set, command - * information is programmed to hardware and transmission is not triggered. - * Caller should call the trigger_command_dma() to start the transmission. This - * flag is valed for kickoff_command() and kickoff_fifo_command() operations. - */ -#define DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER 0x1 - -/** - * enum dsi_ctrl_version - version of the dsi host controller - * @DSI_CTRL_VERSION_UNKNOWN: Unknown controller version - * @DSI_CTRL_VERSION_1_4: DSI host v1.4 controller - * @DSI_CTRL_VERSION_2_0: DSI host v2.0 controller - * @DSI_CTRL_VERSION_MAX: max version - */ -enum dsi_ctrl_version { - DSI_CTRL_VERSION_UNKNOWN, - DSI_CTRL_VERSION_1_4, - DSI_CTRL_VERSION_2_0, - DSI_CTRL_VERSION_MAX -}; - -/** - * enum dsi_ctrl_hw_features - features supported by dsi host controller - * @DSI_CTRL_VIDEO_TPG: Test pattern support for video mode. - * @DSI_CTRL_CMD_TPG: Test pattern support for command mode. - * @DSI_CTRL_VARIABLE_REFRESH_RATE: variable panel timing - * @DSI_CTRL_DYNAMIC_REFRESH: variable pixel clock rate - * @DSI_CTRL_NULL_PACKET_INSERTION: NULL packet insertion - * @DSI_CTRL_DESKEW_CALIB: Deskew calibration support - * @DSI_CTRL_DPHY: Controller support for DPHY - * @DSI_CTRL_CPHY: Controller support for CPHY - * @DSI_CTRL_MAX_FEATURES: - */ -enum dsi_ctrl_hw_features { - DSI_CTRL_VIDEO_TPG, - DSI_CTRL_CMD_TPG, - DSI_CTRL_VARIABLE_REFRESH_RATE, - DSI_CTRL_DYNAMIC_REFRESH, - DSI_CTRL_NULL_PACKET_INSERTION, - DSI_CTRL_DESKEW_CALIB, - DSI_CTRL_DPHY, - DSI_CTRL_CPHY, - DSI_CTRL_MAX_FEATURES -}; - -/** - * enum dsi_test_pattern - test pattern type - * @DSI_TEST_PATTERN_FIXED: Test pattern is fixed, based on init value. - * @DSI_TEST_PATTERN_INC: Incremental test pattern, base on init value. - * @DSI_TEST_PATTERN_POLY: Pattern generated from polynomial and init val. - * @DSI_TEST_PATTERN_MAX: - */ -enum dsi_test_pattern { - DSI_TEST_PATTERN_FIXED = 0, - DSI_TEST_PATTERN_INC, - DSI_TEST_PATTERN_POLY, - DSI_TEST_PATTERN_MAX -}; - -/** - * enum dsi_status_int_type - status interrupts generated by DSI controller - * @DSI_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out. - * @DSI_CMD_STREAM0_FRAME_DONE: A frame of command mode stream0 is sent out. - * @DSI_CMD_STREAM1_FRAME_DONE: A frame of command mode stream1 is sent out. - * @DSI_CMD_STREAM2_FRAME_DONE: A frame of command mode stream2 is sent out. - * @DSI_VIDEO_MODE_FRAME_DONE: A frame of video mode stream is sent out. - * @DSI_BTA_DONE: A BTA is completed. - * @DSI_CMD_FRAME_DONE: A frame of selected command mode stream is - * sent out by MDP. - * @DSI_DYN_REFRESH_DONE: The dynamic refresh operation has completed. - * @DSI_DESKEW_DONE: The deskew calibration operation has completed - * @DSI_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has - * completed. - */ -enum dsi_status_int_type { - DSI_CMD_MODE_DMA_DONE = BIT(0), - DSI_CMD_STREAM0_FRAME_DONE = BIT(1), - DSI_CMD_STREAM1_FRAME_DONE = BIT(2), - DSI_CMD_STREAM2_FRAME_DONE = BIT(3), - DSI_VIDEO_MODE_FRAME_DONE = BIT(4), - DSI_BTA_DONE = BIT(5), - DSI_CMD_FRAME_DONE = BIT(6), - DSI_DYN_REFRESH_DONE = BIT(7), - DSI_DESKEW_DONE = BIT(8), - DSI_DYN_BLANK_DMA_DONE = BIT(9) -}; - -/** - * enum dsi_error_int_type - error interrupts generated by DSI controller - * @DSI_RDBK_SINGLE_ECC_ERR: Single bit ECC error in read packet. - * @DSI_RDBK_MULTI_ECC_ERR: Multi bit ECC error in read packet. - * @DSI_RDBK_CRC_ERR: CRC error in read packet. - * @DSI_RDBK_INCOMPLETE_PKT: Incomplete read packet. - * @DSI_PERIPH_ERROR_PKT: Error packet returned from peripheral, - * @DSI_LP_RX_TIMEOUT: Low power reverse transmission timeout. - * @DSI_HS_TX_TIMEOUT: High speed forward transmission timeout. - * @DSI_BTA_TIMEOUT: BTA timeout. - * @DSI_PLL_UNLOCK: PLL has unlocked. - * @DSI_DLN0_ESC_ENTRY_ERR: Incorrect LP Rx escape entry. - * @DSI_DLN0_ESC_SYNC_ERR: LP Rx data is not byte aligned. - * @DSI_DLN0_LP_CONTROL_ERR: Incorrect LP Rx state sequence. - * @DSI_PENDING_HS_TX_TIMEOUT: Pending High-speed transfer timeout. - * @DSI_INTERLEAVE_OP_CONTENTION: Interleave operation contention. - * @DSI_CMD_DMA_FIFO_UNDERFLOW: Command mode DMA FIFO underflow. - * @DSI_CMD_MDP_FIFO_UNDERFLOW: Command MDP FIFO underflow (failed to - * receive one complete line from MDP). - * @DSI_DLN0_HS_FIFO_OVERFLOW: High speed FIFO for data lane 0 overflows. - * @DSI_DLN1_HS_FIFO_OVERFLOW: High speed FIFO for data lane 1 overflows. - * @DSI_DLN2_HS_FIFO_OVERFLOW: High speed FIFO for data lane 2 overflows. - * @DSI_DLN3_HS_FIFO_OVERFLOW: High speed FIFO for data lane 3 overflows. - * @DSI_DLN0_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 0 underflows. - * @DSI_DLN1_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 1 underflows. - * @DSI_DLN2_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 2 underflows. - * @DSI_DLN3_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 3 undeflows. - * @DSI_DLN0_LP0_CONTENTION: PHY level contention while lane 0 is low. - * @DSI_DLN1_LP0_CONTENTION: PHY level contention while lane 1 is low. - * @DSI_DLN2_LP0_CONTENTION: PHY level contention while lane 2 is low. - * @DSI_DLN3_LP0_CONTENTION: PHY level contention while lane 3 is low. - * @DSI_DLN0_LP1_CONTENTION: PHY level contention while lane 0 is high. - * @DSI_DLN1_LP1_CONTENTION: PHY level contention while lane 1 is high. - * @DSI_DLN2_LP1_CONTENTION: PHY level contention while lane 2 is high. - * @DSI_DLN3_LP1_CONTENTION: PHY level contention while lane 3 is high. - */ -enum dsi_error_int_type { - DSI_RDBK_SINGLE_ECC_ERR = BIT(0), - DSI_RDBK_MULTI_ECC_ERR = BIT(1), - DSI_RDBK_CRC_ERR = BIT(2), - DSI_RDBK_INCOMPLETE_PKT = BIT(3), - DSI_PERIPH_ERROR_PKT = BIT(4), - DSI_LP_RX_TIMEOUT = BIT(5), - DSI_HS_TX_TIMEOUT = BIT(6), - DSI_BTA_TIMEOUT = BIT(7), - DSI_PLL_UNLOCK = BIT(8), - DSI_DLN0_ESC_ENTRY_ERR = BIT(9), - DSI_DLN0_ESC_SYNC_ERR = BIT(10), - DSI_DLN0_LP_CONTROL_ERR = BIT(11), - DSI_PENDING_HS_TX_TIMEOUT = BIT(12), - DSI_INTERLEAVE_OP_CONTENTION = BIT(13), - DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(14), - DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(15), - DSI_DLN0_HS_FIFO_OVERFLOW = BIT(16), - DSI_DLN1_HS_FIFO_OVERFLOW = BIT(17), - DSI_DLN2_HS_FIFO_OVERFLOW = BIT(18), - DSI_DLN3_HS_FIFO_OVERFLOW = BIT(19), - DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(20), - DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(21), - DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(22), - DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(23), - DSI_DLN0_LP0_CONTENTION = BIT(24), - DSI_DLN1_LP0_CONTENTION = BIT(25), - DSI_DLN2_LP0_CONTENTION = BIT(26), - DSI_DLN3_LP0_CONTENTION = BIT(27), - DSI_DLN0_LP1_CONTENTION = BIT(28), - DSI_DLN1_LP1_CONTENTION = BIT(29), - DSI_DLN2_LP1_CONTENTION = BIT(30), - DSI_DLN3_LP1_CONTENTION = BIT(31), -}; - -/** - * struct dsi_ctrl_cmd_dma_info - command buffer information - * @offset: IOMMU VA for command buffer address. - * @length: Length of the command buffer. - * @en_broadcast: Enable broadcast mode if set to true. - * @is_master: Is master in broadcast mode. - * @use_lpm: Use low power mode for command transmission. - */ -struct dsi_ctrl_cmd_dma_info { - u32 offset; - u32 length; - bool en_broadcast; - bool is_master; - bool use_lpm; -}; - -/** - * struct dsi_ctrl_cmd_dma_fifo_info - command payload tp be sent using FIFO - * @command: VA for command buffer. - * @size: Size of the command buffer. - * @en_broadcast: Enable broadcast mode if set to true. - * @is_master: Is master in broadcast mode. - * @use_lpm: Use low power mode for command transmission. - */ -struct dsi_ctrl_cmd_dma_fifo_info { - u32 *command; - u32 size; - bool en_broadcast; - bool is_master; - bool use_lpm; -}; - -struct dsi_ctrl_hw; - -/** - * struct dsi_ctrl_hw_ops - operations supported by dsi host hardware - */ -struct dsi_ctrl_hw_ops { - - /** - * host_setup() - Setup DSI host configuration - * @ctrl: Pointer to controller host hardware. - * @config: Configuration for DSI host controller - */ - void (*host_setup)(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *config); - - /** - * video_engine_en() - enable DSI video engine - * @ctrl: Pointer to controller host hardware. - * @on: Enable/disabel video engine. - */ - void (*video_engine_en)(struct dsi_ctrl_hw *ctrl, bool on); - - /** - * video_engine_setup() - Setup dsi host controller for video mode - * @ctrl: Pointer to controller host hardware. - * @common_cfg: Common configuration parameters. - * @cfg: Video mode configuration. - * - * Set up DSI video engine with a specific configuration. Controller and - * video engine are not enabled as part of this function. - */ - void (*video_engine_setup)(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *common_cfg, - struct dsi_video_engine_cfg *cfg); - - /** - * set_video_timing() - set up the timing for video frame - * @ctrl: Pointer to controller host hardware. - * @mode: Video mode information. - * - * Set up the video timing parameters for the DSI video mode operation. - */ - void (*set_video_timing)(struct dsi_ctrl_hw *ctrl, - struct dsi_mode_info *mode); - - /** - * cmd_engine_setup() - setup dsi host controller for command mode - * @ctrl: Pointer to the controller host hardware. - * @common_cfg: Common configuration parameters. - * @cfg: Command mode configuration. - * - * Setup DSI CMD engine with a specific configuration. Controller and - * command engine are not enabled as part of this function. - */ - void (*cmd_engine_setup)(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *common_cfg, - struct dsi_cmd_engine_cfg *cfg); - - /** - * ctrl_en() - enable DSI controller engine - * @ctrl: Pointer to the controller host hardware. - * @on: turn on/off the DSI controller engine. - */ - void (*ctrl_en)(struct dsi_ctrl_hw *ctrl, bool on); - - /** - * cmd_engine_en() - enable DSI controller command engine - * @ctrl: Pointer to the controller host hardware. - * @on: Turn on/off the DSI command engine. - */ - void (*cmd_engine_en)(struct dsi_ctrl_hw *ctrl, bool on); - - /** - * phy_sw_reset() - perform a soft reset on the PHY. - * @ctrl: Pointer to the controller host hardware. - */ - void (*phy_sw_reset)(struct dsi_ctrl_hw *ctrl); - - /** - * soft_reset() - perform a soft reset on DSI controller - * @ctrl: Pointer to the controller host hardware. - * - * The video, command and controller engines will be disable before the - * reset is triggered. These engines will not be enabled after the reset - * is complete. Caller must re-enable the engines. - * - * If the reset is done while MDP timing engine is turned on, the video - * enigne should be re-enabled only during the vertical blanking time. - */ - void (*soft_reset)(struct dsi_ctrl_hw *ctrl); - - /** - * setup_lane_map() - setup mapping between logical and physical lanes - * @ctrl: Pointer to the controller host hardware. - * @lane_map: Structure defining the mapping between DSI logical - * lanes and physical lanes. - */ - void (*setup_lane_map)(struct dsi_ctrl_hw *ctrl, - struct dsi_lane_mapping *lane_map); - - /** - * kickoff_command() - transmits commands stored in memory - * @ctrl: Pointer to the controller host hardware. - * @cmd: Command information. - * @flags: Modifiers for command transmission. - * - * The controller hardware is programmed with address and size of the - * command buffer. The transmission is kicked off if - * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is - * set, caller should make a separate call to trigger_command_dma() to - * transmit the command. - */ - void (*kickoff_command)(struct dsi_ctrl_hw *ctrl, - struct dsi_ctrl_cmd_dma_info *cmd, - u32 flags); - - /** - * kickoff_fifo_command() - transmits a command using FIFO in dsi - * hardware. - * @ctrl: Pointer to the controller host hardware. - * @cmd: Command information. - * @flags: Modifiers for command transmission. - * - * The controller hardware FIFO is programmed with command header and - * payload. The transmission is kicked off if - * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is - * set, caller should make a separate call to trigger_command_dma() to - * transmit the command. - */ - void (*kickoff_fifo_command)(struct dsi_ctrl_hw *ctrl, - struct dsi_ctrl_cmd_dma_fifo_info *cmd, - u32 flags); - - void (*reset_cmd_fifo)(struct dsi_ctrl_hw *ctrl); - /** - * trigger_command_dma() - trigger transmission of command buffer. - * @ctrl: Pointer to the controller host hardware. - * - * This trigger can be only used if there was a prior call to - * kickoff_command() of kickoff_fifo_command() with - * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag. - */ - void (*trigger_command_dma)(struct dsi_ctrl_hw *ctrl); - - /** - * get_cmd_read_data() - get data read from the peripheral - * @ctrl: Pointer to the controller host hardware. - * @rd_buf: Buffer where data will be read into. - * @total_read_len: Number of bytes to read. - */ - u32 (*get_cmd_read_data)(struct dsi_ctrl_hw *ctrl, - u8 *rd_buf, - u32 total_read_len); - - /** - * ulps_request() - request ulps entry for specified lanes - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes (enum dsi_data_lanes) which need - * to enter ULPS. - * - * Caller should check if lanes are in ULPS mode by calling - * get_lanes_in_ulps() operation. - */ - void (*ulps_request)(struct dsi_ctrl_hw *ctrl, u32 lanes); - - /** - * ulps_exit() - exit ULPS on specified lanes - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes (enum dsi_data_lanes) which need - * to exit ULPS. - * - * Caller should check if lanes are in active mode by calling - * get_lanes_in_ulps() operation. - */ - void (*ulps_exit)(struct dsi_ctrl_hw *ctrl, u32 lanes); - - /** - * clear_ulps_request() - clear ulps request once all lanes are active - * @ctrl: Pointer to controller host hardware. - * @lanes: ORed list of lanes (enum dsi_data_lanes). - * - * ULPS request should be cleared after the lanes have exited ULPS. - */ - void (*clear_ulps_request)(struct dsi_ctrl_hw *ctrl, u32 lanes); - - /** - * get_lanes_in_ulps() - returns the list of lanes in ULPS mode - * @ctrl: Pointer to the controller host hardware. - * - * Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS - * state. If 0 is returned, all the lanes are active. - * - * Return: List of lanes in ULPS state. - */ - u32 (*get_lanes_in_ulps)(struct dsi_ctrl_hw *ctrl); - - /** - * clamp_enable() - enable DSI clamps to keep PHY driving a stable link - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes which need to be clamped. - * @enable_ulps: TODO:?? - */ - void (*clamp_enable)(struct dsi_ctrl_hw *ctrl, - u32 lanes, - bool enable_ulps); - - /** - * clamp_disable() - disable DSI clamps - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes which need to have clamps released. - * @disable_ulps: TODO:?? - */ - void (*clamp_disable)(struct dsi_ctrl_hw *ctrl, - u32 lanes, - bool disable_ulps); - - /** - * get_interrupt_status() - returns the interrupt status - * @ctrl: Pointer to the controller host hardware. - * - * Returns the ORed list of interrupts(enum dsi_status_int_type) that - * are active. This list does not include any error interrupts. Caller - * should call get_error_status for error interrupts. - * - * Return: List of active interrupts. - */ - u32 (*get_interrupt_status)(struct dsi_ctrl_hw *ctrl); - - /** - * clear_interrupt_status() - clears the specified interrupts - * @ctrl: Pointer to the controller host hardware. - * @ints: List of interrupts to be cleared. - */ - void (*clear_interrupt_status)(struct dsi_ctrl_hw *ctrl, u32 ints); - - /** - * enable_status_interrupts() - enable the specified interrupts - * @ctrl: Pointer to the controller host hardware. - * @ints: List of interrupts to be enabled. - * - * Enables the specified interrupts. This list will override the - * previous interrupts enabled through this function. Caller has to - * maintain the state of the interrupts enabled. To disable all - * interrupts, set ints to 0. - */ - void (*enable_status_interrupts)(struct dsi_ctrl_hw *ctrl, u32 ints); - - /** - * get_error_status() - returns the error status - * @ctrl: Pointer to the controller host hardware. - * - * Returns the ORed list of errors(enum dsi_error_int_type) that are - * active. This list does not include any status interrupts. Caller - * should call get_interrupt_status for status interrupts. - * - * Return: List of active error interrupts. - */ - u64 (*get_error_status)(struct dsi_ctrl_hw *ctrl); - - /** - * clear_error_status() - clears the specified errors - * @ctrl: Pointer to the controller host hardware. - * @errors: List of errors to be cleared. - */ - void (*clear_error_status)(struct dsi_ctrl_hw *ctrl, u64 errors); - - /** - * enable_error_interrupts() - enable the specified interrupts - * @ctrl: Pointer to the controller host hardware. - * @errors: List of errors to be enabled. - * - * Enables the specified interrupts. This list will override the - * previous interrupts enabled through this function. Caller has to - * maintain the state of the interrupts enabled. To disable all - * interrupts, set errors to 0. - */ - void (*enable_error_interrupts)(struct dsi_ctrl_hw *ctrl, u64 errors); - - /** - * video_test_pattern_setup() - setup test pattern engine for video mode - * @ctrl: Pointer to the controller host hardware. - * @type: Type of test pattern. - * @init_val: Initial value to use for generating test pattern. - */ - void (*video_test_pattern_setup)(struct dsi_ctrl_hw *ctrl, - enum dsi_test_pattern type, - u32 init_val); - - /** - * cmd_test_pattern_setup() - setup test patttern engine for cmd mode - * @ctrl: Pointer to the controller host hardware. - * @type: Type of test pattern. - * @init_val: Initial value to use for generating test pattern. - * @stream_id: Stream Id on which packets are generated. - */ - void (*cmd_test_pattern_setup)(struct dsi_ctrl_hw *ctrl, - enum dsi_test_pattern type, - u32 init_val, - u32 stream_id); - - /** - * test_pattern_enable() - enable test pattern engine - * @ctrl: Pointer to the controller host hardware. - * @enable: Enable/Disable test pattern engine. - */ - void (*test_pattern_enable)(struct dsi_ctrl_hw *ctrl, bool enable); - - /** - * trigger_cmd_test_pattern() - trigger a command mode frame update with - * test pattern - * @ctrl: Pointer to the controller host hardware. - * @stream_id: Stream on which frame update is sent. - */ - void (*trigger_cmd_test_pattern)(struct dsi_ctrl_hw *ctrl, - u32 stream_id); -}; - -/* - * struct dsi_ctrl_hw - DSI controller hardware object specific to an instance - * @base: VA for the DSI controller base address. - * @length: Length of the DSI controller register map. - * @index: Instance ID of the controller. - * @feature_map: Features supported by the DSI controller. - * @ops: Function pointers to the operations supported by the - * controller. - */ -struct dsi_ctrl_hw { - void __iomem *base; - u32 length; - void __iomem *mmss_misc_base; - u32 mmss_misc_length; - u32 index; - - /* features */ - DECLARE_BITMAP(feature_map, DSI_CTRL_MAX_FEATURES); - struct dsi_ctrl_hw_ops ops; - - /* capabilities */ - u32 supported_interrupts; - u64 supported_errors; -}; - -#endif /* _DSI_CTRL_HW_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c deleted file mode 100644 index 8326024f76ec..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c +++ /dev/null @@ -1,1321 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "dsi-hw:" fmt -#include <linux/delay.h> - -#include "dsi_ctrl_hw.h" -#include "dsi_ctrl_reg_1_4.h" -#include "dsi_hw.h" - -#define MMSS_MISC_CLAMP_REG_OFF 0x0014 - -/* Unsupported formats default to RGB888 */ -static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { - 0x6, 0x7, 0x8, 0x8, 0x0, 0x3, 0x4 }; -static const u8 video_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { - 0x0, 0x1, 0x2, 0x3, 0x3, 0x3, 0x3 }; - - -/** - * dsi_setup_trigger_controls() - setup dsi trigger configurations - * @ctrl: Pointer to the controller host hardware. - * @cfg: DSI host configuration that is common to both video and - * command modes. - */ -static void dsi_setup_trigger_controls(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *cfg) -{ - u32 reg = 0; - const u8 trigger_map[DSI_TRIGGER_MAX] = { - 0x0, 0x2, 0x1, 0x4, 0x5, 0x6 }; - - reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0; - reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7); - reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4; - DSI_W32(ctrl, DSI_TRIG_CTRL, reg); -} - -/** - * dsi_ctrl_hw_14_host_setup() - setup dsi host configuration - * @ctrl: Pointer to the controller host hardware. - * @cfg: DSI host configuration that is common to both video and - * command modes. - */ -void dsi_ctrl_hw_14_host_setup(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *cfg) -{ - u32 reg_value = 0; - - dsi_setup_trigger_controls(ctrl, cfg); - - /* Setup clocking timing controls */ - reg_value = ((cfg->t_clk_post & 0x3F) << 8); - reg_value |= (cfg->t_clk_pre & 0x3F); - DSI_W32(ctrl, DSI_CLKOUT_TIMING_CTRL, reg_value); - - /* EOT packet control */ - reg_value = cfg->append_tx_eot ? 1 : 0; - reg_value |= (cfg->ignore_rx_eot ? (1 << 4) : 0); - DSI_W32(ctrl, DSI_EOT_PACKET_CTRL, reg_value); - - /* Turn on dsi clocks */ - DSI_W32(ctrl, DSI_CLK_CTRL, 0x23F); - - /* Setup DSI control register */ - reg_value = 0; - reg_value |= (cfg->en_crc_check ? BIT(24) : 0); - reg_value |= (cfg->en_ecc_check ? BIT(20) : 0); - reg_value |= BIT(8); /* Clock lane */ - reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_3) ? BIT(7) : 0); - reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_2) ? BIT(6) : 0); - reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_1) ? BIT(5) : 0); - reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_0) ? BIT(4) : 0); - - DSI_W32(ctrl, DSI_CTRL, reg_value); - - /* Enable Timing double buffering */ - DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1); - - pr_debug("[DSI_%d]Host configuration complete\n", ctrl->index); -} - -/** - * phy_sw_reset() - perform a soft reset on the PHY. - * @ctrl: Pointer to the controller host hardware. - */ -void dsi_ctrl_hw_14_phy_sw_reset(struct dsi_ctrl_hw *ctrl) -{ - DSI_W32(ctrl, DSI_PHY_SW_RESET, 0x1); - udelay(1000); - DSI_W32(ctrl, DSI_PHY_SW_RESET, 0x0); - udelay(100); - - pr_debug("[DSI_%d] phy sw reset done\n", ctrl->index); -} - -/** - * soft_reset() - perform a soft reset on DSI controller - * @ctrl: Pointer to the controller host hardware. - * - * The video, command and controller engines will be disable before the - * reset is triggered. These engines will not be enabled after the reset - * is complete. Caller must re-enable the engines. - * - * If the reset is done while MDP timing engine is turned on, the video - * enigne should be re-enabled only during the vertical blanking time. - */ -void dsi_ctrl_hw_14_soft_reset(struct dsi_ctrl_hw *ctrl) -{ - u32 reg = 0; - u32 reg_ctrl = 0; - - /* Clear DSI_EN, VIDEO_MODE_EN, CMD_MODE_EN */ - reg_ctrl = DSI_R32(ctrl, DSI_CTRL); - DSI_W32(ctrl, DSI_CTRL, reg_ctrl & ~0x7); - - /* Force enable PCLK, BYTECLK, AHBM_HCLK */ - reg = DSI_R32(ctrl, DSI_CLK_CTRL); - reg |= 0x23F; - DSI_W32(ctrl, DSI_CLK_CTRL, reg); - - /* Trigger soft reset */ - DSI_W32(ctrl, DSI_SOFT_RESET, 0x1); - udelay(1); - DSI_W32(ctrl, DSI_SOFT_RESET, 0x0); - - /* Disable force clock on */ - reg &= ~(BIT(20) | BIT(11)); - DSI_W32(ctrl, DSI_CLK_CTRL, reg); - - /* Re-enable DSI controller */ - DSI_W32(ctrl, DSI_CTRL, reg_ctrl); - pr_debug("[DSI_%d] ctrl soft reset done\n", ctrl->index); -} - -/** - * set_video_timing() - set up the timing for video frame - * @ctrl: Pointer to controller host hardware. - * @mode: Video mode information. - * - * Set up the video timing parameters for the DSI video mode operation. - */ -void dsi_ctrl_hw_14_set_video_timing(struct dsi_ctrl_hw *ctrl, - struct dsi_mode_info *mode) -{ - u32 reg = 0; - u32 hs_start = 0; - u32 hs_end, active_h_start, active_h_end, h_total; - u32 vs_start = 0, vs_end = 0; - u32 vpos_start = 0, vpos_end, active_v_start, active_v_end, v_total; - - hs_end = mode->h_sync_width; - active_h_start = mode->h_sync_width + mode->h_back_porch; - active_h_end = active_h_start + mode->h_active; - h_total = (mode->h_sync_width + mode->h_back_porch + mode->h_active + - mode->h_front_porch) - 1; - - vpos_end = mode->v_sync_width; - active_v_start = mode->v_sync_width + mode->v_back_porch; - active_v_end = active_v_start + mode->v_active; - v_total = (mode->v_sync_width + mode->v_back_porch + mode->v_active + - mode->v_front_porch) - 1; - - reg = ((active_h_end & 0xFFFF) << 16) | (active_h_start & 0xFFFF); - DSI_W32(ctrl, DSI_VIDEO_MODE_ACTIVE_H, reg); - - reg = ((active_v_end & 0xFFFF) << 16) | (active_v_start & 0xFFFF); - DSI_W32(ctrl, DSI_VIDEO_MODE_ACTIVE_V, reg); - - reg = ((v_total & 0xFFFF) << 16) | (h_total & 0xFFFF); - DSI_W32(ctrl, DSI_VIDEO_MODE_TOTAL, reg); - - reg = ((hs_end & 0xFFFF) << 16) | (hs_start & 0xFFFF); - DSI_W32(ctrl, DSI_VIDEO_MODE_HSYNC, reg); - - reg = ((vs_end & 0xFFFF) << 16) | (vs_start & 0xFFFF); - DSI_W32(ctrl, DSI_VIDEO_MODE_VSYNC, reg); - - reg = ((vpos_end & 0xFFFF) << 16) | (vpos_start & 0xFFFF); - DSI_W32(ctrl, DSI_VIDEO_MODE_VSYNC_VPOS, reg); - - /* TODO: HS TIMER value? */ - DSI_W32(ctrl, DSI_HS_TIMER_CTRL, 0x3FD08); - DSI_W32(ctrl, DSI_MISR_VIDEO_CTRL, 0x10100); - DSI_W32(ctrl, DSI_DSI_TIMING_FLUSH, 0x1); - pr_debug("[DSI_%d] ctrl video parameters updated\n", ctrl->index); -} - -/** - * video_engine_setup() - Setup dsi host controller for video mode - * @ctrl: Pointer to controller host hardware. - * @common_cfg: Common configuration parameters. - * @cfg: Video mode configuration. - * - * Set up DSI video engine with a specific configuration. Controller and - * video engine are not enabled as part of this function. - */ -void dsi_ctrl_hw_14_video_engine_setup(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *common_cfg, - struct dsi_video_engine_cfg *cfg) -{ - u32 reg = 0; - - reg |= (cfg->last_line_interleave_en ? BIT(31) : 0); - reg |= (cfg->pulse_mode_hsa_he ? BIT(28) : 0); - reg |= (cfg->hfp_lp11_en ? BIT(24) : 0); - reg |= (cfg->hbp_lp11_en ? BIT(20) : 0); - reg |= (cfg->hsa_lp11_en ? BIT(16) : 0); - reg |= (cfg->eof_bllp_lp11_en ? BIT(15) : 0); - reg |= (cfg->bllp_lp11_en ? BIT(12) : 0); - reg |= (cfg->traffic_mode & 0x3) << 8; - reg |= (cfg->vc_id & 0x3); - reg |= (video_mode_format_map[common_cfg->dst_format] & 0x3) << 4; - DSI_W32(ctrl, DSI_VIDEO_MODE_CTRL, reg); - - reg = (common_cfg->swap_mode & 0x7) << 12; - reg |= (common_cfg->bit_swap_red ? BIT(0) : 0); - reg |= (common_cfg->bit_swap_green ? BIT(4) : 0); - reg |= (common_cfg->bit_swap_blue ? BIT(8) : 0); - DSI_W32(ctrl, DSI_VIDEO_MODE_DATA_CTRL, reg); - - pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index); -} - -/** - * cmd_engine_setup() - setup dsi host controller for command mode - * @ctrl: Pointer to the controller host hardware. - * @common_cfg: Common configuration parameters. - * @cfg: Command mode configuration. - * - * Setup DSI CMD engine with a specific configuration. Controller and - * command engine are not enabled as part of this function. - */ -void dsi_ctrl_hw_14_cmd_engine_setup(struct dsi_ctrl_hw *ctrl, - struct dsi_host_common_cfg *common_cfg, - struct dsi_cmd_engine_cfg *cfg) -{ - u32 reg = 0; - - reg = (cfg->max_cmd_packets_interleave & 0xF) << 20; - reg |= (common_cfg->bit_swap_red ? BIT(4) : 0); - reg |= (common_cfg->bit_swap_green ? BIT(8) : 0); - reg |= (common_cfg->bit_swap_blue ? BIT(12) : 0); - reg |= cmd_mode_format_map[common_cfg->dst_format]; - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL, reg); - - reg = cfg->wr_mem_start & 0xFF; - reg |= (cfg->wr_mem_continue & 0xFF) << 8; - reg |= (cfg->insert_dcs_command ? BIT(16) : 0); - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL, reg); - - pr_debug("[DSI_%d] Cmd engine setup done\n", ctrl->index); -} - -/** - * video_engine_en() - enable DSI video engine - * @ctrl: Pointer to controller host hardware. - * @on: Enable/disabel video engine. - */ -void dsi_ctrl_hw_14_video_engine_en(struct dsi_ctrl_hw *ctrl, bool on) -{ - u32 reg = 0; - - /* Set/Clear VIDEO_MODE_EN bit */ - reg = DSI_R32(ctrl, DSI_CTRL); - if (on) - reg |= BIT(1); - else - reg &= ~BIT(1); - - DSI_W32(ctrl, DSI_CTRL, reg); - - pr_debug("[DSI_%d] Video engine = %d\n", ctrl->index, on); -} - -/** - * ctrl_en() - enable DSI controller engine - * @ctrl: Pointer to the controller host hardware. - * @on: turn on/off the DSI controller engine. - */ -void dsi_ctrl_hw_14_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on) -{ - u32 reg = 0; - - /* Set/Clear DSI_EN bit */ - reg = DSI_R32(ctrl, DSI_CTRL); - if (on) - reg |= BIT(0); - else - reg &= ~BIT(0); - - DSI_W32(ctrl, DSI_CTRL, reg); - - pr_debug("[DSI_%d] Controller engine = %d\n", ctrl->index, on); -} - -/** - * cmd_engine_en() - enable DSI controller command engine - * @ctrl: Pointer to the controller host hardware. - * @on: Turn on/off the DSI command engine. - */ -void dsi_ctrl_hw_14_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on) -{ - u32 reg = 0; - - /* Set/Clear CMD_MODE_EN bit */ - reg = DSI_R32(ctrl, DSI_CTRL); - if (on) - reg |= BIT(2); - else - reg &= ~BIT(2); - - DSI_W32(ctrl, DSI_CTRL, reg); - - pr_debug("[DSI_%d] command engine = %d\n", ctrl->index, on); -} - -/** - * setup_lane_map() - setup mapping between logical and physical lanes - * @ctrl: Pointer to the controller host hardware. - * @lane_map: Structure defining the mapping between DSI logical - * lanes and physical lanes. - */ -void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl, - struct dsi_lane_mapping *lane_map) -{ - u32 reg_value = 0; - u32 lane_number = ((lane_map->physical_lane0 * 1000)+ - (lane_map->physical_lane1 * 100) + - (lane_map->physical_lane2 * 10) + - (lane_map->physical_lane3)); - - if (lane_number == 123) - reg_value = 0; - else if (lane_number == 3012) - reg_value = 1; - else if (lane_number == 2301) - reg_value = 2; - else if (lane_number == 1230) - reg_value = 3; - else if (lane_number == 321) - reg_value = 4; - else if (lane_number == 1032) - reg_value = 5; - else if (lane_number == 2103) - reg_value = 6; - else if (lane_number == 3210) - reg_value = 7; - - DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, reg_value); - - pr_debug("[DSI_%d] Lane swap setup complete\n", ctrl->index); -} - -/** - * kickoff_command() - transmits commands stored in memory - * @ctrl: Pointer to the controller host hardware. - * @cmd: Command information. - * @flags: Modifiers for command transmission. - * - * The controller hardware is programmed with address and size of the - * command buffer. The transmission is kicked off if - * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is - * set, caller should make a separate call to trigger_command_dma() to - * transmit the command. - */ -void dsi_ctrl_hw_14_kickoff_command(struct dsi_ctrl_hw *ctrl, - struct dsi_ctrl_cmd_dma_info *cmd, - u32 flags) -{ - u32 reg = 0; - - /*Set BROADCAST_EN and EMBEDDED_MODE */ - reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL); - if (cmd->en_broadcast) - reg |= BIT(31); - else - reg &= ~BIT(31); - - if (cmd->is_master) - reg |= BIT(30); - else - reg &= ~BIT(30); - - if (cmd->use_lpm) - reg |= BIT(26); - else - reg &= ~BIT(26); - - reg |= BIT(28); - DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); - - DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset); - DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->length & 0xFFFFFF)); - - /* wait for writes to complete before kick off */ - wmb(); - - if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) - DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); -} - -/** - * kickoff_fifo_command() - transmits a command using FIFO in dsi - * hardware. - * @ctrl: Pointer to the controller host hardware. - * @cmd: Command information. - * @flags: Modifiers for command transmission. - * - * The controller hardware FIFO is programmed with command header and - * payload. The transmission is kicked off if - * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is - * set, caller should make a separate call to trigger_command_dma() to - * transmit the command. - */ -void dsi_ctrl_hw_14_kickoff_fifo_command(struct dsi_ctrl_hw *ctrl, - struct dsi_ctrl_cmd_dma_fifo_info *cmd, - u32 flags) -{ - u32 reg = 0, i = 0; - u32 *ptr = cmd->command; - /* - * Set CMD_DMA_TPG_EN, TPG_DMA_FIFO_MODE and - * CMD_DMA_PATTERN_SEL = custom pattern stored in TPG DMA FIFO - */ - reg = (BIT(1) | BIT(2) | (0x3 << 16)); - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); - - /* - * Program the FIFO with command buffer. Hardware requires an extra - * DWORD (set to zero) if the length of command buffer is odd DWORDS. - */ - for (i = 0; i < cmd->size; i += 4) { - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL, *ptr); - ptr++; - } - - if ((cmd->size / 4) & 0x1) - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL, 0); - - /*Set BROADCAST_EN and EMBEDDED_MODE */ - reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL); - if (cmd->en_broadcast) - reg |= BIT(31); - else - reg &= ~BIT(31); - - if (cmd->is_master) - reg |= BIT(30); - else - reg &= ~BIT(30); - - if (cmd->use_lpm) - reg |= BIT(26); - else - reg &= ~BIT(26); - - reg |= BIT(28); - - DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); - - DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->size & 0xFFFFFFFF)); - /* Finish writes before command trigger */ - wmb(); - - if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) - DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); - - pr_debug("[DSI_%d]size=%d, trigger = %d\n", - ctrl->index, cmd->size, - (flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER) ? false : true); -} - -void dsi_ctrl_hw_14_reset_cmd_fifo(struct dsi_ctrl_hw *ctrl) -{ - /* disable cmd dma tpg */ - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, 0x0); - - DSI_W32(ctrl, DSI_TPG_DMA_FIFO_RESET, 0x1); - udelay(1); - DSI_W32(ctrl, DSI_TPG_DMA_FIFO_RESET, 0x0); -} - -/** - * trigger_command_dma() - trigger transmission of command buffer. - * @ctrl: Pointer to the controller host hardware. - * - * This trigger can be only used if there was a prior call to - * kickoff_command() of kickoff_fifo_command() with - * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag. - */ -void dsi_ctrl_hw_14_trigger_command_dma(struct dsi_ctrl_hw *ctrl) -{ - DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); - pr_debug("[DSI_%d] CMD DMA triggered\n", ctrl->index); -} - -/** - * get_cmd_read_data() - get data read from the peripheral - * @ctrl: Pointer to the controller host hardware. - * @rd_buf: Buffer where data will be read into. - * @total_read_len: Number of bytes to read. - * - * return: number of bytes read. - */ -u32 dsi_ctrl_hw_14_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, - u8 *rd_buf, - u32 read_offset, - u32 total_read_len) -{ - u32 *lp, *temp, data; - int i, j = 0, cnt; - u32 read_cnt; - u32 rx_byte = 0; - u32 repeated_bytes = 0; - u8 reg[16]; - u32 pkt_size = 0; - int buf_offset = read_offset; - - lp = (u32 *)rd_buf; - temp = (u32 *)reg; - cnt = (rx_byte + 3) >> 2; - - if (cnt > 4) - cnt = 4; - - if (rx_byte == 4) - read_cnt = 4; - else - read_cnt = pkt_size + 6; - - if (read_cnt > 16) { - int bytes_shifted; - - bytes_shifted = read_cnt - 16; - repeated_bytes = buf_offset - bytes_shifted; - } - - for (i = cnt - 1; i >= 0; i--) { - data = DSI_R32(ctrl, DSI_RDBK_DATA0 + i*4); - *temp++ = ntohl(data); - } - - for (i = repeated_bytes; i < 16; i++) - rd_buf[j++] = reg[i]; - - pr_debug("[DSI_%d] Read %d bytes\n", ctrl->index, j); - return j; -} -/** - * ulps_request() - request ulps entry for specified lanes - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes (enum dsi_data_lanes) which need - * to enter ULPS. - * - * Caller should check if lanes are in ULPS mode by calling - * get_lanes_in_ulps() operation. - */ -void dsi_ctrl_hw_14_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes) -{ - u32 reg = 0; - - if (lanes & DSI_CLOCK_LANE) - reg = BIT(4); - if (lanes & DSI_DATA_LANE_0) - reg |= BIT(0); - if (lanes & DSI_DATA_LANE_1) - reg |= BIT(1); - if (lanes & DSI_DATA_LANE_2) - reg |= BIT(2); - if (lanes & DSI_DATA_LANE_3) - reg |= BIT(3); - - DSI_W32(ctrl, DSI_LANE_CTRL, reg); - - pr_debug("[DSI_%d] ULPS requested for lanes 0x%x\n", ctrl->index, - lanes); -} - -/** - * ulps_exit() - exit ULPS on specified lanes - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes (enum dsi_data_lanes) which need - * to exit ULPS. - * - * Caller should check if lanes are in active mode by calling - * get_lanes_in_ulps() operation. - */ -void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes) -{ - u32 reg = 0; - - reg = DSI_R32(ctrl, DSI_LANE_CTRL); - if (lanes & DSI_CLOCK_LANE) - reg |= BIT(12); - if (lanes & DSI_DATA_LANE_0) - reg |= BIT(8); - if (lanes & DSI_DATA_LANE_1) - reg |= BIT(9); - if (lanes & DSI_DATA_LANE_2) - reg |= BIT(10); - if (lanes & DSI_DATA_LANE_3) - reg |= BIT(11); - - DSI_W32(ctrl, DSI_LANE_CTRL, reg); - - pr_debug("[DSI_%d] ULPS exit request for lanes=0x%x\n", - ctrl->index, lanes); -} - -/** - * clear_ulps_request() - clear ulps request once all lanes are active - * @ctrl: Pointer to controller host hardware. - * @lanes: ORed list of lanes (enum dsi_data_lanes). - * - * ULPS request should be cleared after the lanes have exited ULPS. - */ -void dsi_ctrl_hw_14_clear_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes) -{ - u32 reg = 0; - - reg = DSI_R32(ctrl, DSI_LANE_CTRL); - reg &= ~BIT(4); /* clock lane */ - if (lanes & DSI_DATA_LANE_0) - reg &= ~BIT(0); - if (lanes & DSI_DATA_LANE_1) - reg &= ~BIT(1); - if (lanes & DSI_DATA_LANE_2) - reg &= ~BIT(2); - if (lanes & DSI_DATA_LANE_3) - reg &= ~BIT(3); - - DSI_W32(ctrl, DSI_LANE_CTRL, reg); - /* - * HPG recommends separate writes for clearing ULPS_REQUEST and - * ULPS_EXIT. - */ - DSI_W32(ctrl, DSI_LANE_CTRL, 0x0); - - pr_debug("[DSI_%d] ULPS request cleared\n", ctrl->index); -} - -/** - * get_lanes_in_ulps() - returns the list of lanes in ULPS mode - * @ctrl: Pointer to the controller host hardware. - * - * Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS - * state. If 0 is returned, all the lanes are active. - * - * Return: List of lanes in ULPS state. - */ -u32 dsi_ctrl_hw_14_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl) -{ - u32 reg = 0; - u32 lanes = 0; - - reg = DSI_R32(ctrl, DSI_LANE_STATUS); - if (!(reg & BIT(8))) - lanes |= DSI_DATA_LANE_0; - if (!(reg & BIT(9))) - lanes |= DSI_DATA_LANE_1; - if (!(reg & BIT(10))) - lanes |= DSI_DATA_LANE_2; - if (!(reg & BIT(11))) - lanes |= DSI_DATA_LANE_3; - if (!(reg & BIT(12))) - lanes |= DSI_CLOCK_LANE; - - pr_debug("[DSI_%d] lanes in ulps = 0x%x\n", ctrl->index, lanes); - return lanes; -} - -/** - * clamp_enable() - enable DSI clamps to keep PHY driving a stable link - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes which need to be clamped. - * @enable_ulps: TODO:?? - */ -void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl, - u32 lanes, - bool enable_ulps) -{ - u32 clamp_reg = 0; - u32 bit_shift = 0; - u32 reg = 0; - - if (ctrl->index == 1) - bit_shift = 16; - - if (lanes & DSI_CLOCK_LANE) { - clamp_reg |= BIT(9); - if (enable_ulps) - clamp_reg |= BIT(8); - } - - if (lanes & DSI_DATA_LANE_0) { - clamp_reg |= BIT(7); - if (enable_ulps) - clamp_reg |= BIT(6); - } - - if (lanes & DSI_DATA_LANE_1) { - clamp_reg |= BIT(5); - if (enable_ulps) - clamp_reg |= BIT(4); - } - - if (lanes & DSI_DATA_LANE_2) { - clamp_reg |= BIT(3); - if (enable_ulps) - clamp_reg |= BIT(2); - } - - if (lanes & DSI_DATA_LANE_3) { - clamp_reg |= BIT(1); - if (enable_ulps) - clamp_reg |= BIT(0); - } - - clamp_reg |= BIT(15); /* Enable clamp */ - - reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); - reg |= (clamp_reg << bit_shift); - DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); - - - reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); - reg |= BIT(30); - DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); - - pr_debug("[DSI_%d] Clamps enabled for lanes=0x%x\n", ctrl->index, - lanes); -} - -/** - * clamp_disable() - disable DSI clamps - * @ctrl: Pointer to the controller host hardware. - * @lanes: ORed list of lanes which need to have clamps released. - * @disable_ulps: TODO:?? - */ -void dsi_ctrl_hw_14_clamp_disable(struct dsi_ctrl_hw *ctrl, - u32 lanes, - bool disable_ulps) -{ - u32 clamp_reg = 0; - u32 bit_shift = 0; - u32 reg = 0; - - if (ctrl->index == 1) - bit_shift = 16; - - if (lanes & DSI_CLOCK_LANE) { - clamp_reg |= BIT(9); - if (disable_ulps) - clamp_reg |= BIT(8); - } - - if (lanes & DSI_DATA_LANE_0) { - clamp_reg |= BIT(7); - if (disable_ulps) - clamp_reg |= BIT(6); - } - - if (lanes & DSI_DATA_LANE_1) { - clamp_reg |= BIT(5); - if (disable_ulps) - clamp_reg |= BIT(4); - } - - if (lanes & DSI_DATA_LANE_2) { - clamp_reg |= BIT(3); - if (disable_ulps) - clamp_reg |= BIT(2); - } - - if (lanes & DSI_DATA_LANE_3) { - clamp_reg |= BIT(1); - if (disable_ulps) - clamp_reg |= BIT(0); - } - - clamp_reg |= BIT(15); /* Enable clamp */ - clamp_reg <<= bit_shift; - - /* Disable PHY reset skip */ - reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); - reg &= ~BIT(30); - DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); - - reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); - reg &= ~(clamp_reg); - DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); - - pr_debug("[DSI_%d] Disable clamps for lanes=%d\n", ctrl->index, lanes); -} - -/** - * get_interrupt_status() - returns the interrupt status - * @ctrl: Pointer to the controller host hardware. - * - * Returns the ORed list of interrupts(enum dsi_status_int_type) that - * are active. This list does not include any error interrupts. Caller - * should call get_error_status for error interrupts. - * - * Return: List of active interrupts. - */ -u32 dsi_ctrl_hw_14_get_interrupt_status(struct dsi_ctrl_hw *ctrl) -{ - u32 reg = 0; - u32 ints = 0; - - reg = DSI_R32(ctrl, DSI_INT_CTRL); - - if (reg & BIT(0)) - ints |= DSI_CMD_MODE_DMA_DONE; - if (reg & BIT(8)) - ints |= DSI_CMD_FRAME_DONE; - if (reg & BIT(10)) - ints |= DSI_CMD_STREAM0_FRAME_DONE; - if (reg & BIT(12)) - ints |= DSI_CMD_STREAM1_FRAME_DONE; - if (reg & BIT(14)) - ints |= DSI_CMD_STREAM2_FRAME_DONE; - if (reg & BIT(16)) - ints |= DSI_VIDEO_MODE_FRAME_DONE; - if (reg & BIT(20)) - ints |= DSI_BTA_DONE; - if (reg & BIT(28)) - ints |= DSI_DYN_REFRESH_DONE; - if (reg & BIT(30)) - ints |= DSI_DESKEW_DONE; - - pr_debug("[DSI_%d] Interrupt status = 0x%x, INT_CTRL=0x%x\n", - ctrl->index, ints, reg); - return ints; -} - -/** - * clear_interrupt_status() - clears the specified interrupts - * @ctrl: Pointer to the controller host hardware. - * @ints: List of interrupts to be cleared. - */ -void dsi_ctrl_hw_14_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints) -{ - u32 reg = 0; - - if (ints & DSI_CMD_MODE_DMA_DONE) - reg |= BIT(0); - if (ints & DSI_CMD_FRAME_DONE) - reg |= BIT(8); - if (ints & DSI_CMD_STREAM0_FRAME_DONE) - reg |= BIT(10); - if (ints & DSI_CMD_STREAM1_FRAME_DONE) - reg |= BIT(12); - if (ints & DSI_CMD_STREAM2_FRAME_DONE) - reg |= BIT(14); - if (ints & DSI_VIDEO_MODE_FRAME_DONE) - reg |= BIT(16); - if (ints & DSI_BTA_DONE) - reg |= BIT(20); - if (ints & DSI_DYN_REFRESH_DONE) - reg |= BIT(28); - if (ints & DSI_DESKEW_DONE) - reg |= BIT(30); - - DSI_W32(ctrl, DSI_INT_CTRL, reg); - - pr_debug("[DSI_%d] Clear interrupts, ints = 0x%x, INT_CTRL=0x%x\n", - ctrl->index, ints, reg); -} - -/** - * enable_status_interrupts() - enable the specified interrupts - * @ctrl: Pointer to the controller host hardware. - * @ints: List of interrupts to be enabled. - * - * Enables the specified interrupts. This list will override the - * previous interrupts enabled through this function. Caller has to - * maintain the state of the interrupts enabled. To disable all - * interrupts, set ints to 0. - */ -void dsi_ctrl_hw_14_enable_status_interrupts(struct dsi_ctrl_hw *ctrl, u32 ints) -{ - u32 reg = 0; - - /* Do not change value of DSI_ERROR_MASK bit */ - reg |= (DSI_R32(ctrl, DSI_INT_CTRL) & BIT(25)); - if (ints & DSI_CMD_MODE_DMA_DONE) - reg |= BIT(1); - if (ints & DSI_CMD_FRAME_DONE) - reg |= BIT(9); - if (ints & DSI_CMD_STREAM0_FRAME_DONE) - reg |= BIT(11); - if (ints & DSI_CMD_STREAM1_FRAME_DONE) - reg |= BIT(13); - if (ints & DSI_CMD_STREAM2_FRAME_DONE) - reg |= BIT(15); - if (ints & DSI_VIDEO_MODE_FRAME_DONE) - reg |= BIT(17); - if (ints & DSI_BTA_DONE) - reg |= BIT(21); - if (ints & DSI_DYN_REFRESH_DONE) - reg |= BIT(29); - if (ints & DSI_DESKEW_DONE) - reg |= BIT(31); - - DSI_W32(ctrl, DSI_INT_CTRL, reg); - - pr_debug("[DSI_%d] Enable interrupts 0x%x, INT_CTRL=0x%x\n", - ctrl->index, ints, reg); -} - -/** - * get_error_status() - returns the error status - * @ctrl: Pointer to the controller host hardware. - * - * Returns the ORed list of errors(enum dsi_error_int_type) that are - * active. This list does not include any status interrupts. Caller - * should call get_interrupt_status for status interrupts. - * - * Return: List of active error interrupts. - */ -u64 dsi_ctrl_hw_14_get_error_status(struct dsi_ctrl_hw *ctrl) -{ - u32 dln0_phy_err; - u32 fifo_status; - u32 ack_error; - u32 timeout_errors; - u32 clk_error; - u32 dsi_status; - u64 errors = 0; - - dln0_phy_err = DSI_R32(ctrl, DSI_DLN0_PHY_ERR); - if (dln0_phy_err & BIT(0)) - errors |= DSI_DLN0_ESC_ENTRY_ERR; - if (dln0_phy_err & BIT(4)) - errors |= DSI_DLN0_ESC_SYNC_ERR; - if (dln0_phy_err & BIT(8)) - errors |= DSI_DLN0_LP_CONTROL_ERR; - if (dln0_phy_err & BIT(12)) - errors |= DSI_DLN0_LP0_CONTENTION; - if (dln0_phy_err & BIT(16)) - errors |= DSI_DLN0_LP1_CONTENTION; - - fifo_status = DSI_R32(ctrl, DSI_FIFO_STATUS); - if (fifo_status & BIT(7)) - errors |= DSI_CMD_MDP_FIFO_UNDERFLOW; - if (fifo_status & BIT(10)) - errors |= DSI_CMD_DMA_FIFO_UNDERFLOW; - if (fifo_status & BIT(18)) - errors |= DSI_DLN0_HS_FIFO_OVERFLOW; - if (fifo_status & BIT(19)) - errors |= DSI_DLN0_HS_FIFO_UNDERFLOW; - if (fifo_status & BIT(22)) - errors |= DSI_DLN1_HS_FIFO_OVERFLOW; - if (fifo_status & BIT(23)) - errors |= DSI_DLN1_HS_FIFO_UNDERFLOW; - if (fifo_status & BIT(26)) - errors |= DSI_DLN2_HS_FIFO_OVERFLOW; - if (fifo_status & BIT(27)) - errors |= DSI_DLN2_HS_FIFO_UNDERFLOW; - if (fifo_status & BIT(30)) - errors |= DSI_DLN3_HS_FIFO_OVERFLOW; - if (fifo_status & BIT(31)) - errors |= DSI_DLN3_HS_FIFO_UNDERFLOW; - - ack_error = DSI_R32(ctrl, DSI_ACK_ERR_STATUS); - if (ack_error & BIT(16)) - errors |= DSI_RDBK_SINGLE_ECC_ERR; - if (ack_error & BIT(17)) - errors |= DSI_RDBK_MULTI_ECC_ERR; - if (ack_error & BIT(20)) - errors |= DSI_RDBK_CRC_ERR; - if (ack_error & BIT(23)) - errors |= DSI_RDBK_INCOMPLETE_PKT; - if (ack_error & BIT(24)) - errors |= DSI_PERIPH_ERROR_PKT; - - timeout_errors = DSI_R32(ctrl, DSI_TIMEOUT_STATUS); - if (timeout_errors & BIT(0)) - errors |= DSI_HS_TX_TIMEOUT; - if (timeout_errors & BIT(4)) - errors |= DSI_LP_RX_TIMEOUT; - if (timeout_errors & BIT(8)) - errors |= DSI_BTA_TIMEOUT; - - clk_error = DSI_R32(ctrl, DSI_CLK_STATUS); - if (clk_error & BIT(16)) - errors |= DSI_PLL_UNLOCK; - - dsi_status = DSI_R32(ctrl, DSI_STATUS); - if (dsi_status & BIT(31)) - errors |= DSI_INTERLEAVE_OP_CONTENTION; - - pr_debug("[DSI_%d] Error status = 0x%llx, phy=0x%x, fifo=0x%x", - ctrl->index, errors, dln0_phy_err, fifo_status); - pr_debug("[DSI_%d] ack=0x%x, timeout=0x%x, clk=0x%x, dsi=0x%x\n", - ctrl->index, ack_error, timeout_errors, clk_error, dsi_status); - return errors; -} - -/** - * clear_error_status() - clears the specified errors - * @ctrl: Pointer to the controller host hardware. - * @errors: List of errors to be cleared. - */ -void dsi_ctrl_hw_14_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors) -{ - u32 dln0_phy_err = 0; - u32 fifo_status = 0; - u32 ack_error = 0; - u32 timeout_error = 0; - u32 clk_error = 0; - u32 dsi_status = 0; - u32 int_ctrl = 0; - - if (errors & DSI_RDBK_SINGLE_ECC_ERR) - ack_error |= BIT(16); - if (errors & DSI_RDBK_MULTI_ECC_ERR) - ack_error |= BIT(17); - if (errors & DSI_RDBK_CRC_ERR) - ack_error |= BIT(20); - if (errors & DSI_RDBK_INCOMPLETE_PKT) - ack_error |= BIT(23); - if (errors & DSI_PERIPH_ERROR_PKT) - ack_error |= BIT(24); - - if (errors & DSI_LP_RX_TIMEOUT) - timeout_error |= BIT(4); - if (errors & DSI_HS_TX_TIMEOUT) - timeout_error |= BIT(0); - if (errors & DSI_BTA_TIMEOUT) - timeout_error |= BIT(8); - - if (errors & DSI_PLL_UNLOCK) - clk_error |= BIT(16); - - if (errors & DSI_DLN0_LP0_CONTENTION) - dln0_phy_err |= BIT(12); - if (errors & DSI_DLN0_LP1_CONTENTION) - dln0_phy_err |= BIT(16); - if (errors & DSI_DLN0_ESC_ENTRY_ERR) - dln0_phy_err |= BIT(0); - if (errors & DSI_DLN0_ESC_SYNC_ERR) - dln0_phy_err |= BIT(4); - if (errors & DSI_DLN0_LP_CONTROL_ERR) - dln0_phy_err |= BIT(8); - - if (errors & DSI_CMD_DMA_FIFO_UNDERFLOW) - fifo_status |= BIT(10); - if (errors & DSI_CMD_MDP_FIFO_UNDERFLOW) - fifo_status |= BIT(7); - if (errors & DSI_DLN0_HS_FIFO_OVERFLOW) - fifo_status |= BIT(18); - if (errors & DSI_DLN1_HS_FIFO_OVERFLOW) - fifo_status |= BIT(22); - if (errors & DSI_DLN2_HS_FIFO_OVERFLOW) - fifo_status |= BIT(26); - if (errors & DSI_DLN3_HS_FIFO_OVERFLOW) - fifo_status |= BIT(30); - if (errors & DSI_DLN0_HS_FIFO_UNDERFLOW) - fifo_status |= BIT(19); - if (errors & DSI_DLN1_HS_FIFO_UNDERFLOW) - fifo_status |= BIT(23); - if (errors & DSI_DLN2_HS_FIFO_UNDERFLOW) - fifo_status |= BIT(27); - if (errors & DSI_DLN3_HS_FIFO_UNDERFLOW) - fifo_status |= BIT(31); - - if (errors & DSI_INTERLEAVE_OP_CONTENTION) - dsi_status |= BIT(31); - - DSI_W32(ctrl, DSI_DLN0_PHY_ERR, dln0_phy_err); - DSI_W32(ctrl, DSI_FIFO_STATUS, fifo_status); - DSI_W32(ctrl, DSI_ACK_ERR_STATUS, ack_error); - DSI_W32(ctrl, DSI_TIMEOUT_STATUS, timeout_error); - DSI_W32(ctrl, DSI_CLK_STATUS, clk_error); - DSI_W32(ctrl, DSI_STATUS, dsi_status); - - int_ctrl = DSI_R32(ctrl, DSI_INT_CTRL); - int_ctrl |= BIT(24); - DSI_W32(ctrl, DSI_INT_CTRL, int_ctrl); - pr_debug("[DSI_%d] clear errors = 0x%llx, phy=0x%x, fifo=0x%x", - ctrl->index, errors, dln0_phy_err, fifo_status); - pr_debug("[DSI_%d] ack=0x%x, timeout=0x%x, clk=0x%x, dsi=0x%x\n", - ctrl->index, ack_error, timeout_error, clk_error, dsi_status); -} - -/** - * enable_error_interrupts() - enable the specified interrupts - * @ctrl: Pointer to the controller host hardware. - * @errors: List of errors to be enabled. - * - * Enables the specified interrupts. This list will override the - * previous interrupts enabled through this function. Caller has to - * maintain the state of the interrupts enabled. To disable all - * interrupts, set errors to 0. - */ -void dsi_ctrl_hw_14_enable_error_interrupts(struct dsi_ctrl_hw *ctrl, - u64 errors) -{ - u32 int_ctrl = 0; - u32 int_mask0 = 0x7FFF3BFF; - - int_ctrl = DSI_R32(ctrl, DSI_INT_CTRL); - if (errors) - int_ctrl |= BIT(25); - else - int_ctrl &= ~BIT(25); - - if (errors & DSI_RDBK_SINGLE_ECC_ERR) - int_mask0 &= ~BIT(0); - if (errors & DSI_RDBK_MULTI_ECC_ERR) - int_mask0 &= ~BIT(1); - if (errors & DSI_RDBK_CRC_ERR) - int_mask0 &= ~BIT(2); - if (errors & DSI_RDBK_INCOMPLETE_PKT) - int_mask0 &= ~BIT(3); - if (errors & DSI_PERIPH_ERROR_PKT) - int_mask0 &= ~BIT(4); - - if (errors & DSI_LP_RX_TIMEOUT) - int_mask0 &= ~BIT(5); - if (errors & DSI_HS_TX_TIMEOUT) - int_mask0 &= ~BIT(6); - if (errors & DSI_BTA_TIMEOUT) - int_mask0 &= ~BIT(7); - - if (errors & DSI_PLL_UNLOCK) - int_mask0 &= ~BIT(28); - - if (errors & DSI_DLN0_LP0_CONTENTION) - int_mask0 &= ~BIT(24); - if (errors & DSI_DLN0_LP1_CONTENTION) - int_mask0 &= ~BIT(25); - if (errors & DSI_DLN0_ESC_ENTRY_ERR) - int_mask0 &= ~BIT(21); - if (errors & DSI_DLN0_ESC_SYNC_ERR) - int_mask0 &= ~BIT(22); - if (errors & DSI_DLN0_LP_CONTROL_ERR) - int_mask0 &= ~BIT(23); - - if (errors & DSI_CMD_DMA_FIFO_UNDERFLOW) - int_mask0 &= ~BIT(9); - if (errors & DSI_CMD_MDP_FIFO_UNDERFLOW) - int_mask0 &= ~BIT(11); - if (errors & DSI_DLN0_HS_FIFO_OVERFLOW) - int_mask0 &= ~BIT(16); - if (errors & DSI_DLN1_HS_FIFO_OVERFLOW) - int_mask0 &= ~BIT(17); - if (errors & DSI_DLN2_HS_FIFO_OVERFLOW) - int_mask0 &= ~BIT(18); - if (errors & DSI_DLN3_HS_FIFO_OVERFLOW) - int_mask0 &= ~BIT(19); - if (errors & DSI_DLN0_HS_FIFO_UNDERFLOW) - int_mask0 &= ~BIT(26); - if (errors & DSI_DLN1_HS_FIFO_UNDERFLOW) - int_mask0 &= ~BIT(27); - if (errors & DSI_DLN2_HS_FIFO_UNDERFLOW) - int_mask0 &= ~BIT(29); - if (errors & DSI_DLN3_HS_FIFO_UNDERFLOW) - int_mask0 &= ~BIT(30); - - if (errors & DSI_INTERLEAVE_OP_CONTENTION) - int_mask0 &= ~BIT(8); - - DSI_W32(ctrl, DSI_INT_CTRL, int_ctrl); - DSI_W32(ctrl, DSI_ERR_INT_MASK0, int_mask0); - - pr_debug("[DSI_%d] enable errors = 0x%llx, int_mask0=0x%x\n", - ctrl->index, errors, int_mask0); -} - -/** - * video_test_pattern_setup() - setup test pattern engine for video mode - * @ctrl: Pointer to the controller host hardware. - * @type: Type of test pattern. - * @init_val: Initial value to use for generating test pattern. - */ -void dsi_ctrl_hw_14_video_test_pattern_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_test_pattern type, - u32 init_val) -{ - u32 reg = 0; - - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_VIDEO_INIT_VAL, init_val); - - switch (type) { - case DSI_TEST_PATTERN_FIXED: - reg |= (0x2 << 4); - break; - case DSI_TEST_PATTERN_INC: - reg |= (0x1 << 4); - break; - case DSI_TEST_PATTERN_POLY: - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_VIDEO_POLY, 0xF0F0F); - break; - default: - break; - } - - DSI_W32(ctrl, DSI_TPG_MAIN_CONTROL, 0x100); - DSI_W32(ctrl, DSI_TPG_VIDEO_CONFIG, 0x5); - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); - - pr_debug("[DSI_%d] Video test pattern setup done\n", ctrl->index); -} - -/** - * cmd_test_pattern_setup() - setup test patttern engine for cmd mode - * @ctrl: Pointer to the controller host hardware. - * @type: Type of test pattern. - * @init_val: Initial value to use for generating test pattern. - * @stream_id: Stream Id on which packets are generated. - */ -void dsi_ctrl_hw_14_cmd_test_pattern_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_test_pattern type, - u32 init_val, - u32 stream_id) -{ - u32 reg = 0; - u32 init_offset; - u32 poly_offset; - u32 pattern_sel_shift; - - switch (stream_id) { - case 0: - init_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL0; - poly_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM0_POLY; - pattern_sel_shift = 8; - break; - case 1: - init_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL1; - poly_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM1_POLY; - pattern_sel_shift = 12; - break; - case 2: - init_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL2; - poly_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY; - pattern_sel_shift = 20; - break; - default: - return; - } - - DSI_W32(ctrl, init_offset, init_val); - - switch (type) { - case DSI_TEST_PATTERN_FIXED: - reg |= (0x2 << pattern_sel_shift); - break; - case DSI_TEST_PATTERN_INC: - reg |= (0x1 << pattern_sel_shift); - break; - case DSI_TEST_PATTERN_POLY: - DSI_W32(ctrl, poly_offset, 0xF0F0F); - break; - default: - break; - } - - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); - pr_debug("[DSI_%d] Cmd test pattern setup done\n", ctrl->index); -} - -/** - * test_pattern_enable() - enable test pattern engine - * @ctrl: Pointer to the controller host hardware. - * @enable: Enable/Disable test pattern engine. - */ -void dsi_ctrl_hw_14_test_pattern_enable(struct dsi_ctrl_hw *ctrl, - bool enable) -{ - u32 reg = DSI_R32(ctrl, DSI_TEST_PATTERN_GEN_CTRL); - - if (enable) - reg |= BIT(0); - else - reg &= ~BIT(0); - - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); - - pr_debug("[DSI_%d] Test pattern enable=%d\n", ctrl->index, enable); -} - -/** - * trigger_cmd_test_pattern() - trigger a command mode frame update with - * test pattern - * @ctrl: Pointer to the controller host hardware. - * @stream_id: Stream on which frame update is sent. - */ -void dsi_ctrl_hw_14_trigger_cmd_test_pattern(struct dsi_ctrl_hw *ctrl, - u32 stream_id) -{ - switch (stream_id) { - case 0: - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER, 0x1); - break; - case 1: - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_STREAM1_TRIGGER, 0x1); - break; - case 2: - DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_STREAM2_TRIGGER, 0x1); - break; - default: - break; - } - - pr_debug("[DSI_%d] Cmd Test pattern trigger\n", ctrl->index); -} diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg_1_4.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg_1_4.h deleted file mode 100644 index 028ad46664a7..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg_1_4.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DSI_CTRL_REG_H_ -#define _DSI_CTRL_REG_H_ - -#define DSI_HW_VERSION (0x0000) -#define DSI_CTRL (0x0004) -#define DSI_STATUS (0x0008) -#define DSI_FIFO_STATUS (0x000C) -#define DSI_VIDEO_MODE_CTRL (0x0010) -#define DSI_VIDEO_MODE_SYNC_DATATYPE (0x0014) -#define DSI_VIDEO_MODE_PIXEL_DATATYPE (0x0018) -#define DSI_VIDEO_MODE_BLANKING_DATATYPE (0x001C) -#define DSI_VIDEO_MODE_DATA_CTRL (0x0020) -#define DSI_VIDEO_MODE_ACTIVE_H (0x0024) -#define DSI_VIDEO_MODE_ACTIVE_V (0x0028) -#define DSI_VIDEO_MODE_TOTAL (0x002C) -#define DSI_VIDEO_MODE_HSYNC (0x0030) -#define DSI_VIDEO_MODE_VSYNC (0x0034) -#define DSI_VIDEO_MODE_VSYNC_VPOS (0x0038) -#define DSI_COMMAND_MODE_DMA_CTRL (0x003C) -#define DSI_COMMAND_MODE_MDP_CTRL (0x0040) -#define DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL (0x0044) -#define DSI_DMA_CMD_OFFSET (0x0048) -#define DSI_DMA_CMD_LENGTH (0x004C) -#define DSI_DMA_FIFO_CTRL (0x0050) -#define DSI_DMA_NULL_PACKET_DATA (0x0054) -#define DSI_COMMAND_MODE_MDP_STREAM0_CTRL (0x0058) -#define DSI_COMMAND_MODE_MDP_STREAM0_TOTAL (0x005C) -#define DSI_COMMAND_MODE_MDP_STREAM1_CTRL (0x0060) -#define DSI_COMMAND_MODE_MDP_STREAM1_TOTAL (0x0064) -#define DSI_ACK_ERR_STATUS (0x0068) -#define DSI_RDBK_DATA0 (0x006C) -#define DSI_RDBK_DATA1 (0x0070) -#define DSI_RDBK_DATA2 (0x0074) -#define DSI_RDBK_DATA3 (0x0078) -#define DSI_RDBK_DATATYPE0 (0x007C) -#define DSI_RDBK_DATATYPE1 (0x0080) -#define DSI_TRIG_CTRL (0x0084) -#define DSI_EXT_MUX (0x0088) -#define DSI_EXT_MUX_TE_PULSE_DETECT_CTRL (0x008C) -#define DSI_CMD_MODE_DMA_SW_TRIGGER (0x0090) -#define DSI_CMD_MODE_MDP_SW_TRIGGER (0x0094) -#define DSI_CMD_MODE_BTA_SW_TRIGGER (0x0098) -#define DSI_RESET_SW_TRIGGER (0x009C) -#define DSI_MISR_CMD_CTRL (0x00A0) -#define DSI_MISR_VIDEO_CTRL (0x00A4) -#define DSI_LANE_STATUS (0x00A8) -#define DSI_LANE_CTRL (0x00AC) -#define DSI_LANE_SWAP_CTRL (0x00B0) -#define DSI_DLN0_PHY_ERR (0x00B4) -#define DSI_LP_TIMER_CTRL (0x00B8) -#define DSI_HS_TIMER_CTRL (0x00BC) -#define DSI_TIMEOUT_STATUS (0x00C0) -#define DSI_CLKOUT_TIMING_CTRL (0x00C4) -#define DSI_EOT_PACKET (0x00C8) -#define DSI_EOT_PACKET_CTRL (0x00CC) -#define DSI_GENERIC_ESC_TX_TRIGGER (0x00D0) -#define DSI_CAM_BIST_CTRL (0x00D4) -#define DSI_CAM_BIST_FRAME_SIZE (0x00D8) -#define DSI_CAM_BIST_BLOCK_SIZE (0x00DC) -#define DSI_CAM_BIST_FRAME_CONFIG (0x00E0) -#define DSI_CAM_BIST_LSFR_CTRL (0x00E4) -#define DSI_CAM_BIST_LSFR_INIT (0x00E8) -#define DSI_CAM_BIST_START (0x00EC) -#define DSI_CAM_BIST_STATUS (0x00F0) -#define DSI_ERR_INT_MASK0 (0x010C) -#define DSI_INT_CTRL (0x0110) -#define DSI_IOBIST_CTRL (0x0114) -#define DSI_SOFT_RESET (0x0118) -#define DSI_CLK_CTRL (0x011C) -#define DSI_CLK_STATUS (0x0120) -#define DSI_PHY_SW_RESET (0x012C) -#define DSI_AXI2AHB_CTRL (0x0130) -#define DSI_MISR_CMD_MDP0_32BIT (0x0134) -#define DSI_MISR_CMD_MDP1_32BIT (0x0138) -#define DSI_MISR_CMD_DMA_32BIT (0x013C) -#define DSI_MISR_VIDEO_32BIT (0x0140) -#define DSI_LANE_MISR_CTRL (0x0144) -#define DSI_LANE0_MISR (0x0148) -#define DSI_LANE1_MISR (0x014C) -#define DSI_LANE2_MISR (0x0150) -#define DSI_LANE3_MISR (0x0154) -#define DSI_TEST_PATTERN_GEN_CTRL (0x015C) -#define DSI_TEST_PATTERN_GEN_VIDEO_POLY (0x0160) -#define DSI_TEST_PATTERN_GEN_VIDEO_INIT_VAL (0x0164) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM0_POLY (0x0168) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL0 (0x016C) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM1_POLY (0x0170) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL1 (0x0174) -#define DSI_TEST_PATTERN_GEN_CMD_DMA_POLY (0x0178) -#define DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL (0x017C) -#define DSI_TEST_PATTERN_GEN_VIDEO_ENABLE (0x0180) -#define DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER (0x0184) -#define DSI_TEST_PATTERN_GEN_CMD_STREAM1_TRIGGER (0x0188) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL2 (0x018C) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY (0x0190) -#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY (0x0190) -#define DSI_COMMAND_MODE_MDP_IDLE_CTRL (0x0194) -#define DSI_TEST_PATTERN_GEN_CMD_STREAM2_TRIGGER (0x0198) -#define DSI_TPG_MAIN_CONTROL (0x019C) -#define DSI_TPG_MAIN_CONTROL2 (0x01A0) -#define DSI_TPG_VIDEO_CONFIG (0x01A4) -#define DSI_TPG_COMPONENT_LIMITS (0x01A8) -#define DSI_TPG_RECTANGLE (0x01AC) -#define DSI_TPG_BLACK_WHITE_PATTERN_FRAMES (0x01B0) -#define DSI_TPG_RGB_MAPPING (0x01B4) -#define DSI_COMMAND_MODE_MDP_CTRL2 (0x01B8) -#define DSI_COMMAND_MODE_MDP_STREAM2_CTRL (0x01BC) -#define DSI_COMMAND_MODE_MDP_STREAM2_TOTAL (0x01C0) -#define DSI_MISR_CMD_MDP2_8BIT (0x01C4) -#define DSI_MISR_CMD_MDP2_32BIT (0x01C8) -#define DSI_VBIF_CTRL (0x01CC) -#define DSI_AES_CTRL (0x01D0) -#define DSI_RDBK_DATA_CTRL (0x01D4) -#define DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2 (0x01D8) -#define DSI_TPG_DMA_FIFO_STATUS (0x01DC) -#define DSI_TPG_DMA_FIFO_WRITE_TRIGGER (0x01E0) -#define DSI_DSI_TIMING_FLUSH (0x01E4) -#define DSI_DSI_TIMING_DB_MODE (0x01E8) -#define DSI_TPG_DMA_FIFO_RESET (0x01EC) -#define DSI_SCRATCH_REGISTER_0 (0x01F0) -#define DSI_VERSION (0x01F4) -#define DSI_SCRATCH_REGISTER_1 (0x01F8) -#define DSI_SCRATCH_REGISTER_2 (0x01FC) -#define DSI_DYNAMIC_REFRESH_CTRL (0x0200) -#define DSI_DYNAMIC_REFRESH_PIPE_DELAY (0x0204) -#define DSI_DYNAMIC_REFRESH_PIPE_DELAY2 (0x0208) -#define DSI_DYNAMIC_REFRESH_PLL_DELAY (0x020C) -#define DSI_DYNAMIC_REFRESH_STATUS (0x0210) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x0214) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x0218) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x021C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x0220) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x0224) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x0228) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x022C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x0230) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x0234) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x0238) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x023C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x0240) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x0244) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x0248) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x024C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x0250) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x0254) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x0258) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x025C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x0260) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x0264) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x0268) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x026C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x0270) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x0274) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x0278) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x027C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x0280) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x0284) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x0288) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x028C) -#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x0290) -#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x0294) -#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x0298) -#define DSI_VIDEO_COMPRESSION_MODE_CTRL (0x02A0) -#define DSI_VIDEO_COMPRESSION_MODE_CTRL2 (0x02A4) -#define DSI_COMMAND_COMPRESSION_MODE_CTRL (0x02A8) -#define DSI_COMMAND_COMPRESSION_MODE_CTRL2 (0x02AC) -#define DSI_COMMAND_COMPRESSION_MODE_CTRL3 (0x02B0) -#define DSI_COMMAND_MODE_NULL_INSERTION_CTRL (0x02B4) -#define DSI_READ_BACK_DISABLE_STATUS (0x02B8) -#define DSI_DESKEW_CTRL (0x02BC) -#define DSI_DESKEW_DELAY_CTRL (0x02C0) -#define DSI_DESKEW_SW_TRIGGER (0x02C4) -#define DSI_SECURE_DISPLAY_STATUS (0x02CC) -#define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0) -#define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4) - - -#endif /* _DSI_CTRL_REG_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h deleted file mode 100644 index ded7ed3710ee..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DSI_DEFS_H_ -#define _DSI_DEFS_H_ - -#include <linux/types.h> - -#define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \ - ((t)->h_sync_width) + ((t)->h_front_porch)) - -#define DSI_V_TOTAL(t) (((t)->v_active) + ((t)->v_back_porch) + \ - ((t)->v_sync_width) + ((t)->v_front_porch)) - -/** - * enum dsi_pixel_format - DSI pixel formats - * @DSI_PIXEL_FORMAT_RGB565: - * @DSI_PIXEL_FORMAT_RGB666: - * @DSI_PIXEL_FORMAT_RGB666_LOOSE: - * @DSI_PIXEL_FORMAT_RGB888: - * @DSI_PIXEL_FORMAT_RGB111: - * @DSI_PIXEL_FORMAT_RGB332: - * @DSI_PIXEL_FORMAT_RGB444: - * @DSI_PIXEL_FORMAT_MAX: - */ -enum dsi_pixel_format { - DSI_PIXEL_FORMAT_RGB565 = 0, - DSI_PIXEL_FORMAT_RGB666, - DSI_PIXEL_FORMAT_RGB666_LOOSE, - DSI_PIXEL_FORMAT_RGB888, - DSI_PIXEL_FORMAT_RGB111, - DSI_PIXEL_FORMAT_RGB332, - DSI_PIXEL_FORMAT_RGB444, - DSI_PIXEL_FORMAT_MAX -}; - -/** - * enum dsi_op_mode - dsi operation mode - * @DSI_OP_VIDEO_MODE: DSI video mode operation - * @DSI_OP_CMD_MODE: DSI Command mode operation - * @DSI_OP_MODE_MAX: - */ -enum dsi_op_mode { - DSI_OP_VIDEO_MODE = 0, - DSI_OP_CMD_MODE, - DSI_OP_MODE_MAX -}; - -/** - * enum dsi_data_lanes - dsi physical lanes - * @DSI_DATA_LANE_0: Physical lane 0 - * @DSI_DATA_LANE_1: Physical lane 1 - * @DSI_DATA_LANE_2: Physical lane 2 - * @DSI_DATA_LANE_3: Physical lane 3 - * @DSI_CLOCK_LANE: Physical clock lane - */ -enum dsi_data_lanes { - DSI_DATA_LANE_0 = BIT(0), - DSI_DATA_LANE_1 = BIT(1), - DSI_DATA_LANE_2 = BIT(2), - DSI_DATA_LANE_3 = BIT(3), - DSI_CLOCK_LANE = BIT(4) -}; - -/** - * enum dsi_logical_lane - dsi logical lanes - * @DSI_LOGICAL_LANE_0: Logical lane 0 - * @DSI_LOGICAL_LANE_1: Logical lane 1 - * @DSI_LOGICAL_LANE_2: Logical lane 2 - * @DSI_LOGICAL_LANE_3: Logical lane 3 - * @DSI_LOGICAL_CLOCK_LANE: Clock lane - * @DSI_LANE_MAX: Maximum lanes supported - */ -enum dsi_logical_lane { - DSI_LOGICAL_LANE_0 = 0, - DSI_LOGICAL_LANE_1, - DSI_LOGICAL_LANE_2, - DSI_LOGICAL_LANE_3, - DSI_LOGICAL_CLOCK_LANE, - DSI_LANE_MAX -}; - -/** - * enum dsi_trigger_type - dsi trigger type - * @DSI_TRIGGER_NONE: No trigger. - * @DSI_TRIGGER_TE: TE trigger. - * @DSI_TRIGGER_SEOF: Start or End of frame. - * @DSI_TRIGGER_SW: Software trigger. - * @DSI_TRIGGER_SW_SEOF: Software trigger and start/end of frame. - * @DSI_TRIGGER_SW_TE: Software and TE triggers. - * @DSI_TRIGGER_MAX: Max trigger values. - */ -enum dsi_trigger_type { - DSI_TRIGGER_NONE = 0, - DSI_TRIGGER_TE, - DSI_TRIGGER_SEOF, - DSI_TRIGGER_SW, - DSI_TRIGGER_SW_SEOF, - DSI_TRIGGER_SW_TE, - DSI_TRIGGER_MAX -}; - -/** - * enum dsi_color_swap_mode - color swap mode - * @DSI_COLOR_SWAP_RGB: - * @DSI_COLOR_SWAP_RBG: - * @DSI_COLOR_SWAP_BGR: - * @DSI_COLOR_SWAP_BRG: - * @DSI_COLOR_SWAP_GRB: - * @DSI_COLOR_SWAP_GBR: - */ -enum dsi_color_swap_mode { - DSI_COLOR_SWAP_RGB = 0, - DSI_COLOR_SWAP_RBG, - DSI_COLOR_SWAP_BGR, - DSI_COLOR_SWAP_BRG, - DSI_COLOR_SWAP_GRB, - DSI_COLOR_SWAP_GBR -}; - -/** - * enum dsi_dfps_type - Dynamic FPS support type - * @DSI_DFPS_NONE: Dynamic FPS is not supported. - * @DSI_DFPS_SUSPEND_RESUME: - * @DSI_DFPS_IMMEDIATE_CLK: - * @DSI_DFPS_IMMEDIATE_HFP: - * @DSI_DFPS_IMMEDIATE_VFP: - * @DSI_DPFS_MAX: - */ -enum dsi_dfps_type { - DSI_DFPS_NONE = 0, - DSI_DFPS_SUSPEND_RESUME, - DSI_DFPS_IMMEDIATE_CLK, - DSI_DFPS_IMMEDIATE_HFP, - DSI_DFPS_IMMEDIATE_VFP, - DSI_DFPS_MAX -}; - -/** - * enum dsi_phy_type - DSI phy types - * @DSI_PHY_TYPE_DPHY: - * @DSI_PHY_TYPE_CPHY: - */ -enum dsi_phy_type { - DSI_PHY_TYPE_DPHY, - DSI_PHY_TYPE_CPHY -}; - -/** - * enum dsi_te_mode - dsi te source - * @DSI_TE_ON_DATA_LINK: TE read from DSI link - * @DSI_TE_ON_EXT_PIN: TE signal on an external GPIO - */ -enum dsi_te_mode { - DSI_TE_ON_DATA_LINK = 0, - DSI_TE_ON_EXT_PIN, -}; - -/** - * enum dsi_video_traffic_mode - video mode pixel transmission type - * @DSI_VIDEO_TRAFFIC_SYNC_PULSES: Non-burst mode with sync pulses. - * @DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS: Non-burst mode with sync start events. - * @DSI_VIDEO_TRAFFIC_BURST_MODE: Burst mode using sync start events. - */ -enum dsi_video_traffic_mode { - DSI_VIDEO_TRAFFIC_SYNC_PULSES = 0, - DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS, - DSI_VIDEO_TRAFFIC_BURST_MODE, -}; - -/** - * struct dsi_mode_info - video mode information dsi frame - * @h_active: Active width of one frame in pixels. - * @h_back_porch: Horizontal back porch in pixels. - * @h_sync_width: HSYNC width in pixels. - * @h_front_porch: Horizontal fron porch in pixels. - * @h_skew: - * @h_sync_polarity: Polarity of HSYNC (false is active low). - * @v_active: Active height of one frame in lines. - * @v_back_porch: Vertical back porch in lines. - * @v_sync_width: VSYNC width in lines. - * @v_front_porch: Vertical front porch in lines. - * @v_sync_polarity: Polarity of VSYNC (false is active low). - * @refresh_rate: Refresh rate in Hz. - */ -struct dsi_mode_info { - u32 h_active; - u32 h_back_porch; - u32 h_sync_width; - u32 h_front_porch; - u32 h_skew; - bool h_sync_polarity; - - u32 v_active; - u32 v_back_porch; - u32 v_sync_width; - u32 v_front_porch; - bool v_sync_polarity; - - u32 refresh_rate; -}; - -/** - * struct dsi_lane_mapping - Mapping between DSI logical and physical lanes - * @physical_lane0: Logical lane to which physical lane 0 is mapped. - * @physical_lane1: Logical lane to which physical lane 1 is mapped. - * @physical_lane2: Logical lane to which physical lane 2 is mapped. - * @physical_lane3: Logical lane to which physical lane 3 is mapped. - */ -struct dsi_lane_mapping { - enum dsi_logical_lane physical_lane0; - enum dsi_logical_lane physical_lane1; - enum dsi_logical_lane physical_lane2; - enum dsi_logical_lane physical_lane3; -}; - -/** - * struct dsi_host_common_cfg - Host configuration common to video and cmd mode - * @dst_format: Destination pixel format. - * @data_lanes: Physical data lanes to be enabled. - * @en_crc_check: Enable CRC checks. - * @en_ecc_check: Enable ECC checks. - * @te_mode: Source for TE signalling. - * @mdp_cmd_trigger: MDP frame update trigger for command mode. - * @dma_cmd_trigger: Command DMA trigger. - * @cmd_trigger_stream: Command mode stream to trigger. - * @bit_swap_read: Is red color bit swapped. - * @bit_swap_green: Is green color bit swapped. - * @bit_swap_blue: Is blue color bit swapped. - * @t_clk_post: Number of byte clock cycles that the transmitter shall - * continue sending after last data lane has transitioned - * to LP mode. - * @t_clk_pre: Number of byte clock cycles that the high spped clock - * shall be driven prior to data lane transitions from LP - * to HS mode. - * @ignore_rx_eot: Ignore Rx EOT packets if set to true. - * @append_tx_eot: Append EOT packets for forward transmissions if set to - * true. - */ -struct dsi_host_common_cfg { - enum dsi_pixel_format dst_format; - enum dsi_data_lanes data_lanes; - bool en_crc_check; - bool en_ecc_check; - enum dsi_te_mode te_mode; - enum dsi_trigger_type mdp_cmd_trigger; - enum dsi_trigger_type dma_cmd_trigger; - u32 cmd_trigger_stream; - enum dsi_color_swap_mode swap_mode; - bool bit_swap_red; - bool bit_swap_green; - bool bit_swap_blue; - u32 t_clk_post; - u32 t_clk_pre; - bool ignore_rx_eot; - bool append_tx_eot; -}; - -/** - * struct dsi_video_engine_cfg - DSI video engine configuration - * @host_cfg: Pointer to host common configuration. - * @last_line_interleave_en: Allow command mode op interleaved on last line of - * video stream. - * @pulse_mode_hsa_he: Send HSA and HE following VS/VE packet if set to - * true. - * @hfp_lp11_en: Enter low power stop mode (LP-11) during HFP. - * @hbp_lp11_en: Enter low power stop mode (LP-11) during HBP. - * @hsa_lp11_en: Enter low power stop mode (LP-11) during HSA. - * @eof_bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP of - * last line of a frame. - * @bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP. - * @traffic_mode: Traffic mode for video stream. - * @vc_id: Virtual channel identifier. - */ -struct dsi_video_engine_cfg { - bool last_line_interleave_en; - bool pulse_mode_hsa_he; - bool hfp_lp11_en; - bool hbp_lp11_en; - bool hsa_lp11_en; - bool eof_bllp_lp11_en; - bool bllp_lp11_en; - enum dsi_video_traffic_mode traffic_mode; - u32 vc_id; -}; - -/** - * struct dsi_cmd_engine_cfg - DSI command engine configuration - * @host_cfg: Pointer to host common configuration. - * @host_cfg: Common host configuration - * @max_cmd_packets_interleave Maximum number of command mode RGB packets to - * send with in one horizontal blanking period - * of the video mode frame. - * @wr_mem_start: DCS command for write_memory_start. - * @wr_mem_continue: DCS command for write_memory_continue. - * @insert_dcs_command: Insert DCS command as first byte of payload - * of the pixel data. - */ -struct dsi_cmd_engine_cfg { - u32 max_cmd_packets_interleave; - u32 wr_mem_start; - u32 wr_mem_continue; - bool insert_dcs_command; -}; - -/** - * struct dsi_host_config - DSI host configuration parameters. - * @panel_mode: Operation mode for panel (video or cmd mode). - * @common_config: Host configuration common to both Video and Cmd mode. - * @video_engine: Video engine configuration if panel is in video mode. - * @cmd_engine: Cmd engine configuration if panel is in cmd mode. - * @esc_clk_rate_khz: Esc clock frequency in Hz. - * @bit_clk_rate_hz: Bit clock frequency in Hz. - * @video_timing: Video timing information of a frame. - * @lane_map: Mapping between logical and physical lanes. - * @phy_type: PHY type to be used. - */ -struct dsi_host_config { - enum dsi_op_mode panel_mode; - struct dsi_host_common_cfg common_config; - union { - struct dsi_video_engine_cfg video_engine; - struct dsi_cmd_engine_cfg cmd_engine; - } u; - u64 esc_clk_rate_hz; - u64 bit_clk_rate_hz; - struct dsi_mode_info video_timing; - struct dsi_lane_mapping lane_map; -}; - -/** - * struct dsi_display_mode - specifies mode for dsi display - * @timing: Timing parameters for the panel. - * @pixel_clk_khz: Pixel clock in Khz. - * @panel_mode: Panel operation mode. - * @flags: Additional flags. - */ -struct dsi_display_mode { - struct dsi_mode_info timing; - u32 pixel_clk_khz; - enum dsi_op_mode panel_mode; - - u32 flags; -}; - -#endif /* _DSI_DEFS_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h deleted file mode 100644 index 01535c02a7f8..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DSI_HW_H_ -#define _DSI_HW_H_ -#include <linux/io.h> - -#define DSI_R32(dsi_hw, off) readl_relaxed((dsi_hw)->base + (off)) -#define DSI_W32(dsi_hw, off, val) \ - do {\ - pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ - (dsi_hw)->index, #off, val); \ - writel_relaxed((val), (dsi_hw)->base + (off)); \ - } while (0) - -#define DSI_MMSS_MISC_R32(dsi_hw, off) \ - readl_relaxed((dsi_hw)->mmss_misc_base + (off)) -#define DSI_MMSS_MISC_W32(dsi_hw, off, val) \ - do {\ - pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ - (dsi_hw)->index, #off, val); \ - writel_relaxed((val), (dsi_hw)->mmss_misc_base + (off)); \ - } while (0) - -#define DSI_R64(dsi_hw, off) readq_relaxed((dsi_hw)->base + (off)) -#define DSI_W64(dsi_hw, off, val) writeq_relaxed((val), (dsi_hw)->base + (off)) - -#endif /* _DSI_HW_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h deleted file mode 100644 index 5edfd5e62738..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _DSI_PHY_HW_H_ -#define _DSI_PHY_HW_H_ - -#include "dsi_defs.h" - -#define DSI_MAX_SETTINGS 8 - -/** - * enum dsi_phy_version - DSI PHY version enumeration - * @DSI_PHY_VERSION_UNKNOWN: Unknown version. - * @DSI_PHY_VERSION_1_0: 28nm-HPM. - * @DSI_PHY_VERSION_2_0: 28nm-LPM. - * @DSI_PHY_VERSION_3_0: 20nm. - * @DSI_PHY_VERSION_4_0: 14nm. - * @DSI_PHY_VERSION_MAX: - */ -enum dsi_phy_version { - DSI_PHY_VERSION_UNKNOWN, - DSI_PHY_VERSION_1_0, /* 28nm-HPM */ - DSI_PHY_VERSION_2_0, /* 28nm-LPM */ - DSI_PHY_VERSION_3_0, /* 20nm */ - DSI_PHY_VERSION_4_0, /* 14nm */ - DSI_PHY_VERSION_MAX -}; - -/** - * enum dsi_phy_hw_features - features supported by DSI PHY hardware - * @DSI_PHY_DPHY: Supports DPHY - * @DSI_PHY_CPHY: Supports CPHY - */ -enum dsi_phy_hw_features { - DSI_PHY_DPHY, - DSI_PHY_CPHY, - DSI_PHY_MAX_FEATURES -}; - -/** - * enum dsi_phy_pll_source - pll clock source for PHY. - * @DSI_PLL_SOURCE_STANDALONE: Clock is sourced from native PLL and is not - * shared by other PHYs. - * @DSI_PLL_SOURCE_NATIVE: Clock is sourced from native PLL and is - * shared by other PHYs. - * @DSI_PLL_SOURCE_NON_NATIVE: Clock is sourced from other PHYs. - * @DSI_PLL_SOURCE_MAX: - */ -enum dsi_phy_pll_source { - DSI_PLL_SOURCE_STANDALONE = 0, - DSI_PLL_SOURCE_NATIVE, - DSI_PLL_SOURCE_NON_NATIVE, - DSI_PLL_SOURCE_MAX -}; - -/** - * struct dsi_phy_per_lane_cfgs - Holds register values for PHY parameters - * @lane: A set of maximum 8 values for each lane. - * @count_per_lane: Number of values per each lane. - */ -struct dsi_phy_per_lane_cfgs { - u8 lane[DSI_LANE_MAX][DSI_MAX_SETTINGS]; - u32 count_per_lane; -}; - -/** - * struct dsi_phy_cfg - DSI PHY configuration - * @lanecfg: Lane configuration settings. - * @strength: Strength settings for lanes. - * @timing: Timing parameters for lanes. - * @regulators: Regulator settings for lanes. - * @pll_source: PLL source. - */ -struct dsi_phy_cfg { - struct dsi_phy_per_lane_cfgs lanecfg; - struct dsi_phy_per_lane_cfgs strength; - struct dsi_phy_per_lane_cfgs timing; - struct dsi_phy_per_lane_cfgs regulators; - enum dsi_phy_pll_source pll_source; -}; - -struct dsi_phy_hw; - -/** - * struct dsi_phy_hw_ops - Operations for DSI PHY hardware. - * @regulator_enable: Enable PHY regulators. - * @regulator_disable: Disable PHY regulators. - * @enable: Enable PHY. - * @disable: Disable PHY. - * @calculate_timing_params: Calculate PHY timing params from mode information - */ -struct dsi_phy_hw_ops { - /** - * regulator_enable() - enable regulators for DSI PHY - * @phy: Pointer to DSI PHY hardware object. - * @reg_cfg: Regulator configuration for all DSI lanes. - */ - void (*regulator_enable)(struct dsi_phy_hw *phy, - struct dsi_phy_per_lane_cfgs *reg_cfg); - - /** - * regulator_disable() - disable regulators - * @phy: Pointer to DSI PHY hardware object. - */ - void (*regulator_disable)(struct dsi_phy_hw *phy); - - /** - * enable() - Enable PHY hardware - * @phy: Pointer to DSI PHY hardware object. - * @cfg: Per lane configurations for timing, strength and lane - * configurations. - */ - void (*enable)(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); - - /** - * disable() - Disable PHY hardware - * @phy: Pointer to DSI PHY hardware object. - */ - void (*disable)(struct dsi_phy_hw *phy); - - /** - * calculate_timing_params() - calculates timing parameters. - * @phy: Pointer to DSI PHY hardware object. - * @mode: Mode information for which timing has to be calculated. - * @config: DSI host configuration for this mode. - * @timing: Timing parameters for each lane which will be returned. - */ - int (*calculate_timing_params)(struct dsi_phy_hw *phy, - struct dsi_mode_info *mode, - struct dsi_host_common_cfg *config, - struct dsi_phy_per_lane_cfgs *timing); -}; - -/** - * struct dsi_phy_hw - DSI phy hardware object specific to an instance - * @base: VA for the DSI PHY base address. - * @length: Length of the DSI PHY register base map. - * @index: Instance ID of the controller. - * @version: DSI PHY version. - * @feature_map: Features supported by DSI PHY. - * @ops: Function pointer to PHY operations. - */ -struct dsi_phy_hw { - void __iomem *base; - u32 length; - u32 index; - - enum dsi_phy_version version; - - DECLARE_BITMAP(feature_map, DSI_PHY_MAX_FEATURES); - struct dsi_phy_hw_ops ops; -}; - -#endif /* _DSI_PHY_HW_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c deleted file mode 100644 index 512352d96f98..000000000000 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#define pr_fmt(fmt) "dsi-phy-hw:" fmt -#include <linux/math64.h> -#include <linux/delay.h> -#include "dsi_hw.h" -#include "dsi_phy_hw.h" - -#define DSIPHY_CMN_REVISION_ID0 0x0000 -#define DSIPHY_CMN_REVISION_ID1 0x0004 -#define DSIPHY_CMN_REVISION_ID2 0x0008 -#define DSIPHY_CMN_REVISION_ID3 0x000C -#define DSIPHY_CMN_CLK_CFG0 0x0010 -#define DSIPHY_CMN_CLK_CFG1 0x0014 -#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018 -#define DSIPHY_CMN_CTRL_0 0x001C -#define DSIPHY_CMN_CTRL_1 0x0020 -#define DSIPHY_CMN_CAL_HW_TRIGGER 0x0024 -#define DSIPHY_CMN_CAL_SW_CFG0 0x0028 -#define DSIPHY_CMN_CAL_SW_CFG1 0x002C -#define DSIPHY_CMN_CAL_SW_CFG2 0x0030 -#define DSIPHY_CMN_CAL_HW_CFG0 0x0034 -#define DSIPHY_CMN_CAL_HW_CFG1 0x0038 -#define DSIPHY_CMN_CAL_HW_CFG2 0x003C -#define DSIPHY_CMN_CAL_HW_CFG3 0x0040 -#define DSIPHY_CMN_CAL_HW_CFG4 0x0044 -#define DSIPHY_CMN_PLL_CNTRL 0x0048 -#define DSIPHY_CMN_LDO_CNTRL 0x004C - -#define DSIPHY_CMN_REGULATOR_CAL_STATUS0 0x0064 -#define DSIPHY_CMN_REGULATOR_CAL_STATUS1 0x0068 - -/* n = 0..3 for data lanes and n = 4 for clock lane */ -#define DSIPHY_DLNX_CFG0(n) (0x100 + ((n) * 0x80)) -#define DSIPHY_DLNX_CFG1(n) (0x104 + ((n) * 0x80)) -#define DSIPHY_DLNX_CFG2(n) (0x108 + ((n) * 0x80)) -#define DSIPHY_DLNX_CFG3(n) (0x10C + ((n) * 0x80)) -#define DSIPHY_DLNX_TEST_DATAPATH(n) (0x110 + ((n) * 0x80)) -#define DSIPHY_DLNX_TEST_STR(n) (0x114 + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_4(n) (0x118 + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_5(n) (0x11C + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_6(n) (0x120 + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_7(n) (0x124 + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_8(n) (0x128 + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_9(n) (0x12C + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_10(n) (0x130 + ((n) * 0x80)) -#define DSIPHY_DLNX_TIMING_CTRL_11(n) (0x134 + ((n) * 0x80)) -#define DSIPHY_DLNX_STRENGTH_CTRL_0(n) (0x138 + ((n) * 0x80)) -#define DSIPHY_DLNX_STRENGTH_CTRL_1(n) (0x13C + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_POLY(n) (0x140 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_SEED0(n) (0x144 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_SEED1(n) (0x148 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_HEAD(n) (0x14C + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_SOT(n) (0x150 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_CTRL0(n) (0x154 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_CTRL1(n) (0x158 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_CTRL2(n) (0x15C + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_CTRL3(n) (0x160 + ((n) * 0x80)) -#define DSIPHY_DLNX_VREG_CNTRL(n) (0x164 + ((n) * 0x80)) -#define DSIPHY_DLNX_HSTX_STR_STATUS(n) (0x168 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_STATUS0(n) (0x16C + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_STATUS1(n) (0x170 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_STATUS2(n) (0x174 + ((n) * 0x80)) -#define DSIPHY_DLNX_BIST_STATUS3(n) (0x178 + ((n) * 0x80)) -#define DSIPHY_DLNX_MISR_STATUS(n) (0x17C + ((n) * 0x80)) - -#define DSIPHY_PLL_CLKBUFLR_EN 0x041C -#define DSIPHY_PLL_PLL_BANDGAP 0x0508 - -/** - * struct timing_entry - Calculated values for each timing parameter. - * @mipi_min: - * @mipi_max: - * @rec_min: - * @rec_max: - * @rec: - * @reg_value: Value to be programmed in register. - */ -struct timing_entry { - s32 mipi_min; - s32 mipi_max; - s32 rec_min; - s32 rec_max; - s32 rec; - u8 reg_value; -}; - -/** - * struct phy_timing_desc - Timing parameters for DSI PHY. - */ -struct phy_timing_desc { - struct timing_entry clk_prepare; - struct timing_entry clk_zero; - struct timing_entry clk_trail; - struct timing_entry hs_prepare; - struct timing_entry hs_zero; - struct timing_entry hs_trail; - struct timing_entry hs_rqst; - struct timing_entry hs_rqst_clk; - struct timing_entry hs_exit; - struct timing_entry ta_go; - struct timing_entry ta_sure; - struct timing_entry ta_set; - struct timing_entry clk_post; - struct timing_entry clk_pre; -}; - -/** - * struct phy_clk_params - Clock parameters for PHY timing calculations. - */ -struct phy_clk_params { - u32 bitclk_mbps; - u32 escclk_numer; - u32 escclk_denom; - u32 tlpx_numer_ns; - u32 treot_ns; -}; - -/** - * regulator_enable() - enable regulators for DSI PHY - * @phy: Pointer to DSI PHY hardware object. - * @reg_cfg: Regulator configuration for all DSI lanes. - */ -void dsi_phy_hw_v4_0_regulator_enable(struct dsi_phy_hw *phy, - struct dsi_phy_per_lane_cfgs *reg_cfg) -{ - int i; - - for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) - DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(i), reg_cfg->lane[i][0]); - - /* make sure all values are written to hardware */ - wmb(); - - pr_debug("[DSI_%d] Phy regulators enabled\n", phy->index); -} - -/** - * regulator_disable() - disable regulators - * @phy: Pointer to DSI PHY hardware object. - */ -void dsi_phy_hw_v4_0_regulator_disable(struct dsi_phy_hw *phy) -{ - pr_debug("[DSI_%d] Phy regulators disabled\n", phy->index); -} - -/** - * enable() - Enable PHY hardware - * @phy: Pointer to DSI PHY hardware object. - * @cfg: Per lane configurations for timing, strength and lane - * configurations. - */ -void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, - struct dsi_phy_cfg *cfg) -{ - int i; - struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; - u32 data; - - DSI_W32(phy, DSIPHY_CMN_LDO_CNTRL, 0x1C); - - DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, 0x1); - for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { - - DSI_W32(phy, DSIPHY_DLNX_CFG0(i), cfg->lanecfg.lane[i][0]); - DSI_W32(phy, DSIPHY_DLNX_CFG1(i), cfg->lanecfg.lane[i][1]); - DSI_W32(phy, DSIPHY_DLNX_CFG2(i), cfg->lanecfg.lane[i][2]); - DSI_W32(phy, DSIPHY_DLNX_CFG3(i), cfg->lanecfg.lane[i][3]); - - DSI_W32(phy, DSIPHY_DLNX_TEST_STR(i), 0x88); - - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_4(i), timing->lane[i][0]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_5(i), timing->lane[i][1]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_6(i), timing->lane[i][2]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_7(i), timing->lane[i][3]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_8(i), timing->lane[i][4]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_9(i), timing->lane[i][5]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_10(i), timing->lane[i][6]); - DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_11(i), timing->lane[i][7]); - - DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_0(i), - cfg->strength.lane[i][0]); - DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_1(i), - cfg->strength.lane[i][1]); - } - - /* make sure all values are written to hardware before enabling phy */ - wmb(); - - DSI_W32(phy, DSIPHY_CMN_CTRL_1, 0x80); - udelay(100); - DSI_W32(phy, DSIPHY_CMN_CTRL_1, 0x00); - - data = DSI_R32(phy, DSIPHY_CMN_GLBL_TEST_CTRL); - - switch (cfg->pll_source) { - case DSI_PLL_SOURCE_STANDALONE: - DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0x01); - data &= ~BIT(2); - break; - case DSI_PLL_SOURCE_NATIVE: - DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0x03); - data &= ~BIT(2); - break; - case DSI_PLL_SOURCE_NON_NATIVE: - DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0x00); - data |= BIT(2); - break; - default: - break; - } - - DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, data); - - /* Enable bias current for pll1 during split display case */ - if (cfg->pll_source == DSI_PLL_SOURCE_NON_NATIVE) - DSI_W32(phy, DSIPHY_PLL_PLL_BANDGAP, 0x3); - - pr_debug("[DSI_%d]Phy enabled ", phy->index); -} - -/** - * disable() - Disable PHY hardware - * @phy: Pointer to DSI PHY hardware object. - */ -void dsi_phy_hw_v4_0_disable(struct dsi_phy_hw *phy) -{ - DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0); - DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, 0); - DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0); - pr_debug("[DSI_%d]Phy disabled ", phy->index); -} - -static const u32 bits_per_pixel[DSI_PIXEL_FORMAT_MAX] = { - 16, 18, 18, 24, 3, 8, 12 }; - -/** - * calc_clk_prepare - calculates prepare timing params for clk lane. - */ -static int calc_clk_prepare(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc, - s32 *actual_frac, - s64 *actual_intermediate) -{ - u32 const min_prepare_frac = 50; - u64 const multiplier = BIT(20); - - struct timing_entry *t = &desc->clk_prepare; - int rc = 0; - u64 dividend, temp, temp_multiple; - s32 frac = 0; - s64 intermediate; - s64 clk_prep_actual; - - dividend = ((t->rec_max - t->rec_min) * min_prepare_frac * multiplier); - temp = roundup(div_s64(dividend, 100), multiplier); - temp += (t->rec_min * multiplier); - t->rec = div_s64(temp, multiplier); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor clk_prepare\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - /* calculate theoretical value */ - temp_multiple = 8 * t->reg_value * clk_params->tlpx_numer_ns - * multiplier; - intermediate = div_s64(temp_multiple, clk_params->bitclk_mbps); - div_s64_rem(temp_multiple, clk_params->bitclk_mbps, &frac); - clk_prep_actual = div_s64((intermediate + frac), multiplier); - - pr_debug("CLK_PREPARE:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max); - pr_debug(" reg_value=%d, actual=%lld\n", t->reg_value, clk_prep_actual); - - *actual_frac = frac; - *actual_intermediate = intermediate; - - return rc; -} - -/** - * calc_clk_zero - calculates zero timing params for clk lane. - */ -static int calc_clk_zero(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc, - s32 actual_frac, - s64 actual_intermediate) -{ - u32 const clk_zero_min_frac = 2; - u64 const multiplier = BIT(20); - - int rc = 0; - struct timing_entry *t = &desc->clk_zero; - s64 mipi_min, rec_temp1, rec_temp2, rec_temp3, rec_min; - - mipi_min = ((300 * multiplier) - (actual_intermediate + actual_frac)); - t->mipi_min = div_s64(mipi_min, multiplier); - - rec_temp1 = div_s64((mipi_min * clk_params->bitclk_mbps), - clk_params->tlpx_numer_ns); - rec_temp2 = (rec_temp1 - (11 * multiplier)); - rec_temp3 = roundup(div_s64(rec_temp2, 8), multiplier); - rec_min = (div_s64(rec_temp3, multiplier) - 3); - t->rec_min = rec_min; - t->rec_max = ((t->rec_min > 255) ? 511 : 255); - - t->rec = DIV_ROUND_UP( - (((t->rec_max - t->rec_min) * clk_zero_min_frac) + - (t->rec_min * 100)), - 100); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor clk_zero\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - pr_debug("CLK_ZERO:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - return rc; -} - -/** - * calc_clk_trail - calculates prepare trail params for clk lane. - */ -static int calc_clk_trail(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc, - s64 *teot_clk_lane) -{ - u64 const multiplier = BIT(20); - u32 const phy_timing_frac = 30; - - int rc = 0; - struct timing_entry *t = &desc->clk_trail; - u64 temp_multiple; - s32 frac; - s64 mipi_max_tr, rec_temp1, rec_temp2, rec_temp3, mipi_max; - s64 teot_clk_lane1; - - temp_multiple = div_s64( - (12 * multiplier * clk_params->tlpx_numer_ns), - clk_params->bitclk_mbps); - div_s64_rem(temp_multiple, multiplier, &frac); - - mipi_max_tr = ((105 * multiplier) + - (temp_multiple + frac)); - teot_clk_lane1 = div_s64(mipi_max_tr, multiplier); - - mipi_max = (mipi_max_tr - (clk_params->treot_ns * multiplier)); - t->mipi_max = div_s64(mipi_max, multiplier); - - temp_multiple = div_s64( - (t->mipi_min * multiplier * clk_params->bitclk_mbps), - clk_params->tlpx_numer_ns); - - div_s64_rem(temp_multiple, multiplier, &frac); - rec_temp1 = temp_multiple + frac + (3 * multiplier); - rec_temp2 = div_s64(rec_temp1, 8); - rec_temp3 = roundup(rec_temp2, multiplier); - - t->rec_min = div_s64(rec_temp3, multiplier); - - /* recommended max */ - rec_temp1 = div_s64((mipi_max * clk_params->bitclk_mbps), - clk_params->tlpx_numer_ns); - rec_temp2 = rec_temp1 + (3 * multiplier); - rec_temp3 = rec_temp2 / 8; - t->rec_max = div_s64(rec_temp3, multiplier); - - t->rec = DIV_ROUND_UP( - (((t->rec_max - t->rec_min) * phy_timing_frac) + - (t->rec_min * 100)), - 100); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor clk_zero\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - *teot_clk_lane = teot_clk_lane1; - pr_debug("CLK_TRAIL:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - return rc; - -} - -/** - * calc_hs_prepare - calculates prepare timing params for data lanes in HS. - */ -static int calc_hs_prepare(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc, - u64 *temp_mul) -{ - u64 const multiplier = BIT(20); - u32 const min_prepare_frac = 50; - int rc = 0; - struct timing_entry *t = &desc->hs_prepare; - u64 temp_multiple, dividend, temp; - s32 frac; - s64 rec_temp1, rec_temp2, mipi_max, mipi_min; - u32 low_clk_multiplier = 0; - - if (clk_params->bitclk_mbps <= 120) - low_clk_multiplier = 2; - /* mipi min */ - temp_multiple = div_s64((4 * multiplier * clk_params->tlpx_numer_ns), - clk_params->bitclk_mbps); - div_s64_rem(temp_multiple, multiplier, &frac); - mipi_min = (40 * multiplier) + (temp_multiple + frac); - t->mipi_min = div_s64(mipi_min, multiplier); - - /* mipi_max */ - temp_multiple = div_s64( - (6 * multiplier * clk_params->tlpx_numer_ns), - clk_params->bitclk_mbps); - div_s64_rem(temp_multiple, multiplier, &frac); - mipi_max = (85 * multiplier) + temp_multiple; - t->mipi_max = div_s64(mipi_max, multiplier); - - /* recommended min */ - temp_multiple = div_s64((mipi_min * clk_params->bitclk_mbps), - clk_params->tlpx_numer_ns); - temp_multiple -= (low_clk_multiplier * multiplier); - div_s64_rem(temp_multiple, multiplier, &frac); - rec_temp1 = roundup(((temp_multiple + frac) / 8), multiplier); - t->rec_min = div_s64(rec_temp1, multiplier); - - /* recommended max */ - temp_multiple = div_s64((mipi_max * clk_params->bitclk_mbps), - clk_params->tlpx_numer_ns); - temp_multiple -= (low_clk_multiplier * multiplier); - div_s64_rem(temp_multiple, multiplier, &frac); - rec_temp2 = rounddown((temp_multiple / 8), multiplier); - t->rec_max = div_s64(rec_temp2, multiplier); - - /* register value */ - dividend = ((rec_temp2 - rec_temp1) * min_prepare_frac); - temp = roundup(div_u64(dividend, 100), multiplier); - t->rec = div_s64((temp + rec_temp1), multiplier); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor hs_prepare\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - temp_multiple = div_s64( - (8 * (temp + rec_temp1) * clk_params->tlpx_numer_ns), - clk_params->bitclk_mbps); - - *temp_mul = temp_multiple; - pr_debug("HS_PREP:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - return rc; -} - -/** - * calc_hs_zero - calculates zero timing params for data lanes in HS. - */ -static int calc_hs_zero(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc, - u64 temp_multiple) -{ - u32 const hs_zero_min_frac = 10; - u64 const multiplier = BIT(20); - int rc = 0; - struct timing_entry *t = &desc->hs_zero; - s64 rec_temp1, rec_temp2, rec_temp3, mipi_min; - s64 rec_min; - - mipi_min = div_s64((10 * clk_params->tlpx_numer_ns * multiplier), - clk_params->bitclk_mbps); - rec_temp1 = (145 * multiplier) + mipi_min - temp_multiple; - t->mipi_min = div_s64(rec_temp1, multiplier); - - /* recommended min */ - rec_temp1 = div_s64((rec_temp1 * clk_params->bitclk_mbps), - clk_params->tlpx_numer_ns); - rec_temp2 = rec_temp1 - (11 * multiplier); - rec_temp3 = roundup((rec_temp2 / 8), multiplier); - rec_min = rec_temp3 - (3 * multiplier); - t->rec_min = div_s64(rec_min, multiplier); - t->rec_max = ((t->rec_min > 255) ? 511 : 255); - - t->rec = DIV_ROUND_UP( - (((t->rec_max - t->rec_min) * hs_zero_min_frac) + - (t->rec_min * 100)), - 100); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor hs_zero\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - pr_debug("HS_ZERO:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - - return rc; -} - -/** - * calc_hs_trail - calculates trail timing params for data lanes in HS. - */ -static int calc_hs_trail(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc, - u64 teot_clk_lane) -{ - u32 const phy_timing_frac = 30; - int rc = 0; - struct timing_entry *t = &desc->hs_trail; - s64 rec_temp1; - - t->mipi_min = 60 + - mult_frac(clk_params->tlpx_numer_ns, 4, - clk_params->bitclk_mbps); - - t->mipi_max = teot_clk_lane - clk_params->treot_ns; - - t->rec_min = DIV_ROUND_UP( - ((t->mipi_min * clk_params->bitclk_mbps) + - (3 * clk_params->tlpx_numer_ns)), - (8 * clk_params->tlpx_numer_ns)); - - rec_temp1 = ((t->mipi_max * clk_params->bitclk_mbps) + - (3 * clk_params->tlpx_numer_ns)); - t->rec_max = (rec_temp1 / (8 * clk_params->tlpx_numer_ns)); - rec_temp1 = DIV_ROUND_UP( - ((t->rec_max - t->rec_min) * phy_timing_frac), - 100); - t->rec = rec_temp1 + t->rec_min; - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor hs_trail\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - pr_debug("HS_TRAIL:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - - return rc; -} - -/** - * calc_hs_rqst - calculates rqst timing params for data lanes in HS. - */ -static int calc_hs_rqst(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc) -{ - int rc = 0; - struct timing_entry *t = &desc->hs_rqst; - - t->rec = DIV_ROUND_UP( - ((t->mipi_min * clk_params->bitclk_mbps) - - (8 * clk_params->tlpx_numer_ns)), - (8 * clk_params->tlpx_numer_ns)); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor hs_rqst, %d\n", t->rec); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - pr_debug("HS_RQST:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - - return rc; -} - -/** - * calc_hs_exit - calculates exit timing params for data lanes in HS. - */ -static int calc_hs_exit(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc) -{ - u32 const hs_exit_min_frac = 10; - int rc = 0; - struct timing_entry *t = &desc->hs_exit; - - t->rec_min = (DIV_ROUND_UP( - (t->mipi_min * clk_params->bitclk_mbps), - (8 * clk_params->tlpx_numer_ns)) - 1); - - t->rec = DIV_ROUND_UP( - (((t->rec_max - t->rec_min) * hs_exit_min_frac) + - (t->rec_min * 100)), - 100); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor hs_exit\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - pr_debug("HS_EXIT:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - - return rc; -} - -/** - * calc_hs_rqst_clk - calculates rqst timing params for clock lane.. - */ -static int calc_hs_rqst_clk(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc) -{ - int rc = 0; - struct timing_entry *t = &desc->hs_rqst_clk; - - t->rec = DIV_ROUND_UP( - ((t->mipi_min * clk_params->bitclk_mbps) - - (8 * clk_params->tlpx_numer_ns)), - (8 * clk_params->tlpx_numer_ns)); - - if (t->rec & 0xffffff00) { - pr_err("Incorrect rec valuefor hs_rqst_clk\n"); - rc = -EINVAL; - } else { - t->reg_value = t->rec; - } - - pr_debug("HS_RQST_CLK:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", - t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, - t->reg_value); - - return rc; -} - -/** - * dsi_phy_calc_timing_params - calculates timing paramets for a given bit clock - */ -static int dsi_phy_calc_timing_params(struct phy_clk_params *clk_params, - struct phy_timing_desc *desc) -{ - int rc = 0; - s32 actual_frac = 0; - s64 actual_intermediate = 0; - u64 temp_multiple; - s64 teot_clk_lane; - - rc = calc_clk_prepare(clk_params, desc, &actual_frac, - &actual_intermediate); - if (rc) { - pr_err("clk_prepare calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_clk_zero(clk_params, desc, actual_frac, actual_intermediate); - if (rc) { - pr_err("clk_zero calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_clk_trail(clk_params, desc, &teot_clk_lane); - if (rc) { - pr_err("clk_trail calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_hs_prepare(clk_params, desc, &temp_multiple); - if (rc) { - pr_err("hs_prepare calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_hs_zero(clk_params, desc, temp_multiple); - if (rc) { - pr_err("hs_zero calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_hs_trail(clk_params, desc, teot_clk_lane); - if (rc) { - pr_err("hs_trail calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_hs_rqst(clk_params, desc); - if (rc) { - pr_err("hs_rqst calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_hs_exit(clk_params, desc); - if (rc) { - pr_err("hs_exit calculations failed, rc=%d\n", rc); - goto error; - } - - rc = calc_hs_rqst_clk(clk_params, desc); - if (rc) { - pr_err("hs_rqst_clk calculations failed, rc=%d\n", rc); - goto error; - } -error: - return rc; -} - -/** - * calculate_timing_params() - calculates timing parameters. - * @phy: Pointer to DSI PHY hardware object. - * @mode: Mode information for which timing has to be calculated. - * @config: DSI host configuration for this mode. - * @timing: Timing parameters for each lane which will be returned. - */ -int dsi_phy_hw_v4_0_calculate_timing_params(struct dsi_phy_hw *phy, - struct dsi_mode_info *mode, - struct dsi_host_common_cfg *host, - struct dsi_phy_per_lane_cfgs *timing) -{ - /* constants */ - u32 const esc_clk_mhz = 192; /* TODO: esc clock is hardcoded */ - u32 const esc_clk_mmss_cc_prediv = 10; - u32 const tlpx_numer = 1000; - u32 const tr_eot = 20; - u32 const clk_prepare_spec_min = 38; - u32 const clk_prepare_spec_max = 95; - u32 const clk_trail_spec_min = 60; - u32 const hs_exit_spec_min = 100; - u32 const hs_exit_reco_max = 255; - u32 const hs_rqst_spec_min = 50; - - /* local vars */ - int rc = 0; - int i; - u32 h_total, v_total; - u64 inter_num; - u32 num_of_lanes = 0; - u32 bpp; - u64 x, y; - struct phy_timing_desc desc; - struct phy_clk_params clk_params = {0}; - - memset(&desc, 0x0, sizeof(desc)); - h_total = DSI_H_TOTAL(mode); - v_total = DSI_V_TOTAL(mode); - - bpp = bits_per_pixel[host->dst_format]; - - inter_num = bpp * mode->refresh_rate; - - if (host->data_lanes & DSI_DATA_LANE_0) - num_of_lanes++; - if (host->data_lanes & DSI_DATA_LANE_1) - num_of_lanes++; - if (host->data_lanes & DSI_DATA_LANE_2) - num_of_lanes++; - if (host->data_lanes & DSI_DATA_LANE_3) - num_of_lanes++; - - - x = mult_frac(v_total * h_total, inter_num, num_of_lanes); - y = rounddown(x, 1); - - clk_params.bitclk_mbps = rounddown(mult_frac(y, 1, 1000000), 1); - clk_params.escclk_numer = esc_clk_mhz; - clk_params.escclk_denom = esc_clk_mmss_cc_prediv; - clk_params.tlpx_numer_ns = tlpx_numer; - clk_params.treot_ns = tr_eot; - - - /* Setup default parameters */ - desc.clk_prepare.mipi_min = clk_prepare_spec_min; - desc.clk_prepare.mipi_max = clk_prepare_spec_max; - desc.clk_trail.mipi_min = clk_trail_spec_min; - desc.hs_exit.mipi_min = hs_exit_spec_min; - desc.hs_exit.rec_max = hs_exit_reco_max; - - desc.clk_prepare.rec_min = DIV_ROUND_UP( - (desc.clk_prepare.mipi_min * clk_params.bitclk_mbps), - (8 * clk_params.tlpx_numer_ns) - ); - - desc.clk_prepare.rec_max = rounddown( - mult_frac((desc.clk_prepare.mipi_max * clk_params.bitclk_mbps), - 1, (8 * clk_params.tlpx_numer_ns)), - 1); - - desc.hs_rqst.mipi_min = hs_rqst_spec_min; - desc.hs_rqst_clk.mipi_min = hs_rqst_spec_min; - - pr_debug("BIT CLOCK = %d, tlpx_numer_ns=%d, treot_ns=%d\n", - clk_params.bitclk_mbps, clk_params.tlpx_numer_ns, - clk_params.treot_ns); - rc = dsi_phy_calc_timing_params(&clk_params, &desc); - if (rc) { - pr_err("Timing calc failed, rc=%d\n", rc); - goto error; - } - - - for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { - timing->lane[i][0] = desc.hs_exit.reg_value; - - if (i == DSI_LOGICAL_CLOCK_LANE) - timing->lane[i][1] = desc.clk_zero.reg_value; - else - timing->lane[i][1] = desc.hs_zero.reg_value; - - if (i == DSI_LOGICAL_CLOCK_LANE) - timing->lane[i][2] = desc.clk_prepare.reg_value; - else - timing->lane[i][2] = desc.hs_prepare.reg_value; - - if (i == DSI_LOGICAL_CLOCK_LANE) - timing->lane[i][3] = desc.clk_trail.reg_value; - else - timing->lane[i][3] = desc.hs_trail.reg_value; - - if (i == DSI_LOGICAL_CLOCK_LANE) - timing->lane[i][4] = desc.hs_rqst_clk.reg_value; - else - timing->lane[i][4] = desc.hs_rqst.reg_value; - - timing->lane[i][5] = 0x3; - timing->lane[i][6] = 0x4; - timing->lane[i][7] = 0xA0; - pr_debug("[%d][%d %d %d %d %d]\n", i, timing->lane[i][0], - timing->lane[i][1], - timing->lane[i][2], - timing->lane[i][3], - timing->lane[i][4]); - } - timing->count_per_lane = 8; - -error: - return rc; -} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 210cedb8134d..b532faa8026d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -595,8 +595,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdelay(16); if (config->platform.iommu) { - mmu = msm_smmu_new(&pdev->dev, - MSM_SMMU_DOMAIN_UNSECURE); + mmu = msm_iommu_new(&pdev->dev, config->platform.iommu); if (IS_ERR(mmu)) { ret = PTR_ERR(mmu); dev_err(dev->dev, "failed to init iommu: %d\n", ret); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 67c4518e22e1..b88ce514eb8e 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -235,20 +235,13 @@ static int msm_unload(struct drm_device *dev) return 0; } -#define KMS_MDP4 0 -#define KMS_MDP5 1 -#define KMS_SDE 2 - static int get_mdp_ver(struct platform_device *pdev) { #ifdef CONFIG_OF static const struct of_device_id match_types[] = { { .compatible = "qcom,mdss_mdp", - .data = (void *)KMS_MDP5, - }, - { - .compatible = "qcom,sde-kms", - .data = (void *)KMS_SDE, + .data = (void *)5, + }, { /* end node */ } }; struct device *dev = &pdev->dev; @@ -257,7 +250,7 @@ static int get_mdp_ver(struct platform_device *pdev) if (match) return (int)(unsigned long)match->data; #endif - return KMS_MDP4; + return 4; } #include <linux/of_address.h> @@ -376,15 +369,12 @@ static int msm_load(struct drm_device *dev, unsigned long flags) goto fail; switch (get_mdp_ver(pdev)) { - case KMS_MDP4: + case 4: kms = mdp4_kms_init(dev); break; - case KMS_MDP5: + case 5: kms = mdp5_kms_init(dev); break; - case KMS_SDE: - kms = sde_kms_init(dev); - break; default: kms = ERR_PTR(-ENODEV); break; @@ -1150,7 +1140,6 @@ static const struct platform_device_id msm_id[] = { static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp" }, /* mdp4 */ { .compatible = "qcom,mdss_mdp" }, /* mdp5 */ - { .compatible = "qcom,sde-kms" }, /* sde */ {} }; MODULE_DEVICE_TABLE(of, dt_match); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index e4ebc0fa2f51..3be7a56b14f1 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -55,12 +55,7 @@ struct msm_rd_state; struct msm_perf_state; struct msm_gem_submit; -#define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ -#define MAX_CRTCS 8 -#define MAX_PLANES 12 -#define MAX_ENCODERS 8 -#define MAX_BRIDGES 8 -#define MAX_CONNECTORS 8 +#define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ struct msm_file_private { /* currently we don't do anything useful with this.. but when @@ -133,19 +128,19 @@ struct msm_drm_private { struct msm_mmu *mmus[NUM_DOMAINS]; unsigned int num_planes; - struct drm_plane *planes[MAX_PLANES]; + struct drm_plane *planes[8]; unsigned int num_crtcs; - struct drm_crtc *crtcs[MAX_CRTCS]; + struct drm_crtc *crtcs[8]; unsigned int num_encoders; - struct drm_encoder *encoders[MAX_ENCODERS]; + struct drm_encoder *encoders[8]; unsigned int num_bridges; - struct drm_bridge *bridges[MAX_BRIDGES]; + struct drm_bridge *bridges[8]; unsigned int num_connectors; - struct drm_connector *connectors[MAX_CONNECTORS]; + struct drm_connector *connectors[8]; /* Properties */ struct drm_property *plane_property[PLANE_PROP_MAX_NUM]; diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 6fa56abf0c78..c76cc853b08a 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -295,23 +295,16 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, if (iommu_present(&platform_bus_type)) { struct msm_mmu *mmu = priv->mmus[id]; + uint32_t offset; if (WARN_ON(!mmu)) return -EINVAL; - if (obj->import_attach && mmu->funcs->map_dma_buf) { - ret = mmu->funcs->map_dma_buf(mmu, msm_obj->sgt, - obj->import_attach->dmabuf, - DMA_BIDIRECTIONAL); - if (ret) { - DRM_ERROR("Unable to map dma buf\n"); - return ret; - } - } - msm_obj->domain[id].iova = - sg_dma_address(msm_obj->sgt->sgl); + offset = (uint32_t)mmap_offset(obj); + ret = mmu->funcs->map(mmu, offset, msm_obj->sgt, + obj->size, IOMMU_READ | IOMMU_WRITE); + msm_obj->domain[id].iova = offset; } else { - WARN_ONCE(1, "physical address being used\n"); msm_obj->domain[id].iova = physaddr(obj); } } @@ -531,11 +524,8 @@ void msm_gem_free_object(struct drm_gem_object *obj) for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { struct msm_mmu *mmu = priv->mmus[id]; if (mmu && msm_obj->domain[id].iova) { - if (obj->import_attach && mmu->funcs->unmap_dma_buf) { - mmu->funcs->unmap_dma_buf(mmu, msm_obj->sgt, - obj->import_attach->dmabuf, - DMA_BIDIRECTIONAL); - } + uint32_t offset = msm_obj->domain[id].iova; + mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size); } } diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 2e4ae6b1c5d0..6fc59bfeedeb 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -53,7 +53,8 @@ struct msm_gem_object { void *vaddr; struct { - dma_addr_t iova; + // XXX + uint32_t iova; } domain[NUM_DOMAINS]; /* normally (resv == &_resv) except for imported bo's */ diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index f2e1a4fb9fae..9bcabaada179 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -76,6 +76,5 @@ static inline void msm_kms_init(struct msm_kms *kms, struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); -struct msm_kms *sde_kms_init(struct drm_device *dev); #endif /* __MSM_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 6d2f5627bfae..7cd88d9dc155 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -20,14 +20,6 @@ #include <linux/iommu.h> -struct msm_mmu; -struct msm_gpu; - -enum msm_mmu_domain_type { - MSM_SMMU_DOMAIN_UNSECURE, - MSM_SMMU_DOMAIN_MAX, -}; - struct msm_mmu_funcs { int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); void (*detach)(struct msm_mmu *mmu, const char **names, int cnt); @@ -35,14 +27,6 @@ struct msm_mmu_funcs { unsigned len, int prot); int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, unsigned len); - int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir); - void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir); - int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir); - void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir); void (*destroy)(struct msm_mmu *mmu); }; @@ -60,7 +44,5 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu); -struct msm_mmu *msm_smmu_new(struct device *dev, - enum msm_mmu_domain_type domain); #endif /* __MSM_MMU_H__ */ diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c deleted file mode 100644 index d51fbedf90c6..000000000000 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ /dev/null @@ -1,432 +0,0 @@ -/* 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 - * 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/module.h> -#include <linux/of_platform.h> -#include <linux/pm_runtime.h> -#include <linux/msm_dma_iommu_mapping.h> - -#include <asm/dma-iommu.h> -#include <soc/qcom/secure_buffer.h> - -#include "msm_drv.h" -#include "msm_mmu.h" - -struct msm_smmu_client { - struct device *dev; - struct dma_iommu_mapping *mmu_mapping; - bool domain_attached; -}; - -struct msm_smmu { - struct msm_mmu base; - struct device *client_dev; - struct msm_smmu_client client; -}; - -struct msm_smmu_domain { - const char *label; - size_t va_start; - size_t va_size; - bool secure; -}; - -#define to_msm_smmu(x) container_of(x, struct msm_smmu, base) -#define msm_smmu_to_client(smmu) (&smmu->client) - -static int _msm_smmu_create_mapping(struct msm_smmu_client *client, - const struct msm_smmu_domain *domain); - -static int msm_smmu_attach(struct msm_mmu *mmu, const char **names, int cnt) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int rc = 0; - - /* domain attach only once */ - if (client->domain_attached) - return 0; - - rc = arm_iommu_attach_device(client->dev, - client->mmu_mapping); - if (rc) { - dev_err(client->dev, "iommu attach dev failed (%d)\n", - rc); - return rc; - } - - client->domain_attached = true; - - dev_dbg(client->dev, "iommu domain attached\n"); - - return 0; -} - -static void msm_smmu_detach(struct msm_mmu *mmu, const char **names, int cnt) -{ - DBG("detaching"); -} - -static int msm_smmu_map(struct msm_mmu *mmu, uint32_t iova, - struct sg_table *sgt, unsigned len, int prot) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - struct scatterlist *sg; - unsigned int da = iova; - unsigned int i, j; - int ret; - - if (!client) - return -ENODEV; - - domain = client->mmu_mapping->domain; - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - u32 pa = sg_phys(sg) - sg->offset; - size_t bytes = sg->length + sg->offset; - - VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); - - ret = iommu_map(domain, da, pa, bytes, prot); - if (ret) - goto fail; - - da += bytes; - } - - return 0; - -fail: - da = iova; - - for_each_sg(sgt->sgl, sg, i, j) { - size_t bytes = sg->length + sg->offset; - - iommu_unmap(domain, da, bytes); - da += bytes; - } - return ret; -} - -static int msm_smmu_map_sg(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int ret; - - ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, dir); - if (ret != sgt->nents) - return -ENOMEM; - - return 0; -} - -static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir); -} - -static int msm_smmu_unmap(struct msm_mmu *mmu, uint32_t iova, - struct sg_table *sgt, unsigned len) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - struct scatterlist *sg; - unsigned int da = iova; - int i; - - if (!client) - return -ENODEV; - - domain = client->mmu_mapping->domain; - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - size_t bytes = sg->length + sg->offset; - size_t unmapped; - - unmapped = iommu_unmap(domain, da, bytes); - if (unmapped < bytes) - return unmapped; - - VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); - - WARN_ON(!PAGE_ALIGNED(bytes)); - - da += bytes; - } - - return 0; -} - -static void msm_smmu_destroy(struct msm_mmu *mmu) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct platform_device *pdev = to_platform_device(smmu->client_dev); - - platform_device_unregister(pdev); - kfree(smmu); -} - -static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int ret; - - ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, dir, - dma_buf); - if (ret != sgt->nents) { - DRM_ERROR("dma map sg failed\n"); - return -ENOMEM; - } - - return 0; -} - - -static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf); -} - -static const struct msm_mmu_funcs funcs = { - .attach = msm_smmu_attach, - .detach = msm_smmu_detach, - .map = msm_smmu_map, - .map_sg = msm_smmu_map_sg, - .unmap_sg = msm_smmu_unmap_sg, - .unmap = msm_smmu_unmap, - .map_dma_buf = msm_smmu_map_dma_buf, - .unmap_dma_buf = msm_smmu_unmap_dma_buf, - .destroy = msm_smmu_destroy, -}; - -static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = { - [MSM_SMMU_DOMAIN_UNSECURE] = { - .label = "mdp_ns", - .va_start = SZ_1M, - .va_size = SZ_2G, - }, -}; - -static const struct of_device_id msm_smmu_dt_match[] = { - { .compatible = "qcom,smmu_mdp_unsec", - .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_UNSECURE] }, - {} -}; -MODULE_DEVICE_TABLE(of, msm_smmu_dt_match); - -static struct device *msm_smmu_device_create(struct device *dev, - enum msm_mmu_domain_type domain, - struct msm_smmu *smmu) -{ - struct device_node *child; - struct platform_device *pdev; - int i; - const char *compat = NULL; - - for (i = 0; i < ARRAY_SIZE(msm_smmu_dt_match); i++) { - if (msm_smmu_dt_match[i].data == &msm_smmu_domains[domain]) { - compat = msm_smmu_dt_match[i].compatible; - break; - } - } - - if (!compat) { - DRM_ERROR("unable to find matching domain for %d\n", domain); - return ERR_PTR(-ENOENT); - } - DRM_INFO("found domain %d compat: %s\n", domain, compat); - - if (domain == MSM_SMMU_DOMAIN_UNSECURE) { - int rc; - - smmu->client.dev = dev; - rc = _msm_smmu_create_mapping(msm_smmu_to_client(smmu), - msm_smmu_dt_match[i].data); - if (rc) - return ERR_PTR(rc); - - return NULL; - } - - child = of_find_compatible_node(dev->of_node, NULL, compat); - if (!child) { - DRM_ERROR("unable to find compatible node for %s\n", compat); - return ERR_PTR(-ENODEV); - } - - pdev = of_platform_device_create(child, NULL, dev); - if (!pdev) { - DRM_ERROR("unable to create smmu platform dev for domain %d\n", - domain); - return ERR_PTR(-ENODEV); - } - - return &pdev->dev; -} - -struct msm_mmu *msm_smmu_new(struct device *dev, - enum msm_mmu_domain_type domain) -{ - struct msm_smmu *smmu; - struct device *client_dev; - - smmu = kzalloc(sizeof(*smmu), GFP_KERNEL); - if (!smmu) - return ERR_PTR(-ENOMEM); - - client_dev = msm_smmu_device_create(dev, domain, smmu); - if (IS_ERR(client_dev)) - return (void *)client_dev ? : ERR_PTR(-ENODEV); - - smmu->client_dev = client_dev; - msm_mmu_init(&smmu->base, dev, &funcs); - - return &smmu->base; -} - -static int _msm_smmu_create_mapping(struct msm_smmu_client *client, - const struct msm_smmu_domain *domain) -{ - int disable_htw = 1; - int rc; - - client->mmu_mapping = arm_iommu_create_mapping(&platform_bus_type, - domain->va_start, domain->va_size); - if (IS_ERR(client->mmu_mapping)) { - dev_err(client->dev, - "iommu create mapping failed for domain=%s\n", - domain->label); - return PTR_ERR(client->mmu_mapping); - } - - if (domain->secure) { - int secure_vmid = VMID_CP_PIXEL; - - rc = iommu_domain_set_attr(client->mmu_mapping->domain, - DOMAIN_ATTR_SECURE_VMID, &secure_vmid); - if (rc) { - dev_err(client->dev, "couldn't set secure pix vmid\n"); - goto error; - } - } - - return 0; - -error: - arm_iommu_release_mapping(client->mmu_mapping); - return rc; -} - -/** - * msm_smmu_probe() - * @pdev: platform device - * - * Each smmu context acts as a separate device and the context banks are - * configured with a VA range. - * Registers the clks as each context bank has its own clks, for which voting - * has to be done everytime before using that context bank. - */ -static int msm_smmu_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct msm_smmu_client *client; - const struct msm_smmu_domain *domain; - int rc; - - match = of_match_device(msm_smmu_dt_match, &pdev->dev); - if (!match || !match->data) { - dev_err(&pdev->dev, "probe failed as match data is invalid\n"); - return -EINVAL; - } - - domain = match->data; - if (!domain) { - dev_err(&pdev->dev, "no matching device found\n"); - return -EINVAL; - } - - DRM_INFO("probing device %s\n", match->compatible); - - client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - client->dev = &pdev->dev; - - rc = _msm_smmu_create_mapping(client, domain); - platform_set_drvdata(pdev, client); - - return rc; -} - -static int msm_smmu_remove(struct platform_device *pdev) -{ - struct msm_smmu_client *client; - - client = platform_get_drvdata(pdev); - if (client->domain_attached) { - arm_iommu_detach_device(client->dev); - client->domain_attached = false; - } - arm_iommu_release_mapping(client->mmu_mapping); - - return 0; -} - -static struct platform_driver msm_smmu_driver = { - .probe = msm_smmu_probe, - .remove = msm_smmu_remove, - .driver = { - .name = "msmdrm_smmu", - .of_match_table = msm_smmu_dt_match, - }, -}; - -static int __init msm_smmu_driver_init(void) -{ - int ret; - - ret = platform_driver_register(&msm_smmu_driver); - if (ret) - pr_err("mdss_smmu_register_driver() failed!\n"); - - return ret; -} -module_init(msm_smmu_driver_init); - -static void __exit msm_smmu_driver_cleanup(void) -{ - platform_driver_unregister(&msm_smmu_driver); -} -module_exit(msm_smmu_driver_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("MSM SMMU driver"); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c deleted file mode 100644 index 5fc1664fd9a0..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ /dev/null @@ -1,676 +0,0 @@ -/* 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 - * 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/sort.h> -#include <drm/drm_mode.h> -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_flip_work.h> - -#include "sde_kms.h" -#include "sde_hw_lm.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_crtc.h" - -#define CTL(i) (CTL_0 + (i)) -#define LM(i) (LM_0 + (i)) -#define INTF(i) (INTF_0 + (i)) - -static struct sde_kms *get_kms(struct drm_crtc *crtc) -{ - struct msm_drm_private *priv = crtc->dev->dev_private; - return to_sde_kms(priv->kms); -} - -static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, - struct drm_encoder *encoder) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_kms *sde_kms = get_kms(crtc); - struct sde_encoder_hw_resources enc_hw_res; - const struct sde_hw_res_map *plat_hw_res_map; - enum sde_lm unused_lm_id[CRTC_DUAL_MIXERS] = {0}; - enum sde_lm lm_idx; - int i, count = 0; - - if (!sde_kms) { - DBG("[%s] invalid kms", __func__); - return -EINVAL; - } - - if (!sde_kms->mmio) - return -EINVAL; - - /* Get unused LMs */ - for (i = 0; i < sde_kms->catalog->mixer_count; i++) { - if (!sde_rm_get_mixer(sde_kms, LM(i))) { - unused_lm_id[count++] = LM(i); - if (count == CRTC_DUAL_MIXERS) - break; - } - } - - /* query encoder resources */ - sde_encoder_get_hw_resources(sde_crtc->encoder, &enc_hw_res); - - /* parse encoder hw resources, find CTL paths */ - for (i = CTL_0; i <= sde_kms->catalog->ctl_count; i++) { - WARN_ON(sde_crtc->num_ctls > CRTC_DUAL_MIXERS); - if (enc_hw_res.ctls[i]) { - struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_ctls]; - mixer->hw_ctl = sde_rm_get_ctl_path(sde_kms, i); - if (IS_ERR_OR_NULL(mixer->hw_ctl)) { - DBG("[%s], Invalid ctl_path", __func__); - return -EACCES; - } - sde_crtc->num_ctls++; - } - } - - /* shortcut this process if encoder has no ctl paths */ - if (!sde_crtc->num_ctls) - return 0; - - /* - * Get default LMs if specified in platform config - * other wise acquire the free LMs - */ - for (i = INTF_0; i <= sde_kms->catalog->intf_count; i++) { - if (enc_hw_res.intfs[i]) { - struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_mixers]; - plat_hw_res_map = sde_rm_get_res_map(sde_kms, i); - - lm_idx = plat_hw_res_map->lm; - if (!lm_idx) - lm_idx = unused_lm_id[sde_crtc->num_mixers]; - - DBG("Acquiring LM %d", lm_idx); - mixer->hw_lm = sde_rm_acquire_mixer(sde_kms, lm_idx); - if (IS_ERR_OR_NULL(mixer->hw_lm)) { - DBG("[%s], Invalid mixer", __func__); - return -EACCES; - } - /* interface info */ - mixer->intf_idx = i; - mixer->mode = enc_hw_res.intfs[i]; - sde_crtc->num_mixers++; - } - } - - DBG("control paths %d, num_mixers %d, lm[0] %d, ctl[0] %d ", - sde_crtc->num_ctls, sde_crtc->num_mixers, - sde_crtc->mixer[0].hw_lm->idx, - sde_crtc->mixer[0].hw_ctl->idx); - if (sde_crtc->num_mixers == CRTC_DUAL_MIXERS) - DBG("lm[1] %d, ctl[1], %d", - sde_crtc->mixer[1].hw_lm->idx, - sde_crtc->mixer[1].hw_ctl->idx); - return 0; -} - -static void sde_crtc_destroy(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - - DBG(""); - drm_crtc_cleanup(crtc); - kfree(sde_crtc); -} - -static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - DBG(""); - return true; -} - -static void sde_crtc_mode_set_nofb(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_crtc_mixer *mixer = sde_crtc->mixer; - struct drm_device *dev = crtc->dev; - struct sde_hw_mixer *lm; - unsigned long flags; - struct drm_display_mode *mode; - struct sde_hw_mixer_cfg cfg; - u32 mixer_width; - int i; - int rc; - - DBG(""); - if (WARN_ON(!crtc->state)) - return; - - mode = &crtc->state->adjusted_mode; - - DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - sde_crtc->name, mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); - - /* - * reserve mixer(s) if not already avaialable - * if dual mode, mixer_width = half mode width - * program mode configuration on mixer(s) - */ - if ((sde_crtc->num_ctls == 0) || - (sde_crtc->num_mixers == 0)) { - rc = sde_crtc_reserve_hw_resources(crtc, sde_crtc->encoder); - if (rc) { - dev_err(dev->dev, " error reserving HW resource for this CRTC\n"); - return; - } - } - - if (sde_crtc->num_mixers == CRTC_DUAL_MIXERS) - mixer_width = mode->hdisplay >> 1; - else - mixer_width = mode->hdisplay; - - spin_lock_irqsave(&sde_crtc->lm_lock, flags); - - for (i = 0; i < sde_crtc->num_mixers; i++) { - lm = mixer[i].hw_lm; - cfg.out_width = mixer_width; - cfg.out_height = mode->vdisplay; - cfg.right_mixer = (i == 0) ? false : true; - cfg.flags = 0; - lm->ops.setup_mixer_out(lm, &cfg); - } - - spin_unlock_irqrestore(&sde_crtc->lm_lock, flags); -} - -static void sde_crtc_get_blend_cfg(struct sde_hw_blend_cfg *cfg, - struct sde_plane_state *pstate) -{ - const struct mdp_format *format; - struct drm_plane *plane; - - format = to_mdp_format( - msm_framebuffer_format(pstate->base.fb)); - plane = pstate->base.plane; - - cfg->fg.alpha_sel = ALPHA_FG_CONST; - cfg->bg.alpha_sel = ALPHA_BG_CONST; - cfg->fg.const_alpha = pstate->alpha; - cfg->bg.const_alpha = 0xFF - pstate->alpha; - - if (format->alpha_enable && pstate->premultiplied) { - cfg->fg.alpha_sel = ALPHA_FG_CONST; - cfg->bg.alpha_sel = ALPHA_FG_PIXEL; - if (pstate->alpha != 0xff) { - cfg->bg.const_alpha = pstate->alpha; - cfg->bg.inv_alpha_sel = 1; - cfg->bg.mod_alpha = 1; - } else { - cfg->bg.inv_mode_alpha = 1; - } - } else if (format->alpha_enable) { - cfg->fg.alpha_sel = ALPHA_FG_PIXEL; - cfg->bg.alpha_sel = ALPHA_FG_PIXEL; - if (pstate->alpha != 0xff) { - cfg->bg.const_alpha = pstate->alpha; - cfg->fg.mod_alpha = 1; - cfg->bg.inv_alpha_sel = 1; - cfg->bg.mod_alpha = 1; - cfg->bg.inv_mode_alpha = 1; - } else { - cfg->bg.inv_mode_alpha = 1; - } - } -} - -static void blend_setup(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_crtc_mixer *mixer = sde_crtc->mixer; - struct drm_plane *plane; - struct sde_plane_state *pstate, *pstates[SDE_STAGE_MAX] = {0}; - struct sde_hw_stage_cfg stage_cfg; - struct sde_hw_blend_cfg blend; - struct sde_hw_ctl *ctl; - struct sde_hw_mixer *lm; - u32 flush_mask = 0; - unsigned long flags; - int i, j, plane_cnt = 0; - - DBG(""); - spin_lock_irqsave(&sde_crtc->lm_lock, flags); - - /* ctl could be reserved already */ - if (!sde_crtc->num_ctls) - goto out; - - /* initialize stage cfg */ - memset(&stage_cfg, 0, sizeof(stage_cfg)); - memset(&blend, 0, sizeof(blend)); - - /* Collect all plane information */ - drm_atomic_crtc_for_each_plane(plane, crtc) { - pstate = to_sde_plane_state(plane->state); - pstates[pstate->stage] = pstate; - plane_cnt++; - for (i = 0; i < sde_crtc->num_mixers; i++) { - stage_cfg.stage[pstate->stage][i] = - sde_plane_pipe(plane); - - /* Cache the flushmask for this layer - * sourcesplit is always enabled, so this layer will - * be staged on both the mixers - */ - ctl = mixer[i].hw_ctl; - ctl->ops.get_bitmask_sspp(ctl, &flush_mask, - sde_plane_pipe(plane)); - } - } - - /* - * If there is no base layer, enable border color. - * currently border color is always black - */ - if ((stage_cfg.stage[SDE_STAGE_BASE][0] == SSPP_NONE) && - plane_cnt) { - stage_cfg.border_enable = 1; - DBG("Border Color is enabled\n"); - } - - /* Program hw */ - for (i = 0; i < sde_crtc->num_mixers; i++) { - if (!mixer[i].hw_lm) - continue; - - if (!mixer[i].hw_ctl) - continue; - - ctl = mixer[i].hw_ctl; - lm = mixer[i].hw_lm; - - /* stage config */ - ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, - &stage_cfg); - /* stage config flush mask */ - mixer[i].flush_mask = flush_mask; - /* get the flush mask for mixer */ - ctl->ops.get_bitmask_mixer(ctl, &mixer[i].flush_mask, - mixer[i].hw_lm->idx); - - /* blend config */ - for (j = SDE_STAGE_0; j < SDE_STAGE_MAX; j++) { - if (!pstates[j]) - continue; - sde_crtc_get_blend_cfg(&blend, pstates[j]); - blend.fg.alpha_sel = ALPHA_FG_CONST; - blend.bg.alpha_sel = ALPHA_BG_CONST; - blend.fg.const_alpha = pstate->alpha; - blend.bg.const_alpha = 0xFF - pstate->alpha; - lm->ops.setup_blend_config(lm, j, &blend); - } - } -out: - spin_unlock_irqrestore(&sde_crtc->lm_lock, flags); -} - -/* if file!=NULL, this is preclose potential cancel-flip path */ -static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct drm_pending_vblank_event *event; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - event = sde_crtc->event; - if (event) { - /* if regular vblank case (!file) or if cancel-flip from - * preclose on file that requested flip, then send the - * event: - */ - if (!file || (event->base.file_priv == file)) { - sde_crtc->event = NULL; - DBG("%s: send event: %pK", sde_crtc->name, event); - drm_send_vblank_event(dev, sde_crtc->id, event); - } - } - spin_unlock_irqrestore(&dev->event_lock, flags); -} - -static void sde_crtc_vblank_cb(void *data) -{ - struct drm_crtc *crtc = (struct drm_crtc *)data; - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - unsigned pending; - - /* unregister callback */ - sde_encoder_register_vblank_callback(sde_crtc->encoder, NULL, NULL); - - pending = atomic_xchg(&sde_crtc->pending, 0); - - if (pending & PENDING_FLIP) - complete_flip(crtc, NULL); -} - -static int frame_flushed(struct sde_crtc *sde_crtc) -{ - struct vsync_info vsync; - - /* encoder get vsync_info */ - /* if frame_count does not match frame is flushed */ - sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync); - - return (vsync.frame_count & sde_crtc->vsync_count); - -} - -void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - u32 pending; - int i, ret; - - /* ref count the vblank event */ - ret = drm_crtc_vblank_get(crtc); - if (ret) - return; - - /* register callback */ - sde_encoder_register_vblank_callback(sde_crtc->encoder, - sde_crtc_vblank_cb, - (void *)crtc); - - /* wait */ - pending = atomic_read(&sde_crtc->pending); - if (pending & PENDING_FLIP) { - wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, - (frame_flushed(sde_crtc) != 0), - msecs_to_jiffies(CRTC_MAX_WAIT_ONE_FRAME)); - if (ret <= 0) - dev_warn(dev->dev, "vblank time out, crtc=%d\n", - sde_crtc->id); - } - - for (i = 0; i < sde_crtc->num_ctls; i++) - sde_crtc->mixer[i].flush_mask = 0; - - /* release */ - drm_crtc_vblank_put(crtc); -} - -static void request_pending(struct drm_crtc *crtc, u32 pending) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct vsync_info vsync; - - /* request vsync info, cache the current frame count */ - sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync); - sde_crtc->vsync_count = vsync.frame_count; - - atomic_or(pending, &sde_crtc->pending); -} - -/** - * Flush the CTL PATH - */ -static u32 crtc_flush_all(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_hw_ctl *ctl; - int i; - - DBG(""); - - for (i = 0; i < sde_crtc->num_ctls; i++) { - ctl = sde_crtc->mixer[i].hw_ctl; - ctl->ops.get_bitmask_intf(ctl, - &(sde_crtc->mixer[i].flush_mask), - sde_crtc->mixer[i].intf_idx); - DBG("Flushing CTL_ID %d, flush_mask %x", ctl->idx, - sde_crtc->mixer[i].flush_mask); - ctl->ops.setup_flush(ctl, - sde_crtc->mixer[i].flush_mask); - } - - return 0; -} - -static void sde_crtc_atomic_begin(struct drm_crtc *crtc, - struct drm_crtc_state *old_crtc_state) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_device *dev = crtc->dev; - unsigned long flags; - - DBG(""); - - WARN_ON(sde_crtc->event); - - spin_lock_irqsave(&dev->event_lock, flags); - sde_crtc->event = crtc->state->event; - spin_unlock_irqrestore(&dev->event_lock, flags); - - /* - * If no CTL has been allocated in sde_crtc_atomic_check(), - * it means we are trying to flush a CRTC whose state is disabled: - * nothing else needs to be done. - */ - if (unlikely(!sde_crtc->num_ctls)) - return; - - blend_setup(crtc); - - /* - * PP_DONE irq is only used by command mode for now. - * It is better to request pending before FLUSH and START trigger - * to make sure no pp_done irq missed. - * This is safe because no pp_done will happen before SW trigger - * in command mode. - */ -} - -static void sde_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_crtc_state *old_crtc_state) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_device *dev = crtc->dev; - unsigned long flags; - - DBG("%s: event: %pK", sde_crtc->name, crtc->state->event); - - WARN_ON(sde_crtc->event); - - spin_lock_irqsave(&dev->event_lock, flags); - sde_crtc->event = crtc->state->event; - spin_unlock_irqrestore(&dev->event_lock, flags); - - /* - * If no CTL has been allocated in sde_crtc_atomic_check(), - * it means we are trying to flush a CRTC whose state is disabled: - * nothing else needs to be done. - */ - if (unlikely(!sde_crtc->num_ctls)) - return; - - crtc_flush_all(crtc); - - request_pending(crtc, PENDING_FLIP); -} - -static int sde_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) -{ - return -EINVAL; -} - -static int sde_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file, uint32_t handle, - uint32_t width, uint32_t height) -{ - return 0; -} - -static int sde_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) -{ - return 0; -} - -static void sde_crtc_disable(struct drm_crtc *crtc) -{ - DBG(""); -} - -static void sde_crtc_enable(struct drm_crtc *crtc) -{ - DBG(""); -} - -struct plane_state { - struct drm_plane *plane; - struct sde_plane_state *state; -}; - -static int pstate_cmp(const void *a, const void *b) -{ - struct plane_state *pa = (struct plane_state *)a; - struct plane_state *pb = (struct plane_state *)b; - - return pa->state->zpos - pb->state->zpos; -} - -static int sde_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_kms *sde_kms = get_kms(crtc); - struct drm_plane *plane; - struct drm_device *dev = crtc->dev; - struct plane_state pstates[SDE_STAGE_MAX]; - int max_stages = CRTC_HW_MIXER_MAXSTAGES(sde_kms->catalog, 0); - int cnt = 0, i; - - DBG("%s: check", sde_crtc->name); - - /* verify that there are not too many planes attached to crtc - * and that we don't have conflicting mixer stages: - */ - drm_atomic_crtc_state_for_each_plane(plane, state) { - struct drm_plane_state *pstate; - - if (cnt >= (max_stages)) { - dev_err(dev->dev, "too many planes!\n"); - return -EINVAL; - } - - pstate = state->state->plane_states[drm_plane_index(plane)]; - - /* plane might not have changed, in which case take - * current state: - */ - if (!pstate) - pstate = plane->state; - pstates[cnt].plane = plane; - pstates[cnt].state = to_sde_plane_state(pstate); - - cnt++; - } - - /* assign a stage based on sorted zpos property */ - sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); - - for (i = 0; i < cnt; i++) { - pstates[i].state->stage = SDE_STAGE_0 + i; - DBG("%s: assign pipe %d on stage=%d", sde_crtc->name, - sde_plane_pipe(pstates[i].plane), - pstates[i].state->stage); - } - - return 0; -} - -static const struct drm_crtc_funcs sde_crtc_funcs = { - .set_config = drm_atomic_helper_set_config, - .destroy = sde_crtc_destroy, - .page_flip = drm_atomic_helper_page_flip, - .set_property = sde_crtc_set_property, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, - .cursor_set = sde_crtc_cursor_set, - .cursor_move = sde_crtc_cursor_move, -}; - -static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = { - .mode_fixup = sde_crtc_mode_fixup, - .mode_set_nofb = sde_crtc_mode_set_nofb, - .disable = sde_crtc_disable, - .enable = sde_crtc_enable, - .atomic_check = sde_crtc_atomic_check, - .atomic_begin = sde_crtc_atomic_begin, - .atomic_flush = sde_crtc_atomic_flush, -}; - -uint32_t sde_crtc_vblank(struct drm_crtc *crtc) -{ - return 0; -} - -void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) -{ -} - -static void sde_crtc_install_properties(struct drm_crtc *crtc, - struct drm_mode_object *obj) -{ -} - - -/* initialize crtc */ -struct drm_crtc *sde_crtc_init(struct drm_device *dev, - struct drm_encoder *encoder, - struct drm_plane *plane, int id) -{ - struct drm_crtc *crtc = NULL; - struct sde_crtc *sde_crtc; - int rc; - - sde_crtc = kzalloc(sizeof(*sde_crtc), GFP_KERNEL); - if (!sde_crtc) - return ERR_PTR(-ENOMEM); - - crtc = &sde_crtc->base; - - sde_crtc->id = id; - sde_crtc->encoder = encoder; - - sde_crtc_install_properties(crtc, &crtc->base); - - drm_crtc_init_with_planes(dev, crtc, plane, NULL, &sde_crtc_funcs); - - drm_crtc_helper_add(crtc, &sde_crtc_helper_funcs); - plane->crtc = crtc; - - rc = sde_crtc_reserve_hw_resources(crtc, encoder); - if (rc) { - dev_err(dev->dev, " error reserving HW resource for this CRTC\n"); - return ERR_PTR(-EINVAL); - } - - DBG("%s: Successfully initialized crtc", __func__); - return crtc; -} diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h deleted file mode 100644 index 9f14f999913d..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _SDE_CRTC_H_ -#define _SDE_CRTC_H_ - -#include "drm_crtc.h" - -#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) - -#define CRTC_DUAL_MIXERS 2 -#define PENDING_FLIP 2 -/* worst case one frame wait time based on 30 FPS : 33.33ms*/ -#define CRTC_MAX_WAIT_ONE_FRAME 34 -#define CRTC_HW_MIXER_MAXSTAGES(c, idx) ((c)->mixer[idx].sblk->maxblendstages) - -/** - * struct sde_crtc_mixer - stores the map for each virtual pipeline in the CRTC - * @hw_dspp : DSPP HW Driver context - * @hw_lm : LM HW Driver context - * @hw_ctl : CTL Path HW driver context - * @intf_idx : Interface idx - * @mode : Interface mode Active/CMD - * @flush_mask : Flush mask value for this commit - */ -struct sde_crtc_mixer { - struct sde_hw_dspp *hw_dspp; - struct sde_hw_mixer *hw_lm; - struct sde_hw_ctl *hw_ctl; - enum sde_intf intf_idx; - enum sde_intf_mode mode; - u32 flush_mask; -}; - -/** - * struct sde_crtc - virtualized CRTC data structure - * @base : Base drm crtc structure - * @name : ASCII description of this crtc - * @encoder : Associated drm encoder object - * @id : Unique crtc identifier - * @lm_lock : LM register access spinlock - * @num_ctls : Number of ctl paths in use - * @num_mixers : Number of mixers in use - * @mixer : List of active mixers - * @event : Pointer to last received drm vblank event - * @pending : Whether or not an update is pending - * @vsync_count : Running count of received vsync events - */ -struct sde_crtc { - struct drm_crtc base; - char name[8]; - struct drm_encoder *encoder; - int id; - - spinlock_t lm_lock; /* protect registers */ - - /* HW Resources reserved for the crtc */ - u32 num_ctls; - u32 num_mixers; - struct sde_crtc_mixer mixer[CRTC_DUAL_MIXERS]; - - /*if there is a pending flip, these will be non-null */ - struct drm_pending_vblank_event *event; - atomic_t pending; - u32 vsync_count; -}; - -#define to_sde_crtc(x) container_of(x, struct sde_crtc, base) - -#endif /* _SDE_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c deleted file mode 100644 index ad72bca11669..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ /dev/null @@ -1,569 +0,0 @@ -/* 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 - * 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 "msm_drv.h" -#include "sde_kms.h" -#include "drm_crtc.h" -#include "drm_crtc_helper.h" - -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_intf.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_mdp_formats.h" - -#include "sde_encoder_phys.h" -#include "display_manager.h" - -#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) - -#ifdef CONFIG_QCOM_BUS_SCALING -#include <linux/msm-bus.h> -#include <linux/msm-bus-board.h> -#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \ - { \ - .src = MSM_BUS_MASTER_MDP_PORT0, \ - .dst = MSM_BUS_SLAVE_EBI_CH0, \ - .ab = (ab_val), \ - .ib = (ib_val), \ - } - -static struct msm_bus_vectors mdp_bus_vectors[] = { - MDP_BUS_VECTOR_ENTRY(0, 0), - MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000), -}; - -static struct msm_bus_paths mdp_bus_usecases[] = { { - .num_paths = 1, - .vectors = - &mdp_bus_vectors[0], - }, { - .num_paths = 1, - .vectors = - &mdp_bus_vectors[1], - } -}; - -static struct msm_bus_scale_pdata mdp_bus_scale_table = { - .usecase = mdp_bus_usecases, - .num_usecases = ARRAY_SIZE(mdp_bus_usecases), - .name = "mdss_mdp", -}; - -static void bs_init(struct sde_encoder_virt *sde_enc) -{ - sde_enc->bus_scaling_client = - msm_bus_scale_register_client(&mdp_bus_scale_table); - DBG("bus scale client: %08x", sde_enc->bus_scaling_client); -} - -static void bs_fini(struct sde_encoder_virt *sde_enc) -{ - if (sde_enc->bus_scaling_client) { - msm_bus_scale_unregister_client(sde_enc->bus_scaling_client); - sde_enc->bus_scaling_client = 0; - } -} - -static void bs_set(struct sde_encoder_virt *sde_enc, int idx) -{ - if (sde_enc->bus_scaling_client) { - DBG("set bus scaling: %d", idx); - idx = 1; - msm_bus_scale_client_update_request(sde_enc->bus_scaling_client, - idx); - } -} -#else -static void bs_init(struct sde_encoder_virt *sde_enc) -{ -} - -static void bs_fini(struct sde_encoder_virt *sde_enc) -{ -} - -static void bs_set(struct sde_encoder_virt *sde_enc, int idx) -{ -} -#endif - -void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc, - struct sde_encoder_hw_resources *hw_res) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - - DBG(""); - - if (!hw_res || !drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - /* Query resources used by phys encs, expected to be without overlap */ - memset(hw_res, 0, sizeof(*hw_res)); - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.get_hw_resources) - phys->phys_ops.get_hw_resources(phys, hw_res); - } -} - -static void sde_encoder_destroy(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < ARRAY_SIZE(sde_enc->phys_encs); i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.destroy) { - phys->phys_ops.destroy(phys); - --sde_enc->num_phys_encs; - sde_enc->phys_encs[i] = NULL; - } - } - - if (sde_enc->num_phys_encs) { - DRM_ERROR("Expected num_phys_encs to be 0 not %d\n", - sde_enc->num_phys_encs); - } - - drm_encoder_cleanup(drm_enc); - bs_fini(sde_enc); - kfree(sde_enc); -} - -static bool sde_encoder_virt_mode_fixup(struct drm_encoder *drm_enc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - bool ret = true; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return false; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.mode_fixup) { - ret = - phys->phys_ops.mode_fixup(phys, mode, - adjusted_mode); - if (!ret) { - DBG("Mode unsupported by phys_enc %d", i); - break; - } - - if (sde_enc->num_phys_encs > 1) { - DBG("ModeFix only checking 1 phys_enc"); - break; - } - } - } - - return ret; -} - -static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - bool splitmode = false; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - /* - * Panel is driven by two interfaces ,each interface drives half of - * the horizontal - */ - if (sde_enc->num_phys_encs == 2) - splitmode = true; - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - if (phys) { - phys->phys_ops.mode_set(phys, - mode, - adjusted_mode, - splitmode); - if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0) - DRM_ERROR("adjusted modes not supported\n"); - } - } -} - -static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - bool splitmode = false; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - bs_set(sde_enc, 1); - - if (sde_enc->num_phys_encs == 2) - splitmode = true; - - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.enable) - - /* enable/disable dual interface top config */ - if (phys->phys_ops.enable_split_config) - phys->phys_ops.enable_split_config(phys, - splitmode); - phys->phys_ops.enable(phys); - } -} - -static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.disable) - phys->phys_ops.disable(phys); - } - - bs_set(sde_enc, 0); -} - -static const struct drm_encoder_helper_funcs sde_encoder_helper_funcs = { - .mode_fixup = sde_encoder_virt_mode_fixup, - .mode_set = sde_encoder_virt_mode_set, - .disable = sde_encoder_virt_disable, - .enable = sde_encoder_virt_enable, -}; - -static const struct drm_encoder_funcs sde_encoder_funcs = { - .destroy = sde_encoder_destroy, -}; - -static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog, - enum sde_intf_type type, u32 controller_id) -{ - int i = 0; - - DBG(""); - - for (i = 0; i < catalog->intf_count; i++) { - if (catalog->intf[i].type == type - && catalog->intf[i].controller_id == controller_id) { - return catalog->intf[i].id; - } - } - - return INTF_MAX; -} - -static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - unsigned long lock_flags; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - spin_lock_irqsave(&sde_enc->spin_lock, lock_flags); - if (sde_enc->kms_vblank_callback) - sde_enc->kms_vblank_callback(sde_enc->kms_vblank_callback_data); - spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags); -} - -static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc, - struct sde_kms *sde_kms, - enum sde_intf intf_idx, - enum sde_ctl ctl_idx) -{ - int ret = 0; - - DBG(""); - - if (sde_enc->num_phys_encs >= ARRAY_SIZE(sde_enc->phys_encs)) { - DRM_ERROR("Too many video encoders %d, unable to add\n", - sde_enc->num_phys_encs); - ret = -EINVAL; - } else { - struct sde_encoder_virt_ops parent_ops = { - sde_encoder_vblank_callback - }; - struct sde_encoder_phys *enc = - sde_encoder_phys_vid_init(sde_kms, intf_idx, ctl_idx, - &sde_enc->base, - parent_ops); - if (IS_ERR(enc)) - ret = PTR_ERR(enc); - - if (!ret) { - sde_enc->phys_encs[sde_enc->num_phys_encs] = enc; - ++sde_enc->num_phys_encs; - } - } - - return ret; -} - -static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, - struct sde_kms *sde_kms, - struct display_info *disp_info, - int *drm_enc_mode) -{ - int ret = 0; - int i = 0; - enum sde_intf_type intf_type = INTF_NONE; - - DBG(""); - - if (disp_info->intf == DISPLAY_INTF_DSI) { - *drm_enc_mode = DRM_MODE_ENCODER_DSI; - intf_type = INTF_DSI; - } else if (disp_info->intf == DISPLAY_INTF_HDMI) { - *drm_enc_mode = DRM_MODE_ENCODER_TMDS; - intf_type = INTF_HDMI; - } else { - DRM_ERROR("Unsupported display interface type"); - return -EINVAL; - } - - WARN_ON(disp_info->num_of_h_tiles < 1); - - DBG("dsi_info->num_of_h_tiles %d", disp_info->num_of_h_tiles); - - for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { - /* - * Left-most tile is at index 0, content is controller id - * h_tile_instance_ids[2] = {0, 1}; DSI0 = left, DSI1 = right - * h_tile_instance_ids[2] = {1, 0}; DSI1 = left, DSI0 = right - */ - const struct sde_hw_res_map *hw_res_map = NULL; - enum sde_intf intf_idx = INTF_MAX; - enum sde_ctl ctl_idx = CTL_MAX; - u32 controller_id = disp_info->h_tile_instance[i]; - - DBG("h_tile_instance %d = %d", i, controller_id); - - intf_idx = sde_encoder_get_intf(sde_kms->catalog, - intf_type, controller_id); - if (intf_idx == INTF_MAX) { - DBG("Error: could not get the interface id"); - ret = -EINVAL; - } - - hw_res_map = sde_rm_get_res_map(sde_kms, intf_idx); - if (IS_ERR_OR_NULL(hw_res_map)) - ret = -EINVAL; - else - ctl_idx = hw_res_map->ctl; - - /* Create both VID and CMD Phys Encoders here */ - if (!ret) - ret = sde_encoder_virt_add_phys_vid_enc( - sde_enc, sde_kms, intf_idx, ctl_idx); - } - - - return ret; -} - -static struct drm_encoder *sde_encoder_virt_init( - struct drm_device *dev, struct display_info *disp_info) -{ - struct msm_drm_private *priv = dev->dev_private; - struct sde_kms *sde_kms = to_sde_kms(priv->kms); - struct drm_encoder *drm_enc = NULL; - struct sde_encoder_virt *sde_enc = NULL; - int drm_enc_mode = DRM_MODE_ENCODER_NONE; - int ret = 0; - - DBG(""); - - sde_enc = kzalloc(sizeof(*sde_enc), GFP_KERNEL); - if (!sde_enc) { - ret = -ENOMEM; - goto fail; - } - - ret = sde_encoder_setup_display(sde_enc, sde_kms, disp_info, - &drm_enc_mode); - if (ret) - goto fail; - - spin_lock_init(&sde_enc->spin_lock); - drm_enc = &sde_enc->base; - drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode); - drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); - bs_init(sde_enc); - - DBG("Created encoder"); - - return drm_enc; - -fail: - DRM_ERROR("Failed to create encoder\n"); - if (drm_enc) - sde_encoder_destroy(drm_enc); - - return ERR_PTR(ret); -} - -void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc, - void (*cb)(void *), void *data) -{ - struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); - unsigned long lock_flags; - - DBG(""); - - spin_lock_irqsave(&sde_enc->spin_lock, lock_flags); - sde_enc->kms_vblank_callback = cb; - sde_enc->kms_vblank_callback_data = data; - spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags); -} - -void sde_encoder_get_vsync_info(struct drm_encoder *drm_enc, - struct vsync_info *vsync) -{ - struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); - struct sde_encoder_phys *phys; - - DBG(""); - - if (!vsync) { - DRM_ERROR("Invalid pointer"); - return; - } - - /* we get the vsync info from the intf at index 0: master index */ - phys = sde_enc->phys_encs[0]; - if (phys) - phys->phys_ops.get_vsync_info(phys, vsync); -} - -/* encoders init, - * initialize encoder based on displays - */ -void sde_encoders_init(struct drm_device *dev) -{ - struct msm_drm_private *priv = NULL; - struct display_manager *disp_man = NULL; - u32 i = 0; - u32 num_displays = 0; - - DBG(""); - - if (!dev || !dev->dev_private) { - DRM_ERROR("Invalid pointer"); - return; - } - - priv = dev->dev_private; - priv->num_encoders = 0; - if (!priv->kms || !priv->dm) { - DRM_ERROR("Invalid pointer"); - return; - } - disp_man = priv->dm; - - num_displays = display_manager_get_count(disp_man); - DBG("num_displays %d", num_displays); - - if (num_displays > ARRAY_SIZE(priv->encoders)) { - num_displays = ARRAY_SIZE(priv->encoders); - DRM_ERROR("Too many displays found, capping to %d", - num_displays); - } - - for (i = 0; i < num_displays; i++) { - struct display_info info = { 0 }; - struct drm_encoder *enc = NULL; - u32 ret = 0; - - ret = display_manager_get_info_by_index(disp_man, i, &info); - if (ret) { - DRM_ERROR("Failed to get display info, %d", ret); - return; - } - - enc = sde_encoder_virt_init(dev, &info); - if (IS_ERR_OR_NULL(enc)) { - DRM_ERROR("Encoder initialization failed"); - return; - } - - ret = display_manager_drm_init_by_index(disp_man, i, enc); - if (ret) { - DRM_ERROR("Display drm_init failed, %d", ret); - return; - } - - priv->encoders[priv->num_encoders++] = enc; - } -} diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h deleted file mode 100644 index d35e084f9bef..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __SDE_ENCODER_PHYS_H__ -#define __SDE_ENCODER_PHYS_H__ - -#include "sde_kms.h" -#include "sde_hw_intf.h" -#include "sde_hw_mdp_ctl.h" - -#define MAX_PHYS_ENCODERS_PER_VIRTUAL 4 - -struct sde_encoder_phys; - -struct sde_encoder_virt_ops { - void (*handle_vblank_virt)(struct drm_encoder *); -}; - -struct sde_encoder_phys_ops { - void (*mode_set)(struct sde_encoder_phys *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - bool splitmode); - bool (*mode_fixup)(struct sde_encoder_phys *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - void (*enable)(struct sde_encoder_phys *encoder); - void (*disable)(struct sde_encoder_phys *encoder); - void (*destroy)(struct sde_encoder_phys *encoder); - void (*get_hw_resources)(struct sde_encoder_phys *encoder, - struct sde_encoder_hw_resources *hw_res); - void (*get_vsync_info)(struct sde_encoder_phys *enc, - struct vsync_info *vsync); - void (*enable_split_config)(struct sde_encoder_phys *enc, - bool enable); -}; - -struct sde_encoder_phys { - struct drm_encoder *parent; - struct sde_encoder_virt_ops parent_ops; - struct sde_encoder_phys_ops phys_ops; - struct sde_hw_intf *hw_intf; - struct sde_hw_ctl *hw_ctl; - struct sde_kms *sde_kms; - struct drm_display_mode cached_mode; - bool enabled; - spinlock_t spin_lock; -}; - -/** - * struct sde_encoder_phys_vid - sub-class of sde_encoder_phys to handle video - * mode specific operations - * @base: Baseclass physical encoder structure - * @irq_idx: IRQ interface lookup index - * @vblank_complete: for vblank irq synchronization - */ -struct sde_encoder_phys_vid { - struct sde_encoder_phys base; - int irq_idx; - struct completion vblank_complete; -}; - -struct sde_encoder_virt { - struct drm_encoder base; - spinlock_t spin_lock; - uint32_t bus_scaling_client; - - int num_phys_encs; - struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; - - void (*kms_vblank_callback)(void *); - void *kms_vblank_callback_data; -}; - -struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms, - enum sde_intf intf_idx, - enum sde_ctl ctl_idx, - struct drm_encoder *parent, - struct sde_encoder_virt_ops - parent_ops); - -#endif /* __sde_encoder_phys_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c deleted file mode 100644 index 693e1f33e7d8..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2015 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 "msm_drv.h" -#include "sde_kms.h" -#include "drm_crtc.h" -#include "drm_crtc_helper.h" - -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_intf.h" -#include "sde_mdp_formats.h" - -#include "sde_encoder_phys.h" diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c deleted file mode 100644 index aefa11d5cdde..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ /dev/null @@ -1,559 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "msm_drv.h" -#include "sde_kms.h" -#include "drm_crtc.h" -#include "drm_crtc_helper.h" - -#include "sde_encoder_phys.h" -#include "sde_mdp_formats.h" -#include "sde_hw_mdp_top.h" - -#define VBLANK_TIMEOUT msecs_to_jiffies(100) - -#define to_sde_encoder_phys_vid(x) \ - container_of(x, struct sde_encoder_phys_vid, base) - -static bool sde_encoder_phys_vid_is_master( - struct sde_encoder_phys *phys_enc) -{ - bool ret = true; - - return ret; -} - -static void sde_encoder_phys_vid_wait_for_vblank( - struct sde_encoder_phys_vid *vid_enc) -{ - int rc = 0; - - DBG(""); - rc = wait_for_completion_timeout(&vid_enc->vblank_complete, - VBLANK_TIMEOUT); - if (rc == 0) - DRM_ERROR("Timed out waiting for vblank irq\n"); -} - -static void drm_mode_to_intf_timing_params( - const struct sde_encoder_phys *phys_enc, - const struct drm_display_mode *mode, - struct intf_timing_params *timing) -{ - memset(timing, 0, sizeof(*timing)); - /* - * https://www.kernel.org/doc/htmldocs/drm/ch02s05.html - * Active Region Front Porch Sync Back Porch - * <-----------------><------------><-----><-----------> - * <- [hv]display ---> - * <--------- [hv]sync_start ------> - * <----------------- [hv]sync_end -------> - * <---------------------------- [hv]total -------------> - */ - timing->width = mode->hdisplay; /* active width */ - timing->height = mode->vdisplay; /* active height */ - timing->xres = timing->width; - timing->yres = timing->height; - timing->h_back_porch = mode->htotal - mode->hsync_end; - timing->h_front_porch = mode->hsync_start - mode->hdisplay; - timing->v_back_porch = mode->vtotal - mode->vsync_end; - timing->v_front_porch = mode->vsync_start - mode->vdisplay; - timing->hsync_pulse_width = mode->hsync_end - mode->hsync_start; - timing->vsync_pulse_width = mode->vsync_end - mode->vsync_start; - timing->hsync_polarity = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0; - timing->vsync_polarity = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; - timing->border_clr = 0; - timing->underflow_clr = 0xff; - timing->hsync_skew = mode->hskew; - - /* DSI controller cannot handle active-low sync signals. */ - if (phys_enc->hw_intf->cap->type == INTF_DSI) { - timing->hsync_polarity = 0; - timing->vsync_polarity = 0; - } - - /* - * For edp only: - * DISPLAY_V_START = (VBP * HCYCLE) + HBP - * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP - */ - /* - * if (vid_enc->hw->cap->type == INTF_EDP) { - * display_v_start += mode->htotal - mode->hsync_start; - * display_v_end -= mode->hsync_start - mode->hdisplay; - * } - */ -} - -static inline u32 get_horizontal_total(const struct intf_timing_params *timing) -{ - u32 active = timing->xres; - u32 inactive = - timing->h_back_porch + timing->h_front_porch + - timing->hsync_pulse_width; - return active + inactive; -} - -static inline u32 get_vertical_total(const struct intf_timing_params *timing) -{ - u32 active = timing->yres; - u32 inactive = - timing->v_back_porch + timing->v_front_porch + - timing->vsync_pulse_width; - return active + inactive; -} - -/* - * programmable_fetch_get_num_lines: - * Number of fetch lines in vertical front porch - * @timing: Pointer to the intf timing information for the requested mode - * - * Returns the number of fetch lines in vertical front porch at which mdp - * can start fetching the next frame. - * - * Number of needed prefetch lines is anything that cannot be absorbed in the - * start of frame time (back porch + vsync pulse width). - * - * Some panels have very large VFP, however we only need a total number of - * lines based on the chip worst case latencies. - */ -static u32 programmable_fetch_get_num_lines( - struct sde_encoder_phys *phys_enc, - const struct intf_timing_params *timing) -{ - u32 worst_case_needed_lines = - phys_enc->hw_intf->cap->prog_fetch_lines_worst_case; - u32 start_of_frame_lines = - timing->v_back_porch + timing->vsync_pulse_width; - u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines; - u32 actual_vfp_lines = 0; - - /* Fetch must be outside active lines, otherwise undefined. */ - - if (start_of_frame_lines >= worst_case_needed_lines) { - DBG("Programmable fetch is not needed due to large vbp+vsw"); - actual_vfp_lines = 0; - } else if (timing->v_front_porch < needed_vfp_lines) { - /* Warn fetch needed, but not enough porch in panel config */ - pr_warn_once - ("low vbp+vfp may lead to perf issues in some cases\n"); - DBG("Less vfp than fetch requires, using entire vfp"); - actual_vfp_lines = timing->v_front_porch; - } else { - DBG("Room in vfp for needed prefetch"); - actual_vfp_lines = needed_vfp_lines; - } - - DBG("v_front_porch %u v_back_porch %u vsync_pulse_width %u", - timing->v_front_porch, timing->v_back_porch, - timing->vsync_pulse_width); - DBG("wc_lines %u needed_vfp_lines %u actual_vfp_lines %u", - worst_case_needed_lines, needed_vfp_lines, actual_vfp_lines); - - return actual_vfp_lines; -} - -/* - * programmable_fetch_config: Programs HW to prefetch lines by offsetting - * the start of fetch into the vertical front porch for cases where the - * vsync pulse width and vertical back porch time is insufficient - * - * Gets # of lines to pre-fetch, then calculate VSYNC counter value. - * HW layer requires VSYNC counter of first pixel of tgt VFP line. - * - * @timing: Pointer to the intf timing information for the requested mode - */ -static void programmable_fetch_config(struct sde_encoder_phys *phys_enc, - const struct intf_timing_params *timing) -{ - struct intf_prog_fetch f = { 0 }; - u32 vfp_fetch_lines = 0; - u32 horiz_total = 0; - u32 vert_total = 0; - u32 vfp_fetch_start_vsync_counter = 0; - unsigned long lock_flags; - - if (WARN_ON_ONCE(!phys_enc->hw_intf->ops.setup_prg_fetch)) - return; - - vfp_fetch_lines = programmable_fetch_get_num_lines(phys_enc, timing); - if (vfp_fetch_lines) { - vert_total = get_vertical_total(timing); - horiz_total = get_horizontal_total(timing); - vfp_fetch_start_vsync_counter = - (vert_total - vfp_fetch_lines) * horiz_total + 1; - f.enable = 1; - f.fetch_start = vfp_fetch_start_vsync_counter; - } - - DBG("vfp_fetch_lines %u vfp_fetch_start_vsync_counter %u", - vfp_fetch_lines, vfp_fetch_start_vsync_counter); - - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.setup_prg_fetch(phys_enc->hw_intf, &f); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); -} - -static bool sde_encoder_phys_vid_mode_fixup( - struct sde_encoder_phys *phys_enc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - DBG(""); - - /* - * Modifying mode has consequences when the mode comes back to us - */ - return true; -} - -static void sde_encoder_phys_vid_flush_intf(struct sde_encoder_phys *phys_enc) -{ - struct sde_hw_intf *intf = phys_enc->hw_intf; - struct sde_hw_ctl *ctl = phys_enc->hw_ctl; - u32 flush_mask = 0; - - DBG(""); - - ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx); - ctl->ops.setup_flush(ctl, flush_mask); - - DBG("Flushing CTL_ID %d, flush_mask %x, INTF %d", - ctl->idx, flush_mask, intf->idx); -} - -static void sde_encoder_phys_vid_mode_set(struct sde_encoder_phys *phys_enc, - struct drm_display_mode *mode, - struct drm_display_mode - *adjusted_mode, - bool splitmode) -{ - mode = adjusted_mode; - phys_enc->cached_mode = *adjusted_mode; - if (splitmode) { - phys_enc->cached_mode.hdisplay >>= 1; - phys_enc->cached_mode.htotal >>= 1; - phys_enc->cached_mode.hsync_start >>= 1; - phys_enc->cached_mode.hsync_end >>= 1; - } - - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, - mode->type, mode->flags); -} - -static void sde_encoder_phys_vid_setup_timing_engine( - struct sde_encoder_phys *phys_enc) -{ - struct drm_display_mode *mode = &phys_enc->cached_mode; - struct intf_timing_params p = { 0 }; - struct sde_mdp_format_params *sde_fmt_params = NULL; - u32 fmt_fourcc = DRM_FORMAT_RGB888; - u32 fmt_mod = 0; - unsigned long lock_flags; - struct sde_hw_intf_cfg intf_cfg = { 0 }; - - if (WARN_ON(!phys_enc->hw_intf->ops.setup_timing_gen)) - return; - - if (WARN_ON(!phys_enc->hw_ctl->ops.setup_intf_cfg)) - return; - - DBG("enable mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, - mode->type, mode->flags); - - drm_mode_to_intf_timing_params(phys_enc, mode, &p); - - sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod); - - intf_cfg.intf = phys_enc->hw_intf->idx; - intf_cfg.wb = SDE_NONE; - - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &p, - sde_fmt_params); - phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); - - programmable_fetch_config(phys_enc, &p); -} - -static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) -{ - struct sde_encoder_phys_vid *vid_enc = arg; - struct sde_encoder_phys *phys_enc = &vid_enc->base; - - phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent); - - /* signal VBLANK completion */ - complete_all(&vid_enc->vblank_complete); -} - -static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - struct sde_irq_callback irq_cb; - int ret = 0; - - vid_enc->irq_idx = sde_irq_idx_lookup(phys_enc->sde_kms, - SDE_IRQ_TYPE_INTF_VSYNC, phys_enc->hw_intf->idx); - if (vid_enc->irq_idx < 0) { - DRM_ERROR( - "Failed to lookup IRQ index for INTF_VSYNC with intf=%d\n", - phys_enc->hw_intf->idx); - return -EINVAL; - } - - irq_cb.func = sde_encoder_phys_vid_vblank_irq; - irq_cb.arg = vid_enc; - ret = sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, - &irq_cb); - if (ret) { - DRM_ERROR("Failed to register IRQ callback INTF_VSYNC\n"); - return ret; - } - - ret = sde_enable_irq(phys_enc->sde_kms, &vid_enc->irq_idx, 1); - if (ret) { - DRM_ERROR( - "Failed to enable IRQ for INTF_VSYNC, intf %d, irq_idx=%d\n", - phys_enc->hw_intf->idx, - vid_enc->irq_idx); - vid_enc->irq_idx = -EINVAL; - - /* Unregister callback on IRQ enable failure */ - sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, - NULL); - return ret; - } - - DBG("Registered IRQ for intf %d, irq_idx=%d\n", - phys_enc->hw_intf->idx, - vid_enc->irq_idx); - - return ret; -} - -static int sde_encoder_phys_vid_unregister_irq( - struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - - sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, NULL); - sde_disable_irq(phys_enc->sde_kms, &vid_enc->irq_idx, 1); - - DBG("Un-Register IRQ for intf %d, irq_idx=%d\n", - phys_enc->hw_intf->idx, - vid_enc->irq_idx); - - return 0; -} - -static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) -{ - int ret = 0; - - DBG(""); - - if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing)) - return; - - sde_encoder_phys_vid_setup_timing_engine(phys_enc); - - sde_encoder_phys_vid_flush_intf(phys_enc); - - /* Register for interrupt unless we're the slave encoder */ - if (sde_encoder_phys_vid_is_master(phys_enc)) - ret = sde_encoder_phys_vid_register_irq(phys_enc); - - if (!ret && !phys_enc->enabled) { - unsigned long lock_flags = 0; - - /* Now enable timing engine */ - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 1); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); - - phys_enc->enabled = true; - } -} - -static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc) -{ - unsigned long lock_flags; - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - - DBG(""); - - if (WARN_ON(!phys_enc->enabled)) - return; - - if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing)) - return; - - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 0); - reinit_completion(&vid_enc->vblank_complete); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); - - /* - * Wait for a vsync so we know the ENABLE=0 latched before - * the (connector) source of the vsync's gets disabled, - * otherwise we end up in a funny state if we re-enable - * before the disable latches, which results that some of - * the settings changes for the new modeset (like new - * scanout buffer) don't latch properly.. - */ - sde_encoder_phys_vid_wait_for_vblank(vid_enc); - sde_encoder_phys_vid_unregister_irq(phys_enc); - phys_enc->enabled = false; -} - -static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - DBG(""); - kfree(phys_enc->hw_intf); - kfree(vid_enc); -} - -static void sde_encoder_phys_vid_get_hw_resources( - struct sde_encoder_phys *phys_enc, - struct sde_encoder_hw_resources *hw_res) -{ - struct msm_drm_private *priv = phys_enc->parent->dev->dev_private; - struct sde_kms *sde_kms = to_sde_kms(priv->kms); - const struct sde_hw_res_map *hw_res_map; - - DBG("Intf %d\n", phys_enc->hw_intf->idx); - - hw_res->intfs[phys_enc->hw_intf->idx] = INTF_MODE_VIDEO; - /* - * defaults should not be in use, - * otherwise signal/return failure - */ - hw_res_map = sde_rm_get_res_map(sde_kms, phys_enc->hw_intf->idx); - - /* This is video mode panel so PINGPONG will be in by-pass mode - * only assign ctl path.For cmd panel check if pp_split is - * enabled, override default map - */ - hw_res->ctls[hw_res_map->ctl] = true; -} - -/** - * video mode will use the intf (get_status) - * cmd mode will use the pingpong (get_vsync_info) - * to get this information - */ -static void sde_encoder_intf_get_vsync_info(struct sde_encoder_phys *phys_enc, - struct vsync_info *vsync) -{ - struct intf_status status; - - DBG(""); - phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status); - vsync->frame_count = status.frame_count; - vsync->line_count = status.line_count; - DBG(" sde_encoder_intf_get_vsync_info, count %d", vsync->frame_count); -} - -static void sde_encoder_intf_split_config(struct sde_encoder_phys *phys_enc, - bool enable) -{ - struct msm_drm_private *priv = phys_enc->parent->dev->dev_private; - struct sde_kms *sde_kms = to_sde_kms(priv->kms); - struct sde_hw_mdp *mdp = sde_hw_mdptop_init(MDP_TOP, sde_kms->mmio, - sde_kms->catalog); - struct split_pipe_cfg cfg; - - DBG("%p", mdp); - cfg.en = true; - cfg.mode = INTF_MODE_VIDEO; - if (!IS_ERR_OR_NULL(mdp)) - mdp->ops.setup_split_pipe(mdp, &cfg); -} - -static void sde_encoder_phys_vid_init_cbs(struct sde_encoder_phys_ops *ops) -{ - ops->mode_set = sde_encoder_phys_vid_mode_set; - ops->mode_fixup = sde_encoder_phys_vid_mode_fixup; - ops->enable = sde_encoder_phys_vid_enable; - ops->disable = sde_encoder_phys_vid_disable; - ops->destroy = sde_encoder_phys_vid_destroy; - ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources; - ops->get_vsync_info = sde_encoder_intf_get_vsync_info; - ops->enable_split_config = sde_encoder_intf_split_config; -} - -struct sde_encoder_phys *sde_encoder_phys_vid_init( - struct sde_kms *sde_kms, - enum sde_intf intf_idx, - enum sde_ctl ctl_idx, - struct drm_encoder *parent, - struct sde_encoder_virt_ops parent_ops) -{ - struct sde_encoder_phys *phys_enc = NULL; - struct sde_encoder_phys_vid *vid_enc = NULL; - int ret = 0; - - DBG(""); - - vid_enc = kzalloc(sizeof(*vid_enc), GFP_KERNEL); - if (!vid_enc) { - ret = -ENOMEM; - goto fail; - } - vid_enc->irq_idx = -EINVAL; - init_completion(&vid_enc->vblank_complete); - - phys_enc = &vid_enc->base; - - phys_enc->hw_intf = - sde_hw_intf_init(intf_idx, sde_kms->mmio, sde_kms->catalog); - if (!phys_enc->hw_intf) { - ret = -ENOMEM; - goto fail; - } - - phys_enc->hw_ctl = sde_rm_acquire_ctl_path(sde_kms, ctl_idx); - if (!phys_enc->hw_ctl) { - ret = -ENOMEM; - goto fail; - } - - sde_encoder_phys_vid_init_cbs(&phys_enc->phys_ops); - phys_enc->parent = parent; - phys_enc->parent_ops = parent_ops; - phys_enc->sde_kms = sde_kms; - spin_lock_init(&phys_enc->spin_lock); - - DBG("Created sde_encoder_phys_vid for intf %d", phys_enc->hw_intf->idx); - - return phys_enc; - -fail: - DRM_ERROR("Failed to create encoder\n"); - if (vid_enc) - sde_encoder_phys_vid_destroy(phys_enc); - - return ERR_PTR(ret); -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c deleted file mode 100644 index 118bb786da7e..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ /dev/null @@ -1,37 +0,0 @@ -/* 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 - * 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 "sde_hw_catalog.h" - -struct sde_mdss_hw_cfg_handler cfg_table[] = { - { .major = 1, .minor = 7, .cfg_init = sde_mdss_cfg_170_init}, -}; - -/** - * sde_hw_catalog_init: Returns the catalog information for the - * passed HW version - * @major: Major version of the MDSS HW - * @minor: Minor version - * @step: step version - */ -struct sde_mdss_cfg *sde_hw_catalog_init(u32 major, u32 minor, u32 step) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cfg_table); i++) { - if ((cfg_table[i].major == major) && - (cfg_table[i].minor == minor)) - return cfg_table[i].cfg_init(step); - } - - return ERR_PTR(-ENODEV); -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h deleted file mode 100644 index 46972f2d5dfd..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ /dev/null @@ -1,479 +0,0 @@ -/* 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 - * 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 _SDE_HW_CATALOG_H -#define _SDE_HW_CATALOG_H - -#include <linux/kernel.h> -#include <linux/bug.h> -#include <linux/bitmap.h> -#include <linux/err.h> - -#define MAX_BLOCKS 8 -#define MAX_LAYERS 12 - -#define SDE_HW_VER(MAJOR, MINOR, STEP) (((MAJOR & 0xF) << 28) |\ - ((MINOR & 0xFFF) << 16) |\ - (STEP & 0xFFFF)) - -#define SDE_HW_MAJOR(rev) ((rev) >> 28) -#define SDE_HW_MINOR(rev) .(((rev) >> 16) & 0xFFF) -#define SDE_HW_STEP(rev) ((rev) & 0xFFFF) -#define SDE_HW_MAJOR_MINOR(rev) ((rev) >> 16) - -#define IS_SDE_MAJOR_MINOR_SAME(rev1, rev2) \ - (SDE_HW_MAJOR_MINOR((rev1)) == SDE_HW_MAJOR_MINOR((rev2))) - -#define SDE_HW_VER_170 SDE_HW_VER(1, 7, 0) /* 8996 v1.0 */ -#define SDE_HW_VER_171 SDE_HW_VER(1, 7, 1) /* 8996 v2.0 */ -#define SDE_HW_VER_172 SDE_HW_VER(1, 7, 2) /* 8996 v3.0 */ -#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */ - -/** - * MDP TOP BLOCK features - * @SDE_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe - * @SDE_MDP_10BIT_SUPPORT, Chipset supports 10 bit pixel formats - * @SDE_MDP_BWC, MDSS HW supports Bandwidth compression. - * @SDE_MDP_UBWC_1_0, This chipsets supports Universal Bandwidth - * compression initial revision - * @SDE_MDP_UBWC_1_5, Universal Bandwidth compression version 1.5 - * @SDE_MDP_CDP, Client driven prefetch - * @SDE_MDP_MAX Maximum value - - */ -enum { - SDE_MDP_PANIC_PER_PIPE = 0x1, - SDE_MDP_10BIT_SUPPORT, - SDE_MDP_BWC, - SDE_MDP_UBWC_1_0, - SDE_MDP_UBWC_1_5, - SDE_MDP_CDP, - SDE_MDP_MAX -}; - -/** - * SSPP sub-blocks/features - * @SDE_SSPP_SRC Src and fetch part of the pipes, - * @SDE_SSPP_SCALAR_QSEED2, QSEED2 algorithm support - * @SDE_SSPP_SCALAR_QSEED3, QSEED3 algorithm support - * @SDE_SSPP_SCALAR_RGB, RGB Scalar, supported by RGB pipes - * @SDE_SSPP_CSC, Support of Color space conversion - * @SDE_SSPP_PA_V1, Common op-mode register for PA blocks - * @SDE_SSPP_HIST_V1 Histogram programming method V1 - * @SDE_SSPP_IGC, Inverse gamma correction - * @SDE_SSPP_PCC, Color correction support - * @SDE_SSPP_CURSOR, SSPP can be used as a cursor layer - * @SDE_SSPP_MAX maximum value - */ -enum { - SDE_SSPP_SRC = 0x1, - SDE_SSPP_SCALAR_QSEED2, - SDE_SSPP_SCALAR_QSEED3, - SDE_SSPP_SCALAR_RGB, - SDE_SSPP_CSC, - SDE_SSPP_PA_V1, /* Common op-mode register for PA blocks */ - SDE_SSPP_HIST_V1, - SDE_SSPP_IGC, - SDE_SSPP_PCC, - SDE_SSPP_CURSOR, - SDE_SSPP_MAX -}; - -/* - * MIXER sub-blocks/features - * @SDE_MIXER_LAYER Layer mixer layer blend configuration, - * @SDE_MIXER_SOURCESPLIT Layer mixer supports source-split configuration - * @SDE_MIXER_GC Gamma correction block - * @SDE_MIXER_MAX maximum value - */ -enum { - SDE_MIXER_LAYER = 0x1, - SDE_MIXER_SOURCESPLIT, - SDE_MIXER_GC, - SDE_MIXER_MAX -}; - -/** - * DSPP sub-blocks - * @SDE_DSPP_IGC DSPP Inverse gamma correction block - * @SDE_DSPP_PCC Panel color correction block - * @SDE_DSPP_GC Gamma correction block - * @SDE_DSPP_PA Picture adjustment block - * @SDE_DSPP_GAMUT Gamut bloc - * @SDE_DSPP_DITHER Dither block - * @SDE_DSPP_HIST Histogram bloc - * @SDE_DSPP_MAX maximum value - */ -enum { - SDE_DSPP_IGC = 0x1, - SDE_DSPP_PCC, - SDE_DSPP_GC, - SDE_DSPP_PA, - SDE_DSPP_GAMUT, - SDE_DSPP_DITHER, - SDE_DSPP_HIST, - SDE_DSPP_MAX -}; - -/** - * PINGPONG sub-blocks - * @SDE_PINGPONG_TE Tear check block - * @SDE_PINGPONG_TE2 Additional tear check block for split pipes - * @SDE_PINGPONG_SPLIT PP block supports split fifo - * @SDE_PINGPONG_DSC, Display stream compression blocks - * @SDE_PINGPONG_MAX - */ -enum { - SDE_PINGPONG_TE = 0x1, - SDE_PINGPONG_TE2, - SDE_PINGPONG_SPLIT, - SDE_PINGPONG_DSC, - SDE_PINGPONG_MAX -}; - -/** - * WB sub-blocks and features - * @SDE_WB_LINE_MODE Writeback module supports line/linear mode - * @SDE_WB_BLOCK_MODE Writeback module supports block mode read - * @SDE_WB_ROTATE rotation support,this is available if writeback - * supports block mode read - * @SDE_WB_CSC Writeback color conversion block support - * @SDE_WB_CHROMA_DOWN, Writeback chroma down block, - * @SDE_WB_DOWNSCALE, Writeback integer downscaler, - * @SDE_WB_DITHER, Dither block - * @SDE_WB_TRAFFIC_SHAPER, Writeback traffic shaper bloc - * @SDE_WB_UBWC_1_0, Writeback Universal bandwidth compression 1.0 - * support - * @SDE_WB_WBWC_1_5 UBWC 1.5 support - * @SDE_WB_MAX maximum value - */ -enum { - SDE_WB_LINE_MODE = 0x1, - SDE_WB_BLOCK_MODE, - SDE_WB_ROTATE = SDE_WB_BLOCK_MODE, - SDE_WB_CSC, - SDE_WB_CHROMA_DOWN, - SDE_WB_DOWNSCALE, - SDE_WB_DITHER, - SDE_WB_TRAFFIC_SHAPER, - SDE_WB_UBWC_1_0, - SDE_WB_MAX -}; - -/** - * MACRO SDE_HW_BLK_INFO - information of HW blocks inside SDE - * @id: enum identifying this block - * @base: register base offset to mdss - * @features bit mask identifying sub-blocks/features - */ -#define SDE_HW_BLK_INFO \ - u32 id; \ - u32 base; \ - unsigned long features - -/** - * MACRO SDE_HW_SUBBLK_INFO - information of HW sub-block inside SDE - * @id: enum identifying this sub-block - * @base: offset of this sub-block relative to the block - * offset - * @len register block length of this sub-block - */ -#define SDE_HW_SUBBLK_INFO \ - u32 id; \ - u32 base; \ - u32 len - -/** - * struct sde_src_blk: SSPP part of the source pipes - * @info: HW register and features supported by this sub-blk - */ -struct sde_src_blk { - SDE_HW_SUBBLK_INFO; -}; - -/** - * struct sde_scalar_info: Scalar information - * @info: HW register and features supported by this sub-blk - */ -struct sde_scalar_blk { - SDE_HW_SUBBLK_INFO; -}; - -struct sde_csc_blk { - SDE_HW_SUBBLK_INFO; -}; - -/** - * struct sde_pp_blk : Pixel processing sub-blk information - * @info: HW register and features supported by this sub-blk - * @version: HW Algorithm version - */ -struct sde_pp_blk { - SDE_HW_SUBBLK_INFO; - u32 version; -}; - -/** - * struct sde_sspp_sub_blks : SSPP sub-blocks - * @maxdwnscale: max downscale ratio supported(without DECIMATION) - * @maxupscale: maxupscale ratio supported - * @maxwidth: max pixelwidth supported by this pipe - * @danger_lut: LUT to generate danger signals - * @safe_lut: LUT to generate safe signals - * @src_blk: - * @scalar_blk: - * @csc_blk: - * @pa_blk: - * @hist_lut: - * @pcc_blk: - */ -struct sde_sspp_sub_blks { - u32 maxlinewidth; - u32 danger_lut; - u32 safe_lut; - u32 maxdwnscale; - u32 maxupscale; - struct sde_src_blk src_blk; - struct sde_scalar_blk scalar_blk; - struct sde_pp_blk csc_blk; - struct sde_pp_blk pa_blk; - struct sde_pp_blk hist_lut; - struct sde_pp_blk pcc_blk; -}; - -/** - * struct sde_lm_sub_blks: information of mixer block - * @maxwidth: Max pixel width supported by this mixer - * @maxblendstages: Max number of blend-stages supported - * @blendstage_base: Blend-stage register base offset - */ -struct sde_lm_sub_blks { - u32 maxwidth; - u32 maxblendstages; - u32 blendstage_base[MAX_BLOCKS]; -}; - -struct sde_dspp_sub_blks { - struct sde_pp_blk igc; - struct sde_pp_blk pcc; - struct sde_pp_blk gc; - struct sde_pp_blk pa; - struct sde_pp_blk gamut; - struct sde_pp_blk dither; - struct sde_pp_blk hist; -}; - -struct sde_pingpong_sub_blks { - struct sde_pp_blk te; - struct sde_pp_blk te2; - struct sde_pp_blk dsc; -}; - -struct sde_wb_sub_blocks { - u32 maxlinewidth; -}; - -struct sde_mdss_base_cfg { - SDE_HW_BLK_INFO; -}; - -/* struct sde_mdp_cfg : MDP TOP-BLK instance info - * @id: index identifying this block - * @base: register base offset to mdss - * @features bit mask identifying sub-blocks/features - * @highest_bank_bit: UBWC parameter - */ -struct sde_mdp_cfg { - SDE_HW_BLK_INFO; - u32 highest_bank_bit; -}; - -/* struct sde_mdp_cfg : MDP TOP-BLK instance info - * @id: index identifying this block - * @base: register base offset to mdss - * @features bit mask identifying sub-blocks/features - */ -struct sde_ctl_cfg { - SDE_HW_BLK_INFO; -}; - -/** - * struct sde_sspp_cfg - information of source pipes - * @id: index identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - * @sblk: Sub-blocks of SSPP - */ -struct sde_sspp_cfg { - SDE_HW_BLK_INFO; - const struct sde_sspp_sub_blks *sblk; -}; - -/** - * struct sde_lm_cfg - information of layer mixer blocks - * @id: index identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - * @sblk: Sub-blocks of SSPP - */ -struct sde_lm_cfg { - SDE_HW_BLK_INFO; - const struct sde_lm_sub_blks *sblk; -}; - -/** - * struct sde_dspp_cfg - information of DSPP blocks - * @id enum identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - * supported by this block - * @sblk sub-blocks information - */ -struct sde_dspp_cfg { - SDE_HW_BLK_INFO; - const struct sde_dspp_sub_blks *sblk; -}; - -/** - * struct sde_pingpong_cfg - information of PING-PONG blocks - * @id enum identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - * @sblk sub-blocks information - */ -struct sde_pingpong_cfg { - SDE_HW_BLK_INFO; - const struct sde_pingpong_sub_blks *sblk; -}; - -/** - * struct sde_cdm_cfg - information of chroma down blocks - * @id enum identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - * @intf_connect Connects to which interfaces - * @wb_connect: Connects to which writebacks - */ -struct sde_cdm_cfg { - SDE_HW_BLK_INFO; - u32 intf_connect[MAX_BLOCKS]; - u32 wb_connect[MAX_BLOCKS]; -}; - -/** - * struct sde_intf_cfg - information of timing engine blocks - * @id enum identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - * @type: Interface type(DSI, DP, HDMI) - * @controller_id: Controller Instance ID in case of multiple of intf type - * @prog_fetch_lines_worst_case Worst case latency num lines needed to prefetch - */ -struct sde_intf_cfg { - SDE_HW_BLK_INFO; - u32 type; /* interface type*/ - u32 controller_id; - u32 prog_fetch_lines_worst_case; -}; - -/** - * struct sde_wb_cfg - information of writeback blocks - * @id enum identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - */ -struct sde_wb_cfg { - SDE_HW_BLK_INFO; - struct sde_wb_sub_blocks *sblk; -}; - -/** - * struct sde_ad_cfg - information of Assertive Display blocks - * @id enum identifying this block - * @base register offset of this block - * @features bit mask identifying sub-blocks/features - */ -struct sde_ad_cfg { - SDE_HW_BLK_INFO; -}; - -/** - * struct sde_mdss_cfg - information of MDSS HW - * This is the main catalog data structure representing - * this HW version. Contains number of instances, - * register offsets, capabilities of the all MDSS HW sub-blocks. - */ -struct sde_mdss_cfg { - u32 hwversion; - - u32 mdss_count; - struct sde_mdss_base_cfg mdss[MAX_BLOCKS]; - - u32 mdp_count; - struct sde_mdp_cfg mdp[MAX_BLOCKS]; - - u32 ctl_count; - struct sde_ctl_cfg ctl[MAX_BLOCKS]; - - u32 sspp_count; - struct sde_sspp_cfg sspp[MAX_LAYERS]; - - u32 mixer_count; - struct sde_lm_cfg mixer[MAX_BLOCKS]; - - u32 dspp_count; - struct sde_dspp_cfg dspp[MAX_BLOCKS]; - - u32 pingpong_count; - struct sde_pingpong_cfg pingpong[MAX_BLOCKS]; - - u32 cdm_count; - struct sde_cdm_cfg cdm[MAX_BLOCKS]; - - u32 intf_count; - struct sde_intf_cfg intf[MAX_BLOCKS]; - - u32 wb_count; - struct sde_wb_cfg wb[MAX_BLOCKS]; - - u32 ad_count; - struct sde_ad_cfg ad[MAX_BLOCKS]; - /* Add additional block data structures here */ -}; - -struct sde_mdss_hw_cfg_handler { - u32 major; - u32 minor; - struct sde_mdss_cfg* (*cfg_init)(u32); -}; - -/* - * Access Macros - */ -#define BLK_MDP(s) ((s)->mdp) -#define BLK_CTL(s) ((s)->ctl) -#define BLK_VIG(s) ((s)->vig) -#define BLK_RGB(s) ((s)->rgb) -#define BLK_DMA(s) ((s)->dma) -#define BLK_CURSOR(s) ((s)->cursor) -#define BLK_MIXER(s) ((s)->mixer) -#define BLK_DSPP(s) ((s)->dspp) -#define BLK_PINGPONG(s) ((s)->pingpong) -#define BLK_CDM(s) ((s)->cdm) -#define BLK_INTF(s) ((s)->intf) -#define BLK_WB(s) ((s)->wb) -#define BLK_AD(s) ((s)->ad) - -struct sde_mdss_cfg *sde_mdss_cfg_170_init(u32 step); -struct sde_mdss_cfg *sde_hw_catalog_init(u32 major, u32 minor, u32 step); - -#endif /* _SDE_HW_CATALOG_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c deleted file mode 100644 index 7fb5a0616838..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c +++ /dev/null @@ -1,303 +0,0 @@ -/* 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 - * 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 "sde_hw_catalog.h" -#include "sde_hw_mdss.h" -#include "sde_hwio.h" - -/* VIG layer capability */ -#define VIG_17X_MASK \ - (BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_SCALAR_QSEED2) |\ - BIT(SDE_SSPP_CSC) | BIT(SDE_SSPP_PA_V1) |\ - BIT(SDE_SSPP_HIST_V1) | BIT(SDE_SSPP_PCC) |\ - BIT(SDE_SSPP_IGC)) - -/* RGB layer capability */ -#define RGB_17X_MASK \ - (BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_SCALAR_RGB) |\ - BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC)) - -/* DMA layer capability */ -#define DMA_17X_MASK \ - (BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_PA_V1) |\ - BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC)) - -/* Cursor layer capability */ -#define CURSOR_17X_MASK (BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_CURSOR)) - -#define MIXER_17X_MASK (BIT(SDE_MIXER_SOURCESPLIT) |\ - BIT(SDE_MIXER_GC)) - -#define DSPP_17X_MASK \ - (BIT(SDE_DSPP_IGC) | BIT(SDE_DSPP_PCC) |\ - BIT(SDE_DSPP_GC) | BIT(SDE_DSPP_PA) | BIT(SDE_DSPP_GAMUT) |\ - BIT(SDE_DSPP_DITHER) | BIT(SDE_DSPP_HIST)) - -#define PINGPONG_17X_MASK \ - (BIT(SDE_PINGPONG_TE) | BIT(SDE_PINGPONG_DSC)) - -#define PINGPONG_17X_SPLIT_MASK \ - (PINGPONG_17X_MASK | BIT(SDE_PINGPONG_SPLIT) |\ - BIT(SDE_PINGPONG_TE2)) - -#define WB01_17X_MASK \ - (BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_BLOCK_MODE) |\ - BIT(SDE_WB_CSC) | BIT(SDE_WB_CHROMA_DOWN) | BIT(SDE_WB_DOWNSCALE) |\ - BIT(SDE_WB_DITHER) | BIT(SDE_WB_TRAFFIC_SHAPER) |\ - BIT(SDE_WB_UBWC_1_0)) - -#define WB2_17X_MASK \ - (BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_TRAFFIC_SHAPER)) - -/** - * set_cfg_1xx_init(): populate sde sub-blocks reg offsets and instance counts - */ -static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg) -{ - - /* Layer capability */ - static const struct sde_sspp_sub_blks layer = { - .maxlinewidth = 2560, - .danger_lut = 0xFFFF, - .safe_lut = 0xFF00, - .maxdwnscale = 4, .maxupscale = 20, - .src_blk = {.id = SDE_SSPP_SRC, - .base = 0x00, .len = 0x150,}, - .scalar_blk = {.id = SDE_SSPP_SCALAR_QSEED2, - .base = 0x200, .len = 0x70,}, - .csc_blk = {.id = SDE_SSPP_CSC, - .base = 0x320, .len = 0x44,}, - .pa_blk = {.id = SDE_SSPP_PA_V1, - .base = 0x200, .len = 0x0,}, - .hist_lut = {.id = SDE_SSPP_HIST_V1, - .base = 0xA00, .len = 0x400,}, - .pcc_blk = {.id = SDE_SSPP_PCC, - .base = 0x1780, .len = 0x64,}, - }; - - static const struct sde_sspp_sub_blks dma = { - .maxlinewidth = 2560, - .danger_lut = 0xFFFF, - .safe_lut = 0xFF00, - .maxdwnscale = 0, .maxupscale = 0, - .src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,}, - .scalar_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - .csc_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - .pa_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - .hist_lut = {.id = 0, .base = 0x00, .len = 0x0,}, - .pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x01780, .len = 0x64,}, - }; - - static const struct sde_sspp_sub_blks cursor = { - .maxlinewidth = 128, - .danger_lut = 0xFFFF, - .safe_lut = 0xFF00, - .maxdwnscale = 0, .maxupscale = 0, - .src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,}, - .scalar_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - .csc_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - .pa_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - .hist_lut = {.id = 0, .base = 0x00, .len = 0x0,}, - .pcc_blk = {.id = 0, .base = 0x00, .len = 0x0,}, - }; - - /* MIXER capability */ - static const struct sde_lm_sub_blks lm = { - .maxwidth = 2560, - .maxblendstages = 7, /* excluding base layer */ - .blendstage_base = { /* offsets relative to mixer base */ - 0x20, 0x50, 0x80, 0xB0, 0x230, 0x260, 0x290 } - }; - - /* DSPP capability */ - static const struct sde_dspp_sub_blks pp = { - .igc = {.id = SDE_DSPP_GC, .base = 0x17c0, .len = 0x0, - .version = 0x1}, - .pcc = {.id = SDE_DSPP_PCC, .base = 0x00, .len = 0x0, - .version = 0x1}, - .gamut = {.id = SDE_DSPP_GAMUT, .base = 0x01600, .len = 0x0, - .version = 0x1}, - .dither = {.id = SDE_DSPP_DITHER, .base = 0x00, .len = 0x0, - .version = 0x1}, - .pa = {.id = SDE_DSPP_PA, .base = 0x00, .len = 0x0, - .version = 0x1}, - .hist = {.id = SDE_DSPP_HIST, .base = 0x00, .len = 0x0, - .version = 0x1}, - }; - - /* PINGPONG capability */ - static const struct sde_pingpong_sub_blks p_p = { - .te = {.id = SDE_PINGPONG_TE, .base = 0x0000, .len = 0x0, - .version = 0x1}, - .te2 = {.id = SDE_PINGPONG_TE2, .base = 0x2000, .len = 0x0, - .version = 0x1}, - .dsc = {.id = SDE_PINGPONG_DSC, .base = 0x10000, .len = 0x0, - .version = 0x1}, - }; - - /* Setup Register maps and defaults */ - *cfg = (struct sde_mdss_cfg){ - .mdss_count = 1, - .mdss = { - {.id = MDP_TOP, .base = 0x00000000, .features = 0} - }, - .mdp_count = 1, - .mdp = { - {.id = MDP_TOP, .base = 0x00001000, .features = 0, - .highest_bank_bit = 0x2}, - }, - .ctl_count = 5, - .ctl = { - {.id = CTL_0, .base = 0x00002000}, - {.id = CTL_1, .base = 0x00002200}, - {.id = CTL_2, .base = 0x00002400}, - {.id = CTL_3, .base = 0x00002600}, - {.id = CTL_4, .base = 0x00002800}, - }, - /* 4 VIG, + 4 RGB + 2 DMA + 2 CURSOR */ - .sspp_count = 12, - .sspp = { - {.id = SSPP_VIG0, .base = 0x00005000, - .features = VIG_17X_MASK, .sblk = &layer}, - {.id = SSPP_VIG1, .base = 0x00007000, - .features = VIG_17X_MASK, .sblk = &layer}, - {.id = SSPP_VIG2, .base = 0x00009000, - .features = VIG_17X_MASK, .sblk = &layer}, - {.id = SSPP_VIG3, .base = 0x0000b000, - .features = VIG_17X_MASK, .sblk = &layer}, - - {.id = SSPP_RGB0, .base = 0x00015000, - .features = RGB_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB1, .base = 0x00017000, - .features = RGB_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB2, .base = 0x00019000, - .features = RGB_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB3, .base = 0x0001B000, - .features = RGB_17X_MASK, .sblk = &layer}, - - {.id = SSPP_DMA0, .base = 0x00025000, - .features = DMA_17X_MASK, .sblk = &dma}, - {.id = SSPP_DMA1, .base = 0x00027000, - .features = DMA_17X_MASK, .sblk = &dma}, - - {.id = SSPP_CURSOR0, .base = 0x00035000, - .features = CURSOR_17X_MASK, .sblk = &cursor}, - {.id = SSPP_CURSOR1, .base = 0x00037000, - .features = CURSOR_17X_MASK, .sblk = &cursor}, - }, - .mixer_count = 6, - .mixer = { - {.id = LM_0, .base = 0x00045000, - .features = MIXER_17X_MASK, - .sblk = &lm}, - {.id = LM_1, .base = 0x00046000, - .features = MIXER_17X_MASK, - .sblk = &lm}, - {.id = LM_2, .base = 0x00047000, - .features = MIXER_17X_MASK, - .sblk = &lm}, - {.id = LM_3, .base = 0x00048000, - .features = MIXER_17X_MASK, - .sblk = &lm}, - {.id = LM_4, .base = 0x00049000, - .features = MIXER_17X_MASK, - .sblk = &lm}, - {.id = LM_5, .base = 0x0004a000, - .features = MIXER_17X_MASK, - .sblk = &lm}, - }, - .dspp_count = 2, - .dspp = { - {.id = DSPP_0, .base = 0x00055000, - .features = DSPP_17X_MASK, - .sblk = &pp}, - {.id = DSPP_1, .base = 0x00057000, - .features = DSPP_17X_MASK, - .sblk = &pp}, - }, - .pingpong_count = 4, - .pingpong = { - {.id = PINGPONG_0, .base = 0x00071000, - .features = PINGPONG_17X_SPLIT_MASK, - .sblk = &p_p}, - {.id = PINGPONG_1, .base = 0x00071800, - .features = PINGPONG_17X_SPLIT_MASK, - .sblk = &p_p}, - {.id = PINGPONG_2, .base = 0x00072000, - .features = PINGPONG_17X_MASK, - .sblk = &p_p}, - {.id = PINGPONG_3, .base = 0x00072800, - .features = PINGPONG_17X_MASK, - .sblk = &p_p}, - }, - .cdm_count = 1, - .cdm = { - {.id = CDM_0, .base = 0x0007A200, .features = 0, - .intf_connect = { BIT(INTF_3)}, - .wb_connect = { BIT(WB_2)},} - }, - .intf_count = 4, - .intf = { - {.id = INTF_0, .base = 0x0006B000, - .type = INTF_NONE, .controller_id = 0, - .prog_fetch_lines_worst_case = 21}, - {.id = INTF_1, .base = 0x0006B800, - .type = INTF_DSI, .controller_id = 0, - .prog_fetch_lines_worst_case = 21}, - {.id = INTF_2, .base = 0x0006C000, - .type = INTF_DSI, .controller_id = 1, - .prog_fetch_lines_worst_case = 21}, - {.id = INTF_3, .base = 0x0006C800, - .type = INTF_HDMI, .controller_id = 0, - .prog_fetch_lines_worst_case = 21}, - }, - .wb_count = 3, - .wb = { - {.id = WB_0, .base = 0x00065000, - .features = WB01_17X_MASK}, - {.id = WB_1, .base = 0x00065800, - .features = WB01_17X_MASK}, - {.id = WB_2, .base = 0x00066000, - .features = WB2_17X_MASK}, - }, - .ad_count = 2, - .ad = { - {.id = AD_0, .base = 0x00079000}, - {.id = AD_1, .base = 0x00079800}, - }, - }; - return 0; -} - -/** - * sde_mdp_cfg_170_init(): Populate the sde sub-blocks catalog information - */ -struct sde_mdss_cfg *sde_mdss_cfg_170_init(u32 step) -{ - struct sde_mdss_cfg *m = NULL; - - /* - * This function, for each sub-block sets, - * instance count, IO regions, - * default capabilities and this version capabilities, - * Additional catalog items - */ - - m = kzalloc(sizeof(*m), GFP_KERNEL); - if (!m) - return NULL; - - set_cfg_1xx_init(m); - m->hwversion = SDE_HW_VER(1, 7, step); - - return m; -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c deleted file mode 100644 index 25fc55191045..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c +++ /dev/null @@ -1,296 +0,0 @@ -/* 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 - * 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 "sde_hw_mdss.h" -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_cdm.h" - -#define CDM_CSC_10_OPMODE 0x000 -#define CDM_CSC_10_BASE 0x004 - -#define CDM_CDWN2_OP_MODE 0x100 -#define CDM_CDWN2_CLAMP_OUT 0x104 -#define CDM_CDWN2_PARAMS_3D_0 0x108 -#define CDM_CDWN2_PARAMS_3D_1 0x10C -#define CDM_CDWN2_COEFF_COSITE_H_0 0x110 -#define CDM_CDWN2_COEFF_COSITE_H_1 0x114 -#define CDM_CDWN2_COEFF_COSITE_H_2 0x118 -#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C -#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 -#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 -#define CDM_CDWN2_COEFF_COSITE_V 0x128 -#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C -#define CDM_CDWN2_OUT_SIZE 0x130 - -#define CDM_HDMI_PACK_OP_MODE 0x200 -#define CDM_CSC_10_MATRIX_COEFF_0 0x204 - -/** - * Horizontal coeffiecients for cosite chroma downscale - * s13 repesentation of coefficients - */ -static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; - -/** - * Horizontal coefficients for offsite chroma downscale - */ -static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; - -/** - * Vertical coefficients for cosite chroma downscale - */ -static u32 cosite_v_coeff[] = {0x00080004}; -/** - * Vertical coefficients for offsite chroma downscale - */ -static u32 offsite_v_coeff[] = {0x00060002}; - -/* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */ -static struct sde_csc_cfg rgb2yuv_cfg = { - { - 0x0083, 0x0102, 0x0032, - 0x1fb5, 0x1f6c, 0x00e1, - 0x00e1, 0x1f45, 0x1fdc - }, - { 0x00, 0x00, 0x00 }, - { 0x0040, 0x0200, 0x0200 }, - { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, - { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, -}; - -static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->cdm_count; i++) { - if (cdm == m->cdm[i].id) { - b->base_off = addr; - b->blk_off = m->cdm[i].base; - b->hwversion = m->hwversion; - return &m->cdm[i]; - } - } - - return ERR_PTR(-EINVAL); -} - -static void sde_hw_cdm_setup_csc_10bit(struct sde_hw_cdm *ctx, - struct sde_csc_cfg *data) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - - sde_hw_csc_setup(c, CDM_CSC_10_MATRIX_COEFF_0, data); -} - -int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx, - struct sde_hw_cdm_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 opmode = 0; - u32 out_size = 0; - - if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT) - opmode &= ~BIT(7); - else - opmode |= BIT(7); - - /* ENABLE DWNS_H bit */ - opmode |= BIT(1); - - switch (cfg->h_cdwn_type) { - case CDM_CDWN_DISABLE: - /* CLEAR METHOD_H field */ - opmode &= ~(0x18); - /* CLEAR DWNS_H bit */ - opmode &= ~BIT(1); - break; - case CDM_CDWN_PIXEL_DROP: - /* Clear METHOD_H field (pixel drop is 0) */ - opmode &= ~(0x18); - break; - case CDM_CDWN_AVG: - /* Clear METHOD_H field (Average is 0x1) */ - opmode &= ~(0x18); - opmode |= (0x1 << 0x3); - break; - case CDM_CDWN_COSITE: - /* Clear METHOD_H field (Average is 0x2) */ - opmode &= ~(0x18); - opmode |= (0x2 << 0x3); - /* Co-site horizontal coefficients */ - SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, - cosite_h_coeff[0]); - SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, - cosite_h_coeff[1]); - SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, - cosite_h_coeff[2]); - break; - case CDM_CDWN_OFFSITE: - /* Clear METHOD_H field (Average is 0x3) */ - opmode &= ~(0x18); - opmode |= (0x3 << 0x3); - - /* Off-site horizontal coefficients */ - SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, - offsite_h_coeff[0]); - SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, - offsite_h_coeff[1]); - SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, - offsite_h_coeff[2]); - break; - default: - pr_err("%s invalid horz down sampling type\n", __func__); - return -EINVAL; - } - - /* ENABLE DWNS_V bit */ - opmode |= BIT(2); - - switch (cfg->v_cdwn_type) { - case CDM_CDWN_DISABLE: - /* CLEAR METHOD_V field */ - opmode &= ~(0x60); - /* CLEAR DWNS_V bit */ - opmode &= ~BIT(2); - break; - case CDM_CDWN_PIXEL_DROP: - /* Clear METHOD_V field (pixel drop is 0) */ - opmode &= ~(0x60); - break; - case CDM_CDWN_AVG: - /* Clear METHOD_V field (Average is 0x1) */ - opmode &= ~(0x60); - opmode |= (0x1 << 0x5); - break; - case CDM_CDWN_COSITE: - /* Clear METHOD_V field (Average is 0x2) */ - opmode &= ~(0x60); - opmode |= (0x2 << 0x5); - /* Co-site vertical coefficients */ - SDE_REG_WRITE(c, - CDM_CDWN2_COEFF_COSITE_V, - cosite_v_coeff[0]); - break; - case CDM_CDWN_OFFSITE: - /* Clear METHOD_V field (Average is 0x3) */ - opmode &= ~(0x60); - opmode |= (0x3 << 0x5); - - /* Off-site vertical coefficients */ - SDE_REG_WRITE(c, - CDM_CDWN2_COEFF_OFFSITE_V, - offsite_v_coeff[0]); - break; - default: - return -EINVAL; - } - - if (cfg->v_cdwn_type || cfg->h_cdwn_type) - opmode |= BIT(0); /* EN CDWN module */ - else - opmode &= ~BIT(0); - - out_size = (cfg->output_width & 0xFFFF) | - ((cfg->output_height & 0xFFFF) << 16); - SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); - SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); - SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, - ((0x3FF << 16) | 0x0)); - - return 0; -} - -int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, - struct sde_hw_cdm_cfg *cdm) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - struct sde_mdp_format_params *fmt = cdm->output_fmt; - u32 opmode = 0; - u32 cdm_enable = 0; - u32 csc = 0; - - if (!fmt->is_yuv) - return 0; - - if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { - if (fmt->chroma_sample != SDE_MDP_CHROMA_H1V2) - return -EINVAL; /*unsupported format */ - opmode = BIT(0); - opmode |= (fmt->chroma_sample << 1); - cdm_enable |= BIT(19); - } else { - opmode = 0; - cdm_enable = BIT(24); - } - - csc |= BIT(2); - csc &= ~BIT(1); - csc |= BIT(0); - - /* For this register we need to offset it to MDP TOP BLOCK */ - SDE_REG_WRITE(c, MDP_OUT_CTL_0, cdm_enable); - - SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); - SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); - return 0; -} - -void sde_hw_cdm_disable(struct sde_hw_cdm *ctx) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - - /* mdp top block */ - SDE_REG_WRITE(c, MDP_OUT_CTL_0, 0); /* bypass mode */ -} - -static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops, - unsigned long features) -{ - ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit; - ops->setup_cdwn = sde_hw_cdm_setup_cdwn; - ops->enable = sde_hw_cdm_enable; - ops->disable = sde_hw_cdm_disable; -} - -struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_cdm *c; - struct sde_cdm_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _cdm_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - c->idx = idx; - c->cdm_hw_cap = cfg; - _setup_cdm_ops(&c->ops, c->cdm_hw_cap->features); - - /* - * Perform any default initialization for the chroma down module - * @setup default csc coefficients - */ - sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg); - - return c; -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h deleted file mode 100644 index ea19dc208c7f..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h +++ /dev/null @@ -1,115 +0,0 @@ -/* 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 - * 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 _SDE_HW_CDM_H -#define _SDE_HW_CDM_H - -#include "sde_hw_mdss.h" - -struct sde_hw_cdm; - -struct sde_hw_cdm_cfg { - u32 output_width; - u32 output_height; - u32 output_bit_depth; - u32 h_cdwn_type; - u32 v_cdwn_type; - struct sde_mdp_format_params *output_fmt; - u32 output_type; - int flags; -}; - -enum sde_hw_cdwn_type { - CDM_CDWN_DISABLE, - CDM_CDWN_PIXEL_DROP, - CDM_CDWN_AVG, - CDM_CDWN_COSITE, - CDM_CDWN_OFFSITE, -}; - -enum sde_hw_cdwn_output_type { - CDM_CDWN_OUTPUT_HDMI, - CDM_CDWN_OUTPUT_WB, -}; - -enum sde_hw_cdwn_output_bit_depth { - CDM_CDWN_OUTPUT_8BIT, - CDM_CDWN_OUTPUT_10BIT, -}; - -/** - * struct sde_hw_cdm_ops : Interface to the chroma down Hw driver functions - * Assumption is these functions will be called after - * clocks are enabled - * @setup_csc: Programs the csc matrix - * @setup_cdwn: Sets up the chroma down sub module - * @enable: Enables the output to interface and programs the - * output packer - * @disable: Puts the cdm in bypass mode - */ -struct sde_hw_cdm_ops { - /** - * Programs the CSC matrix for conversion from RGB space to YUV space, - * it is optinal to call this function as this matrix is automatically - * set during initialization, user should call this if it wants - * to program a different matrix than default matrix. - * @cdm: Pointer to the chroma down context structure - * @data Pointer to CSC configuration data - */ - void (*setup_csc_data)(struct sde_hw_cdm *cdm, - struct sde_csc_cfg *data); - - /** - * Programs the Chroma downsample part. - * @cdm Pointer to chroma down context - */ - int (*setup_cdwn)(struct sde_hw_cdm *cdm, - struct sde_hw_cdm_cfg *cfg); - - /** - * Enable the CDM module - * @cdm Pointer to chroma down context - */ - int (*enable)(struct sde_hw_cdm *cdm, - struct sde_hw_cdm_cfg *cfg); - - /** - * Disable the CDM module - * @cdm Pointer to chroma down context - */ - void (*disable)(struct sde_hw_cdm *cdm); -}; - -struct sde_hw_cdm { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* chroma down */ - const struct sde_cdm_cfg *cdm_hw_cap; - enum sde_cdm idx; - - /* ops */ - struct sde_hw_cdm_ops ops; -}; - -/** - * sde_hw_cdm_init(): Initializes the cdm hw driver object. - * should be called once before accessing every cdm. - * @idx: cdm index for which driver object is required - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -#endif /*_SDE_HW_CDM_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c deleted file mode 100644 index e87ca9570443..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 - * 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 "sde_hw_mdss.h" -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_dspp.h" - -static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->dspp_count; i++) { - if (dspp == m->dspp[i].id) { - b->base_off = addr; - b->blk_off = m->dspp[i].base; - b->hwversion = m->hwversion; - return &m->dspp[i]; - } - } - - return ERR_PTR(-EINVAL); -} - -void sde_dspp_setup_histogram(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_read_histogram(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_update_igc(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_setup_pa(struct sde_hw_dspp *dspp, void *cfg) -{ -} - -void sde_dspp_setup_pcc(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_setup_sharpening(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_setup_pa_memcolor(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_setup_sixzone(struct sde_hw_dspp *dspp) -{ -} - -void sde_dspp_setup_danger_safe(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -void sde_dspp_setup_dither(struct sde_hw_dspp *ctx, void *cfg) -{ -} - -static void _setup_dspp_ops(struct sde_hw_dspp_ops *ops, - unsigned long features) -{ -} -struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_dspp *c; - struct sde_dspp_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _dspp_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - /* Assign ops */ - c->idx = idx; - c->cap = cfg; - _setup_dspp_ops(&c->ops, c->cap->features); - - return c; -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h deleted file mode 100644 index eef4fbdff2a7..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h +++ /dev/null @@ -1,127 +0,0 @@ -/* 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 - * 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 _SDE_HW_DSPP_H -#define _SDE_HW_DSPP_H - -struct sde_hw_dspp; - -/** - * struct sde_hw_dspp_ops - interface to the dspp hardware driver functions - * Caller must call the init function to get the dspp context for each dspp - * Assumption is these functions will be called after clocks are enabled - */ -struct sde_hw_dspp_ops { - /** - * setup_histogram - setup dspp histogram - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_histogram)(struct sde_hw_dspp *ctx, void *cfg); - - /** - * read_histogram - read dspp histogram - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*read_histogram)(struct sde_hw_dspp *ctx, void *cfg); - - /** - * update_igc - update dspp igc - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*update_igc)(struct sde_hw_dspp *ctx, void *cfg); - - /** - * setup_pa - setup dspp pa - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_pa)(struct sde_hw_dspp *dspp, void *cfg); - - /** - * setup_pcc - setup dspp pcc - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_pcc)(struct sde_hw_dspp *ctx, void *cfg); - - /** - * setup_sharpening - setup dspp sharpening - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_sharpening)(struct sde_hw_dspp *ctx, void *cfg); - - /** - * setup_pa_memcolor - setup dspp memcolor - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_pa_memcolor)(struct sde_hw_dspp *ctx, void *cfg); - - /** - * setup_sixzone - setup dspp six zone - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_sixzone)(struct sde_hw_dspp *dspp); - - /** - * setup_danger_safe - setup danger safe LUTS - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_danger_safe)(struct sde_hw_dspp *ctx, void *cfg); - /** - * setup_dither - setup dspp dither - * @ctx: Pointer to dspp context - * @cfg: Pointer to configuration - */ - void (*setup_dither)(struct sde_hw_dspp *ctx, void *cfg); -}; - -/** - * struct sde_hw_dspp - dspp description - * @base_off: MDP register mapped offset - * @blk_off: DSPP offset relative to mdss offset - * @length Length of register block offset - * @hwversion Mdss hw version number - * @idx: DSPP index - * @dspp_hw_cap: Pointer to layer_cfg - * @highest_bank_bit: - * @ops: Pointer to operations possible for this dspp - */ -struct sde_hw_dspp { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* dspp */ - enum sde_dspp idx; - const struct sde_dspp_cfg *cap; - - /* Ops */ - struct sde_hw_dspp_ops ops; -}; - -/** - * sde_hw_dspp_init - initializes the dspp hw driver object. - * should be called once before accessing every dspp. - * @idx: DSPP index for which driver object is required - * @addr: Mapped register io address of MDP - */ -struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -#endif /*_SDE_HW_DSPP_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c deleted file mode 100644 index 99aa2e59dd85..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c +++ /dev/null @@ -1,969 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/bitops.h> -#include <linux/slab.h> - -#include "sde_kms.h" -#include "sde_hw_interrupts.h" -#include "sde_hw_mdp_util.h" -#include "sde_hw_mdss.h" - -/** - * Register offsets in MDSS register file for the interrupt registers - * w.r.t. to the MDSS base - */ -#define HW_INTR_STATUS 0x0010 -#define MDP_SSPP_TOP0_OFF 0x1000 -#define MDP_INTF_0_OFF 0x6B000 -#define MDP_INTF_1_OFF 0x6B800 -#define MDP_INTF_2_OFF 0x6C000 -#define MDP_INTF_3_OFF 0x6C800 -#define MDP_INTF_4_OFF 0x6D000 - -/** - * WB interrupt status bit definitions - */ -#define SDE_INTR_WB_0_DONE BIT(0) -#define SDE_INTR_WB_1_DONE BIT(1) -#define SDE_INTR_WB_2_DONE BIT(4) - -/** - * WDOG timer interrupt status bit definitions - */ -#define SDE_INTR_WD_TIMER_0_DONE BIT(2) -#define SDE_INTR_WD_TIMER_1_DONE BIT(3) -#define SDE_INTR_WD_TIMER_2_DONE BIT(5) -#define SDE_INTR_WD_TIMER_3_DONE BIT(6) -#define SDE_INTR_WD_TIMER_4_DONE BIT(7) - -/** - * Pingpong interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_0_DONE BIT(8) -#define SDE_INTR_PING_PONG_1_DONE BIT(9) -#define SDE_INTR_PING_PONG_2_DONE BIT(10) -#define SDE_INTR_PING_PONG_3_DONE BIT(11) -#define SDE_INTR_PING_PONG_0_RD_PTR BIT(12) -#define SDE_INTR_PING_PONG_1_RD_PTR BIT(13) -#define SDE_INTR_PING_PONG_2_RD_PTR BIT(14) -#define SDE_INTR_PING_PONG_3_RD_PTR BIT(15) -#define SDE_INTR_PING_PONG_0_WR_PTR BIT(16) -#define SDE_INTR_PING_PONG_1_WR_PTR BIT(17) -#define SDE_INTR_PING_PONG_2_WR_PTR BIT(18) -#define SDE_INTR_PING_PONG_3_WR_PTR BIT(19) -#define SDE_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20) -#define SDE_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21) -#define SDE_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22) -#define SDE_INTR_PING_PONG_3_AUTOREFRESH_DONE BIT(23) - -/** - * Interface interrupt status bit definitions - */ -#define SDE_INTR_INTF_0_UNDERRUN BIT(24) -#define SDE_INTR_INTF_1_UNDERRUN BIT(26) -#define SDE_INTR_INTF_2_UNDERRUN BIT(28) -#define SDE_INTR_INTF_3_UNDERRUN BIT(30) -#define SDE_INTR_INTF_0_VSYNC BIT(25) -#define SDE_INTR_INTF_1_VSYNC BIT(27) -#define SDE_INTR_INTF_2_VSYNC BIT(29) -#define SDE_INTR_INTF_3_VSYNC BIT(31) - -/** - * Pingpong Secondary interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE BIT(0) -#define SDE_INTR_PING_PONG_S0_WR_PTR BIT(4) -#define SDE_INTR_PING_PONG_S0_RD_PTR BIT(8) -#define SDE_INTR_PING_PONG_S0_TEAR_DETECTED BIT(22) -#define SDE_INTR_PING_PONG_S0_TE_DETECTED BIT(28) - -/** - * Pingpong TEAR detection interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_0_TEAR_DETECTED BIT(16) -#define SDE_INTR_PING_PONG_1_TEAR_DETECTED BIT(17) -#define SDE_INTR_PING_PONG_2_TEAR_DETECTED BIT(18) -#define SDE_INTR_PING_PONG_3_TEAR_DETECTED BIT(19) - -/** - * Pingpong TE detection interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_0_TE_DETECTED BIT(24) -#define SDE_INTR_PING_PONG_1_TE_DETECTED BIT(25) -#define SDE_INTR_PING_PONG_2_TE_DETECTED BIT(26) -#define SDE_INTR_PING_PONG_3_TE_DETECTED BIT(27) - -/** - * Concurrent WB overflow interrupt status bit definitions - */ -#define SDE_INTR_CWB_2_OVERFLOW BIT(14) -#define SDE_INTR_CWB_3_OVERFLOW BIT(15) - -/** - * Histogram VIG done interrupt status bit definitions - */ -#define SDE_INTR_HIST_VIG_0_DONE BIT(0) -#define SDE_INTR_HIST_VIG_1_DONE BIT(4) -#define SDE_INTR_HIST_VIG_2_DONE BIT(8) -#define SDE_INTR_HIST_VIG_3_DONE BIT(10) - -/** - * Histogram VIG reset Sequence done interrupt status bit definitions - */ -#define SDE_INTR_HIST_VIG_0_RSTSEQ_DONE BIT(1) -#define SDE_INTR_HIST_VIG_1_RSTSEQ_DONE BIT(5) -#define SDE_INTR_HIST_VIG_2_RSTSEQ_DONE BIT(9) -#define SDE_INTR_HIST_VIG_3_RSTSEQ_DONE BIT(11) - -/** - * Histogram DSPP done interrupt status bit definitions - */ -#define SDE_INTR_HIST_DSPP_0_DONE BIT(12) -#define SDE_INTR_HIST_DSPP_1_DONE BIT(16) -#define SDE_INTR_HIST_DSPP_2_DONE BIT(20) -#define SDE_INTR_HIST_DSPP_3_DONE BIT(22) - -/** - * Histogram DSPP reset Sequence done interrupt status bit definitions - */ -#define SDE_INTR_HIST_DSPP_0_RSTSEQ_DONE BIT(13) -#define SDE_INTR_HIST_DSPP_1_RSTSEQ_DONE BIT(17) -#define SDE_INTR_HIST_DSPP_2_RSTSEQ_DONE BIT(21) -#define SDE_INTR_HIST_DSPP_3_RSTSEQ_DONE BIT(23) - -/** - * INTF interrupt status bit definitions - */ -#define SDE_INTR_VIDEO_INTO_STATIC BIT(0) -#define SDE_INTR_VIDEO_OUTOF_STATIC BIT(1) -#define SDE_INTR_DSICMD_0_INTO_STATIC BIT(2) -#define SDE_INTR_DSICMD_0_OUTOF_STATIC BIT(3) -#define SDE_INTR_DSICMD_1_INTO_STATIC BIT(4) -#define SDE_INTR_DSICMD_1_OUTOF_STATIC BIT(5) -#define SDE_INTR_DSICMD_2_INTO_STATIC BIT(6) -#define SDE_INTR_DSICMD_2_OUTOF_STATIC BIT(7) -#define SDE_INTR_PROG_LINE BIT(8) - -/** - * struct sde_intr_reg - array of SDE register sets - * @clr_off: offset to CLEAR reg - * @en_off: offset to ENABLE reg - * @status_off: offset to STATUS reg - */ -struct sde_intr_reg { - u32 clr_off; - u32 en_off; - u32 status_off; -}; - -/** - * struct sde_irq_type - maps each irq with i/f - * @intr_type: type of interrupt listed in sde_intr_type - * @instance_idx: instance index of the associated HW block in SDE - * @irq_mask: corresponding bit in the interrupt status reg - * @reg_idx: which reg set to use - */ -struct sde_irq_type { - u32 intr_type; - u32 instance_idx; - u32 irq_mask; - u32 reg_idx; -}; - -/** - * List of SDE interrupt registers - */ -static const struct sde_intr_reg sde_intr_set[] = { - { - MDP_SSPP_TOP0_OFF+INTR_CLEAR, - MDP_SSPP_TOP0_OFF+INTR_EN, - MDP_SSPP_TOP0_OFF+INTR_STATUS - }, - { - MDP_SSPP_TOP0_OFF+INTR2_CLEAR, - MDP_SSPP_TOP0_OFF+INTR2_EN, - MDP_SSPP_TOP0_OFF+INTR2_STATUS - }, - { - MDP_SSPP_TOP0_OFF+HIST_INTR_CLEAR, - MDP_SSPP_TOP0_OFF+HIST_INTR_EN, - MDP_SSPP_TOP0_OFF+HIST_INTR_STATUS - }, - { - MDP_INTF_0_OFF+INTF_INTR_CLEAR, - MDP_INTF_0_OFF+INTF_INTR_EN, - MDP_INTF_0_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_1_OFF+INTF_INTR_CLEAR, - MDP_INTF_1_OFF+INTF_INTR_EN, - MDP_INTF_1_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_2_OFF+INTF_INTR_CLEAR, - MDP_INTF_2_OFF+INTF_INTR_EN, - MDP_INTF_2_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_3_OFF+INTF_INTR_CLEAR, - MDP_INTF_3_OFF+INTF_INTR_EN, - MDP_INTF_3_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_4_OFF+INTF_INTR_CLEAR, - MDP_INTF_4_OFF+INTF_INTR_EN, - MDP_INTF_4_OFF+INTF_INTR_STATUS - } -}; - -/** - * IRQ mapping table - use for lookup an irq_idx in this table that have - * a matching interface type and instance index. - */ -static const struct sde_irq_type sde_irq_map[] = { - /* BEGIN MAP_RANGE: 0-31, INTR */ - /* irq_idx: 0-3 */ - { SDE_IRQ_TYPE_WB_ROT_COMP, WB_0, SDE_INTR_WB_0_DONE, 0}, - { SDE_IRQ_TYPE_WB_ROT_COMP, WB_1, SDE_INTR_WB_1_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_0, SDE_INTR_WD_TIMER_0_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_1, SDE_INTR_WD_TIMER_1_DONE, 0}, - /* irq_idx: 4-7 */ - { SDE_IRQ_TYPE_WB_WFD_COMP, WB_2, SDE_INTR_WB_2_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_2, SDE_INTR_WD_TIMER_2_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_3, SDE_INTR_WD_TIMER_3_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_4, SDE_INTR_WD_TIMER_4_DONE, 0}, - /* irq_idx: 8-11 */ - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_0, - SDE_INTR_PING_PONG_0_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_1, - SDE_INTR_PING_PONG_1_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_2, - SDE_INTR_PING_PONG_2_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_3, - SDE_INTR_PING_PONG_3_DONE, 0}, - /* irq_idx: 12-15 */ - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_0, - SDE_INTR_PING_PONG_0_RD_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_1, - SDE_INTR_PING_PONG_1_RD_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_2, - SDE_INTR_PING_PONG_2_RD_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_3, - SDE_INTR_PING_PONG_3_RD_PTR, 0}, - /* irq_idx: 16-19 */ - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_0, - SDE_INTR_PING_PONG_0_WR_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_1, - SDE_INTR_PING_PONG_1_WR_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_2, - SDE_INTR_PING_PONG_2_WR_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_3, - SDE_INTR_PING_PONG_3_WR_PTR, 0}, - /* irq_idx: 20-23 */ - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_0, - SDE_INTR_PING_PONG_0_AUTOREFRESH_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_1, - SDE_INTR_PING_PONG_1_AUTOREFRESH_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_2, - SDE_INTR_PING_PONG_2_AUTOREFRESH_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_3, - SDE_INTR_PING_PONG_3_AUTOREFRESH_DONE, 0}, - /* irq_idx: 24-27 */ - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_0, SDE_INTR_INTF_0_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_0, SDE_INTR_INTF_0_VSYNC, 0}, - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_1, SDE_INTR_INTF_1_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_1, SDE_INTR_INTF_1_VSYNC, 0}, - /* irq_idx: 28-31 */ - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_2, SDE_INTR_INTF_2_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_2, SDE_INTR_INTF_2_VSYNC, 0}, - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_3, SDE_INTR_INTF_3_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_3, SDE_INTR_INTF_3_VSYNC, 0}, - - /* BEGIN MAP_RANGE: 32-64, INTR2 */ - /* irq_idx: 32-35 */ - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 36-39 */ - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_WR_PTR, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 40-43 */ - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_RD_PTR, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 44-47 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_2, SDE_INTR_CWB_2_OVERFLOW, 1}, - { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_3, SDE_INTR_CWB_3_OVERFLOW, 1}, - /* irq_idx: 48-51 */ - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_0, - SDE_INTR_PING_PONG_0_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_1, - SDE_INTR_PING_PONG_1_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_2, - SDE_INTR_PING_PONG_2_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_3, - SDE_INTR_PING_PONG_3_TEAR_DETECTED, 1}, - /* irq_idx: 52-55 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 56-59 */ - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_0, - SDE_INTR_PING_PONG_0_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_1, - SDE_INTR_PING_PONG_1_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_2, - SDE_INTR_PING_PONG_2_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_3, - SDE_INTR_PING_PONG_3_TE_DETECTED, 1}, - /* irq_idx: 60-63 */ - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - - /* BEGIN MAP_RANGE: 64-95 HIST */ - /* irq_idx: 64-67 */ - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG0, SDE_INTR_HIST_VIG_0_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG0, - SDE_INTR_HIST_VIG_0_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 68-71 */ - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG1, SDE_INTR_HIST_VIG_1_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG1, - SDE_INTR_HIST_VIG_1_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 68-71 */ - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG2, SDE_INTR_HIST_VIG_2_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG2, - SDE_INTR_HIST_VIG_2_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG3, SDE_INTR_HIST_VIG_3_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG3, - SDE_INTR_HIST_VIG_3_RSTSEQ_DONE, 2}, - /* irq_idx: 72-75 */ - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_0, SDE_INTR_HIST_DSPP_0_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_0, - SDE_INTR_HIST_DSPP_0_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 76-79 */ - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_1, SDE_INTR_HIST_DSPP_1_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_1, - SDE_INTR_HIST_DSPP_1_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 80-83 */ - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_2, SDE_INTR_HIST_DSPP_2_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_2, - SDE_INTR_HIST_DSPP_2_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_3, SDE_INTR_HIST_DSPP_3_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_3, - SDE_INTR_HIST_DSPP_3_RSTSEQ_DONE, 2}, - /* irq_idx: 84-87 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 88-91 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 92-95 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - - /* BEGIN MAP_RANGE: 96-127 INTF_0_INTR */ - /* irq_idx: 96-99 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_0, - SDE_INTR_VIDEO_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_0, - SDE_INTR_VIDEO_OUTOF_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_0, - SDE_INTR_DSICMD_0_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_0, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 3}, - /* irq_idx: 100-103 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_0, - SDE_INTR_DSICMD_1_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_0, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_0, - SDE_INTR_DSICMD_2_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_0, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 3}, - /* irq_idx: 104-107 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_0, SDE_INTR_PROG_LINE, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 108-111 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 112-115 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 116-119 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 120-123 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 124-127 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - - /* BEGIN MAP_RANGE: 128-159 INTF_1_INTR */ - /* irq_idx: 128-131 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_1, - SDE_INTR_VIDEO_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_1, - SDE_INTR_VIDEO_OUTOF_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_1, - SDE_INTR_DSICMD_0_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_1, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 4}, - /* irq_idx: 132-135 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_1, - SDE_INTR_DSICMD_1_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_1, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_1, - SDE_INTR_DSICMD_2_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_1, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 4}, - /* irq_idx: 136-139 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_1, SDE_INTR_PROG_LINE, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 140-143 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 144-147 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 148-151 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 152-155 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 156-159 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - - /* BEGIN MAP_RANGE: 160-191 INTF_2_INTR */ - /* irq_idx: 160-163 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_2, - SDE_INTR_VIDEO_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_2, - SDE_INTR_VIDEO_OUTOF_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_2, - SDE_INTR_DSICMD_0_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_2, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 5}, - /* irq_idx: 164-167 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_2, - SDE_INTR_DSICMD_1_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_2, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_2, - SDE_INTR_DSICMD_2_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_2, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 5}, - /* irq_idx: 168-171 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_2, SDE_INTR_PROG_LINE, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 172-175 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 176-179 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 180-183 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 184-187 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 188-191 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - - /* BEGIN MAP_RANGE: 192-223 INTF_3_INTR */ - /* irq_idx: 192-195 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_3, - SDE_INTR_VIDEO_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_3, - SDE_INTR_VIDEO_OUTOF_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_3, - SDE_INTR_DSICMD_0_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_3, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 6}, - /* irq_idx: 196-199 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_3, - SDE_INTR_DSICMD_1_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_3, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_3, - SDE_INTR_DSICMD_2_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_3, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 6}, - /* irq_idx: 200-203 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_3, SDE_INTR_PROG_LINE, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 204-207 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 208-211 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 212-215 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 216-219 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 220-223 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - - /* BEGIN MAP_RANGE: 224-255 INTF_4_INTR */ - /* irq_idx: 224-227 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_4, - SDE_INTR_VIDEO_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_4, - SDE_INTR_VIDEO_OUTOF_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_4, - SDE_INTR_DSICMD_0_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_4, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 7}, - /* irq_idx: 228-231 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_4, - SDE_INTR_DSICMD_1_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_4, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_4, - SDE_INTR_DSICMD_2_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_4, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 7}, - /* irq_idx: 232-235 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_4, SDE_INTR_PROG_LINE, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 236-239 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 240-243 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 244-247 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 248-251 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 252-255 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, -}; - -static int sde_hw_intr_irqidx_lookup(enum sde_intr_type intr_type, - u32 instance_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sde_irq_map); i++) { - if (intr_type == sde_irq_map[i].intr_type && - instance_idx == sde_irq_map[i].instance_idx) - return i; - } - - pr_debug("IRQ lookup fail!! intr_type=%d, instance_idx=%d\n", - intr_type, instance_idx); - return -EINVAL; -} - -static void sde_hw_intr_set_mask(struct sde_hw_intr *intr, uint32_t reg_off, - uint32_t mask) -{ - SDE_REG_WRITE(&intr->hw, reg_off, mask); -} - -static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr, - void (*cbfunc)(void *, int), - void *arg) -{ - int reg_idx; - int irq_idx; - int start_idx; - int end_idx; - u32 irq_status; - unsigned long irq_flags; - - /* - * The dispatcher will save the IRQ status before calling here. - * Now need to go through each IRQ status and find matching - * irq lookup index. - */ - spin_lock_irqsave(&intr->status_lock, irq_flags); - for (reg_idx = 0; reg_idx < ARRAY_SIZE(sde_intr_set); reg_idx++) { - irq_status = intr->save_irq_status[reg_idx]; - - /* - * Each Interrupt register has a range of 32 indexes, and - * that is static for sde_irq_map. - */ - start_idx = reg_idx * 32; - end_idx = start_idx + 32; - - /* - * Search through matching intr status from irq map. - * start_idx and end_idx defined the search range in - * the sde_irq_map. - */ - for (irq_idx = start_idx; - (irq_idx < end_idx) && irq_status; - irq_idx++) - if ((irq_status & sde_irq_map[irq_idx].irq_mask) && - (sde_irq_map[irq_idx].reg_idx == reg_idx)) { - /* - * Once a match on irq mask, perform a callback - * to the given cbfunc. cbfunc will take care - * the interrupt status clearing. If cbfunc is - * not provided, then the interrupt clearing - * is here. - */ - if (cbfunc) - cbfunc(arg, irq_idx); - else - intr->ops.clear_interrupt_status( - intr, irq_idx); - - /* - * When callback finish, clear the irq_status - * with the matching mask. Once irq_status - * is all cleared, the search can be stopped. - */ - irq_status &= ~sde_irq_map[irq_idx].irq_mask; - } - } - spin_unlock_irqrestore(&intr->status_lock, irq_flags); -} - -static int sde_hw_intr_enable_irq(struct sde_hw_intr *intr, int irq_idx) -{ - int reg_idx; - unsigned long irq_flags; - const struct sde_intr_reg *reg; - const struct sde_irq_type *irq; - const char *dbgstr = NULL; - uint32_t cache_irq_mask; - - if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) { - pr_err("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - irq = &sde_irq_map[irq_idx]; - reg_idx = irq->reg_idx; - reg = &sde_intr_set[reg_idx]; - - spin_lock_irqsave(&intr->mask_lock, irq_flags); - cache_irq_mask = intr->cache_irq_mask[reg_idx]; - if (cache_irq_mask & irq->irq_mask) { - dbgstr = "SDE IRQ already set:"; - } else { - dbgstr = "SDE IRQ enabled:"; - - cache_irq_mask |= irq->irq_mask; - /* Cleaning any pending interrupt */ - SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); - /* Enabling interrupts with the new mask */ - SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); - - intr->cache_irq_mask[reg_idx] = cache_irq_mask; - } - spin_unlock_irqrestore(&intr->mask_lock, irq_flags); - - pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, - irq->irq_mask, cache_irq_mask); - - return 0; -} - -static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx) -{ - int reg_idx; - unsigned long irq_flags; - const struct sde_intr_reg *reg; - const struct sde_irq_type *irq; - const char *dbgstr = NULL; - uint32_t cache_irq_mask; - - if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) { - pr_err("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - irq = &sde_irq_map[irq_idx]; - reg_idx = irq->reg_idx; - reg = &sde_intr_set[reg_idx]; - - spin_lock_irqsave(&intr->mask_lock, irq_flags); - cache_irq_mask = intr->cache_irq_mask[reg_idx]; - if ((cache_irq_mask & irq->irq_mask) == 0) { - dbgstr = "SDE IRQ is already cleared:"; - } else { - dbgstr = "SDE IRQ mask disable:"; - - cache_irq_mask &= ~irq->irq_mask; - /* Disable interrupts based on the new mask */ - SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); - /* Cleaning any pending interrupt */ - SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); - - intr->cache_irq_mask[reg_idx] = cache_irq_mask; - } - spin_unlock_irqrestore(&intr->mask_lock, irq_flags); - - pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, - irq->irq_mask, cache_irq_mask); - - return 0; -} - -static int sde_hw_intr_clear_irqs(struct sde_hw_intr *intr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) - SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, 0xffffffff); - - return 0; -} - -static int sde_hw_intr_disable_irqs(struct sde_hw_intr *intr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) - SDE_REG_WRITE(&intr->hw, sde_intr_set[i].en_off, 0x00000000); - - return 0; -} - -static int sde_hw_intr_get_valid_interrupts(struct sde_hw_intr *intr, - uint32_t *mask) -{ - *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1 - | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP; - return 0; -} - -static int sde_hw_intr_get_interrupt_sources(struct sde_hw_intr *intr, - uint32_t *sources) -{ - *sources = SDE_REG_READ(&intr->hw, HW_INTR_STATUS); - return 0; -} - -static void sde_hw_intr_get_interrupt_statuses(struct sde_hw_intr *intr) -{ - int i; - u32 enable_mask; - unsigned long irq_flags; - - spin_lock_irqsave(&intr->status_lock, irq_flags); - for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) { - /* Read interrupt status */ - intr->save_irq_status[i] = SDE_REG_READ(&intr->hw, - sde_intr_set[i].status_off); - - /* Read enable mask */ - enable_mask = SDE_REG_READ(&intr->hw, sde_intr_set[i].en_off); - - /* and clear the interrupt */ - if (intr->save_irq_status[i]) - SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, - intr->save_irq_status[i]); - - /* Finally update IRQ status based on enable mask */ - intr->save_irq_status[i] &= enable_mask; - } - spin_unlock_irqrestore(&intr->status_lock, irq_flags); -} - -static void sde_hw_intr_clear_interrupt_status(struct sde_hw_intr *intr, - int irq_idx) -{ - int reg_idx; - unsigned long irq_flags; - - spin_lock_irqsave(&intr->mask_lock, irq_flags); - - reg_idx = sde_irq_map[irq_idx].reg_idx; - SDE_REG_WRITE(&intr->hw, sde_intr_set[reg_idx].clr_off, - sde_irq_map[irq_idx].irq_mask); - - spin_unlock_irqrestore(&intr->mask_lock, irq_flags); -} - - -static void __setup_intr_ops(struct sde_hw_intr_ops *ops) -{ - ops->set_mask = sde_hw_intr_set_mask; - ops->irq_idx_lookup = sde_hw_intr_irqidx_lookup; - ops->enable_irq = sde_hw_intr_enable_irq; - ops->disable_irq = sde_hw_intr_disable_irq; - ops->dispatch_irqs = sde_hw_intr_dispatch_irq; - ops->clear_all_irqs = sde_hw_intr_clear_irqs; - ops->disable_all_irqs = sde_hw_intr_disable_irqs; - ops->get_valid_interrupts = sde_hw_intr_get_valid_interrupts; - ops->get_interrupt_sources = sde_hw_intr_get_interrupt_sources; - ops->get_interrupt_statuses = sde_hw_intr_get_interrupt_statuses; - ops->clear_interrupt_status = sde_hw_intr_clear_interrupt_status; -} - -static struct sde_mdss_base_cfg *__intr_offset(struct sde_mdss_cfg *m, - void __iomem *addr, struct sde_hw_blk_reg_map *hw) -{ - if (m->mdp_count == 0) - return NULL; - - hw->base_off = addr; - hw->blk_off = m->mdss[0].base; - hw->hwversion = m->hwversion; - return &m->mdss[0]; -} - -struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_intr *intr = kzalloc(sizeof(*intr), GFP_KERNEL); - struct sde_mdss_base_cfg *cfg; - - if (!intr) - return ERR_PTR(-ENOMEM); - - cfg = __intr_offset(m, addr, &intr->hw); - if (!cfg) { - kfree(intr); - return ERR_PTR(-EINVAL); - } - __setup_intr_ops(&intr->ops); - - intr->irq_idx_tbl_size = ARRAY_SIZE(sde_irq_map); - - intr->cache_irq_mask = kcalloc(ARRAY_SIZE(sde_intr_set), sizeof(u32), - GFP_KERNEL); - if (intr->cache_irq_mask == NULL) { - kfree(intr); - return ERR_PTR(-ENOMEM); - } - - intr->save_irq_status = kcalloc(ARRAY_SIZE(sde_intr_set), sizeof(u32), - GFP_KERNEL); - if (intr->save_irq_status == NULL) { - kfree(intr->cache_irq_mask); - kfree(intr); - return ERR_PTR(-ENOMEM); - } - - spin_lock_init(&intr->mask_lock); - spin_lock_init(&intr->status_lock); - - return intr; -} - -void sde_hw_intr_destroy(struct sde_hw_intr *intr) -{ - if (intr) { - kfree(intr->cache_irq_mask); - kfree(intr->save_irq_status); - kfree(intr); - } -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h deleted file mode 100644 index 0ddb1e78a953..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h +++ /dev/null @@ -1,245 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _SDE_HW_INTERRUPTS_H -#define _SDE_HW_INTERRUPTS_H - -#include <linux/types.h> - -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_mdp_util.h" -#include "sde_hw_mdss.h" - -#define IRQ_SOURCE_MDP BIT(0) -#define IRQ_SOURCE_DSI0 BIT(4) -#define IRQ_SOURCE_DSI1 BIT(5) -#define IRQ_SOURCE_HDMI BIT(8) -#define IRQ_SOURCE_EDP BIT(12) -#define IRQ_SOURCE_MHL BIT(16) - -/** - * sde_intr_type - HW Interrupt Type - * @SDE_IRQ_TYPE_WB_ROT_COMP: WB rotator done - * @SDE_IRQ_TYPE_WB_WFD_COMP: WB WFD done - * @SDE_IRQ_TYPE_PING_PONG_COMP: PingPong done - * @SDE_IRQ_TYPE_PING_PONG_RD_PTR: PingPong read pointer - * @SDE_IRQ_TYPE_PING_PONG_WR_PTR: PingPong write pointer - * @SDE_IRQ_TYPE_PING_PONG_AUTO_REF: PingPong auto refresh - * @SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK: PingPong Tear check - * @SDE_IRQ_TYPE_PING_PONG_TE_CHECK: PingPong TE detection - * @SDE_IRQ_TYPE_INTF_UNDER_RUN: INTF underrun - * @SDE_IRQ_TYPE_INTF_VSYNC: INTF VSYNC - * @SDE_IRQ_TYPE_CWB_OVERFLOW: Concurrent WB overflow - * @SDE_IRQ_TYPE_HIST_VIG_DONE: VIG Histogram done - * @SDE_IRQ_TYPE_HIST_VIG_RSTSEQ: VIG Histogram reset - * @SDE_IRQ_TYPE_HIST_DSPP_DONE: DSPP Histogram done - * @SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ: DSPP Histogram reset - * @SDE_IRQ_TYPE_WD_TIMER: Watchdog timer - * @SDE_IRQ_TYPE_SFI_VIDEO_IN: Video static frame INTR into static - * @SDE_IRQ_TYPE_SFI_VIDEO_OUT: Video static frame INTR out-of static - * @SDE_IRQ_TYPE_SFI_CMD_0_IN: DSI CMD0 static frame INTR into static - * @SDE_IRQ_TYPE_SFI_CMD_0_OUT: DSI CMD0 static frame INTR out-of static - * @SDE_IRQ_TYPE_SFI_CMD_1_IN: DSI CMD1 static frame INTR into static - * @SDE_IRQ_TYPE_SFI_CMD_1_OUT: DSI CMD1 static frame INTR out-of static - * @SDE_IRQ_TYPE_SFI_CMD_2_IN: DSI CMD2 static frame INTR into static - * @SDE_IRQ_TYPE_SFI_CMD_2_OUT: DSI CMD2 static frame INTR out-of static - * @SDE_IRQ_TYPE_PROG_LINE: Programmable Line interrupt - * @SDE_IRQ_TYPE_RESERVED: Reserved for expansion - */ -enum sde_intr_type { - SDE_IRQ_TYPE_WB_ROT_COMP, - SDE_IRQ_TYPE_WB_WFD_COMP, - SDE_IRQ_TYPE_PING_PONG_COMP, - SDE_IRQ_TYPE_PING_PONG_RD_PTR, - SDE_IRQ_TYPE_PING_PONG_WR_PTR, - SDE_IRQ_TYPE_PING_PONG_AUTO_REF, - SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, - SDE_IRQ_TYPE_PING_PONG_TE_CHECK, - SDE_IRQ_TYPE_INTF_UNDER_RUN, - SDE_IRQ_TYPE_INTF_VSYNC, - SDE_IRQ_TYPE_CWB_OVERFLOW, - SDE_IRQ_TYPE_HIST_VIG_DONE, - SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, - SDE_IRQ_TYPE_HIST_DSPP_DONE, - SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, - SDE_IRQ_TYPE_WD_TIMER, - SDE_IRQ_TYPE_SFI_VIDEO_IN, - SDE_IRQ_TYPE_SFI_VIDEO_OUT, - SDE_IRQ_TYPE_SFI_CMD_0_IN, - SDE_IRQ_TYPE_SFI_CMD_0_OUT, - SDE_IRQ_TYPE_SFI_CMD_1_IN, - SDE_IRQ_TYPE_SFI_CMD_1_OUT, - SDE_IRQ_TYPE_SFI_CMD_2_IN, - SDE_IRQ_TYPE_SFI_CMD_2_OUT, - SDE_IRQ_TYPE_PROG_LINE, - SDE_IRQ_TYPE_RESERVED, -}; - -struct sde_hw_intr; - -/** - * Interrupt operations. - */ -struct sde_hw_intr_ops { - /** - * set_mask - Programs the given interrupt register with the - * given interrupt mask. Register value will get overwritten. - * @intr: HW interrupt handle - * @reg_off: MDSS HW register offset - * @irqmask: IRQ mask value - */ - void (*set_mask)( - struct sde_hw_intr *intr, - uint32_t reg, - uint32_t irqmask); - - /** - * irq_idx_lookup - Lookup IRQ index on the HW interrupt type - * Used for all irq related ops - * @intr_type: Interrupt type defined in sde_intr_type - * @instance_idx: HW interrupt block instance - * @return: irq_idx or -EINVAL for lookup fail - */ - int (*irq_idx_lookup)( - enum sde_intr_type intr_type, - u32 instance_idx); - - /** - * enable_irq - Enable IRQ based on lookup IRQ index - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @return: 0 for success, otherwise failure - */ - int (*enable_irq)( - struct sde_hw_intr *intr, - int irq_idx); - - /** - * disable_irq - Disable IRQ based on lookup IRQ index - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @return: 0 for success, otherwise failure - */ - int (*disable_irq)( - struct sde_hw_intr *intr, - int irq_idx); - - /** - * clear_all_irqs - Clears all the interrupts (i.e. acknowledges - * any asserted IRQs). Useful during reset. - * @intr: HW interrupt handle - * @return: 0 for success, otherwise failure - */ - int (*clear_all_irqs)( - struct sde_hw_intr *intr); - - /** - * disable_all_irqs - Disables all the interrupts. Useful during reset. - * @intr: HW interrupt handle - * @return: 0 for success, otherwise failure - */ - int (*disable_all_irqs)( - struct sde_hw_intr *intr); - - /** - * dispatch_irqs - IRQ dispatcher will call the given callback - * function when a matching interrupt status bit is - * found in the irq mapping table. - * @intr: HW interrupt handle - * @cbfunc: Callback function pointer - * @arg: Argument to pass back during callback - */ - void (*dispatch_irqs)( - struct sde_hw_intr *intr, - void (*cbfunc)(void *arg, int irq_idx), - void *arg); - - /** - * get_interrupt_statuses - Gets and store value from all interrupt - * status registers that are currently fired. - * @intr: HW interrupt handle - */ - void (*get_interrupt_statuses)( - struct sde_hw_intr *intr); - - /** - * clear_interrupt_status - Clears HW interrupt status based on given - * lookup IRQ index. - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - */ - void (*clear_interrupt_status)( - struct sde_hw_intr *intr, - int irq_idx); - - /** - * get_valid_interrupts - Gets a mask of all valid interrupt sources - * within SDE. These are actually status bits - * within interrupt registers that specify the - * source of the interrupt in IRQs. For example, - * valid interrupt sources can be MDP, DSI, - * HDMI etc. - * @intr: HW interrupt handle - * @mask: Returning the interrupt source MASK - * @return: 0 for success, otherwise failure - */ - int (*get_valid_interrupts)( - struct sde_hw_intr *intr, - uint32_t *mask); - - /** - * get_interrupt_sources - Gets the bitmask of the SDE interrupt - * source that are currently fired. - * @intr: HW interrupt handle - * @sources: Returning the SDE interrupt source status bit mask - * @return: 0 for success, otherwise failure - */ - int (*get_interrupt_sources)( - struct sde_hw_intr *intr, - uint32_t *sources); -}; - -/** - * struct sde_hw_intr: hw interrupts handling data structure - * @hw: virtual address mapping - * @ops: function pointer mapping for IRQ handling - * @cache_irq_mask: array of IRQ enable masks reg storage created during init - * @save_irq_status: array of IRQ status reg storage created during init - * @irq_idx_tbl_size: total number of irq_idx mapped in the hw_interrupts - * @mask_lock: spinlock for accessing IRQ mask - * @status_lock: spinlock for accessing IRQ status - */ -struct sde_hw_intr { - struct sde_hw_blk_reg_map hw; - struct sde_hw_intr_ops ops; - u32 *cache_irq_mask; - u32 *save_irq_status; - u32 irq_idx_tbl_size; - spinlock_t mask_lock; - spinlock_t status_lock; -}; - -/** - * sde_hw_intr_init(): Initializes the interrupts hw object - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr, - struct sde_mdss_cfg *m); - -/** - * sde_hw_intr_destroy(): Cleanup interrutps hw object - * @intr: pointer to interrupts hw object - */ -void sde_hw_intr_destroy(struct sde_hw_intr *intr); -#endif diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c deleted file mode 100644 index 8dd306720e90..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c +++ /dev/null @@ -1,389 +0,0 @@ -/* 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 - * 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 "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_intf.h" -#include "sde_hw_mdp_top.h" - -#define INTF_TIMING_ENGINE_EN 0x000 -#define INTF_CONFIG 0x004 -#define INTF_HSYNC_CTL 0x008 -#define INTF_VSYNC_PERIOD_F0 0x00C -#define INTF_VSYNC_PERIOD_F1 0x010 -#define INTF_VSYNC_PULSE_WIDTH_F0 0x014 -#define INTF_VSYNC_PULSE_WIDTH_F1 0x018 -#define INTF_DISPLAY_V_START_F0 0x01C -#define INTF_DISPLAY_V_START_F1 0x020 -#define INTF_DISPLAY_V_END_F0 0x024 -#define INTF_DISPLAY_V_END_F1 0x028 -#define INTF_ACTIVE_V_START_F0 0x02C -#define INTF_ACTIVE_V_START_F1 0x030 -#define INTF_ACTIVE_V_END_F0 0x034 -#define INTF_ACTIVE_V_END_F1 0x038 -#define INTF_DISPLAY_HCTL 0x03C -#define INTF_ACTIVE_HCTL 0x040 -#define INTF_BORDER_COLOR 0x044 -#define INTF_UNDERFLOW_COLOR 0x048 -#define INTF_HSYNC_SKEW 0x04C -#define INTF_POLARITY_CTL 0x050 -#define INTF_TEST_CTL 0x054 -#define INTF_TP_COLOR0 0x058 -#define INTF_TP_COLOR1 0x05C -#define INTF_FRAME_LINE_COUNT_EN 0x0A8 -#define INTF_FRAME_COUNT 0x0AC -#define INTF_LINE_COUNT 0x0B0 - -#define INTF_DEFLICKER_CONFIG 0x0F0 -#define INTF_DEFLICKER_STRNG_COEFF 0x0F4 -#define INTF_DEFLICKER_WEAK_COEFF 0x0F8 - -#define INTF_DSI_CMD_MODE_TRIGGER_EN 0x084 -#define INTF_PANEL_FORMAT 0x090 -#define INTF_TPG_ENABLE 0x100 -#define INTF_TPG_MAIN_CONTROL 0x104 -#define INTF_TPG_VIDEO_CONFIG 0x108 -#define INTF_TPG_COMPONENT_LIMITS 0x10C -#define INTF_TPG_RECTANGLE 0x110 -#define INTF_TPG_INITIAL_VALUE 0x114 -#define INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118 -#define INTF_TPG_RGB_MAPPING 0x11C -#define INTF_PROG_FETCH_START 0x170 - -#define INTF_FRAME_LINE_COUNT_EN 0x0A8 -#define INTF_FRAME_COUNT 0x0AC -#define INTF_LINE_COUNT 0x0B0 - -static struct sde_intf_cfg *_intf_offset(enum sde_intf intf, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->intf_count; i++) { - if ((intf == m->intf[i].id) && - (m->intf[i].type != INTF_NONE)) { - b->base_off = addr; - b->blk_off = m->intf[i].base; - b->hwversion = m->hwversion; - return &m->intf[i]; - } - } - - return ERR_PTR(-EINVAL); -} - -static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, - struct intf_timing_params *p, - struct sde_mdp_format_params *fmt) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 hsync_period, vsync_period; - u32 display_v_start, display_v_end; - u32 hsync_start_x, hsync_end_x; - u32 active_h_start, active_h_end; - u32 active_v_start, active_v_end; - u32 active_hctl, display_hctl, hsync_ctl; - u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity; - u32 panel_format; - u32 intf_cfg; - - /* read interface_cfg */ - intf_cfg = SDE_REG_READ(c, INTF_CONFIG); - hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + - p->h_front_porch; - vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + - p->v_front_porch; - - display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * - hsync_period) + p->hsync_skew; - display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + - p->hsync_skew - 1; - - if (ctx->cap->type == INTF_EDP) { - display_v_start += p->hsync_pulse_width + p->h_back_porch; - display_v_end -= p->h_front_porch; - } - - hsync_start_x = p->h_back_porch + p->hsync_pulse_width; - hsync_end_x = hsync_period - p->h_front_porch - 1; - - if (p->width != p->xres) { - active_h_start = hsync_start_x; - active_h_end = active_h_start + p->xres - 1; - } else { - active_h_start = 0; - active_h_end = 0; - } - - if (p->height != p->yres) { - active_v_start = display_v_start; - active_v_end = active_v_start + (p->yres * hsync_period) - 1; - } else { - active_v_start = 0; - active_v_end = 0; - } - - if (active_h_end) { - active_hctl = (active_h_end << 16) | active_h_start; - intf_cfg |= BIT(29); /* ACTIVE_H_ENABLE */ - } else { - active_hctl = 0; - } - - if (active_v_end) - intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */ - - hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; - display_hctl = (hsync_end_x << 16) | hsync_start_x; - - den_polarity = 0; - if (ctx->cap->type == INTF_HDMI) { - hsync_polarity = p->yres >= 720 ? 0 : 1; - vsync_polarity = p->yres >= 720 ? 0 : 1; - } else { - hsync_polarity = 0; - vsync_polarity = 0; - } - polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ - (vsync_polarity << 1) | /* VSYNC Polarity */ - (hsync_polarity << 0); /* HSYNC Polarity */ - - if (!fmt->is_yuv) - panel_format = (fmt->bits[C0_G_Y] | - (fmt->bits[C1_B_Cb] << 2) | - (fmt->bits[C2_R_Cr] << 4) | - (0x21 << 8)); - else - /* Interface treats all the pixel data in RGB888 format */ - panel_format = (COLOR_8BIT | - (COLOR_8BIT << 2) | - (COLOR_8BIT << 4) | - (0x21 << 8)); - - SDE_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl); - SDE_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, - vsync_period * hsync_period); - SDE_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0, - p->vsync_pulse_width * hsync_period); - SDE_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl); - SDE_REG_WRITE(c, INTF_DISPLAY_V_START_F0, - display_v_start); - SDE_REG_WRITE(c, INTF_DISPLAY_V_END_F0, - display_v_end); - SDE_REG_WRITE(c, INTF_ACTIVE_HCTL, active_hctl); - SDE_REG_WRITE(c, INTF_ACTIVE_V_START_F0, - active_v_start); - SDE_REG_WRITE(c, INTF_ACTIVE_V_END_F0, - active_v_end); - - SDE_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr); - SDE_REG_WRITE(c, INTF_UNDERFLOW_COLOR, - p->underflow_clr); - SDE_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew); - SDE_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl); - SDE_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3); - SDE_REG_WRITE(c, INTF_CONFIG, intf_cfg); - SDE_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); -} - -static void sde_hw_intf_enable_timing_engine( - struct sde_hw_intf *intf, - u8 enable) -{ - struct sde_hw_blk_reg_map *c = &intf->hw; - u32 intf_sel; - - /* Display interface select */ - if (enable) { - /* top block */ - struct sde_hw_mdp *mdp = sde_hw_mdptop_init(MDP_TOP, - c->base_off, - intf->mdss); - struct sde_hw_blk_reg_map *top = &mdp->hw; - - intf_sel = SDE_REG_READ(top, DISP_INTF_SEL); - - intf_sel |= (intf->cap->type << ((intf->idx - INTF_0) * 8)); - SDE_REG_WRITE(top, DISP_INTF_SEL, intf_sel); - } - - SDE_REG_WRITE(c, INTF_TIMING_ENGINE_EN, - enable & 0x1); -} - -static void sde_hw_intf_setup_prg_fetch( - struct sde_hw_intf *intf, - struct intf_prog_fetch *fetch) -{ - struct sde_hw_blk_reg_map *c = &intf->hw; - int fetch_enable; - - /* - * Fetch should always be outside the active lines. If the fetching - * is programmed within active region, hardware behavior is unknown. - */ - - fetch_enable = SDE_REG_READ(c, INTF_CONFIG); - if (fetch->enable) { - fetch_enable |= BIT(31); - SDE_REG_WRITE(c, INTF_PROG_FETCH_START, - fetch->fetch_start); - } else { - fetch_enable &= ~BIT(31); - } - - SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable); -} - -static void sde_hw_intf_get_timing_config( - struct sde_hw_intf *intf, - struct intf_timing_params *cfg) -{ - struct sde_hw_blk_reg_map *c = &intf->hw; - u32 vsync_period; - u32 display_v_start, display_v_end; - u32 hsync_start_x, hsync_end_x; - u32 active_v_start, active_v_end; - u32 active_hctl, display_hctl, hsync_ctl; - u32 polarity_ctl; - u32 pulse_width; - u32 htotal, vtotal; - u32 intf_cfg; - - hsync_ctl = SDE_REG_READ(c, INTF_HSYNC_CTL); - vsync_period = SDE_REG_READ(c, INTF_VSYNC_PERIOD_F0); - pulse_width = SDE_REG_READ(c, INTF_VSYNC_PULSE_WIDTH_F0); - display_hctl = SDE_REG_READ(c, INTF_DISPLAY_HCTL); - display_v_start = SDE_REG_READ(c, INTF_DISPLAY_V_START_F0); - display_v_end = SDE_REG_READ(c, INTF_DISPLAY_V_END_F0); - active_hctl = SDE_REG_READ(c, INTF_ACTIVE_HCTL); - active_v_start = SDE_REG_READ(c, INTF_ACTIVE_V_START_F0); - active_v_end = SDE_REG_READ(c, INTF_ACTIVE_V_END_F0); - intf_cfg = SDE_REG_READ(c, INTF_CONFIG); - cfg->border_clr = SDE_REG_READ(c, INTF_BORDER_COLOR); - cfg->underflow_clr = SDE_REG_READ(c, INTF_UNDERFLOW_COLOR); - cfg->hsync_skew = SDE_REG_READ(c, INTF_HSYNC_SKEW); - polarity_ctl = SDE_REG_READ(c, INTF_POLARITY_CTL); - - hsync_start_x = (display_hctl & 0xffff); - hsync_end_x = (display_hctl & 0xffff0000) >> 16; - cfg->hsync_pulse_width = (hsync_ctl & 0xffff); - htotal = (hsync_ctl & 0xffff0000) >> 16; - - if (htotal != 0) { - vtotal = vsync_period / htotal; - cfg->vsync_pulse_width = pulse_width/htotal; - - /* porches */ - cfg->h_front_porch = htotal - hsync_end_x - 1; - cfg->h_back_porch = hsync_start_x - cfg->hsync_pulse_width; - cfg->v_front_porch = vsync_period - display_v_end; - cfg->v_back_porch = display_v_start - cfg->vsync_pulse_width; - - /* active resolution */ - cfg->width = htotal - cfg->hsync_pulse_width - - cfg->h_back_porch - - cfg->h_front_porch; - cfg->height = vtotal - cfg->vsync_pulse_width - - cfg->v_back_porch - cfg->v_front_porch; - - /* display panel resolution */ - if (intf_cfg & BIT(29)) - cfg->xres = ((active_hctl & 0xffff0000) >> 16) - - (active_hctl & 0xffff) + 1; - else - cfg->xres = cfg->width; - - if (intf_cfg & BIT(30)) - cfg->yres = (active_v_end - active_v_start + 1 - )/htotal; - else - cfg->yres = cfg->height; - } else { - cfg->vsync_pulse_width = 0; - cfg->h_front_porch = 0; - cfg->h_back_porch = 0; - cfg->v_front_porch = 0; - cfg->v_back_porch = 0; - cfg->width = 0; - cfg->height = 0; - } - - cfg->hsync_polarity = polarity_ctl & 1; - cfg->vsync_polarity = (polarity_ctl & 2) >> 1; -} - -static void sde_hw_intf_get_status( - struct sde_hw_intf *intf, - struct intf_status *s) -{ - struct sde_hw_blk_reg_map *c = &intf->hw; - - s->is_en = SDE_REG_READ(c, INTF_TIMING_ENGINE_EN); - if (s->is_en) { - s->frame_count = SDE_REG_READ(c, INTF_FRAME_COUNT); - s->line_count = SDE_REG_READ(c, INTF_LINE_COUNT); - } else { - s->line_count = 0; - s->frame_count = 0; - } -} - -static void _setup_intf_ops(struct sde_hw_intf_ops *ops, - unsigned long cap) -{ - ops->setup_timing_gen = sde_hw_intf_setup_timing_engine; - ops->setup_prg_fetch = sde_hw_intf_setup_prg_fetch; - ops->get_timing_gen = sde_hw_intf_get_timing_config; - ops->get_status = sde_hw_intf_get_status; - ops->enable_timing = sde_hw_intf_enable_timing_engine; -} - -struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_intf *c; - struct sde_intf_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _intf_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - pr_err("Error Panic\n"); - return ERR_PTR(-EINVAL); - } - - /* - * Assign ops - */ - c->idx = idx; - c->cap = cfg; - c->mdss = m; - _setup_intf_ops(&c->ops, c->cap->features); - - /* - * Perform any default initialization for the intf - */ - return c; -} - -void sde_hw_intf_deinit(struct sde_hw_intf *intf) -{ - kfree(intf); -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h deleted file mode 100644 index 2de57868901a..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h +++ /dev/null @@ -1,107 +0,0 @@ -/* 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 - * 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 _SDE_HW_INTF_H -#define _SDE_HW_INTF_H - -#include "sde_hw_catalog.h" -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" - -struct sde_hw_intf; - -/* intf timing settings */ -struct intf_timing_params { - u32 width; /* active width */ - u32 height; /* active height */ - u32 xres; /* Display panel width */ - u32 yres; /* Display panel height */ - - u32 h_back_porch; - u32 h_front_porch; - u32 v_back_porch; - u32 v_front_porch; - u32 hsync_pulse_width; - u32 vsync_pulse_width; - u32 hsync_polarity; - u32 vsync_polarity; - u32 border_clr; - u32 underflow_clr; - u32 hsync_skew; -}; - -struct intf_prog_fetch { - u8 enable; - /* vsync counter for the front porch pixel line */ - u32 fetch_start; -}; - -struct intf_status { - u8 is_en; /* interface timing engine is enabled or not */ - u32 frame_count; /* frame count since timing engine enabled */ - u32 line_count; /* current line count including blanking */ -}; - -/** - * struct sde_hw_intf_ops : Interface to the interface Hw driver functions - * Assumption is these functions will be called after clocks are enabled - * @ setup_timing_gen : programs the timing engine - * @ setup_prog_fetch : enables/disables the programmable fetch logic - * @ enable_timing: enable/disable timing engine - * @ get_timing_gen: get timing generator programmed configuration - * @ get_status: returns if timing engine is enabled or not - */ -struct sde_hw_intf_ops { - void (*setup_timing_gen)(struct sde_hw_intf *intf, - struct intf_timing_params *p, - struct sde_mdp_format_params *fmt); - - void (*setup_prg_fetch)(struct sde_hw_intf *intf, - struct intf_prog_fetch *fetch); - - void (*enable_timing)(struct sde_hw_intf *intf, - u8 enable); - - void (*get_timing_gen)(struct sde_hw_intf *intf, - struct intf_timing_params *cfg); - - void (*get_status)(struct sde_hw_intf *intf, - struct intf_status *status); -}; - -struct sde_hw_intf { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* intf */ - enum sde_intf idx; - const struct sde_intf_cfg *cap; - const struct sde_mdss_cfg *mdss; - - /* ops */ - struct sde_hw_intf_ops ops; -}; - -/** - * sde_hw_intf_init(): Initializes the intf driver for the passed - * interface idx. - * @idx: interface index for which driver object is required - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -void sde_hw_intf_deinit(struct sde_hw_intf *intf); - -#endif /*_SDE_HW_INTF_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c deleted file mode 100644 index 56ebe8fa05b5..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c +++ /dev/null @@ -1,192 +0,0 @@ -/* 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 - * 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 "sde_hw_catalog.h" -#include "sde_hwio.h" -#include "sde_hw_lm.h" -#include "sde_hw_mdss.h" - -#define LM_OP_MODE 0x00 -#define LM_OUT_SIZE 0x04 -#define LM_BORDER_COLOR_0 0x08 -#define LM_BORDER_COLOR_1 0x010 - -/* These register are offset to mixer base + stage base */ -#define LM_BLEND0_OP 0x00 -#define LM_BLEND0_FG_ALPHA 0x04 -#define LM_BLEND0_BG_ALPHA 0x08 - -static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->mixer_count; i++) { - if (mixer == m->mixer[i].id) { - b->base_off = addr; - b->blk_off = m->mixer[i].base; - b->hwversion = m->hwversion; - return &m->mixer[i]; - } - } - - return ERR_PTR(-ENOMEM); -} - -/** - * _stage_offset(): returns the relative offset of the blend registers - * for the stage to be setup - * @c: mixer ctx contains the mixer to be programmed - * @stage: stage index to setup - */ -static inline int _stage_offset(struct sde_hw_mixer *ctx, enum sde_stage stage) -{ - const struct sde_lm_sub_blks *sblk = ctx->cap->sblk; - - if (WARN_ON(stage == SDE_STAGE_BASE)) - return -EINVAL; - - if ((stage - SDE_STAGE_0) <= sblk->maxblendstages) - return sblk->blendstage_base[stage - 1]; - else - return -EINVAL; -} - -static void sde_hw_lm_setup_out(struct sde_hw_mixer *ctx, - struct sde_hw_mixer_cfg *mixer) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 outsize; - u32 opmode; - - opmode = SDE_REG_READ(c, LM_OP_MODE); - - outsize = mixer->out_height << 16 | mixer->out_width; - SDE_REG_WRITE(c, LM_OUT_SIZE, outsize); - - /* SPLIT_LEFT_RIGHT */ - opmode = (opmode & ~(1 << 31)) | ((mixer->right_mixer) ? (1 << 31) : 0); - SDE_REG_WRITE(c, LM_OP_MODE, opmode); -} - -static void sde_hw_lm_setup_border_color(struct sde_hw_mixer *ctx, - struct sde_mdss_color *color, - u8 border_en) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - - if (border_en) { - SDE_REG_WRITE(c, LM_BORDER_COLOR_0, - (color->color_0 & 0xFFF) | - ((color->color_1 & 0xFFF) << 0x10)); - SDE_REG_WRITE(c, LM_BORDER_COLOR_1, - (color->color_2 & 0xFFF) | - ((color->color_3 & 0xFFF) << 0x10)); - } -} - -static void sde_hw_lm_setup_blendcfg(struct sde_hw_mixer *ctx, - int stage, - struct sde_hw_blend_cfg *blend) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 blend_op; - struct sde_hw_alpha_cfg *fg, *bg; - int stage_off; - - stage_off = _stage_offset(ctx, stage); - if (WARN_ON(stage_off < 0)) - return; - - fg = &(blend->fg); - bg = &(blend->bg); - - /* fg */ - blend_op = (fg->alpha_sel & 3); - blend_op |= (fg->inv_alpha_sel & 1) << 2; - blend_op |= (fg->mod_alpha & 1) << 3; - blend_op |= (fg->inv_mode_alpha & 1) << 4; - - /* bg */ - blend_op |= (bg->alpha_sel & 3) << 8; - blend_op |= (bg->inv_alpha_sel & 1) << 2; - blend_op |= (bg->mod_alpha & 1) << 3; - blend_op |= (bg->inv_mode_alpha & 1) << 4; - - SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, - fg->const_alpha); - SDE_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, - bg->const_alpha); - SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); -} - -static void sde_hw_lm_setup_color3(struct sde_hw_mixer *ctx, - struct sde_hw_color3_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - int maxblendstages = ctx->cap->sblk->maxblendstages; - int i; - int op_mode; - - /* read the existing op_mode configuration */ - op_mode = SDE_REG_READ(c, LM_OP_MODE); - - for (i = 0; i < maxblendstages; i++) - op_mode |= ((cfg->keep_fg[i] & 0x1) << i); - - SDE_REG_WRITE(c, LM_OP_MODE, op_mode); -} - -static void sde_hw_lm_gammacorrection(struct sde_hw_mixer *mixer, - void *cfg) -{ -} - -static void _setup_mixer_ops(struct sde_hw_lm_ops *ops, - unsigned long cap) -{ - ops->setup_mixer_out = sde_hw_lm_setup_out; - ops->setup_blend_config = sde_hw_lm_setup_blendcfg; - ops->setup_alpha_out = sde_hw_lm_setup_color3; - ops->setup_border_color = sde_hw_lm_setup_border_color; - ops->setup_gammcorrection = sde_hw_lm_gammacorrection; -}; - -struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_mixer *c; - struct sde_lm_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _lm_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - /* Assign ops */ - c->idx = idx; - c->cap = cfg; - _setup_mixer_ops(&c->ops, c->cap->features); - - /* - * Perform any default initialization for the sspp blocks - */ - return c; -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h deleted file mode 100644 index b48e8e1b8e94..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 - * 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 _SDE_HW_LM_H -#define _SDE_HW_LM_H - -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" - -struct sde_hw_mixer; - -struct sde_hw_mixer_cfg { - u32 out_width; - u32 out_height; - bool right_mixer; - int flags; -}; - -struct sde_hw_color3_cfg { - u8 keep_fg[SDE_STAGE_MAX]; -}; - -/** - * - * struct sde_hw_lm_ops : Interface to the mixer Hw driver functions - * Assumption is these functions will be called after clocks are enabled - */ -struct sde_hw_lm_ops { - /* - * Sets up mixer output width and height - * and border color if enabled - */ - void (*setup_mixer_out)(struct sde_hw_mixer *ctx, - struct sde_hw_mixer_cfg *cfg); - - /* - * Alpha blending configuration - * for the specified stage - */ - void (*setup_blend_config)(struct sde_hw_mixer *ctx, - int stage, - struct sde_hw_blend_cfg *blend); - - /* - * Alpha color component selection from either fg or bg - */ - void (*setup_alpha_out)(struct sde_hw_mixer *ctx, - struct sde_hw_color3_cfg *cfg); - - /** - * setup_border_color : enable/disable border color - */ - void (*setup_border_color)(struct sde_hw_mixer *ctx, - struct sde_mdss_color *color, - u8 border_en); - - void (*setup_gammcorrection)(struct sde_hw_mixer *mixer, - void *cfg); - -}; - -struct sde_hw_mixer { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* lm */ - enum sde_lm idx; - const struct sde_lm_cfg *cap; - const struct sde_mdp_cfg *mdp; - const struct sde_ctl_cfg *ctl; - - /* ops */ - struct sde_hw_lm_ops ops; -}; - -/** - * sde_hw_lm_init(): Initializes the mixer hw driver object. - * should be called once before accessing every mixer. - * @idx: mixer index for which driver object is required - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -#endif /*_SDE_HW_LM_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c deleted file mode 100644 index f7181ab9ed3d..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c +++ /dev/null @@ -1,364 +0,0 @@ -/* 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 - * 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/delay.h> -#include "sde_hwio.h" -#include "sde_hw_mdp_ctl.h" - -#define CTL_LAYER(lm) \ - (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004)) -#define CTL_LAYER_EXT(lm) \ - (0x40 + (((lm) - LM_0) * 0x004)) -#define CTL_TOP 0x014 -#define CTL_FLUSH 0x018 -#define CTL_START 0x01C -#define CTL_PACK_3D 0x020 -#define CTL_SW_RESET 0x030 -#define CTL_LAYER_EXTN_OFFSET 0x40 - -#define SDE_REG_RESET_TIMEOUT_COUNT 20 - -static struct sde_ctl_cfg *_ctl_offset(enum sde_ctl ctl, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->ctl_count; i++) { - if (ctl == m->ctl[i].id) { - b->base_off = addr; - b->blk_off = m->ctl[i].base; - b->hwversion = m->hwversion; - return &m->ctl[i]; - } - } - return ERR_PTR(-ENOMEM); -} - -static int _mixer_stages(const struct sde_lm_cfg *mixer, int count, - enum sde_lm lm) -{ - int i; - int stages = -EINVAL; - - for (i = 0; i < count; i++) { - if (lm == mixer[i].id) { - stages = mixer[i].sblk->maxblendstages; - break; - } - } - - return stages; -} - -static inline void sde_hw_ctl_force_start(struct sde_hw_ctl *ctx) -{ - SDE_REG_WRITE(&ctx->hw, CTL_START, 0x1); -} - -static inline void sde_hw_ctl_setup_flush(struct sde_hw_ctl *ctx, u32 flushbits) -{ - SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, flushbits); -} - -static inline int sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx, - u32 *flushbits, enum sde_sspp sspp) -{ - switch (sspp) { - case SSPP_VIG0: - *flushbits |= BIT(0); - break; - case SSPP_VIG1: - *flushbits |= BIT(1); - break; - case SSPP_VIG2: - *flushbits |= BIT(2); - break; - case SSPP_VIG3: - *flushbits |= BIT(18); - break; - case SSPP_RGB0: - *flushbits |= BIT(3); - break; - case SSPP_RGB1: - *flushbits |= BIT(4); - break; - case SSPP_RGB2: - *flushbits |= BIT(5); - break; - case SSPP_RGB3: - *flushbits |= BIT(19); - break; - case SSPP_DMA0: - *flushbits |= BIT(11); - break; - case SSPP_DMA1: - *flushbits |= BIT(12); - break; - case SSPP_CURSOR0: - *flushbits |= BIT(22); - break; - case SSPP_CURSOR1: - *flushbits |= BIT(23); - break; - default: - return -EINVAL; - } - return 0; -} - -static inline int sde_hw_ctl_get_bitmask_mixer(struct sde_hw_ctl *ctx, - u32 *flushbits, enum sde_lm lm) -{ - switch (lm) { - case LM_0: - *flushbits |= BIT(6); - break; - case LM_1: - *flushbits |= BIT(7); - break; - case LM_2: - *flushbits |= BIT(8); - break; - case LM_3: - *flushbits |= BIT(9); - break; - case LM_4: - *flushbits |= BIT(10); - break; - case LM_5: - *flushbits |= BIT(20); - break; - default: - return -EINVAL; - } - *flushbits |= BIT(17); /* CTL */ - return 0; -} - -static inline int sde_hw_ctl_get_bitmask_dspp(struct sde_hw_ctl *ctx, - u32 *flushbits, enum sde_dspp dspp) -{ - switch (dspp) { - case DSPP_0: - *flushbits |= BIT(13); - break; - case DSPP_1: - *flushbits |= BIT(14); - break; - default: - return -EINVAL; - } - return 0; -} - -static inline int sde_hw_ctl_get_bitmask_intf(struct sde_hw_ctl *ctx, - u32 *flushbits, enum sde_intf intf) -{ - switch (intf) { - case INTF_0: - *flushbits |= BIT(31); - break; - case INTF_1: - *flushbits |= BIT(30); - break; - case INTF_2: - *flushbits |= BIT(29); - break; - case INTF_3: - *flushbits |= BIT(28); - break; - default: - return -EINVAL; - } - return 0; -} - -static inline int sde_hw_ctl_get_bitmask_cdm(struct sde_hw_ctl *ctx, - u32 *flushbits, enum sde_cdm cdm) -{ - switch (cdm) { - case CDM_0: - *flushbits |= BIT(26); - break; - default: - return -EINVAL; - } - return 0; -} - -static int sde_hw_ctl_reset_control(struct sde_hw_ctl *ctx) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - int count = SDE_REG_RESET_TIMEOUT_COUNT; - int reset; - - SDE_REG_WRITE(c, CTL_SW_RESET, 0x1); - - for (; count > 0; count--) { - /* insert small delay to avoid spinning the cpu while waiting */ - usleep_range(20, 50); - reset = SDE_REG_READ(c, CTL_SW_RESET); - if (reset == 0) - return 0; - } - - return -EINVAL; -} - -static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx, - enum sde_lm lm, - struct sde_hw_stage_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 mixercfg, mixercfg_ext = 0; - int i, j; - u8 stages; - int pipes_per_stage; - - stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm); - if (WARN_ON(stages < 0)) - return; - - if (test_bit(SDE_MIXER_SOURCESPLIT, - &ctx->mixer_hw_caps->features)) - pipes_per_stage = PIPES_PER_STAGE; - else - pipes_per_stage = 1; - - mixercfg = cfg->border_enable << 24; /* BORDER_OUT */ - - for (i = 0; i <= stages; i++) { - for (j = 0; j < pipes_per_stage; j++) { - switch (cfg->stage[i][j]) { - case SSPP_VIG0: - mixercfg |= (i + 1) << 0; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0; - break; - case SSPP_VIG1: - mixercfg |= (i + 1) << 3; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 2; - break; - case SSPP_VIG2: - mixercfg |= (i + 1) << 6; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 4; - break; - case SSPP_VIG3: - mixercfg |= (i + 1) << 26; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 4; - break; - case SSPP_RGB0: - mixercfg |= (i + 1) << 9; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 8; - break; - case SSPP_RGB1: - mixercfg |= (i + 1) << 12; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 10; - break; - case SSPP_RGB2: - mixercfg |= (i + 1) << 15; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 12; - break; - case SSPP_RGB3: - mixercfg |= (i + 1) << 29; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 14; - break; - case SSPP_DMA0: - mixercfg |= (i + 1) << 0; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0; - break; - case SSPP_DMA1: - mixercfg |= (i + 1) << 0; - mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0; - break; - case SSPP_CURSOR0: - mixercfg_ext |= (i + 1) << 20; - break; - case SSPP_CURSOR1: - mixercfg_ext |= (i + 1) << 26; - break; - default: - break; - } - } - } - - SDE_REG_WRITE(c, CTL_LAYER(lm), mixercfg); - SDE_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); -} - -static void sde_hw_ctl_intf_cfg(struct sde_hw_ctl *ctx, - struct sde_hw_intf_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 intf_cfg = 0; - - intf_cfg |= (cfg->intf & 0xF) << 4; - - if (cfg->wb) - intf_cfg |= (cfg->wb & 0x3) + 2; - - if (cfg->mode_3d) { - intf_cfg |= BIT(19); - intf_cfg |= (cfg->mode_3d - 1) << 20; - } - - SDE_REG_WRITE(c, CTL_TOP, intf_cfg); -} - -static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, - unsigned long cap) -{ - ops->setup_flush = sde_hw_ctl_setup_flush; - ops->setup_start = sde_hw_ctl_force_start; - ops->setup_intf_cfg = sde_hw_ctl_intf_cfg; - ops->reset = sde_hw_ctl_reset_control; - ops->setup_blendstage = sde_hw_ctl_setup_blendstage; - ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp; - ops->get_bitmask_mixer = sde_hw_ctl_get_bitmask_mixer; - ops->get_bitmask_dspp = sde_hw_ctl_get_bitmask_dspp; - ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf; - ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm; -}; - -struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_ctl *c; - struct sde_ctl_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _ctl_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - pr_err("Error Panic\n"); - return ERR_PTR(-EINVAL); - } - - c->caps = cfg; - _setup_ctl_ops(&c->ops, c->caps->features); - c->idx = idx; - c->mixer_count = m->mixer_count; - c->mixer_hw_caps = m->mixer; - - return c; -} - -void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx) -{ - kfree(ctx); -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h deleted file mode 100644 index e914abd69906..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h +++ /dev/null @@ -1,138 +0,0 @@ -/* 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 - * 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 _SDE_HW_MDP_CTL_H -#define _SDE_HW_MDP_CTL_H - -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" -#include "sde_hw_catalog.h" - -struct sde_hw_ctl; -/** - * struct sde_hw_stage_cfg - blending stage cfg - * @stage - * @border_enable - */ -struct sde_hw_stage_cfg { - enum sde_sspp stage[SDE_STAGE_MAX][PIPES_PER_STAGE]; - u8 border_enable; -}; - -/** - * struct sde_hw_intf_cfg :Desbribes how the mdp writes data to - * output interface - * @intf : Interface id - * @wb: writeback id - * @mode_3d: 3d mux configuration - */ -struct sde_hw_intf_cfg { - enum sde_intf intf; - enum sde_wb wb; - enum sde_3d_blend_mode mode_3d; -}; - -/** - * struct sde_hw_ctl_ops - Interface to the wb Hw driver functions - * Assumption is these functions will be called after clocks are enabled - */ -struct sde_hw_ctl_ops { - /** - * kickoff hw operation for Sw controlled interfaces - * DSI cmd mode and WB interface are SW controlled - * @ctx : ctl path ctx pointer - */ - void (*setup_start)(struct sde_hw_ctl *ctx); - - /** - * FLUSH the modules for this control path - * @ctx : ctl path ctx pointer - * @flushbits : module flushmask - */ - void (*setup_flush)(struct sde_hw_ctl *ctx, - u32 flushbits); - - /** - * Setup ctl_path interface config - * @ctx - * @cfg : interface config structure pointer - */ - void (*setup_intf_cfg)(struct sde_hw_ctl *ctx, - struct sde_hw_intf_cfg *cfg); - - int (*reset)(struct sde_hw_ctl *c); - - int (*get_bitmask_sspp)(struct sde_hw_ctl *ctx, - u32 *flushbits, - enum sde_sspp blk); - - int (*get_bitmask_mixer)(struct sde_hw_ctl *ctx, - u32 *flushbits, - enum sde_lm blk); - - int (*get_bitmask_dspp)(struct sde_hw_ctl *ctx, - u32 *flushbits, - enum sde_dspp blk); - - int (*get_bitmask_intf)(struct sde_hw_ctl *ctx, - u32 *flushbits, - enum sde_intf blk); - - int (*get_bitmask_cdm)(struct sde_hw_ctl *ctx, - u32 *flushbits, - enum sde_cdm blk); - - void (*setup_blendstage)(struct sde_hw_ctl *ctx, - enum sde_lm lm, - struct sde_hw_stage_cfg *cfg); -}; - -/** - * struct sde_hw_ctl : CTL PATH driver object - * @struct sde_hw_blk_reg_map *hw; - * @idx - * @ctl_hw_caps - * @mixer_hw_caps - * @ops - */ -struct sde_hw_ctl { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* ctl path */ - int idx; - const struct sde_ctl_cfg *caps; - int mixer_count; - const struct sde_lm_cfg *mixer_hw_caps; - - /* ops */ - struct sde_hw_ctl_ops ops; -}; - -/** - * sde_hw_ctl_init(): Initializes the ctl_path hw driver object. - * should be called before accessing every ctl path registers. - * @idx: ctl_path index for which driver object is required - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -/** - * sde_hw_ctl_destroy(): Destroys ctl driver context - * should be called to free the context - */ -void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx); - -#endif /*_SDE_HW_MDP_CTL_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_hwio.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_hwio.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_hwio.h +++ /dev/null diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c deleted file mode 100644 index 92c08fff2031..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c +++ /dev/null @@ -1,110 +0,0 @@ -/* 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 - * 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 "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_mdp_top.h" - -#define SPLIT_DISPLAY_ENABLE 0x2F4 -#define LOWER_PIPE_CTRL 0x2F8 -#define UPPER_PIPE_CTRL 0x3F0 -#define TE_LINE_INTERVAL 0x3F4 - -static void sde_hw_setup_split_pipe_control(struct sde_hw_mdp *mdp, - struct split_pipe_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &mdp->hw; - u32 upper_pipe; - u32 lower_pipe; - - if (cfg->en) { - upper_pipe = BIT(8); - lower_pipe = BIT(8); - - if (cfg->mode == INTF_MODE_CMD) { - upper_pipe |= BIT(0); - lower_pipe |= BIT(0); - } - - SDE_REG_WRITE(c, LOWER_PIPE_CTRL, lower_pipe); - SDE_REG_WRITE(c, UPPER_PIPE_CTRL, upper_pipe); - } - - SDE_REG_WRITE(c, SPLIT_DISPLAY_ENABLE, cfg->en & 0x1); -} - -static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, - unsigned long cap) -{ - ops->setup_split_pipe = sde_hw_setup_split_pipe_control; -} - -static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp, - const struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->mdp_count; i++) { - if (mdp == m->mdp[i].id) { - b->base_off = addr; - b->blk_off = m->mdp[i].base; - b->hwversion = m->hwversion; - return &m->mdp[i]; - } - } - - return ERR_PTR(-EINVAL); -} - -struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, - void __iomem *addr, - const struct sde_mdss_cfg *m) -{ - static struct sde_hw_mdp *c; - const struct sde_mdp_cfg *cfg; - - /* mdp top is singleton */ - if (c) { - pr_err(" %s returning %pK", __func__, c); - return c; - } - - c = kzalloc(sizeof(*c), GFP_KERNEL); - pr_err(" %s returning %pK", __func__, c); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _top_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - /* - * Assign ops - */ - c->idx = idx; - c->cap = cfg; - _setup_mdp_ops(&c->ops, c->cap->features); - - /* - * Perform any default initialization for the intf - */ - return c; -} - -void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp) -{ -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.h deleted file mode 100644 index 216a27e93d46..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.h +++ /dev/null @@ -1,66 +0,0 @@ -/* 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 - * 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 _SDE_HW_MDP_TOP_H -#define _SDE_HW_MDP_TOP_H - -#include "sde_hw_catalog.h" -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" - -struct sde_hw_mdp; - -/** - * struct split_pipe_cfg - pipe configuration for dual display panels - * @en : Enable/disable dual pipe confguration - * @mode : Panel interface mode - */ -struct split_pipe_cfg { - bool en; - enum sde_intf_mode mode; -}; - -/** - * struct sde_hw_mdp_ops - interface to the MDP TOP Hw driver functions - * Assumption is these functions will be called after clocks are enabled. - * @setup_split_pipe : Programs the pipe control registers - */ -struct sde_hw_mdp_ops { - void (*setup_split_pipe)(struct sde_hw_mdp *mdp, - struct split_pipe_cfg *p); -}; - -struct sde_hw_mdp { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* intf */ - enum sde_mdp idx; - const struct sde_mdp_cfg *cap; - - /* ops */ - struct sde_hw_mdp_ops ops; -}; - -/** - * sde_hw_intf_init - initializes the intf driver for the passed interface idx - * @idx: Interface index for which driver object is required - * @addr: Mapped register io address of MDP - * @m: Pointer to mdss catalog data - */ -struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, - void __iomem *addr, - const struct sde_mdss_cfg *m); - -void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp); - -#endif /*_SDE_HW_MDP_TOP_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.c deleted file mode 100644 index 6be57b06a7cf..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.c +++ /dev/null @@ -1,73 +0,0 @@ -/* 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 - * 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 "sde_hw_mdp_util.h" - -void sde_hw_reg_write(void __iomem *base, u32 blk_off, u32 reg_off, u32 val) -{ - writel_relaxed(val, base + blk_off + reg_off); -} - -u32 sde_hw_reg_read(void __iomem *base, u32 blk_off, u32 reg_off) -{ - return readl_relaxed(base + blk_off + reg_off); -} - -void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c, - u32 csc_reg_off, - struct sde_csc_cfg *data) -{ - u32 val; - - /* Matrix coeff */ - val = (data->csc_mv[0] & 0x1FF) | - ((data->csc_mv[1] & 0x1FF) << 16); - SDE_REG_WRITE(c, csc_reg_off, val); - val = (data->csc_mv[2] & 0x1FF) | - ((data->csc_mv[3] & 0x1FF) << 16); - SDE_REG_WRITE(c, csc_reg_off + 0x4, val); - val = (data->csc_mv[4] & 0x1FF) | - ((data->csc_mv[5] & 0x1FF) >> 16); - SDE_REG_WRITE(c, csc_reg_off + 0x8, val); - val = (data->csc_mv[6] & 0x1FF) | - ((data->csc_mv[7] & 0x1FF) << 16); - SDE_REG_WRITE(c, csc_reg_off + 0xc, val); - val = data->csc_mv[8] & 0x1FF; - SDE_REG_WRITE(c, csc_reg_off + 0x10, val); - - /* Pre clamp */ - val = (data->csc_pre_lv[0] << 8) | data->csc_pre_lv[1]; - SDE_REG_WRITE(c, csc_reg_off + 0x14, val); - val = (data->csc_pre_lv[2] << 8) | data->csc_pre_lv[3]; - SDE_REG_WRITE(c, csc_reg_off + 0x18, val); - val = (data->csc_pre_lv[4] << 8) | data->csc_pre_lv[5]; - SDE_REG_WRITE(c, csc_reg_off + 0x1c, val); - - /* Post clamp */ - val = (data->csc_post_lv[0] << 8) | data->csc_post_lv[1]; - SDE_REG_WRITE(c, csc_reg_off + 0x20, val); - val = (data->csc_post_lv[2] << 8) | data->csc_post_lv[3]; - SDE_REG_WRITE(c, csc_reg_off + 0x24, val); - val = (data->csc_post_lv[4] << 8) | data->csc_post_lv[5]; - SDE_REG_WRITE(c, csc_reg_off + 0x28, val); - - /* Pre-Bias */ - SDE_REG_WRITE(c, csc_reg_off + 0x2c, data->csc_pre_bv[0]); - SDE_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]); - SDE_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]); - - /* Post-Bias */ - SDE_REG_WRITE(c, csc_reg_off + 0x38, data->csc_post_bv[0]); - SDE_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); - SDE_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.h deleted file mode 100644 index b57e64eba423..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.h +++ /dev/null @@ -1,56 +0,0 @@ -/* 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 - * 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 _SDE_HW_MDP_UTIL_H -#define _SDE_HW_MDP_UTIL_H - -#include <linux/io.h> -#include <linux/slab.h> -#include "sde_hw_mdss.h" - -/* - * This is the common struct maintained by each sub block - * for mapping the register offsets in this block to the - * absoulute IO address - * @base_off: mdp register mapped offset - * @blk_off: pipe offset relative to mdss offset - * @length length of register block offset - * @hwversion mdss hw version number - */ -struct sde_hw_blk_reg_map { - void __iomem *base_off; - u32 blk_off; - u32 length; - u32 hwversion; -}; - -void sde_hw_reg_write(void __iomem *base, u32 blk_offset, u32 reg, u32 val); - -u32 sde_hw_reg_read(void __iomem *base, u32 blk_offset, u32 reg); - -static inline void SDE_REG_WRITE(struct sde_hw_blk_reg_map *c, u32 reg_off, - u32 val) -{ - sde_hw_reg_write(c->base_off, c->blk_off, reg_off, val); -} - -static inline int SDE_REG_READ(struct sde_hw_blk_reg_map *c, u32 reg_off) -{ - return sde_hw_reg_read(c->base_off, c->blk_off, reg_off); -} - -void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c, - u32 csc_reg_off, - struct sde_csc_cfg *data); - -#endif /* _SDE_HW_MDP_UTIL_H */ - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h deleted file mode 100644 index 075e78042f17..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ /dev/null @@ -1,358 +0,0 @@ -/* 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 - * 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 _SDE_HW_MDSS_H -#define _SDE_HW_MDSS_H - -#include <linux/kernel.h> -#include <linux/err.h> - -#define SDE_NONE 0 -#define SDE_CSC_MATRIX_COEFF_SIZE 9 -#define SDE_CSC_CLAMP_SIZE 6 -#define SDE_CSC_BIAS_SIZE 3 - -#define SDE_MAX_PLANES 4 -#define PIPES_PER_STAGE 2 -#define VALID_ROT_WB_FORMAT BIT(0) - -enum sde_mdp { - MDP_TOP = 0x1, - MDP_MAX, -}; - -enum sde_sspp { - SSPP_NONE, - SSPP_VIG0, - SSPP_VIG1, - SSPP_VIG2, - SSPP_VIG3, - SSPP_RGB0, - SSPP_RGB1, - SSPP_RGB2, - SSPP_RGB3, - SSPP_DMA0, - SSPP_DMA1, - SSPP_DMA2, - SSPP_DMA3, - SSPP_CURSOR0, - SSPP_CURSOR1, - SSPP_MAX -}; - -enum sde_sspp_type { - SSPP_TYPE_VIG, - SSPP_TYPE_RGB, - SSPP_TYPE_DMA, - SSPP_TYPE_CURSOR, - SSPP_TYPE_MAX -}; - -enum sde_lm { - LM_0 = 1, - LM_1, - LM_2, - LM_3, - LM_4, - LM_5, - LM_6, - LM_MAX -}; - -enum sde_stage { - SDE_STAGE_BASE = 0, - SDE_STAGE_0, - SDE_STAGE_1, - SDE_STAGE_2, - SDE_STAGE_3, - SDE_STAGE_4, - SDE_STAGE_5, - SDE_STAGE_6, - SDE_STAGE_MAX -}; -enum sde_dspp { - DSPP_0 = 1, - DSPP_1, - DSPP_2, - DSPP_3, - DSPP_MAX -}; - -enum sde_ctl { - CTL_0 = 1, - CTL_1, - CTL_2, - CTL_3, - CTL_4, - CTL_MAX -}; - -enum sde_cdm { - CDM_0 = 1, - CDM_1, - CDM_MAX -}; - -enum sde_pingpong { - PINGPONG_0 = 1, - PINGPONG_1, - PINGPONG_2, - PINGPONG_3, - PINGPONG_4, - PINGPONG_S0, - PINGPONG_MAX -}; - -enum sde_intf { - INTF_0 = 1, - INTF_1, - INTF_2, - INTF_3, - INTF_4, - INTF_5, - INTF_6, - INTF_MAX -}; - -enum sde_intf_type { - INTF_NONE = 0x0, - INTF_DSI = 0x1, - INTF_HDMI = 0x3, - INTF_LCDC = 0x5, - INTF_EDP = 0x9, - INTF_TYPE_MAX -}; - -enum sde_intf_mode { - INTF_MODE_NONE = 0, - INTF_MODE_CMD, - INTF_MODE_VIDEO, - INTF_MODE_WB_BLOCK, - INTF_MODE_WB_LINE, - INTF_MODE_MAX -}; - -enum sde_wb { - WB_0 = 1, - WB_1, - WB_2, - WB_3, - WB_MAX -}; - -enum sde_ad { - AD_0 = 0x1, - AD_1, - AD_MAX -}; - -enum sde_cwb { - CWB_0 = 0x1, - CWB_1, - CWB_2, - CWB_3, - CWB_MAX -}; - -enum sde_wd_timer { - WD_TIMER_0 = 0x1, - WD_TIMER_1, - WD_TIMER_2, - WD_TIMER_3, - WD_TIMER_4, - WD_TIMER_5, - WD_TIMER_MAX -}; - -/** - * MDP HW,Component order color map - */ -enum { - C0_G_Y = 0, - C1_B_Cb = 1, - C2_R_Cr = 2, - C3_ALPHA = 3 -}; - -/** - * enum sde_mdp_plane_type - defines how the color component pixel packing - * @SDE_MDP_PLANE_INTERLEAVED : Color components in single plane - * @SDE_MDP_PLANE_PLANAR : Color component in separate planes - * @SDE_MDP_PLANE_PSEUDO_PLANAR : Chroma components interleaved in separate - * plane - */ -enum sde_mdp_plane_type { - SDE_MDP_PLANE_INTERLEAVED, - SDE_MDP_PLANE_PLANAR, - SDE_MDP_PLANE_PSEUDO_PLANAR, -}; - -/** - * enum sde_mdp_chroma_samp_type - chroma sub-samplng type - * @SDE_MDP_CHROMA_RGB : no chroma subsampling - * @SDE_MDP_CHROMA_H2V1 : chroma pixels are horizontally subsampled - * @SDE_MDP_CHROMA_H1V2 : chroma pixels are vertically subsampled - * @SDE_MDP_CHROMA_420 : 420 subsampling - */ -enum sde_mdp_chroma_samp_type { - SDE_MDP_CHROMA_RGB, - SDE_MDP_CHROMA_H2V1, - SDE_MDP_CHROMA_H1V2, - SDE_MDP_CHROMA_420 -}; - -/** - * enum sde_mdp_fetch_type - format id, used by drm-driver only to map drm forcc - * Defines How MDP HW fetches data - * @SDE_MDP_FETCH_LINEAR : fetch is line by line - * @SDE_MDP_FETCH_TILE : fetches data in Z order from a tile - * @SDE_MDP_FETCH_UBWC : fetch and decompress data - */ -enum sde_mdp_fetch_type { - SDE_MDP_FETCH_LINEAR, - SDE_MDP_FETCH_TILE, - SDE_MDP_FETCH_UBWC -}; - -/** - * Value of enum chosen to fit the number of bits - * expected by the HW programming. - */ -enum { - COLOR_1BIT = 0, - COLOR_5BIT = 1, - COLOR_6BIT = 2, - COLOR_8BIT = 3, -}; - -enum sde_alpha_blend_type { - ALPHA_FG_CONST = 0, - ALPHA_BG_CONST, - ALPHA_FG_PIXEL, - ALPHA_BG_PIXEL, - ALPHA_MAX -}; - - -/** - * enum sde_3d_blend_mode - * Desribes how the 3d data is blended - * @BLEND_3D_NONE : 3d blending not enabled - * @BLEND_3D_FRAME_INT : Frame interleaving - * @BLEND_3D_H_ROW_INT : Horizontal row interleaving - * @BLEND_3D_V_ROW_INT : vertical row interleaving - * @BLEND_3D_COL_INT : column interleaving - * @BLEND_3D_MAX : - */ -enum sde_3d_blend_mode { - BLEND_3D_NONE = 0, - BLEND_3D_FRAME_INT, - BLEND_3D_H_ROW_INT, - BLEND_3D_V_ROW_INT, - BLEND_3D_COL_INT, - BLEND_3D_MAX -}; - -struct addr_info { - u32 plane[SDE_MAX_PLANES]; -}; - -/** - * struct sde_mdp_format_params - defines the format configuration which - * allows MDP HW to correctly fetch and decode the format - * @format : format id, used by drm-driver only to map drm forcc - * @flag - * @chroma_sample - * @fetch_planes - * @unpack_align_msb - * @unpack_tight - * @unpack_count - * @bpp - * @alpha_enable - * @fetch_mode - * @bits - * @element - */ -struct sde_mdp_format_params { - u32 format; - enum sde_mdp_plane_type fetch_planes; - u8 element[SDE_MAX_PLANES]; - u8 bits[SDE_MAX_PLANES]; - enum sde_mdp_chroma_samp_type chroma_sample; - u8 unpack_align_msb; /* 0 to LSB, 1 to MSB */ - u8 unpack_tight; /* 0 for loose, 1 for tight */ - u8 unpack_count; /* 0 = 1 component, 1 = 2 component ... */ - u8 bpp; /* Bytes per pixel */ - u8 alpha_enable; /* source has alpha */ - enum sde_mdp_fetch_type fetch_mode; - u8 is_yuv; - u32 flag; -}; - -/** - * struct sde_hw_source_info - format information of the source pixel data - * @format : pixel format parameters - * @width : image width @height: image height - * @num_planes : number of planes including the meta data planes for the - * compressed formats @plane: per plane information - */ -struct sde_hw_source_info { - struct sde_mdp_format_params *format; - u32 width; - u32 height; - u32 num_planes; - u32 ystride[SDE_MAX_PLANES]; -}; - -struct sde_rect { - u16 x; - u16 y; - u16 w; - u16 h; -}; - -struct sde_hw_alpha_cfg { - u32 const_alpha; - enum sde_alpha_blend_type alpha_sel; - u8 inv_alpha_sel; - u8 mod_alpha; - u8 inv_mode_alpha; -}; - -struct sde_hw_blend_cfg { - struct sde_hw_alpha_cfg fg; - struct sde_hw_alpha_cfg bg; -}; - -struct sde_csc_cfg { - uint32_t csc_mv[SDE_CSC_MATRIX_COEFF_SIZE]; - uint32_t csc_pre_bv[SDE_CSC_BIAS_SIZE]; - uint32_t csc_post_bv[SDE_CSC_BIAS_SIZE]; - uint32_t csc_pre_lv[SDE_CSC_CLAMP_SIZE]; - uint32_t csc_post_lv[SDE_CSC_CLAMP_SIZE]; -}; - -/** - * struct sde_mdss_color - mdss color description - * color 0 : green - * color 1 : blue - * color 2 : red - * color 3 : alpha - */ -struct sde_mdss_color { - u32 color_0; - u32 color_1; - u32 color_2; - u32 color_3; -}; - -#endif /* _SDE_HW_MDSS_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c deleted file mode 100644 index 6bee52fd670d..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c +++ /dev/null @@ -1,159 +0,0 @@ -/* 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 - * 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 "sde_hw_mdss.h" -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_pingpong.h" - -#define PP_TEAR_CHECK_EN 0x000 -#define PP_SYNC_CONFIG_VSYNC 0x004 -#define PP_SYNC_CONFIG_HEIGHT 0x008 -#define PP_SYNC_WRCOUNT 0x00C -#define PP_VSYNC_INIT_VAL 0x010 -#define PP_INT_COUNT_VAL 0x014 -#define PP_SYNC_THRESH 0x018 -#define PP_START_POS 0x01C -#define PP_RD_PTR_IRQ 0x020 -#define PP_WR_PTR_IRQ 0x024 -#define PP_OUT_LINE_COUNT 0x028 -#define PP_LINE_COUNT 0x02C -#define PP_AUTOREFRESH_CONFIG 0x030 - -#define PP_FBC_MODE 0x034 -#define PP_FBC_BUDGET_CTL 0x038 -#define PP_FBC_LOSSY_MODE 0x03C -#define PP_DSC_MODE 0x0a0 -#define PP_DCE_DATA_IN_SWAP 0x0ac -#define PP_DCE_DATA_OUT_SWAP 0x0c8 - -static struct sde_pingpong_cfg *_pingpong_offset(enum sde_pingpong pp, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->pingpong_count; i++) { - if (pp == m->pingpong[i].id) { - b->base_off = addr; - b->blk_off = m->pingpong[i].base; - b->hwversion = m->hwversion; - return &m->pingpong[i]; - } - } - - return ERR_PTR(-EINVAL); -} - -static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp, - struct sde_hw_tear_check *te) -{ - struct sde_hw_blk_reg_map *c = &pp->hw; - int cfg; - - cfg = BIT(19); /*VSYNC_COUNTER_EN */ - if (te->hw_vsync_mode) - cfg |= BIT(20); - - cfg |= te->vsync_count; - - SDE_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg); - SDE_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); - SDE_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val); - SDE_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq); - SDE_REG_WRITE(c, PP_START_POS, te->start_pos); - SDE_REG_WRITE(c, PP_SYNC_THRESH, - ((te->sync_threshold_continue << 16) | - te->sync_threshold_start)); - SDE_REG_WRITE(c, PP_SYNC_WRCOUNT, - (te->start_pos + te->sync_threshold_start + 1)); - - return 0; -} - -int sde_hw_pp_setup_autorefresh_config(struct sde_hw_pingpong *pp, - struct sde_hw_autorefresh *cfg) -{ - struct sde_hw_blk_reg_map *c = &pp->hw; - u32 refresh_cfg; - - if (cfg->enable) - refresh_cfg = BIT(31) | cfg->frame_count; - else - refresh_cfg = 0; - - SDE_REG_WRITE(c, PP_AUTOREFRESH_CONFIG, - refresh_cfg); - - return 0; -} - -int sde_hw_pp_setup_dsc_compression(struct sde_hw_pingpong *pp, - struct sde_hw_dsc_cfg *cfg) -{ - return 0; -} -int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable) -{ - struct sde_hw_blk_reg_map *c = &pp->hw; - - SDE_REG_WRITE(c, PP_TEAR_CHECK_EN, enable); - return 0; -} - -int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp, - struct sde_hw_pp_vsync_info *info) -{ - struct sde_hw_blk_reg_map *c = &pp->hw; - - info->init_val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xffff; - info->vsync_count = SDE_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xffff; - info->line_count = SDE_REG_READ(c, PP_INT_COUNT_VAL) & 0xffff; - - return 0; -} - -static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops, - unsigned long cap) -{ - ops->setup_tearcheck = sde_hw_pp_setup_te_config; - ops->enable_tearcheck = sde_hw_pp_enable_te; - ops->get_vsync_info = sde_hw_pp_get_vsync_info; - ops->setup_autorefresh = sde_hw_pp_setup_autorefresh_config; - ops->setup_dsc = sde_hw_pp_setup_dsc_compression; -}; - -struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_pingpong *c; - struct sde_pingpong_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _pingpong_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - c->idx = idx; - c->pingpong_hw_cap = cfg; - _setup_pingpong_ops(&c->ops, c->pingpong_hw_cap->features); - - return c; -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h deleted file mode 100644 index 7cb4cf184e48..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h +++ /dev/null @@ -1,115 +0,0 @@ -/* 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 - * 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 _SDE_HW_PINGPONG_H -#define _SDE_HW_PINGPONG_H - -struct sde_hw_pingpong; - -struct sde_hw_tear_check { - /* - * This is ratio of MDP VSYNC clk freq(Hz) to - * refresh rate divided by no of lines - */ - u32 vsync_count; - u32 sync_cfg_height; - u32 vsync_init_val; - u32 sync_threshold_start; - u32 sync_threshold_continue; - u32 start_pos; - u32 rd_ptr_irq; - u8 hw_vsync_mode; -}; - -struct sde_hw_autorefresh { - bool enable; - u32 frame_count; -}; - -struct sde_hw_pp_vsync_info { - u32 init_val; /* value of rd pointer at vsync edge */ - u32 vsync_count; /* mdp clocks to complete one line */ - u32 line_count; /* current line count */ -}; - -struct sde_hw_dsc_cfg { - u8 enable; -}; - -/** - * - * struct sde_hw_pingpong_ops : Interface to the pingpong Hw driver functions - * Assumption is these functions will be called after clocks are enabled - * @setup_tearcheck : - * @enable_tearcheck : - * @get_vsync_info : - * @setup_autorefresh : - * #setup_dsc : - */ -struct sde_hw_pingpong_ops { - /** - * enables vysnc generation and sets up init value of - * read pointer and programs the tear check cofiguration - */ - int (*setup_tearcheck)(struct sde_hw_pingpong *pp, - struct sde_hw_tear_check *cfg); - - /** - * enables tear check block - */ - int (*enable_tearcheck)(struct sde_hw_pingpong *pp, - bool enable); - - /** - * provides the programmed and current - * line_count - */ - int (*get_vsync_info)(struct sde_hw_pingpong *pp, - struct sde_hw_pp_vsync_info *info); - - /** - * configure and enable the autorefresh config - */ - int (*setup_autorefresh)(struct sde_hw_pingpong *pp, - struct sde_hw_autorefresh *cfg); - - /** - * Program the dsc compression block - */ - int (*setup_dsc)(struct sde_hw_pingpong *pp, - struct sde_hw_dsc_cfg *cfg); -}; - -struct sde_hw_pingpong { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* pingpong */ - enum sde_pingpong idx; - const struct sde_pingpong_cfg *pingpong_hw_cap; - - /* ops */ - struct sde_hw_pingpong_ops ops; -}; - -/** - * sde_hw_pingpong_init(): Initializes the pingpong driver for the passed - * pingpong idx. - * @idx: pingpong index for which driver object is required - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -#endif /*_SDE_HW_PINGPONG_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c deleted file mode 100644 index 8180078ac950..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c +++ /dev/null @@ -1,589 +0,0 @@ -/* 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 - * 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 "sde_hw_sspp.h" -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_lm.h" - -#define SDE_MDP_FETCH_CONFIG_RESET_VALUE 0x00000087 - -/* SDE_SSPP_SRC */ -#define SSPP_SRC_SIZE 0x00 -#define SSPP_SRC_XY 0x08 -#define SSPP_OUT_SIZE 0x0c -#define SSPP_OUT_XY 0x10 -#define SSPP_SRC0_ADDR 0x14 -#define SSPP_SRC1_ADDR 0x18 -#define SSPP_SRC2_ADDR 0x1C -#define SSPP_SRC3_ADDR 0x20 -#define SSPP_SRC_YSTRIDE0 0x24 -#define SSPP_SRC_YSTRIDE1 0x28 -#define SSPP_SRC_FORMAT 0x30 -#define SSPP_SRC_UNPACK_PATTERN 0x34 -#define SSPP_SRC_OP_MODE 0x38 -#define MDSS_MDP_OP_DEINTERLACE BIT(22) - -#define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23) -#define MDSS_MDP_OP_IGC_ROM_1 BIT(18) -#define MDSS_MDP_OP_IGC_ROM_0 BIT(17) -#define MDSS_MDP_OP_IGC_EN BIT(16) -#define MDSS_MDP_OP_FLIP_UD BIT(14) -#define MDSS_MDP_OP_FLIP_LR BIT(13) -#define MDSS_MDP_OP_BWC_EN BIT(0) -#define MDSS_MDP_OP_PE_OVERRIDE BIT(31) -#define MDSS_MDP_OP_BWC_LOSSLESS (0 << 1) -#define MDSS_MDP_OP_BWC_Q_HIGH (1 << 1) -#define MDSS_MDP_OP_BWC_Q_MED (2 << 1) - -#define SSPP_SRC_CONSTANT_COLOR 0x3c -#define SSPP_FETCH_CONFIG 0x048 -#define SSPP_DANGER_LUT 0x60 -#define SSPP_SAFE_LUT 0x64 -#define SSPP_CREQ_LUT 0x68 -#define SSPP_DECIMATION_CONFIG 0xB4 -#define SSPP_SRC_ADDR_SW_STATUS 0x70 -#define SSPP_SW_PIX_EXT_C0_LR 0x100 -#define SSPP_SW_PIX_EXT_C0_TB 0x104 -#define SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108 -#define SSPP_SW_PIX_EXT_C1C2_LR 0x110 -#define SSPP_SW_PIX_EXT_C1C2_TB 0x114 -#define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS 0x118 -#define SSPP_SW_PIX_EXT_C3_LR 0x120 -#define SSPP_SW_PIX_EXT_C3_TB 0x124 -#define SSPP_SW_PIX_EXT_C3_REQ_PIXELS 0x128 -#define SSPP_UBWC_ERROR_STATUS 0x138 -#define SSPP_VIG_OP_MODE 0x200 - -/* SDE_SSPP_SCALAR_QSEED2 */ -#define SCALE_CONFIG 0x04 -#define COMP0_3_PHASE_STEP_X 0x10 -#define COMP0_3_PHASE_STEP_Y 0x14 -#define COMP1_2_PHASE_STEP_X 0x18 -#define COMP1_2_PHASE_STEP_Y 0x1c -#define COMP0_3_INIT_PHASE_X 0x20 -#define COMP0_3_INIT_PHASE_Y 0x24 -#define COMP1_2_INIT_PHASE_X 0x28 -#define COMP1_2_INIT_PHASE_Y 0x2C -#define VIG_0_QSEED2_SHARP 0x30 - -#define VIG_0_CSC_1_MATRIX_COEFF_0 0x20 -#define VIG_0_CSC_1_COMP_0_PRE_CLAMP 0x34 -#define VIG_0_CSC_1_COMP_0_POST_CLAMP 0x40 -#define VIG_0_CSC_1_COMP_0_PRE_BIAS 0x4C -#define VIG_0_CSC_1_COMP_0_POST_BIAS 0x60 - -/* - * MDP Solid fill configuration - * argb8888 - */ -#define SSPP_SOLID_FILL 0x4037ff - -enum { - CSC = 0x1, - PA, - HIST, - SKIN_COL, - FOIL, - SKY_COL, - MEM_PROT_HUE, - MEM_PROT_SAT, - MEM_PROT_VAL, - MEM_PROT_CONT, - MEM_PROT_BLEND, - PA_SAT_ADJ -}; - -static inline int _sspp_subblk_offset(struct sde_hw_pipe *ctx, - int s_id, - u32 *idx) -{ - int rc = 0; - const struct sde_sspp_sub_blks *sblk = ctx->cap->sblk; - - switch (s_id) { - case SDE_SSPP_SRC: - *idx = sblk->src_blk.base; - break; - case SDE_SSPP_SCALAR_QSEED2: - case SDE_SSPP_SCALAR_QSEED3: - case SDE_SSPP_SCALAR_RGB: - *idx = sblk->scalar_blk.base; - break; - case SDE_SSPP_CSC: - *idx = sblk->csc_blk.base; - break; - case SDE_SSPP_PA_V1: - *idx = sblk->pa_blk.base; - break; - case SDE_SSPP_HIST_V1: - *idx = sblk->hist_lut.base; - break; - case SDE_SSPP_PCC: - *idx = sblk->pcc_blk.base; - break; - default: - rc = -EINVAL; - pr_err("Unsupported SSPP sub-blk for this hw\n"); - } - - return rc; -} - -static void _sspp_setup_opmode(struct sde_hw_pipe *ctx, - u32 op, u8 en) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 idx; - u32 opmode; - - if (ctx->cap->features == SDE_SSPP_PA_V1) { - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - opmode = SDE_REG_READ(c, SSPP_VIG_OP_MODE + idx); - - /* ops */ - switch (op) { - case CSC: - if (en) - /* CSC_1_EN and CSC_SRC_DATA_FORMAT*/ - opmode |= BIT(18) | BIT(17); - else - opmode &= ~BIT(17); - break; - default: - pr_err(" Unsupported operation\n"); - } - SDE_REG_WRITE(c, SSPP_VIG_OP_MODE + idx, opmode); - } -} -/** - * Setup source pixel format, flip, - */ -static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg, - u32 flags) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - struct sde_mdp_format_params *fmt; - u32 chroma_samp, unpack, src_format; - u32 secure = 0; - u32 opmode = 0; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - opmode = SDE_REG_READ(c, SSPP_SRC_OP_MODE + idx); - - /* format info */ - fmt = cfg->src.format; - if (WARN_ON(!fmt)) - return; - - if (flags & SDE_SSPP_SECURE_OVERLAY_SESSION) - secure = 0xF; - - if (flags & SDE_SSPP_FLIP_LR) - opmode |= MDSS_MDP_OP_FLIP_LR; - if (flags & SDE_SSPP_FLIP_UD) - opmode |= MDSS_MDP_OP_FLIP_UD; - - chroma_samp = fmt->chroma_sample; - if (flags & SDE_SSPP_SOURCE_ROTATED_90) { - if (chroma_samp == SDE_MDP_CHROMA_H2V1) - chroma_samp = SDE_MDP_CHROMA_H1V2; - else if (chroma_samp == SDE_MDP_CHROMA_H1V2) - chroma_samp = SDE_MDP_CHROMA_H2V1; - } - - src_format = (chroma_samp << 23) | (fmt->fetch_planes << 19) | - (fmt->bits[C3_ALPHA] << 6) | (fmt->bits[C2_R_Cr] << 4) | - (fmt->bits[C1_B_Cb] << 2) | (fmt->bits[C0_G_Y] << 0); - - if (flags & SDE_SSPP_ROT_90) - src_format |= BIT(11); /* ROT90 */ - - if (fmt->alpha_enable && - fmt->fetch_planes != SDE_MDP_PLANE_INTERLEAVED) - src_format |= BIT(8); /* SRCC3_EN */ - - unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) | - (fmt->element[1] << 8) | (fmt->element[0] << 0); - src_format |= ((fmt->unpack_count - 1) << 12) | - (fmt->unpack_tight << 17) | - (fmt->unpack_align_msb << 18) | - ((fmt->bpp - 1) << 9); - - if (fmt->fetch_mode != SDE_MDP_FETCH_LINEAR) { - opmode |= MDSS_MDP_OP_BWC_EN; - src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */ - SDE_REG_WRITE(c, SSPP_FETCH_CONFIG, - SDE_MDP_FETCH_CONFIG_RESET_VALUE | - ctx->highest_bank_bit << 18); - } - - /* if this is YUV pixel format, enable CSC */ - if (fmt->is_yuv) - src_format |= BIT(15); - _sspp_setup_opmode(ctx, CSC, fmt->is_yuv); - - opmode |= MDSS_MDP_OP_PE_OVERRIDE; - - SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format); - SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack); - SDE_REG_WRITE(c, SSPP_SRC_OP_MODE + idx, opmode); - SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure); - - /* clear previous UBWC error */ - SDE_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS + idx, BIT(31)); -} - -static void sde_hw_sspp_setup_pe_config(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg, - struct sde_hw_pixel_ext *pe_ext) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u8 color; - u32 lr_pe[4], tb_pe[4], tot_req_pixels[4]; - const u32 bytemask = 0xff; - const u32 shortmask = 0xffff; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - /* program SW pixel extension override for all pipes*/ - for (color = 0; color < 4; color++) { - /* color 2 has the same set of registers as color 1 */ - if (color == 2) - continue; - - lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24)| - ((pe_ext->right_rpt[color] & bytemask) << 16)| - ((pe_ext->left_ftch[color] & bytemask) << 8)| - (pe_ext->left_rpt[color] & bytemask); - - tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24)| - ((pe_ext->btm_rpt[color] & bytemask) << 16)| - ((pe_ext->top_ftch[color] & bytemask) << 8)| - (pe_ext->top_rpt[color] & bytemask); - - tot_req_pixels[color] = (((pe_ext->roi_h[color] + - pe_ext->num_ext_pxls_top[color] + - pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) | - ((pe_ext->roi_w[color] + - pe_ext->num_ext_pxls_left[color] + - pe_ext->num_ext_pxls_right[color]) & shortmask); - } - - /* color 0 */ - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_LR + idx, lr_pe[0]); - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_TB + idx, tb_pe[0]); - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_REQ_PIXELS + idx, - tot_req_pixels[0]); - - /* color 1 and color 2 */ - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_LR + idx, lr_pe[1]); - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_TB + idx, tb_pe[1]); - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS + idx, - tot_req_pixels[1]); - - /* color 3 */ - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_LR + idx, lr_pe[3]); - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_TB + idx, lr_pe[3]); - SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_REQ_PIXELS + idx, - tot_req_pixels[3]); -} - -static void sde_hw_sspp_setup_scalar(struct sde_hw_pipe *ctx, - struct sde_hw_pixel_ext *pe_ext) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - int scale_config; - const u8 mask = 0x3; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALAR_QSEED2, &idx)) - return; - - scale_config = BIT(0) | BIT(1); - /* RGB/YUV config */ - scale_config |= (pe_ext->horz_filter[SDE_SSPP_COMP_LUMA] & mask) << 8; - scale_config |= (pe_ext->vert_filter[SDE_SSPP_COMP_LUMA] & mask) << 10; - /* Aplha config*/ - scale_config |= (pe_ext->horz_filter[SDE_SSPP_COMP_ALPHA] & mask) << 16; - scale_config |= (pe_ext->vert_filter[SDE_SSPP_COMP_ALPHA] & mask) << 18; - - SDE_REG_WRITE(c, SCALE_CONFIG + idx, scale_config); - SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_X + idx, - pe_ext->init_phase_x[SDE_SSPP_COMP_LUMA]); - SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_Y + idx, - pe_ext->init_phase_y[SDE_SSPP_COMP_LUMA]); - SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_X + idx, - pe_ext->phase_step_x[SDE_SSPP_COMP_LUMA]); - SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_Y + idx, - pe_ext->phase_step_y[SDE_SSPP_COMP_LUMA]); - - SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_X + idx, - pe_ext->init_phase_x[SDE_SSPP_COMP_CHROMA]); - SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_Y + idx, - pe_ext->init_phase_y[SDE_SSPP_COMP_CHROMA]); - SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_X + idx, - pe_ext->phase_step_x[SDE_SSPP_COMP_CHROMA]); - SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_Y + idx, - pe_ext->phase_step_y[SDE_SSPP_COMP_CHROMA]); -} - -/** - * sde_hw_sspp_setup_rects() - */ -static void sde_hw_sspp_setup_rects(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg, - struct sde_hw_pixel_ext *pe_ext) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 src_size, src_xy, dst_size, dst_xy, ystride0, ystride1; - u32 decimation = 0; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - /* program pixel extension override */ - if (pe_ext) - sde_hw_sspp_setup_pe_config(ctx, cfg, pe_ext); - - /* src and dest rect programming */ - src_xy = (cfg->src_rect.y << 16) | - (cfg->src_rect.x); - src_size = (cfg->src_rect.h << 16) | - (cfg->src_rect.w); - dst_xy = (cfg->dst_rect.y << 16) | - (cfg->dst_rect.x); - dst_size = (cfg->dst_rect.h << 16) | - (cfg->dst_rect.w); - - ystride0 = (cfg->src.ystride[0]) | - (cfg->src.ystride[1] << 16); - ystride1 = (cfg->src.ystride[2]) | - (cfg->src.ystride[3] << 16); - - /* program scalar, phase registers, if pipes supporting scaling */ - if (src_size != dst_size) { - if (test_bit(SDE_SSPP_SCALAR_RGB, &ctx->cap->features) || - test_bit(SDE_SSPP_SCALAR_QSEED2, &ctx->cap->features)) { - /* program decimation */ - decimation = ((1 << cfg->horz_decimation) - 1) << 8; - decimation |= ((1 << cfg->vert_decimation) - 1); - - sde_hw_sspp_setup_scalar(ctx, pe_ext); - } - } - - /* Rectangle Register programming */ - SDE_REG_WRITE(c, SSPP_SRC_SIZE + idx, src_size); - SDE_REG_WRITE(c, SSPP_SRC_XY + idx, src_xy); - SDE_REG_WRITE(c, SSPP_OUT_SIZE + idx, dst_size); - SDE_REG_WRITE(c, SSPP_OUT_XY + idx, dst_xy); - - SDE_REG_WRITE(c, SSPP_SRC_YSTRIDE0 + idx, ystride0); - SDE_REG_WRITE(c, SSPP_SRC_YSTRIDE1 + idx, ystride1); - SDE_REG_WRITE(c, SSPP_DECIMATION_CONFIG + idx, decimation); -} - -static void sde_hw_sspp_setup_sourceaddress(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - int i; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - for (i = 0; i < cfg->src.num_planes; i++) - SDE_REG_WRITE(c, SSPP_SRC0_ADDR + idx + i*0x4, - cfg->addr.plane[i]); -} - -static void sde_hw_sspp_setup_csc_8bit(struct sde_hw_pipe *ctx, - struct sde_csc_cfg *data) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - - sde_hw_csc_setup(c, VIG_0_CSC_1_MATRIX_COEFF_0, data); -} - -static void sde_hw_sspp_setup_sharpening(struct sde_hw_pipe *ctx, - struct sde_hw_sharp_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx, cfg->strength); - SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0x4, cfg->edge_thr); - SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0x8, cfg->smooth_thr); - SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0xC, cfg->noise_thr); -} - -static void sde_hw_sspp_setup_solidfill(struct sde_hw_pipe *ctx, - u32 const_color, - u32 flags) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 secure = 0; - u32 unpack, src_format, opmode = 0; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - /* format info */ - src_format = SSPP_SOLID_FILL; - unpack = (C3_ALPHA << 24) | (C2_R_Cr << 16) | - (C1_B_Cb << 8) | (C0_G_Y << 0); - secure = (flags & SDE_SSPP_SECURE_OVERLAY_SESSION) ? 0xF : 0x00; - opmode = MDSS_MDP_OP_PE_OVERRIDE; - - SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format); - SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack); - SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure); - SDE_REG_WRITE(c, SSPP_SRC_CONSTANT_COLOR + idx, const_color); - SDE_REG_WRITE(c, SSPP_SRC_OP_MODE + idx, opmode); -} - -static void sde_hw_sspp_setup_histogram_v1(struct sde_hw_pipe *ctx, - void *cfg) -{ -} - -static void sde_hw_sspp_setup_memcolor(struct sde_hw_pipe *ctx, - u32 memcolortype, u8 en) -{ -} - -static void sde_hw_sspp_setup_igc(struct sde_hw_pipe *ctx) -{ -} - -void sde_sspp_setup_pa(struct sde_hw_pipe *c) -{ -} - -static void sde_hw_sspp_setup_danger_safe(struct sde_hw_pipe *ctx, - u32 danger_lut, u32 safe_lut) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 idx; - - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) - return; - - SDE_REG_WRITE(c, SSPP_DANGER_LUT + idx, danger_lut); - SDE_REG_WRITE(c, SSPP_SAFE_LUT + idx, safe_lut); -} - -static void sde_hw_sspp_qseed2_coeff(void *ctx) -{ -} - -static void _setup_layer_ops(struct sde_hw_sspp_ops *ops, - unsigned long features) -{ - if (test_bit(SDE_SSPP_SRC, &features)) { - ops->setup_sourceformat = sde_hw_sspp_setup_format; - ops->setup_rects = sde_hw_sspp_setup_rects; - ops->setup_sourceaddress = sde_hw_sspp_setup_sourceaddress; - ops->setup_solidfill = sde_hw_sspp_setup_solidfill; - ops->setup_danger_safe = sde_hw_sspp_setup_danger_safe; - } - if (test_bit(SDE_SSPP_CSC, &features)) - ops->setup_csc = sde_hw_sspp_setup_csc_8bit; - - if (test_bit(SDE_SSPP_PA_V1, &features)) { - ops->setup_sharpening = sde_hw_sspp_setup_sharpening; - ops->setup_pa_memcolor = sde_hw_sspp_setup_memcolor; - } - if (test_bit(SDE_SSPP_HIST_V1, &features)) - ops->setup_histogram = sde_hw_sspp_setup_histogram_v1; - - if (test_bit(SDE_SSPP_IGC, &features)) - ops->setup_igc = sde_hw_sspp_setup_igc; -} - -static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->sspp_count; i++) { - if (sspp == m->sspp[i].id) { - b->base_off = addr; - b->blk_off = m->sspp[i].base; - b->hwversion = m->hwversion; - return &m->sspp[i]; - } - } - - return ERR_PTR(-ENOMEM); -} - -struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_pipe *c; - struct sde_sspp_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _sspp_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - /* Assign ops */ - c->idx = idx; - c->cap = cfg; - _setup_layer_ops(&c->ops, c->cap->features); - c->highest_bank_bit = m->mdp[0].highest_bank_bit; - - /* - * Perform any default initialization for the sspp blocks - */ - if (test_bit(SDE_SSPP_SCALAR_QSEED2, &cfg->features)) - sde_hw_sspp_qseed2_coeff(c); - - if (test_bit(SDE_MDP_PANIC_PER_PIPE, &m->mdp[0].features)) - sde_hw_sspp_setup_danger_safe(c, - cfg->sblk->danger_lut, - cfg->sblk->safe_lut); - - return c; -} - -void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx) -{ - kfree(ctx); -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h deleted file mode 100644 index 0e78c52cde56..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h +++ /dev/null @@ -1,282 +0,0 @@ -/* 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 - * 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 _SDE_HW_SSPP_H -#define _SDE_HW_SSPP_H - -#include "sde_hw_catalog.h" -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" - -struct sde_hw_pipe; - -/** - * Flags - */ -#define SDE_SSPP_SECURE_OVERLAY_SESSION 0x1 -#define SDE_SSPP_FLIP_LR 0x2 -#define SDE_SSPP_FLIP_UD 0x4 -#define SDE_SSPP_SOURCE_ROTATED_90 0x8 -#define SDE_SSPP_ROT_90 0x10 - -/** - * Component indices - */ -enum { - SDE_SSPP_COMP_LUMA = 0, - SDE_SSPP_COMP_CHROMA = 1, - SDE_SSPP_COMP_ALPHA = 3 -}; - -enum { - SDE_MDP_FRAME_LINEAR, - SDE_MDP_FRAME_TILE_A4X, - SDE_MDP_FRAME_TILE_A5X, -}; - -enum sde_hw_filter { - SDE_MDP_SCALE_FILTER_NEAREST = 0, - SDE_MDP_SCALE_FILTER_BIL, - SDE_MDP_SCALE_FILTER_PCMN, - SDE_MDP_SCALE_FILTER_CA, - SDE_MDP_SCALE_FILTER_MAX -}; - -struct sde_hw_sharp_cfg { - u32 strength; - u32 edge_thr; - u32 smooth_thr; - u32 noise_thr; -}; - -struct sde_hw_pixel_ext { - /* scaling factors are enabled for this input layer */ - uint8_t enable_pxl_ext; - - int init_phase_x[SDE_MAX_PLANES]; - int phase_step_x[SDE_MAX_PLANES]; - int init_phase_y[SDE_MAX_PLANES]; - int phase_step_y[SDE_MAX_PLANES]; - - /* - * Number of pixels extension in left, right, top and bottom direction - * for all color components. This pixel value for each color component - * should be sum of fetch + repeat pixels. - */ - int num_ext_pxls_left[SDE_MAX_PLANES]; - int num_ext_pxls_right[SDE_MAX_PLANES]; - int num_ext_pxls_top[SDE_MAX_PLANES]; - int num_ext_pxls_btm[SDE_MAX_PLANES]; - - /* - * Number of pixels needs to be overfetched in left, right, top and - * bottom directions from source image for scaling. - */ - int left_ftch[SDE_MAX_PLANES]; - int right_ftch[SDE_MAX_PLANES]; - int top_ftch[SDE_MAX_PLANES]; - int btm_ftch[SDE_MAX_PLANES]; - - /* - * Number of pixels needs to be repeated in left, right, top and - * bottom directions for scaling. - */ - int left_rpt[SDE_MAX_PLANES]; - int right_rpt[SDE_MAX_PLANES]; - int top_rpt[SDE_MAX_PLANES]; - int btm_rpt[SDE_MAX_PLANES]; - - uint32_t roi_w[SDE_MAX_PLANES]; - uint32_t roi_h[SDE_MAX_PLANES]; - - /* - * Filter type to be used for scaling in horizontal and vertical - * directions - */ - enum sde_hw_filter horz_filter[SDE_MAX_PLANES]; - enum sde_hw_filter vert_filter[SDE_MAX_PLANES]; - -}; - -/** - * struct sde_hw_pipe_cfg : Pipe description - * @src: source surface information - * @src_rect: src ROI, caller takes into account the different operations - * such as decimation, flip etc to program this field - * @dest_rect: destination ROI. - * @ horz_decimation : horizontal decimation factor( 0, 2, 4, 8, 16) - * @ vert_decimation : vertical decimation factor( 0, 2, 4, 8, 16) - * 2: Read 1 line/pixel drop 1 line/pixel - * 4: Read 1 line/pixel drop 3 lines/pixels - * 8: Read 1 line/pixel drop 7 lines/pixels - * 16: Read 1 line/pixel drop 15 line/pixels - * @addr: source surface address - */ -struct sde_hw_pipe_cfg { - struct sde_hw_source_info src; - struct sde_rect src_rect; - struct sde_rect dst_rect; - u8 horz_decimation; - u8 vert_decimation; - struct addr_info addr; -}; - -/** - * struct danger_safe_cfg: - * @danger_lut: - * @safe_lut: - */ -struct danger_safe_cfg { - u32 danger_lut; - u32 safe_lut; -}; - -/** - * struct sde_hw_sspp_ops - interface to the SSPP Hw driver functions - * Caller must call the init function to get the pipe context for each pipe - * Assumption is these functions will be called after clocks are enabled - */ -struct sde_hw_sspp_ops { - /** - * setup_sourceformat - setup pixel format cropping rectangle, flip - * @ctx: Pointer to pipe context - * @cfg: Pointer to pipe config structure - * @flags: Format flags - */ - void (*setup_sourceformat)(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg, - u32 flags); - - /** - * setup_rects - setup pipe ROI rectangles - * @ctx: Pointer to pipe context - * @cfg: Pointer to pipe config structure - * @pe_ext: Pointer to pixel ext settings - */ - void (*setup_rects)(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg, - struct sde_hw_pixel_ext *pe_ext); - - /** - * setup_sourceaddress - setup pipe source addresses - * @ctx: Pointer to pipe context - * @cfg: Pointer to pipe config structure - */ - void (*setup_sourceaddress)(struct sde_hw_pipe *ctx, - struct sde_hw_pipe_cfg *cfg); - - /** - * setup_csc - setup color space coversion - * @ctx: Pointer to pipe context - * @data: Pointer to config structure - */ - void (*setup_csc)(struct sde_hw_pipe *ctx, - struct sde_csc_cfg *data); - - /** - * setup_solidfill - enable/disable colorfill - * @ctx: Pointer to pipe context - * @const_color: Fill color value - * @flags: Pipe flags - */ - void (*setup_solidfill)(struct sde_hw_pipe *ctx, - u32 const_color, - u32 flags); - - /** - * setup_sharpening - setup sharpening - * @ctx: Pointer to pipe context - * @cfg: Pointer to config structure - */ - void (*setup_sharpening)(struct sde_hw_pipe *ctx, - struct sde_hw_sharp_cfg *cfg); - - /** - * setup_pa_memcolor - setup source color processing - * @ctx: Pointer to pipe context - * @memcolortype: Memcolor type - * @en: PA enable - */ - void (*setup_pa_memcolor)(struct sde_hw_pipe *ctx, - u32 memcolortype, u8 en); - - /** - * setup_igc - setup inverse gamma correction - * @ctx: Pointer to pipe context - */ - void (*setup_igc)(struct sde_hw_pipe *ctx); - - /** - * setup_danger_safe - setup danger safe LUTS - * @ctx: Pointer to pipe context - * @danger_lut: Danger LUT setting - * @safe_lut: Safe LUT setting - */ - void (*setup_danger_safe)(struct sde_hw_pipe *ctx, - u32 danger_lut, - u32 safe_lut); - - /** - * setup_histogram - setup histograms - * @ctx: Pointer to pipe context - * @cfg: Pointer to histogram configuration - */ - void (*setup_histogram)(struct sde_hw_pipe *ctx, - void *cfg); -}; - -/** - * struct sde_hw_pipe - pipe description - * @base_off: mdp register mapped offset - * @blk_off: pipe offset relative to mdss offset - * @length length of register block offset - * @hwversion mdss hw version number - * @idx: pipe index - * @type : pipe type, VIG/DMA/RGB/CURSOR, certain operations are not - * supported for each pipe type - * @pipe_hw_cap: pointer to layer_cfg - * @highest_bank_bit: - * @ops: pointer to operations possible for this pipe - */ -struct sde_hw_pipe { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* Pipe */ - enum sde_sspp idx; - const struct sde_sspp_cfg *cap; - u32 highest_bank_bit; - - /* Ops */ - struct sde_hw_sspp_ops ops; -}; - -/** - * sde_hw_sspp_init - initializes the sspp hw driver object. - * Should be called once before accessing every pipe. - * @idx: Pipe index for which driver object is required - * @addr: Mapped register io address of MDP - * @m: pointer to mdss catalog data @ops: - */ -struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -/** - * sde_hw_sspp_destroy(): Destroys SSPP driver context - * should be called during Hw pipe cleanup. - * @ctx: Pointer to SSPP driver context returned by sde_hw_sspp_init - */ -void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx); - -#endif /*_SDE_HW_SSPP_H */ - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.c b/drivers/gpu/drm/msm/sde/sde_hw_wb.c deleted file mode 100644 index 9ed3f8586fd1..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_wb.c +++ /dev/null @@ -1,120 +0,0 @@ -/* 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 - * 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 "sde_hw_mdss.h" -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_wb.h" - -static struct sde_wb_cfg *_wb_offset(enum sde_wb wb, - struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->wb_count; i++) { - if (wb == m->wb[i].id) { - b->base_off = addr; - b->blk_off = m->wb[i].base; - b->hwversion = m->hwversion; - return &m->wb[i]; - } - } - return ERR_PTR(-EINVAL); -} - -static void sde_hw_wb_setup_csc_8bit(struct sde_hw_wb *ctx, - struct sde_csc_cfg *data) -{ -} - -static void sde_hw_wb_setup_outaddress(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *data) -{ -} - -static void sde_hw_wb_setup_format(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *data) -{ -} - -static void sde_hw_wb_setup_rotator(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *data) -{ -} - -static void sde_hw_setup_dither(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *data) -{ -} - -static void sde_hw_wb_setup_cdwn(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *data) -{ -} -static void sde_hw_wb_traffic_shaper(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *data) -{ -} - -static void _setup_wb_ops(struct sde_hw_wb_ops *ops, - unsigned long features) -{ - if (test_bit(SDE_WB_CSC, &features)) - ops->setup_csc_data = sde_hw_wb_setup_csc_8bit; - - ops->setup_outaddress = sde_hw_wb_setup_outaddress; - ops->setup_outformat = sde_hw_wb_setup_format; - - if (test_bit(SDE_WB_BLOCK_MODE, &features)) - ops->setup_rotator = sde_hw_wb_setup_rotator; - - if (test_bit(SDE_WB_DITHER, &features)) - ops->setup_dither = sde_hw_setup_dither; - - if (test_bit(SDE_WB_CHROMA_DOWN, &features)) - ops->setup_cdwn = sde_hw_wb_setup_cdwn; - - if (test_bit(SDE_WB_TRAFFIC_SHAPER, &features)) - ops->setup_trafficshaper = sde_hw_wb_traffic_shaper; -} - -struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx, - void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_wb *c; - struct sde_wb_cfg *cfg; - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _wb_offset(idx, m, addr, &c->hw); - if (!cfg) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - /* Assign ops */ - c->idx = idx; - c->caps = cfg; - _setup_wb_ops(&c->ops, c->caps->features); - - /* - * Perform any default initialization for the chroma down module - */ - - return c; -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.h b/drivers/gpu/drm/msm/sde/sde_hw_wb.h deleted file mode 100644 index 32e2ee87ef7f..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_wb.h +++ /dev/null @@ -1,85 +0,0 @@ -/* 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 - * 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 _SDE_HW_WB_H -#define _SDE_HW_WB_H - -#include "sde_hw_catalog.h" -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" - -struct sde_hw_wb; - -struct sde_hw_wb_cfg { - struct sde_hw_source_info dest; -}; - -/** - * - * struct sde_hw_wb_ops : Interface to the wb Hw driver functions - * Assumption is these functions will be called after clocks are enabled - */ -struct sde_hw_wb_ops { - void (*setup_csc_data)(struct sde_hw_wb *ctx, - struct sde_csc_cfg *data); - - void (*setup_outaddress)(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *wb); - - void (*setup_outformat)(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *wb); - - void (*setup_rotator)(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *wb); - - void (*setup_dither)(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *wb); - - void (*setup_cdwn)(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *wb); - - void (*setup_trafficshaper)(struct sde_hw_wb *ctx, - struct sde_hw_wb_cfg *wb); -}; - -/** - * struct sde_hw_wb : WB driver object - * @struct sde_hw_blk_reg_map *hw; - * @idx - * @wb_hw_caps - * @mixer_hw_caps - * @ops - */ -struct sde_hw_wb { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* wb path */ - int idx; - const struct sde_wb_cfg *caps; - - /* ops */ - struct sde_hw_wb_ops ops; -}; - -/** - * sde_hw_wb_init(): Initializes the wb_path hw driver object. - * should be called before accessing every mixer. - * @idx: wb_path index for which driver object is required - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx, - void __iomem *addr, - struct sde_mdss_cfg *m); - -#endif /*_SDE_HW_WB_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h deleted file mode 100644 index 2531463b654e..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hwio.h +++ /dev/null @@ -1,59 +0,0 @@ -/* 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 - * 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 _SDE_HWIO_H -#define _SDE_HWIO_H - -#include "sde_hw_mdp_util.h" - -/** - * MDP TOP block Register and bit fields and defines - */ -#define DISP_INTF_SEL 0x004 -#define INTR_EN 0x010 -#define INTR_STATUS 0x014 -#define INTR_CLEAR 0x018 -#define INTR2_EN 0x008 -#define INTR2_STATUS 0x00c -#define INTR2_CLEAR 0x02c -#define HIST_INTR_EN 0x01c -#define HIST_INTR_STATUS 0x020 -#define HIST_INTR_CLEAR 0x024 -#define INTF_INTR_EN 0x1C0 -#define INTF_INTR_STATUS 0x1C4 -#define INTF_INTR_CLEAR 0x1C8 -#define SPLIT_DISPLAY_EN 0x2F4 -#define SPLIT_DISPLAY_UPPER_PIPE_CTRL 0x2F8 -#define DSPP_IGC_COLOR0_RAM_LUTN 0x300 -#define DSPP_IGC_COLOR1_RAM_LUTN 0x304 -#define DSPP_IGC_COLOR2_RAM_LUTN 0x308 -#define PPB0_CNTL 0x330 -#define PPB0_CONFIG 0x334 -#define PPB1_CNTL 0x338 -#define PPB1_CONFIG 0x33C -#define HW_EVENTS_CTL 0x37C -#define CLK_CTRL3 0x3A8 -#define CLK_STATUS3 0x3AC -#define CLK_CTRL4 0x3B0 -#define CLK_STATUS4 0x3B4 -#define CLK_CTRL5 0x3B8 -#define CLK_STATUS5 0x3BC -#define CLK_CTRL7 0x3D0 -#define CLK_STATUS7 0x3D4 -#define SPLIT_DISPLAY_LOWER_PIPE_CTRL 0x3F0 -#define SPLIT_DISPLAY_TE_LINE_INTERVAL 0x3F4 -#define INTF_SW_RESET_MASK 0x3FC -#define MDP_OUT_CTL_0 0x410 -#define MDP_VSYNC_SEL 0x414 -#define DCE_SEL 0x450 - -#endif /*_SDE_HWIO_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c deleted file mode 100644 index 722845df3d0b..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ /dev/null @@ -1,350 +0,0 @@ -/* 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 - * 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/irqdomain.h> -#include <linux/irq.h> -#include <linux/kthread.h> - -#include "msm_drv.h" -#include "sde_kms.h" - -static void sde_irq_callback_handler(void *arg, int irq_idx) -{ - struct sde_kms *sde_kms = arg; - struct sde_irq *irq_obj = &sde_kms->irq_obj; - - /* - * Perform registered function callback - */ - if (irq_obj->irq_cb_tbl && irq_obj->irq_cb_tbl[irq_idx].func) - irq_obj->irq_cb_tbl[irq_idx].func( - irq_obj->irq_cb_tbl[irq_idx].arg, - irq_idx); - - /* - * Clear pending interrupt status in HW. - * NOTE: sde_irq_callback_handler is protected by top-level - * spinlock, so it is safe to clear any interrupt status here. - */ - sde_kms->hw_intr->ops.clear_interrupt_status( - sde_kms->hw_intr, - irq_idx); -} - -static void sde_irq_intf_error_handler(void *arg, int irq_idx) -{ - DRM_ERROR("INTF underrun detected, irq_idx=%d\n", irq_idx); -} - -void sde_set_irqmask(struct sde_kms *sde_kms, uint32_t reg, uint32_t irqmask) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.set_mask) - return; - - sde_kms->hw_intr->ops.set_mask(sde_kms->hw_intr, reg, irqmask); -} - -int sde_irq_idx_lookup(struct sde_kms *sde_kms, enum sde_intr_type intr_type, - u32 instance_idx) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.irq_idx_lookup) - return -EINVAL; - - return sde_kms->hw_intr->ops.irq_idx_lookup(intr_type, - instance_idx); -} - -int sde_enable_irq(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count) -{ - int i; - int ret = 0; - - if (!sde_kms || !irq_idxs || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.enable_irq) - return -EINVAL; - - for (i = 0; i < irq_count; i++) { - ret = sde_kms->hw_intr->ops.enable_irq( - sde_kms->hw_intr, - irq_idxs[i]); - if (ret) { - DRM_ERROR("Fail to enable IRQ for irq_idx:%d\n", - irq_idxs[i]); - return ret; - } - } - - return ret; -} - -int sde_disable_irq(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count) -{ - int i; - int ret = 0; - - if (!sde_kms || !irq_idxs || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.disable_irq) - return -EINVAL; - - for (i = 0; i < irq_count; i++) { - ret = sde_kms->hw_intr->ops.disable_irq( - sde_kms->hw_intr, - irq_idxs[i]); - if (ret) { - DRM_ERROR("Fail to disable IRQ for irq_idx:%d\n", - irq_idxs[i]); - return ret; - } - } - - return ret; -} - -int sde_register_irq_callback(struct sde_kms *sde_kms, int irq_idx, - struct sde_irq_callback *register_irq_cb) -{ - struct sde_irq_callback *irq_cb_tbl; - unsigned long irq_flags; - - /* - * We allow NULL register_irq_cb as input for callback registration - */ - if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl) - return -EINVAL; - - if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) { - DRM_ERROR("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - irq_cb_tbl = sde_kms->irq_obj.irq_cb_tbl; - spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); - irq_cb_tbl[irq_idx].func = register_irq_cb ? - register_irq_cb->func : NULL; - irq_cb_tbl[irq_idx].arg = register_irq_cb ? - register_irq_cb->arg : NULL; - spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); - - return 0; -} - -void sde_clear_all_irqs(struct sde_kms *sde_kms) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.clear_all_irqs) - return; - - sde_kms->hw_intr->ops.clear_all_irqs(sde_kms->hw_intr); -} - -void sde_disable_all_irqs(struct sde_kms *sde_kms) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.disable_all_irqs) - return; - - sde_kms->hw_intr->ops.disable_all_irqs(sde_kms->hw_intr); -} - -void sde_irq_preinstall(struct msm_kms *kms) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - - sde_enable(sde_kms); - sde_clear_all_irqs(sde_kms); - sde_disable_all_irqs(sde_kms); - sde_disable(sde_kms); - - spin_lock_init(&sde_kms->irq_obj.cb_lock); - - /* Create irq callbacks for all possible irq_idx */ - sde_kms->irq_obj.total_irqs = sde_kms->hw_intr->irq_idx_tbl_size; - sde_kms->irq_obj.irq_cb_tbl = kcalloc(sde_kms->irq_obj.total_irqs, - sizeof(struct sde_irq_callback), GFP_KERNEL); - if (!sde_kms->irq_obj.irq_cb_tbl) - DRM_ERROR("Fail to allocate memory of IRQ callback list\n"); -} - -int sde_irq_postinstall(struct msm_kms *kms) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - struct sde_irq_callback irq_cb; - int irq_idx; - int i; - - irq_cb.func = sde_irq_intf_error_handler; - irq_cb.arg = sde_kms; - - /* Register interface underrun callback */ - sde_enable(sde_kms); - for (i = 0; i < sde_kms->catalog->intf_count; i++) { - irq_idx = sde_irq_idx_lookup(sde_kms, - SDE_IRQ_TYPE_INTF_UNDER_RUN, i+INTF_0); - sde_register_irq_callback(sde_kms, irq_idx, &irq_cb); - sde_enable_irq(sde_kms, &irq_idx, 1); - } - sde_disable(sde_kms); - - return 0; -} - -void sde_irq_uninstall(struct msm_kms *kms) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - - sde_enable(sde_kms); - sde_clear_all_irqs(sde_kms); - sde_disable_all_irqs(sde_kms); - sde_disable(sde_kms); - - kfree(sde_kms->irq_obj.irq_cb_tbl); -} - -static void _sde_irq_mdp_done(struct sde_kms *sde_kms) -{ - /* - * Read interrupt status from all sources. Interrupt status are - * stored within hw_intr. - * Function will also clear the interrupt status after reading. - * Individual interrupt status bit will only get stored if it - * is enabled. - */ - sde_kms->hw_intr->ops.get_interrupt_statuses(sde_kms->hw_intr); - - /* - * Dispatch to HW driver to handle interrupt lookup that is being - * fired. When matching interrupt is located, HW driver will call to - * sde_irq_callback_handler with the irq_idx from the lookup table. - * sde_irq_callback_handler will perform the registered function - * callback, and do the interrupt status clearing once the registered - * callback is finished. - */ - sde_kms->hw_intr->ops.dispatch_irqs( - sde_kms->hw_intr, - sde_irq_callback_handler, - sde_kms); -} - -irqreturn_t sde_irq(struct msm_kms *kms) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - u32 interrupts; - - sde_kms->hw_intr->ops.get_interrupt_sources(sde_kms->hw_intr, - &interrupts); - - /* - * Taking care of MDP interrupt - */ - if (interrupts & IRQ_SOURCE_MDP) { - interrupts &= ~IRQ_SOURCE_MDP; - _sde_irq_mdp_done(sde_kms); - } - - /* - * Routing all other interrupts to external drivers - */ - while (interrupts) { - irq_hw_number_t hwirq = fls(interrupts) - 1; - - generic_handle_irq(irq_find_mapping( - sde_kms->irqcontroller.domain, hwirq)); - interrupts &= ~(1 << hwirq); - } - - return IRQ_HANDLED; -} - -int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) -{ - return sde_crtc_vblank(crtc); -} - -void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) -{ -} - -static void sde_hw_irq_mask(struct irq_data *irqd) -{ - struct sde_kms *sde_kms = irq_data_get_irq_chip_data(irqd); - - smp_mb__before_atomic(); - clear_bit(irqd->hwirq, &sde_kms->irqcontroller.enabled_mask); - smp_mb__after_atomic(); -} - -static void sde_hw_irq_unmask(struct irq_data *irqd) -{ - struct sde_kms *sde_kms = irq_data_get_irq_chip_data(irqd); - - smp_mb__before_atomic(); - set_bit(irqd->hwirq, &sde_kms->irqcontroller.enabled_mask); - smp_mb__after_atomic(); -} - -static struct irq_chip sde_hw_irq_chip = { - .name = "sde", - .irq_mask = sde_hw_irq_mask, - .irq_unmask = sde_hw_irq_unmask, -}; - -static int sde_hw_irqdomain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) -{ - struct sde_kms *sde_kms = d->host_data; - uint32_t valid_irqs; - - sde_kms->hw_intr->ops.get_valid_interrupts(sde_kms->hw_intr, - &valid_irqs); - - if (!(valid_irqs & (1 << hwirq))) - return -EPERM; - - irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq); - irq_set_chip_data(irq, sde_kms); - - return 0; -} - -static struct irq_domain_ops sde_hw_irqdomain_ops = { - .map = sde_hw_irqdomain_map, - .xlate = irq_domain_xlate_onecell, -}; - -int sde_irq_domain_init(struct sde_kms *sde_kms) -{ - struct device *dev = sde_kms->dev->dev; - struct irq_domain *d; - - d = irq_domain_add_linear(dev->of_node, 32, - &sde_hw_irqdomain_ops, sde_kms); - - if (!d) - return -ENXIO; - - sde_kms->irqcontroller.enabled_mask = 0; - sde_kms->irqcontroller.domain = d; - - return 0; -} - -int sde_irq_domain_fini(struct sde_kms *sde_kms) -{ - if (sde_kms->irqcontroller.domain) { - irq_domain_remove(sde_kms->irqcontroller.domain); - sde_kms->irqcontroller.domain = NULL; - } - return 0; -} - diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c deleted file mode 100644 index 7fba38b9e60d..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ /dev/null @@ -1,499 +0,0 @@ -/* 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 - * 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 <drm/drm_crtc.h> -#include "msm_drv.h" -#include "msm_mmu.h" -#include "sde_kms.h" -#include "sde_hw_mdss.h" -#include "sde_hw_intf.h" - -static const char * const iommu_ports[] = { - "mdp_0", -}; - -static const struct sde_hw_res_map res_table[INTF_MAX] = { - { SDE_NONE, SDE_NONE, SDE_NONE, SDE_NONE}, - { INTF_0, SDE_NONE, SDE_NONE, SDE_NONE}, - { INTF_1, LM_0, PINGPONG_0, CTL_0}, - { INTF_2, LM_1, PINGPONG_1, CTL_1}, - { INTF_3, SDE_NONE, SDE_NONE, CTL_2}, -}; - - -#define DEFAULT_MDP_SRC_CLK 200000000 - -int sde_disable(struct sde_kms *sde_kms) -{ - DBG(""); - - return 0; -} - -int sde_enable(struct sde_kms *sde_kms) -{ - DBG(""); - - clk_prepare_enable(sde_kms->ahb_clk); - clk_prepare_enable(sde_kms->axi_clk); - clk_prepare_enable(sde_kms->core_clk); - if (sde_kms->lut_clk) - clk_prepare_enable(sde_kms->lut_clk); - - return 0; -} - -static void sde_prepare_commit(struct msm_kms *kms, - struct drm_atomic_state *state) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - sde_enable(sde_kms); -} - -static void sde_complete_commit(struct msm_kms *kms, - struct drm_atomic_state *state) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - sde_disable(sde_kms); -} - -static void sde_wait_for_crtc_commit_done(struct msm_kms *kms, - struct drm_crtc *crtc) -{ - sde_crtc_wait_for_commit_done(crtc); -} -static int modeset_init(struct sde_kms *sde_kms) -{ - struct msm_drm_private *priv = sde_kms->dev->dev_private; - int i; - int ret; - struct sde_mdss_cfg *catalog = sde_kms->catalog; - struct drm_device *dev = sde_kms->dev; - struct drm_plane *primary_planes[MAX_PLANES]; - int primary_planes_idx = 0; - - int num_private_planes = catalog->mixer_count; - - ret = sde_irq_domain_init(sde_kms); - if (ret) - goto fail; - - /* Create the planes */ - for (i = 0; i < catalog->sspp_count; i++) { - struct drm_plane *plane; - bool primary = true; - - if (catalog->sspp[i].features & BIT(SDE_SSPP_CURSOR) - || !num_private_planes) - primary = false; - - plane = sde_plane_init(dev, catalog->sspp[i].id, primary); - if (IS_ERR(plane)) { - pr_err("%s: sde_plane_init failed", __func__); - ret = PTR_ERR(plane); - goto fail; - } - priv->planes[priv->num_planes++] = plane; - - if (primary) - primary_planes[primary_planes_idx++] = plane; - if (primary && num_private_planes) - num_private_planes--; - } - - /* Need enough primary planes to assign one per mixer (CRTC) */ - if (primary_planes_idx < catalog->mixer_count) { - ret = -EINVAL; - goto fail; - } - - /* - * Enumerate displays supported - */ - sde_encoders_init(dev); - - /* Create one CRTC per display */ - for (i = 0; i < priv->num_encoders; i++) { - /* - * Each CRTC receives a private plane. We start - * with first RGB, and then DMA and then VIG. - */ - struct drm_crtc *crtc; - - crtc = sde_crtc_init(dev, priv->encoders[i], - primary_planes[i], i); - if (IS_ERR(crtc)) { - ret = PTR_ERR(crtc); - goto fail; - } - priv->crtcs[priv->num_crtcs++] = crtc; - } - - /* - * Iterate through the list of encoders and - * set the possible CRTCs - */ - for (i = 0; i < priv->num_encoders; i++) - priv->encoders[i]->possible_crtcs = (1 << priv->num_crtcs) - 1; - - return 0; -fail: - return ret; -} - -static int sde_hw_init(struct msm_kms *kms) -{ - return 0; -} - -static long sde_round_pixclk(struct msm_kms *kms, unsigned long rate, - struct drm_encoder *encoder) -{ - return rate; -} - -static void sde_preclose(struct msm_kms *kms, struct drm_file *file) -{ -} - -static void sde_destroy(struct msm_kms *kms) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - - sde_irq_domain_fini(sde_kms); - sde_hw_intr_destroy(sde_kms->hw_intr); - kfree(sde_kms); -} - -static const struct msm_kms_funcs kms_funcs = { - .hw_init = sde_hw_init, - .irq_preinstall = sde_irq_preinstall, - .irq_postinstall = sde_irq_postinstall, - .irq_uninstall = sde_irq_uninstall, - .irq = sde_irq, - .prepare_commit = sde_prepare_commit, - .complete_commit = sde_complete_commit, - .wait_for_crtc_commit_done = sde_wait_for_crtc_commit_done, - .enable_vblank = sde_enable_vblank, - .disable_vblank = sde_disable_vblank, - .get_format = mdp_get_format, - .round_pixclk = sde_round_pixclk, - .preclose = sde_preclose, - .destroy = sde_destroy, -}; - -static int get_clk(struct platform_device *pdev, struct clk **clkp, - const char *name, bool mandatory) -{ - struct device *dev = &pdev->dev; - struct clk *clk = devm_clk_get(dev, name); - - if (IS_ERR(clk) && mandatory) { - dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk)); - return PTR_ERR(clk); - } - if (IS_ERR(clk)) - DBG("skipping %s", name); - else - *clkp = clk; - - return 0; -} - -struct sde_kms *sde_hw_setup(struct platform_device *pdev) -{ - struct sde_kms *sde_kms; - struct msm_kms *kms = NULL; - int ret; - - sde_kms = kzalloc(sizeof(*sde_kms), GFP_KERNEL); - if (!sde_kms) - return NULL; - - msm_kms_init(&sde_kms->base, &kms_funcs); - - kms = &sde_kms->base; - - sde_kms->mmio = msm_ioremap(pdev, "mdp_phys", "SDE"); - if (IS_ERR(sde_kms->mmio)) { - ret = PTR_ERR(sde_kms->mmio); - goto fail; - } - pr_err("Mapped Mdp address space @%pK", sde_kms->mmio); - - sde_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); - if (IS_ERR(sde_kms->vbif)) { - ret = PTR_ERR(sde_kms->vbif); - goto fail; - } - - sde_kms->venus = devm_regulator_get_optional(&pdev->dev, "gdsc-venus"); - if (IS_ERR(sde_kms->venus)) { - ret = PTR_ERR(sde_kms->venus); - DBG("failed to get Venus GDSC regulator: %d\n", ret); - sde_kms->venus = NULL; - } - - if (sde_kms->venus) { - ret = regulator_enable(sde_kms->venus); - if (ret) { - DBG("failed to enable venus GDSC: %d\n", ret); - goto fail; - } - } - - sde_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(sde_kms->vdd)) { - ret = PTR_ERR(sde_kms->vdd); - goto fail; - } - - ret = regulator_enable(sde_kms->vdd); - if (ret) { - DBG("failed to enable regulator vdd: %d\n", ret); - goto fail; - } - - sde_kms->mmagic = devm_regulator_get_optional(&pdev->dev, "mmagic"); - if (IS_ERR(sde_kms->mmagic)) { - ret = PTR_ERR(sde_kms->mmagic); - DBG("failed to get mmagic GDSC regulator: %d\n", ret); - sde_kms->mmagic = NULL; - } - - /* mandatory clocks: */ - ret = get_clk(pdev, &sde_kms->axi_clk, "bus_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &sde_kms->ahb_clk, "iface_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &sde_kms->src_clk, "core_clk_src", true); - if (ret) - goto fail; - ret = get_clk(pdev, &sde_kms->core_clk, "core_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &sde_kms->vsync_clk, "vsync_clk", true); - if (ret) - goto fail; - - /* optional clocks: */ - get_clk(pdev, &sde_kms->lut_clk, "lut_clk", false); - get_clk(pdev, &sde_kms->mmagic_clk, "mmagic_clk", false); - get_clk(pdev, &sde_kms->iommu_clk, "iommu_clk", false); - - if (sde_kms->mmagic) { - ret = regulator_enable(sde_kms->mmagic); - if (ret) { - dev_err(sde_kms->dev->dev, - "failed to enable mmagic GDSC: %d\n", ret); - goto fail; - } - } - if (sde_kms->mmagic_clk) { - clk_prepare_enable(sde_kms->mmagic_clk); - if (ret) { - dev_err(sde_kms->dev->dev, "failed to enable mmagic_clk\n"); - goto undo_gdsc; - } - } - - return sde_kms; - -undo_gdsc: - if (sde_kms->mmagic) - regulator_disable(sde_kms->mmagic); -fail: - if (kms) - sde_destroy(kms); - - return ERR_PTR(ret); -} - -static int sde_translation_ctrl_pwr(struct sde_kms *sde_kms, bool on) -{ - struct device *dev = sde_kms->dev->dev; - int ret; - - if (on) { - if (sde_kms->iommu_clk) { - ret = clk_prepare_enable(sde_kms->iommu_clk); - if (ret) { - dev_err(dev, "failed to enable iommu_clk\n"); - goto undo_mmagic_clk; - } - } - } else { - if (sde_kms->iommu_clk) - clk_disable_unprepare(sde_kms->iommu_clk); - if (sde_kms->mmagic_clk) - clk_disable_unprepare(sde_kms->mmagic_clk); - if (sde_kms->mmagic) - regulator_disable(sde_kms->mmagic); - } - - return 0; - -undo_mmagic_clk: - if (sde_kms->mmagic_clk) - clk_disable_unprepare(sde_kms->mmagic_clk); - - return ret; -} -int sde_mmu_init(struct sde_kms *sde_kms) -{ - struct sde_mdss_cfg *catalog = sde_kms->catalog; - struct sde_hw_intf *intf = NULL; - struct iommu_domain *iommu; - struct msm_mmu *mmu; - int i, ret; - - /* - * Make sure things are off before attaching iommu (bootloader could - * have left things on, in which case we'll start getting faults if - * we don't disable): - */ - sde_enable(sde_kms); - for (i = 0; i < catalog->intf_count; i++) { - intf = sde_hw_intf_init(catalog->intf[i].id, - sde_kms->mmio, - catalog); - if (!IS_ERR_OR_NULL(intf)) { - intf->ops.enable_timing(intf, 0x0); - sde_hw_intf_deinit(intf); - } - } - sde_disable(sde_kms); - msleep(20); - - iommu = iommu_domain_alloc(&platform_bus_type); - - if (!IS_ERR_OR_NULL(iommu)) { - mmu = msm_smmu_new(sde_kms->dev->dev, MSM_SMMU_DOMAIN_UNSECURE); - if (IS_ERR(mmu)) { - ret = PTR_ERR(mmu); - dev_err(sde_kms->dev->dev, - "failed to init iommu: %d\n", ret); - iommu_domain_free(iommu); - goto fail; - } - - ret = sde_translation_ctrl_pwr(sde_kms, true); - if (ret) { - dev_err(sde_kms->dev->dev, - "failed to power iommu: %d\n", ret); - mmu->funcs->destroy(mmu); - goto fail; - } - - ret = mmu->funcs->attach(mmu, (const char **)iommu_ports, - ARRAY_SIZE(iommu_ports)); - if (ret) { - dev_err(sde_kms->dev->dev, - "failed to attach iommu: %d\n", ret); - mmu->funcs->destroy(mmu); - goto fail; - } - } else { - dev_info(sde_kms->dev->dev, - "no iommu, fallback to phys contig buffers for scanout\n"); - mmu = NULL; - } - sde_kms->mmu = mmu; - - sde_kms->mmu_id = msm_register_mmu(sde_kms->dev, mmu); - if (sde_kms->mmu_id < 0) { - ret = sde_kms->mmu_id; - dev_err(sde_kms->dev->dev, - "failed to register sde iommu: %d\n", ret); - goto fail; - } - - return 0; -fail: - return ret; - -} - -struct msm_kms *sde_kms_init(struct drm_device *dev) -{ - struct platform_device *pdev = dev->platformdev; - struct sde_mdss_cfg *catalog; - struct sde_kms *sde_kms; - struct msm_kms *msm_kms; - int ret = 0; - - sde_kms = sde_hw_setup(pdev); - if (IS_ERR(sde_kms)) { - ret = PTR_ERR(sde_kms); - goto fail; - } - - sde_kms->dev = dev; - msm_kms = &sde_kms->base; - - /* - * Currently hardcoding to MDSS version 1.7.0 (8996) - */ - catalog = sde_hw_catalog_init(1, 7, 0); - if (!catalog) - goto fail; - - sde_kms->catalog = catalog; - - /* we need to set a default rate before enabling. - * Set a safe rate first, before initializing catalog - * later set more optimal rate based on bandwdith/clock - * requirements - */ - - clk_set_rate(sde_kms->src_clk, DEFAULT_MDP_SRC_CLK); - sde_enable(sde_kms); - sde_kms->hw_res.res_table = res_table; - - /* - * Now we need to read the HW catalog and initialize resources such as - * clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc - */ - sde_mmu_init(sde_kms); - - /* - * modeset_init should create the DRM related objects i.e. CRTCs, - * planes, encoders, connectors and so forth - */ - modeset_init(sde_kms); - - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - - /* - * we can assume the max crtc width is equal to the max supported - * by LM_0 - * Also fixing the max height to 4k - */ - dev->mode_config.max_width = catalog->mixer[0].sblk->maxwidth; - dev->mode_config.max_height = 4096; - - sde_kms->hw_intr = sde_rm_acquire_intr(sde_kms); - - if (IS_ERR_OR_NULL(sde_kms->hw_intr)) - goto fail; - - return msm_kms; - -fail: - if (msm_kms) - sde_destroy(msm_kms); - - return ERR_PTR(ret); -} diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h deleted file mode 100644 index 7ac1b6b827bc..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ /dev/null @@ -1,304 +0,0 @@ -/* 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 - * 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 __SDE_KMS_H__ -#define __SDE_KMS_H__ - -#include "msm_drv.h" -#include "msm_kms.h" -#include "mdp/mdp_kms.h" -#include "sde_hw_catalog.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_hw_lm.h" -#include "sde_hw_interrupts.h" - -/* - * struct sde_irq_callback - IRQ callback handlers - * @func: intr handler - * @arg: argument for the handler - */ -struct sde_irq_callback { - void (*func)(void *arg, int irq_idx); - void *arg; -}; - -/** - * struct sde_irq: IRQ structure contains callback registration info - * @total_irq: total number of irq_idx obtained from HW interrupts mapping - * @irq_cb_tbl: array of IRQ callbacks setting - * @cb_lock: callback lock - */ -struct sde_irq { - u32 total_irqs; - struct sde_irq_callback *irq_cb_tbl; - spinlock_t cb_lock; -}; - -/** - * struct sde_hw_res_map : Default resource table identifying default - * hw resource map. Primarily used for forcing DSI to use CTL_0/1 - * and Pingpong 0/1, if the field is set to SDE_NONE means any HW - * intstance for that tpye is allowed as long as it is unused. - */ -struct sde_hw_res_map { - enum sde_intf intf; - enum sde_lm lm; - enum sde_pingpong pp; - enum sde_ctl ctl; -}; - -/* struct sde_hw_resource_manager : Resource mananger maintains the current - * platform configuration and manages shared - * hw resources ex:ctl_path hw driver context - * is needed by CRTCs/PLANEs/ENCODERs - * @ctl : table of control path hw driver contexts allocated - * @mixer : list of mixer hw drivers contexts allocated - * @intr : pointer to hw interrupt context - * @res_table : pointer to default hw_res table for this platform - * @feature_map :BIT map for default enabled features ex:specifies if PP_SPLIT - * is enabled/disabled by defalt for this platform - */ -struct sde_hw_resource_manager { - struct sde_hw_ctl *ctl[CTL_MAX]; - struct sde_hw_mixer *mixer[LM_MAX]; - struct sde_hw_intr *intr; - const struct sde_hw_res_map *res_table; - bool feature_map; -}; - -struct sde_kms { - struct msm_kms base; - struct drm_device *dev; - int rev; - struct sde_mdss_cfg *catalog; - - struct msm_mmu *mmu; - int mmu_id; - - /* io/register spaces: */ - void __iomem *mmio, *vbif; - - struct regulator *vdd; - struct regulator *mmagic; - struct regulator *venus; - - struct clk *axi_clk; - struct clk *ahb_clk; - struct clk *src_clk; - struct clk *core_clk; - struct clk *lut_clk; - struct clk *mmagic_clk; - struct clk *iommu_clk; - struct clk *vsync_clk; - - struct { - unsigned long enabled_mask; - struct irq_domain *domain; - } irqcontroller; - - struct sde_hw_intr *hw_intr; - struct sde_irq irq_obj; - struct sde_hw_resource_manager hw_res; -}; - -struct vsync_info { - u32 frame_count; - u32 line_count; -}; - -#define to_sde_kms(x) container_of(x, struct sde_kms, base) - -struct sde_plane_state { - struct drm_plane_state base; - - /* aligned with property */ - uint8_t premultiplied; - uint8_t zpos; - uint8_t alpha; - - /* assigned by crtc blender */ - enum sde_stage stage; - - /* some additional transactional status to help us know in the - * apply path whether we need to update SMP allocation, and - * whether current update is still pending: - */ - bool mode_changed : 1; - bool pending : 1; -}; - -#define to_sde_plane_state(x) \ - container_of(x, struct sde_plane_state, base) - -int sde_disable(struct sde_kms *sde_kms); -int sde_enable(struct sde_kms *sde_kms); - -/** - * HW resource manager functions - * @sde_rm_acquire_ctl_path : Allocates control path - * @sde_rm_get_ctl_path : returns control path driver context for already - * acquired ctl path - * @sde_rm_release_ctl_path : Frees control path driver context - * @sde_rm_acquire_mixer : Allocates mixer hw driver context - * @sde_rm_get_mixer : returns mixer context for already - * acquired mixer - * @sde_rm_release_mixer : Frees mixer hw driver context - * @sde_rm_get_hw_res_map : Returns map for the passed INTF - */ -struct sde_hw_ctl *sde_rm_acquire_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx); -struct sde_hw_ctl *sde_rm_get_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx); -void sde_rm_release_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx); -struct sde_hw_mixer *sde_rm_acquire_mixer(struct sde_kms *sde_kms, - enum sde_lm idx); -struct sde_hw_mixer *sde_rm_get_mixer(struct sde_kms *sde_kms, - enum sde_lm idx); -void sde_rm_release_mixer(struct sde_kms *sde_kms, - enum sde_lm idx); -struct sde_hw_intr *sde_rm_acquire_intr(struct sde_kms *sde_kms); -struct sde_hw_intr *sde_rm_get_intr(struct sde_kms *sde_kms); - -const struct sde_hw_res_map *sde_rm_get_res_map(struct sde_kms *sde_kms, - enum sde_intf idx); - -/** - * IRQ functions - */ -int sde_irq_domain_init(struct sde_kms *sde_kms); -int sde_irq_domain_fini(struct sde_kms *sde_kms); -void sde_irq_preinstall(struct msm_kms *kms); -int sde_irq_postinstall(struct msm_kms *kms); -void sde_irq_uninstall(struct msm_kms *kms); -irqreturn_t sde_irq(struct msm_kms *kms); - -/** - * sde_set_irqmask - IRQ helper function for writing IRQ mask - * to SDE HW interrupt register. - * @sde_kms: SDE handle - * @reg_off: SDE HW interrupt register offset - * @irqmask: IRQ mask - */ -void sde_set_irqmask( - struct sde_kms *sde_kms, - uint32_t reg_off, - uint32_t irqmask); - -/** - * sde_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW - * interrupt mapping table. - * @sde_kms: SDE handle - * @intr_type: SDE HW interrupt type for lookup - * @instance_idx: SDE HW block instance defined in sde_hw_mdss.h - * @return: irq_idx or -EINVAL when fail to lookup - */ -int sde_irq_idx_lookup( - struct sde_kms *sde_kms, - enum sde_intr_type intr_type, - uint32_t instance_idx); - -/** - * sde_enable_irq - IRQ helper function for enabling one or more IRQs - * @sde_kms: SDE handle - * @irq_idxs: Array of irq index - * @irq_count: Number of irq_idx provided in the array - * @return: 0 for success enabling IRQ, otherwise failure - */ -int sde_enable_irq( - struct sde_kms *sde_kms, - int *irq_idxs, - uint32_t irq_count); - -/** - * sde_disable_irq - IRQ helper function for diabling one of more IRQs - * @sde_kms: SDE handle - * @irq_idxs: Array of irq index - * @irq_count: Number of irq_idx provided in the array - * @return: 0 for success disabling IRQ, otherwise failure - */ -int sde_disable_irq( - struct sde_kms *sde_kms, - int *irq_idxs, - uint32_t irq_count); - -/** - * sde_register_irq_callback - For registering callback function on IRQ - * interrupt - * @sde_kms: SDE handle - * @irq_idx: irq index - * @irq_cb: IRQ callback structure, containing callback function - * and argument. Passing NULL for irq_cb will unregister - * the callback for the given irq_idx - * @return: 0 for success registering callback, otherwise failure - */ -int sde_register_irq_callback( - struct sde_kms *sde_kms, - int irq_idx, - struct sde_irq_callback *irq_cb); - -/** - * sde_clear_all_irqs - Clearing all SDE IRQ interrupt status - * @sde_kms: SDE handle - */ -void sde_clear_all_irqs(struct sde_kms *sde_kms); - -/** - * sde_disable_all_irqs - Diabling all SDE IRQ interrupt - * @sde_kms: SDE handle - */ -void sde_disable_all_irqs(struct sde_kms *sde_kms); - -/** - * Vblank enable/disable functions - */ -int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); -void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); - -/** - * Plane functions - */ -enum sde_sspp sde_plane_pipe(struct drm_plane *plane); -struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe, - bool private_plane); - -/** - * CRTC functions - */ -uint32_t sde_crtc_vblank(struct drm_crtc *crtc); -void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc); -void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); -struct drm_crtc *sde_crtc_init(struct drm_device *dev, - struct drm_encoder *encoder, - struct drm_plane *plane, int id); - -/** - * Encoder functions and data types - */ -struct sde_encoder_hw_resources { - enum sde_intf_mode intfs[INTF_MAX]; - bool pingpongs[PINGPONG_MAX]; - bool ctls[CTL_MAX]; - bool pingpongsplit; -}; - -void sde_encoder_get_hw_resources(struct drm_encoder *encoder, - struct sde_encoder_hw_resources *hw_res); -void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc, - void (*cb)(void *), void *data); -void sde_encoders_init(struct drm_device *dev); -void sde_encoder_get_vsync_info(struct drm_encoder *encoder, - struct vsync_info *vsync); - - - -#endif /* __sde_kms_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c deleted file mode 100644 index 9d6f28cfc06c..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sde_kms.h" -#include "sde_hw_lm.h" -#include "sde_hw_mdp_ctl.h" - -struct sde_hw_intr *sde_rm_acquire_intr(struct sde_kms *sde_kms) -{ - struct sde_hw_intr *hw_intr; - - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - if (sde_kms->hw_res.intr) { - DRM_ERROR("intr already in use "); - return ERR_PTR(-ENODEV); - } - - sde_enable(sde_kms); - hw_intr = sde_hw_intr_init(sde_kms->mmio, - sde_kms->catalog); - sde_disable(sde_kms); - - if (!IS_ERR_OR_NULL(hw_intr)) - sde_kms->hw_res.intr = hw_intr; - - return hw_intr; -} - -struct sde_hw_intr *sde_rm_get_intr(struct sde_kms *sde_kms) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - return sde_kms->hw_res.intr; -} - -struct sde_hw_ctl *sde_rm_acquire_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx) -{ - struct sde_hw_ctl *hw_ctl; - - if (!sde_kms) { - DRM_ERROR("Invalid KMS driver"); - return ERR_PTR(-EINVAL); - } - - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->ctl_count)) { - DRM_ERROR("Invalid Ctl Path Idx %d", idx); - return ERR_PTR(-EINVAL); - } - - if (sde_kms->hw_res.ctl[idx]) { - DRM_ERROR("CTL path %d already in use ", idx); - return ERR_PTR(-ENODEV); - } - - sde_enable(sde_kms); - hw_ctl = sde_hw_ctl_init(idx, sde_kms->mmio, sde_kms->catalog); - sde_disable(sde_kms); - - if (!IS_ERR_OR_NULL(hw_ctl)) - sde_kms->hw_res.ctl[idx] = hw_ctl; - - return hw_ctl; -} - -struct sde_hw_ctl *sde_rm_get_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->ctl_count)) { - DRM_ERROR("Invalid Ctl path Idx %d", idx); - return ERR_PTR(-EINVAL); - } - - return sde_kms->hw_res.ctl[idx]; -} - -void sde_rm_release_ctl_path(struct sde_kms *sde_kms, enum sde_ctl idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid pointer\n"); - return; - } - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->ctl_count)) { - DRM_ERROR("Invalid Ctl path Idx %d", idx); - return; - } -} - -struct sde_hw_mixer *sde_rm_acquire_mixer(struct sde_kms *sde_kms, - enum sde_lm idx) -{ - struct sde_hw_mixer *mixer; - - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->mixer_count)) { - DBG("Invalid mixer id %d", idx); - return ERR_PTR(-EINVAL); - } - - if (sde_kms->hw_res.mixer[idx]) { - DRM_ERROR("mixer %d already in use ", idx); - return ERR_PTR(-ENODEV); - } - - sde_enable(sde_kms); - mixer = sde_hw_lm_init(idx, sde_kms->mmio, sde_kms->catalog); - sde_disable(sde_kms); - - if (!IS_ERR_OR_NULL(mixer)) - sde_kms->hw_res.mixer[idx] = mixer; - - return mixer; -} - -struct sde_hw_mixer *sde_rm_get_mixer(struct sde_kms *sde_kms, - enum sde_lm idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->mixer_count)) { - DRM_ERROR("Invalid mixer id %d", idx); - return ERR_PTR(-EINVAL); - } - - return sde_kms->hw_res.mixer[idx]; -} - -const struct sde_hw_res_map *sde_rm_get_res_map(struct sde_kms *sde_kms, - enum sde_intf idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->intf_count)) { - DRM_ERROR("Invalid intf id %d", idx); - return ERR_PTR(-EINVAL); - } - - DBG(" Platform Resource map for INTF %d -> lm %d, pp %d ctl %d", - sde_kms->hw_res.res_table[idx].intf, - sde_kms->hw_res.res_table[idx].lm, - sde_kms->hw_res.res_table[idx].pp, - sde_kms->hw_res.res_table[idx].ctl); - return &(sde_kms->hw_res.res_table[idx]); -} diff --git a/drivers/gpu/drm/msm/sde/sde_mdp_formats.c b/drivers/gpu/drm/msm/sde/sde_mdp_formats.c deleted file mode 100644 index 56b65d4bd45e..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_mdp_formats.c +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include "sde_mdp_formats.h" - -static struct sde_mdp_format_params sde_mdp_format_map[] = { - INTERLEAVED_RGB_FMT(ARGB8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, - true, 4, 0), - - INTERLEAVED_RGB_FMT(ABGR8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, - true, 4, 0), - - INTERLEAVED_RGB_FMT(RGBA8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, - true, 4, 0), - - INTERLEAVED_RGB_FMT(BGRA8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, - true, 4, 0), - - INTERLEAVED_RGB_FMT(XRGB8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, - true, 4, 0), - - INTERLEAVED_RGB_FMT(RGB888, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, 0, - false, 3, 0), - - INTERLEAVED_RGB_FMT(BGR888, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, - false, 3, 0), - - INTERLEAVED_RGB_FMT(RGB565, - 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, 0, - false, 2, 0), - - INTERLEAVED_RGB_FMT(BGR565, - 0, 5, 6, 5, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, - false, 2, 0), - - PSEDUO_YUV_FMT(NV12, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C2_R_Cr, - SDE_MDP_CHROMA_420, 0), - - PSEDUO_YUV_FMT(NV21, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C1_B_Cb, - SDE_MDP_CHROMA_420, 0), - - PSEDUO_YUV_FMT(NV16, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C2_R_Cr, - SDE_MDP_CHROMA_H2V1, 0), - - PSEDUO_YUV_FMT(NV61, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C1_B_Cb, - SDE_MDP_CHROMA_H2V1, 0), - - INTERLEAVED_YUV_FMT(VYUY, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - INTERLEAVED_YUV_FMT(UYVY, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - INTERLEAVED_YUV_FMT(YUYV, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - INTERLEAVED_YUV_FMT(YVYU, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - PLANAR_YUV_FMT(YUV420, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C1_B_Cb, C0_G_Y, - false, SDE_MDP_CHROMA_420, 2, - 0), - - PLANAR_YUV_FMT(YVU420, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C2_R_Cr, C0_G_Y, - false, SDE_MDP_CHROMA_420, 2, - 0), -}; - -struct sde_mdp_format_params *sde_mdp_get_format_params(u32 format, - u32 fmt_modifier) -{ - u32 i = 0; - struct sde_mdp_format_params *fmt = NULL; - - for (i = 0; i < sizeof(sde_mdp_format_map)/sizeof(*sde_mdp_format_map); - i++) - if (format == sde_mdp_format_map[i].format) { - fmt = &sde_mdp_format_map[i]; - break; - } - - return fmt; -} - diff --git a/drivers/gpu/drm/msm/sde/sde_mdp_formats.h b/drivers/gpu/drm/msm/sde/sde_mdp_formats.h deleted file mode 100644 index e6f1c60aad11..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_mdp_formats.h +++ /dev/null @@ -1,104 +0,0 @@ -/* 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 - * 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 _SDE_MDP_FORMATS_H -#define _SDE_MDP_FORMATS_H - -#include <drm/drm_fourcc.h> -#include "sde_hw_mdss.h" - -/** - * MDP supported format packing, bpp, and other format - * information. - * MDP currently only supports interleaved RGB formats - * UBWC support for a pixel format is indicated by the flag, - * there is additional meta data plane for such formats - */ - -#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, alpha, bp, flg) \ -{ \ - .format = DRM_FORMAT_ ## fmt, \ - .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ - .alpha_enable = alpha, \ - .element = { (e0), (e1), (e2), (e3) }, \ - .bits = { a, r, g, b}, \ - .chroma_sample = SDE_MDP_CHROMA_RGB, \ - .unpack_align_msb = 0, \ - .unpack_tight = 1, \ - .unpack_count = (alpha == true) ? 4:3, \ - .bpp = bp, \ - .fetch_mode = SDE_MDP_FETCH_LINEAR, \ - .is_yuv = false, \ - .flag = flg \ -} - -#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \ -alpha, chroma, count, bp, flg) \ -{ \ - .format = DRM_FORMAT_ ## fmt, \ - .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ - .alpha_enable = alpha, \ - .element = { (e0), (e1), (e2), (e3)}, \ - .bits = { a, r, g, b}, \ - .chroma_sample = chroma, \ - .unpack_align_msb = 0, \ - .unpack_tight = 1, \ - .unpack_count = count, \ - .bpp = bp, \ - .fetch_mode = SDE_MDP_FETCH_LINEAR, \ - .is_yuv = true, \ - .flag = flg \ -} - -#define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg) \ -{ \ - .format = DRM_FORMAT_ ## fmt, \ - .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, \ - .alpha_enable = false, \ - .element = { (e0), (e1), 0, 0 }, \ - .bits = { a, r, g, b}, \ - .chroma_sample = chroma, \ - .unpack_align_msb = 0, \ - .unpack_tight = 1, \ - .unpack_count = 2, \ - .bpp = 2, \ - .fetch_mode = SDE_MDP_FETCH_LINEAR, \ - .is_yuv = true, \ - .flag = flg \ -} - -#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, flg)\ -{ \ - .format = DRM_FORMAT_ ## fmt, \ - .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ - .alpha_enable = alpha, \ - .element = { (e0), (e1), (e2), 0 }, \ - .bits = { a, r, g, b}, \ - .chroma_sample = chroma, \ - .unpack_align_msb = 0, \ - .unpack_tight = 1, \ - .unpack_count = 0, \ - .bpp = bp, \ - .fetch_mode = SDE_MDP_FETCH_LINEAR, \ - .is_yuv = true, \ - .flag = flg \ -} - -/** - * sde_mdp_get_format_params(): Returns sde format structure pointer. - * @format: DRM format - * @fmt_modifier: DRM format modifier - */ -struct sde_mdp_format_params *sde_mdp_get_format_params(u32 format, - u32 fmt_modifier); - -#endif /*_SDE_MDP_FORMATS_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c deleted file mode 100644 index cf34de2f1e3d..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ /dev/null @@ -1,767 +0,0 @@ -/* 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 - * 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 "sde_kms.h" -#include "sde_hwio.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_mdp_formats.h" -#include "sde_hw_sspp.h" - -#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci)) -#define PHASE_STEP_SHIFT 21 -#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT)) -#define PHASE_RESIDUAL 15 - -#define SDE_PLANE_FEATURE_SCALER \ - (BIT(SDE_SSPP_SCALAR_QSEED2)| \ - BIT(SDE_SSPP_SCALAR_QSEED3)| \ - BIT(SDE_SSPP_SCALAR_RGB)) - -#ifndef SDE_PLANE_DEBUG_START -#define SDE_PLANE_DEBUG_START() -#endif - -#ifndef SDE_PLANE_DEBUG_END -#define SDE_PLANE_DEBUG_END() -#endif - -struct sde_plane { - struct drm_plane base; - const char *name; - - int mmu_id; - - enum sde_sspp pipe; - uint32_t features; /* capabilities from catalog */ - uint32_t flush_mask; /* used to commit pipe registers */ - uint32_t nformats; - uint32_t formats[32]; - - struct sde_hw_pipe *pipe_hw; - struct sde_hw_pipe_cfg pipe_cfg; - struct sde_hw_pixel_ext pixel_ext; -}; -#define to_sde_plane(x) container_of(x, struct sde_plane, base) - -static bool sde_plane_enabled(struct drm_plane_state *state) -{ - return state->fb && state->crtc; -} - -static void sde_plane_set_scanout(struct drm_plane *plane, - struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb) -{ - struct sde_plane *psde = to_sde_plane(plane); - int i; - - if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) { - /* stride */ - i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES); - while (i) { - --i; - pipe_cfg->src.ystride[i] = fb->pitches[i]; - } - - /* address */ - for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i) - pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb, - psde->mmu_id, i); - - /* hw driver */ - psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg); - } -} - -static void sde_plane_scale_helper(struct drm_plane *plane, - uint32_t src, uint32_t dst, uint32_t *phase_steps, - enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt, - uint32_t chroma_subsampling) -{ - /* calcualte phase steps, leave init phase as zero */ - phase_steps[SDE_SSPP_COMP_LUMA] = - mult_frac(1 << PHASE_STEP_SHIFT, src, dst); - phase_steps[SDE_SSPP_COMP_CHROMA] = - phase_steps[SDE_SSPP_COMP_LUMA] / chroma_subsampling; - - /* calculate scaler config, if necessary */ - if (src != dst) { - filter[SDE_SSPP_COMP_ALPHA] = (src < dst) ? - SDE_MDP_SCALE_FILTER_BIL : - SDE_MDP_SCALE_FILTER_PCMN; - - if (fmt->is_yuv) - filter[SDE_SSPP_COMP_LUMA] = SDE_MDP_SCALE_FILTER_CA; - else - filter[SDE_SSPP_COMP_LUMA] = - filter[SDE_SSPP_COMP_ALPHA]; - } -} - -/* CIFIX: clean up fmt/subsampling params once we're using fourcc formats */ -static void _sde_plane_pixel_ext_helper(struct drm_plane *plane, - uint32_t src, uint32_t dst, uint32_t decimated_src, - uint32_t *phase_steps, uint32_t *out_src, int *out_edge1, - int *out_edge2, struct sde_mdp_format_params *fmt, - uint32_t chroma_subsampling, bool post_compare) -{ - /* CIFIX: adapted from mdss_mdp_pipe_calc_pixel_extn() */ - int64_t edge1, edge2, caf; - uint32_t src_work; - int i, tmp; - - if (plane && phase_steps && out_src && out_edge1 && out_edge2 && fmt) { - /* enable CAF for YUV formats */ - if (fmt->is_yuv) - caf = PHASE_STEP_UNIT_SCALE; - else - caf = 0; - - for (i = 0; i < SDE_MAX_PLANES; i++) { - src_work = decimated_src; - if (i == 1 || i == 2) - src_work /= chroma_subsampling; - if (post_compare) - src = src_work; - if (!(fmt->is_yuv) && (src == dst)) { - /* unity */ - edge1 = 0; - edge2 = 0; - } else if (dst >= src) { - /* upscale */ - edge1 = (1 << PHASE_RESIDUAL); - edge1 -= caf; - edge2 = (1 << PHASE_RESIDUAL); - edge2 += (dst - 1) * *(phase_steps + i); - edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE; - edge2 += caf; - edge2 = -(edge2); - } else { - /* downscale */ - edge1 = 0; - edge2 = (dst - 1) * *(phase_steps + i); - edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE; - edge2 += *(phase_steps + i); - edge2 = -(edge2); - } - - /* only enable CAF for luma plane */ - caf = 0; - - /* populate output arrays */ - *(out_src + i) = src_work; - - /* edge updates taken from __pxl_extn_helper */ - /* CIFIX: why are we casting first to uint32_t? */ - if (edge1 >= 0) { - tmp = (uint32_t)edge1; - tmp >>= PHASE_STEP_SHIFT; - *(out_edge1 + i) = -tmp; - } else { - tmp = (uint32_t)(-edge1); - *(out_edge1 + i) = (tmp + PHASE_STEP_UNIT_SCALE - - 1) >> PHASE_STEP_SHIFT; - } - if (edge2 >= 0) { - tmp = (uint32_t)edge2; - tmp >>= PHASE_STEP_SHIFT; - *(out_edge2 + i) = -tmp; - } else { - tmp = (uint32_t)(-edge2); - *(out_edge2 + i) = (tmp + PHASE_STEP_UNIT_SCALE - - 1) >> PHASE_STEP_SHIFT; - } - } - } -} - -static int sde_plane_mode_set(struct drm_plane *plane, - struct drm_crtc *crtc, struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - struct sde_plane *psde = to_sde_plane(plane); - struct sde_plane_state *pstate; - const struct mdp_format *format; - uint32_t nplanes, pix_format, tmp; - int i; - struct sde_mdp_format_params *fmt; - struct sde_hw_pixel_ext *pe; - int ret = 0; - - SDE_PLANE_DEBUG_START(); - nplanes = drm_format_num_planes(fb->pixel_format); - - pstate = to_sde_plane_state(plane->state); - - format = to_mdp_format(msm_framebuffer_format(fb)); - pix_format = format->base.pixel_format; - - /* src values are in Q16 fixed point, convert to integer */ - src_x = src_x >> 16; - src_y = src_y >> 16; - src_w = src_w >> 16; - src_h = src_h >> 16; - - DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->name, - fb->base.id, src_x, src_y, src_w, src_h, - crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); - - /* update format configuration */ - memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg)); - - psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format, - 0/* CIFIX: fmt_modifier */); - psde->pipe_cfg.src.width = fb->width; - psde->pipe_cfg.src.height = fb->height; - psde->pipe_cfg.src.num_planes = nplanes; - - sde_plane_set_scanout(plane, &psde->pipe_cfg, fb); - - psde->pipe_cfg.src_rect.x = src_x; - psde->pipe_cfg.src_rect.y = src_y; - psde->pipe_cfg.src_rect.w = src_w; - psde->pipe_cfg.src_rect.h = src_h; - - psde->pipe_cfg.dst_rect.x = crtc_x; - psde->pipe_cfg.dst_rect.y = crtc_y; - psde->pipe_cfg.dst_rect.w = crtc_w; - psde->pipe_cfg.dst_rect.h = crtc_h; - - psde->pipe_cfg.horz_decimation = 0; - psde->pipe_cfg.vert_decimation = 0; - - /* get sde pixel format definition */ - fmt = psde->pipe_cfg.src.format; - - /* update pixel extensions */ - pe = &(psde->pixel_ext); - if (!pe->enable_pxl_ext) { - uint32_t chroma_subsample_h, chroma_subsample_v; - - chroma_subsample_h = psde->pipe_cfg.horz_decimation ? 1 : - drm_format_horz_chroma_subsampling(pix_format); - chroma_subsample_v = psde->pipe_cfg.vert_decimation ? 1 : - drm_format_vert_chroma_subsampling(pix_format); - - memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); - - /* calculate phase steps */ - sde_plane_scale_helper(plane, src_w, crtc_w, - pe->phase_step_x, - pe->horz_filter, fmt, chroma_subsample_h); - sde_plane_scale_helper(plane, src_h, crtc_h, - pe->phase_step_y, - pe->vert_filter, fmt, chroma_subsample_v); - - /* calculate left/right/top/bottom pixel extentions */ - tmp = DECIMATED_DIMENSION(src_w, - psde->pipe_cfg.horz_decimation); - if (fmt->is_yuv) - tmp &= ~0x1; - _sde_plane_pixel_ext_helper(plane, src_w, crtc_w, tmp, - pe->phase_step_x, - pe->roi_w, - pe->num_ext_pxls_left, - pe->num_ext_pxls_right, fmt, - chroma_subsample_h, 0); - - tmp = DECIMATED_DIMENSION(src_h, - psde->pipe_cfg.vert_decimation); - _sde_plane_pixel_ext_helper(plane, src_h, crtc_h, tmp, - pe->phase_step_y, - pe->roi_h, - pe->num_ext_pxls_top, - pe->num_ext_pxls_btm, fmt, - chroma_subsample_v, 1); - - /* CIFIX: port "Single pixel rgb scale adjustment"? */ - - for (i = 0; i < SDE_MAX_PLANES; i++) { - if (pe->num_ext_pxls_left[i] >= 0) - pe->left_rpt[i] = - pe->num_ext_pxls_left[i]; - else - pe->left_ftch[i] = - pe->num_ext_pxls_left[i]; - - if (pe->num_ext_pxls_right[i] >= 0) - pe->right_rpt[i] = - pe->num_ext_pxls_right[i]; - else - pe->right_ftch[i] = - pe->num_ext_pxls_right[i]; - - if (pe->num_ext_pxls_top[i] >= 0) - pe->top_rpt[i] = - pe->num_ext_pxls_top[i]; - else - pe->top_ftch[i] = - pe->num_ext_pxls_top[i]; - - if (pe->num_ext_pxls_btm[i] >= 0) - pe->btm_rpt[i] = - pe->num_ext_pxls_btm[i]; - else - pe->btm_ftch[i] = - pe->num_ext_pxls_btm[i]; - } - } - - if (psde->pipe_hw->ops.setup_sourceformat) - psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw, - &psde->pipe_cfg, 0 /* CIFIX: flags */); - if (psde->pipe_hw->ops.setup_rects) - psde->pipe_hw->ops.setup_rects(psde->pipe_hw, - &psde->pipe_cfg, &psde->pixel_ext); - - /* update csc */ - - SDE_PLANE_DEBUG_END(); - return ret; -} - -static int sde_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) -{ - struct drm_framebuffer *fb = new_state->fb; - struct sde_plane *psde = to_sde_plane(plane); - - if (!new_state->fb) - return 0; - - SDE_PLANE_DEBUG_START(); - SDE_PLANE_DEBUG_END(); - DBG("%s: prepare: FB[%u]", psde->name, fb->base.id); - return msm_framebuffer_prepare(fb, psde->mmu_id); -} - -static void sde_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) -{ - struct drm_framebuffer *fb = old_state->fb; - struct sde_plane *psde = to_sde_plane(plane); - - if (!fb) - return; - - SDE_PLANE_DEBUG_START(); - SDE_PLANE_DEBUG_END(); - DBG("%s: cleanup: FB[%u]", psde->name, fb->base.id); - msm_framebuffer_cleanup(fb, psde->mmu_id); -} - -static int sde_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state) -{ - struct sde_plane *psde = to_sde_plane(plane); - struct drm_plane_state *old_state = plane->state; - const struct mdp_format *format; - - SDE_PLANE_DEBUG_START(); - SDE_PLANE_DEBUG_END(); - DBG("%s: check (%d -> %d)", psde->name, - sde_plane_enabled(old_state), sde_plane_enabled(state)); - - if (sde_plane_enabled(state)) { - /* CIFIX: don't use mdp format? */ - format = to_mdp_format(msm_framebuffer_format(state->fb)); - if (MDP_FORMAT_IS_YUV(format) && - (!(psde->features & SDE_PLANE_FEATURE_SCALER) || - !(psde->features & BIT(SDE_SSPP_CSC)))) { - dev_err(plane->dev->dev, - "Pipe doesn't support YUV\n"); - - return -EINVAL; - } - - if (!(psde->features & SDE_PLANE_FEATURE_SCALER) && - (((state->src_w >> 16) != state->crtc_w) || - ((state->src_h >> 16) != state->crtc_h))) { - dev_err(plane->dev->dev, - "Pipe doesn't support scaling (%dx%d -> %dx%d)\n", - state->src_w >> 16, state->src_h >> 16, - state->crtc_w, state->crtc_h); - - return -EINVAL; - } - } - - if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) { - /* we cannot change SMP block configuration during scanout: */ - bool full_modeset = false; - - if (state->fb->pixel_format != old_state->fb->pixel_format) { - DBG("%s: pixel_format change!", psde->name); - full_modeset = true; - } - if (state->src_w != old_state->src_w) { - DBG("%s: src_w change!", psde->name); - full_modeset = true; - } - if (to_sde_plane_state(old_state)->pending) { - DBG("%s: still pending!", psde->name); - full_modeset = true; - } - if (full_modeset) { - struct drm_crtc_state *crtc_state = - drm_atomic_get_crtc_state(state->state, - state->crtc); - crtc_state->mode_changed = true; - to_sde_plane_state(state)->mode_changed = true; - } - } else { - to_sde_plane_state(state)->mode_changed = true; - } - - return 0; -} - -static void sde_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - struct sde_plane *sde_plane = to_sde_plane(plane); - struct drm_plane_state *state = plane->state; - - DBG("%s: update", sde_plane->name); - - SDE_PLANE_DEBUG_START(); - if (!sde_plane_enabled(state)) { - to_sde_plane_state(state)->pending = true; - } else if (to_sde_plane_state(state)->mode_changed) { - int ret; - - to_sde_plane_state(state)->pending = true; - ret = sde_plane_mode_set(plane, - state->crtc, state->fb, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x, state->src_y, - state->src_w, state->src_h); - /* atomic_check should have ensured that this doesn't fail */ - WARN_ON(ret < 0); - } else { - sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb); - } - SDE_PLANE_DEBUG_END(); -} - -/* helper to install properties which are common to planes and crtcs */ -static void sde_plane_install_properties(struct drm_plane *plane, - struct drm_mode_object *obj) -{ - struct drm_device *dev = plane->dev; - struct msm_drm_private *dev_priv = dev->dev_private; - struct drm_property *prop; - - SDE_PLANE_DEBUG_START(); -#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \ - prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \ - if (!prop) { \ - prop = drm_property_##fnc(dev, 0, #name, \ - ##__VA_ARGS__); \ - if (!prop) { \ - dev_warn(dev->dev, \ - "Create property %s failed\n", \ - #name); \ - return; \ - } \ - dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \ - } \ - drm_object_attach_property(&plane->base, prop, init_val); \ - } while (0) - -#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \ - INSTALL_PROPERTY(name, NAME, init_val, \ - create_range, min, max) - -#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \ - INSTALL_PROPERTY(name, NAME, init_val, \ - create_enum, name##_prop_enum_list, \ - ARRAY_SIZE(name##_prop_enum_list)) - - INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1); - -#undef INSTALL_RANGE_PROPERTY -#undef INSTALL_ENUM_PROPERTY -#undef INSTALL_PROPERTY - SDE_PLANE_DEBUG_END(); -} - -static int sde_plane_atomic_set_property(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = plane->dev; - struct sde_plane_state *pstate; - struct msm_drm_private *dev_priv = dev->dev_private; - int ret = 0; - - SDE_PLANE_DEBUG_START(); - - pstate = to_sde_plane_state(state); - -#define SET_PROPERTY(name, NAME, type) do { \ - if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ - pstate->name = (type)val; \ - DBG("Set property %s %d", #name, (type)val); \ - goto done; \ - } \ - } while (0) - - SET_PROPERTY(zpos, ZPOS, uint8_t); - - dev_err(dev->dev, "Invalid property\n"); - ret = -EINVAL; -done: - SDE_PLANE_DEBUG_END(); - return ret; -#undef SET_PROPERTY -} - -static int sde_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) -{ - int rc; - - SDE_PLANE_DEBUG_START(); - rc = sde_plane_atomic_set_property(plane, plane->state, property, - val); - SDE_PLANE_DEBUG_END(); - return rc; -} - -static int sde_plane_atomic_get_property(struct drm_plane *plane, - const struct drm_plane_state *state, - struct drm_property *property, uint64_t *val) -{ - struct drm_device *dev = plane->dev; - struct sde_plane_state *pstate; - struct msm_drm_private *dev_priv = dev->dev_private; - int ret = 0; - - SDE_PLANE_DEBUG_START(); - pstate = to_sde_plane_state(state); - -#define GET_PROPERTY(name, NAME, type) do { \ - if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ - *val = pstate->name; \ - DBG("Get property %s %lld", #name, *val); \ - goto done; \ - } \ - } while (0) - - GET_PROPERTY(zpos, ZPOS, uint8_t); - - dev_err(dev->dev, "Invalid property\n"); - ret = -EINVAL; -done: - SDE_PLANE_DEBUG_END(); - return ret; -#undef SET_PROPERTY -} - -static void sde_plane_destroy(struct drm_plane *plane) -{ - struct sde_plane *psde = to_sde_plane(plane); - - SDE_PLANE_DEBUG_START(); - - if (psde->pipe_hw) - sde_hw_sspp_destroy(psde->pipe_hw); - - drm_plane_helper_disable(plane); - drm_plane_cleanup(plane); - - kfree(psde); - - SDE_PLANE_DEBUG_END(); -} - -static void sde_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - SDE_PLANE_DEBUG_START(); - if (state->fb) - drm_framebuffer_unreference(state->fb); - - kfree(to_sde_plane_state(state)); - SDE_PLANE_DEBUG_END(); -} - -static struct drm_plane_state * -sde_plane_duplicate_state(struct drm_plane *plane) -{ - struct sde_plane_state *pstate; - - if (WARN_ON(!plane->state)) - return NULL; - - SDE_PLANE_DEBUG_START(); - pstate = kmemdup(to_sde_plane_state(plane->state), - sizeof(*pstate), GFP_KERNEL); - - if (pstate && pstate->base.fb) - drm_framebuffer_reference(pstate->base.fb); - - pstate->mode_changed = false; - pstate->pending = false; - SDE_PLANE_DEBUG_END(); - - return &pstate->base; -} - -static void sde_plane_reset(struct drm_plane *plane) -{ - struct sde_plane_state *pstate; - - SDE_PLANE_DEBUG_START(); - if (plane->state && plane->state->fb) - drm_framebuffer_unreference(plane->state->fb); - - kfree(to_sde_plane_state(plane->state)); - pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); - - memset(pstate, 0, sizeof(struct sde_plane_state)); - - /* assign default blend parameters */ - pstate->alpha = 255; - pstate->premultiplied = 0; - - if (plane->type == DRM_PLANE_TYPE_PRIMARY) - pstate->zpos = STAGE_BASE; - else - pstate->zpos = STAGE0 + drm_plane_index(plane); - - pstate->base.plane = plane; - - plane->state = &pstate->base; - SDE_PLANE_DEBUG_END(); -} - -static const struct drm_plane_funcs sde_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = sde_plane_destroy, - .set_property = sde_plane_set_property, - .atomic_set_property = sde_plane_atomic_set_property, - .atomic_get_property = sde_plane_atomic_get_property, - .reset = sde_plane_reset, - .atomic_duplicate_state = sde_plane_duplicate_state, - .atomic_destroy_state = sde_plane_destroy_state, -}; - -static const struct drm_plane_helper_funcs sde_plane_helper_funcs = { - .prepare_fb = sde_plane_prepare_fb, - .cleanup_fb = sde_plane_cleanup_fb, - .atomic_check = sde_plane_atomic_check, - .atomic_update = sde_plane_atomic_update, -}; - -enum sde_sspp sde_plane_pipe(struct drm_plane *plane) -{ - struct sde_plane *sde_plane = to_sde_plane(plane); - - return sde_plane->pipe; -} - -/* initialize plane */ -struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe, - bool private_plane) -{ - static const char tmp_name[] = "---"; - struct drm_plane *plane = NULL; - struct sde_plane *psde; - struct sde_hw_ctl *sde_ctl; - struct msm_drm_private *priv; - struct sde_kms *kms; - struct sde_mdss_cfg *sde_cat; - int ret; - enum drm_plane_type type; - - priv = dev->dev_private; - if (!priv) { - DRM_ERROR("[%u]Private data is NULL\n", pipe); - goto exit; - } - - if (!priv->kms) { - DRM_ERROR("[%u]Invalid KMS reference\n", pipe); - goto exit; - } - kms = to_sde_kms(priv->kms); - - psde = kzalloc(sizeof(*psde), GFP_KERNEL); - if (!psde) { - ret = -ENOMEM; - goto fail; - } - - memset(psde, 0, sizeof(*psde)); - - plane = &psde->base; - - psde->pipe = pipe; - psde->name = tmp_name; - - if (kms) { - /* mmu id for buffer mapping */ - psde->mmu_id = kms->mmu_id; - - /* check catalog for features mask */ - sde_cat = kms->catalog; - if (sde_cat) - psde->features = sde_cat->sspp[pipe].features; - } - psde->nformats = mdp_get_formats(psde->formats, - ARRAY_SIZE(psde->formats), - !(psde->features & BIT(SDE_SSPP_CSC)) || - !(psde->features & SDE_PLANE_FEATURE_SCALER)); - - type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; - ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs, - psde->formats, psde->nformats, - type); - if (ret) - goto fail; - - drm_plane_helper_add(plane, &sde_plane_helper_funcs); - - sde_plane_install_properties(plane, &plane->base); - - psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat); - if (IS_ERR(psde->pipe_hw)) { - ret = PTR_ERR(psde->pipe_hw); - psde->pipe_hw = NULL; - goto fail; - } - - /* cache flush mask for later */ - sde_ctl = sde_hw_ctl_init(CTL_0, kms->mmio, sde_cat); - if (!IS_ERR(sde_ctl)) { - if (sde_ctl->ops.get_bitmask_sspp) - sde_ctl->ops.get_bitmask_sspp(sde_ctl, - &psde->flush_mask, pipe); - sde_hw_ctl_destroy(sde_ctl); - } - - pr_err("%s: Successfully created plane\n", __func__); - return plane; - -fail: - pr_err("%s: Plane creation failed\n", __func__); - if (plane) - sde_plane_destroy(plane); -exit: - return ERR_PTR(ret); -} diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index bd93ded07131..bc7c0badf189 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.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 @@ -943,11 +943,13 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, a5xx_snapshot_debugbus(device, snapshot); /* Preemption record */ - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, - snapshot, snapshot_preemption_record, - &rb->preemption_desc); + if (adreno_is_preemption_enabled(adreno_dev)) { + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, + snapshot, snapshot_preemption_record, + &rb->preemption_desc); + } } } diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index bd1e432d8c7d..bb92b8b79d93 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -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 @@ -299,6 +299,7 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, struct page *p = NULL; int order = get_order(*page_size); int pool_idx; + size_t size = 0; if ((pages == NULL) || pages_len < (*page_size >> PAGE_SHIFT)) return -EINVAL; @@ -311,11 +312,8 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, if (page == NULL) { /* Retry with lower order pages */ if (order > 0) { - size_t size = PAGE_SIZE << --order; - *page_size = kgsl_get_page_size(size, - ilog2(size)); - *align = ilog2(*page_size); - return -EAGAIN; + size = PAGE_SIZE << --order; + goto eagain; } else return -ENOMEM; @@ -325,8 +323,25 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } pool = _kgsl_get_pool_from_order(order); - if (pool == NULL) - return -EINVAL; + if (pool == NULL) { + /* Retry with lower order pages */ + if (order > 0) { + size = PAGE_SIZE << --order; + goto eagain; + } else { + /* + * Fall back to direct allocation in case + * pool with zero order is not present + */ + gfp_t gfp_mask = kgsl_gfp_mask(order); + + page = alloc_pages(gfp_mask, order); + if (page == NULL) + return -ENOMEM; + _kgsl_pool_zero_page(page, order); + goto done; + } + } pool_idx = kgsl_pool_idx_lookup(order); page = _kgsl_pool_get_page(pool); @@ -337,10 +352,9 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, /* Only allocate non-reserved memory for certain pools */ if (!pool->allocation_allowed && pool_idx > 0) { - *page_size = PAGE_SIZE << + size = PAGE_SIZE << kgsl_pools[pool_idx-1].pool_order; - *align = ilog2(*page_size); - return -EAGAIN; + goto eagain; } page = alloc_pages(gfp_mask, order); @@ -348,10 +362,9 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, if (!page) { if (pool_idx > 0) { /* Retry with lower order pages */ - *page_size = PAGE_SIZE << + size = PAGE_SIZE << kgsl_pools[pool_idx-1].pool_order; - *align = ilog2(*page_size); - return -EAGAIN; + goto eagain; } else return -ENOMEM; } @@ -367,6 +380,12 @@ done: } return pcount; + +eagain: + *page_size = kgsl_get_page_size(size, + ilog2(size)); + *align = ilog2(*page_size); + return -EAGAIN; } void kgsl_pool_free_page(struct page *page) diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index cd9a82a9bf4a..fe6aa45901d0 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1994,6 +1994,42 @@ static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level) return clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], rate); } +static inline void _close_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->pcl) + msm_bus_scale_unregister_client(pwr->pcl); + + pwr->pcl = 0; +} + +static inline void _close_ocmem_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->ocmem_pcl) + msm_bus_scale_unregister_client(pwr->ocmem_pcl); + + pwr->ocmem_pcl = 0; +} + +static inline void _close_regulators(struct kgsl_pwrctrl *pwr) +{ + int i; + + for (i = 0; i < KGSL_MAX_REGULATORS; i++) + pwr->regulators[i].reg = NULL; +} + +static inline void _close_clks(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int i; + + for (i = 0; i < KGSL_MAX_CLKS; i++) + pwr->grp_clks[i] = NULL; + + if (pwr->gpu_bimc_int_clk) + devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); +} + int kgsl_pwrctrl_init(struct kgsl_device *device) { int i, k, m, n = 0, result; @@ -2011,7 +2047,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = _get_clocks(device); if (result) - return result; + goto error_cleanup_clks; /* Make sure we have a source clk for freq setting */ if (pwr->grp_clks[0] == NULL) @@ -2029,7 +2065,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) if (pwr->num_pwrlevels == 0) { KGSL_PWR_ERR(device, "No power levels are defined\n"); - return -EINVAL; + result = -EINVAL; + goto error_cleanup_clks; } /* Initialize the user and thermal clock constraints */ @@ -2059,7 +2096,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = get_regulators(device); if (result) - return result; + goto error_cleanup_regulators; pwr->power_flags = 0; @@ -2079,8 +2116,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->ocmem_pcl = msm_bus_scale_register_client (ocmem_scale_table); - if (!pwr->ocmem_pcl) - return -EINVAL; + if (!pwr->ocmem_pcl) { + result = -EINVAL; + goto error_disable_pm; + } } /* Bus width in bytes, set it to zero if not found */ @@ -2110,14 +2149,18 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) * from the driver. */ pwr->pcl = msm_bus_scale_register_client(bus_scale_table); - if (pwr->pcl == 0) - return -EINVAL; + if (pwr->pcl == 0) { + result = -EINVAL; + goto error_cleanup_ocmem_pcl; + } } pwr->bus_ib = kzalloc(bus_scale_table->num_usecases * sizeof(*pwr->bus_ib), GFP_KERNEL); - if (pwr->bus_ib == NULL) - return -ENOMEM; + if (pwr->bus_ib == NULL) { + result = -ENOMEM; + goto error_cleanup_pcl; + } /* * Pull the BW vote out of the bus table. They will be used to @@ -2175,36 +2218,26 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) &pwr->tsens_name); return result; + +error_cleanup_pcl: + _close_pcl(pwr); +error_cleanup_ocmem_pcl: + _close_ocmem_pcl(pwr); +error_disable_pm: + pm_runtime_disable(&pdev->dev); +error_cleanup_regulators: + _close_regulators(pwr); +error_cleanup_clks: + _close_clks(device); + return result; } void kgsl_pwrctrl_close(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int i; KGSL_PWR_INFO(device, "close device %d\n", device->id); - pm_runtime_disable(&device->pdev->dev); - - if (pwr->pcl) - msm_bus_scale_unregister_client(pwr->pcl); - - pwr->pcl = 0; - - if (pwr->ocmem_pcl) - msm_bus_scale_unregister_client(pwr->ocmem_pcl); - - pwr->ocmem_pcl = 0; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->regulators[i].reg = NULL; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->grp_clks[i] = NULL; - - if (pwr->gpu_bimc_int_clk) - devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); - pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { @@ -2213,6 +2246,16 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) pwr->sysfs_pwr_limit = NULL; } kfree(pwr->bus_ib); + + _close_pcl(pwr); + + _close_ocmem_pcl(pwr); + + pm_runtime_disable(&device->pdev->dev); + + _close_regulators(pwr); + + _close_clks(device); } /** diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 70766e208217..ce15e150277e 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -410,8 +410,8 @@ struct arm_smmu_device { struct mutex power_lock; unsigned int power_count; - struct msm_bus_client_handle *bus_client; - char *bus_client_name; + u32 bus_client; + struct msm_bus_scale_pdata *bus_pdata; enum tz_smmu_device_id sec_id; }; @@ -912,14 +912,14 @@ static int arm_smmu_request_bus(struct arm_smmu_device *smmu) { if (!smmu->bus_client) return 0; - return msm_bus_scale_update_bw(smmu->bus_client, 0, 1000); + return msm_bus_scale_client_update_request(smmu->bus_client, 1); } static int arm_smmu_unrequest_bus(struct arm_smmu_device *smmu) { if (!smmu->bus_client) return 0; - return msm_bus_scale_update_bw(smmu->bus_client, 0, 0); + return msm_bus_scale_client_update_request(smmu->bus_client, 0); } static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu) @@ -3531,8 +3531,10 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) smmu->num_clocks = of_property_count_strings(dev->of_node, "clock-names"); - if (smmu->num_clocks < 1) + if (smmu->num_clocks < 1) { + smmu->num_clocks = 0; return 0; + } smmu->clocks = devm_kzalloc( dev, sizeof(*smmu->clocks) * smmu->num_clocks, @@ -3569,34 +3571,37 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) static int arm_smmu_init_bus_scaling(struct platform_device *pdev, struct arm_smmu_device *smmu) { - u32 master_id; - - if (of_property_read_u32(pdev->dev.of_node, "qcom,bus-master-id", - &master_id)) { - dev_dbg(smmu->dev, "No bus scaling info\n"); + if (!of_find_property(pdev->dev.of_node, "qcom,msm-bus,name", NULL)) { + dev_dbg(&pdev->dev, "No bus scaling info\n"); return 0; } - smmu->bus_client_name = devm_kasprintf( - smmu->dev, GFP_KERNEL, "smmu-bus-client-%s", - dev_name(smmu->dev)); - - if (!smmu->bus_client_name) - return -ENOMEM; - - smmu->bus_client = msm_bus_scale_register( - master_id, MSM_BUS_SLAVE_EBI_CH0, smmu->bus_client_name, true); - if (IS_ERR(&smmu->bus_client)) { - int ret = PTR_ERR(smmu->bus_client); + smmu->bus_pdata = msm_bus_cl_get_pdata(pdev); + if (!smmu->bus_pdata) { + dev_err(&pdev->dev, "Unable to read bus-scaling from DT\n"); + return -EINVAL; + } - if (ret != -EPROBE_DEFER) - dev_err(smmu->dev, "Bus client registration failed\n"); - return ret; + smmu->bus_client = msm_bus_scale_register_client(smmu->bus_pdata); + if (!smmu->bus_client) { + dev_err(&pdev->dev, "Bus client registration failed\n"); + return -EINVAL; } return 0; } +static void arm_smmu_exit_bus_scaling(struct arm_smmu_device *smmu) +{ + if (smmu->bus_client) + msm_bus_scale_unregister_client(smmu->bus_client); + if (smmu->bus_pdata) + msm_bus_cl_clear_pdata(smmu->bus_pdata); + + smmu->bus_client = 0; + smmu->bus_pdata = NULL; +} + static int arm_smmu_parse_impl_def_registers(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; @@ -4033,6 +4038,7 @@ out_free_irqs: free_irq(smmu->irqs[i], smmu); out_put_masters: + arm_smmu_exit_bus_scaling(smmu); for (node = rb_first(&smmu->masters); node; node = rb_next(node)) { struct arm_smmu_master *master = container_of(node, struct arm_smmu_master, node); @@ -4084,7 +4090,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev) arm_smmu_power_off(smmu); mutex_unlock(&smmu->attach_lock); - msm_bus_scale_unregister(smmu->bus_client); + arm_smmu_exit_bus_scaling(smmu); return 0; } 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 54c0aa39cdd3..1c0a10e2fbef 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 @@ -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 @@ -1212,6 +1212,25 @@ static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx, return CAM_SMMU_BUFF_NOT_EXIST; } +static enum cam_smmu_buf_state cam_smmu_check_secure_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + mapping->ref_count++; + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + return CAM_SMMU_BUFF_NOT_EXIST; +} + int cam_smmu_get_handle(char *identifier, int *handle_ptr) { int ret = 0; @@ -1935,7 +1954,8 @@ int cam_smmu_get_stage2_phy_addr(int handle, goto get_addr_end; } - buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + buf_state = cam_smmu_check_secure_fd_in_list(idx, ion_fd, paddr_ptr, + len_ptr); if (buf_state == CAM_SMMU_BUFF_EXIST) { CDBG("ion_fd:%d already in the list, give same addr back", ion_fd); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 0db901de4562..af82b84f613f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1680,11 +1680,6 @@ void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event) temp_dev->hw_info->vfe_ops.core_ops. set_halt_restart_mask(temp_dev); } - /* heavy spin lock in axi halt, avoid spin lock outside. */ - msm_isp_axi_halt(vfe_dev, &halt_cmd); - if (temp_dev) - msm_isp_axi_halt(temp_dev, &halt_cmd); - error_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 4b6005b9af46..39811aa84e8e 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1930,7 +1930,7 @@ static int32_t msm_actuator_platform_probe(struct platform_device *pdev) } rc = msm_sensor_driver_get_gpio_data(&(msm_actuator_t->gconf), (&pdev->dev)->of_node); - if (rc < 0) { + if (rc <= 0) { pr_err("%s: No/Error Actuator GPIOs\n", __func__); } else { msm_actuator_t->cam_pinctrl_status = 1; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h index 80da9b4cfcb6..c04e71f459d1 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -96,6 +96,7 @@ enum sde_bus_clients { enum sde_rot_regdump_access { SDE_ROT_REGDUMP_READ, SDE_ROT_REGDUMP_WRITE, + SDE_ROT_REGDUMP_VBIF, SDE_ROT_REGDUMP_MAX }; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index 920f5a809777..29215c1a5910 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -1523,20 +1523,20 @@ static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr, u8 out_v_subsample, out_h_subsample; if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true)) { - SDEROT_DBG("Invalid input format %x\n", in_fmt->format); - return false; + SDEROT_ERR("Invalid input format %x\n", in_fmt->format); + goto verify_error; } if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false)) { - SDEROT_DBG("Invalid output format %x\n", out_fmt->format); - return false; + SDEROT_ERR("Invalid output format %x\n", out_fmt->format); + goto verify_error; } if ((in_fmt->is_yuv != out_fmt->is_yuv) || (in_fmt->pixel_mode != out_fmt->pixel_mode) || (in_fmt->unpack_tight != out_fmt->unpack_tight)) { - SDEROT_DBG("Rotator does not support CSC\n"); - return false; + SDEROT_ERR("Rotator does not support CSC\n"); + goto verify_error; } /* Forcing same pixel depth */ @@ -1546,8 +1546,8 @@ static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr, (in_fmt->bits[C2_R_Cr] != out_fmt->bits[C2_R_Cr]) || (in_fmt->bits[C0_G_Y] != out_fmt->bits[C0_G_Y]) || (in_fmt->bits[C1_B_Cb] != out_fmt->bits[C1_B_Cb])) { - SDEROT_DBG("Bit format does not match\n"); - return false; + SDEROT_ERR("Bit format does not match\n"); + goto verify_error; } } @@ -1560,87 +1560,161 @@ static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr, if ((in_v_subsample != out_h_subsample) || (in_h_subsample != out_v_subsample)) { - SDEROT_DBG("Rotation has invalid subsampling\n"); - return false; + SDEROT_ERR("Rotation has invalid subsampling\n"); + goto verify_error; } } else { if (in_fmt->chroma_sample != out_fmt->chroma_sample) { - SDEROT_DBG("Format subsampling mismatch\n"); - return false; + SDEROT_ERR("Format subsampling mismatch\n"); + goto verify_error; } } - SDEROT_DBG("in_fmt=%0d, out_fmt=%d\n", in_fmt->format, out_fmt->format); return true; + +verify_error: + SDEROT_ERR("in_fmt=0x%x, out_fmt=0x%x\n", + in_fmt->format, out_fmt->format); + return false; } -int sde_rotator_verify_config(struct sde_rot_mgr *mgr, - struct sde_rotation_config *config) +static struct sde_mdp_format_params *__verify_input_config( + struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) { - struct sde_mdp_format_params *in_fmt, *out_fmt; + struct sde_mdp_format_params *in_fmt; u8 in_v_subsample, in_h_subsample; - u8 out_v_subsample, out_h_subsample; - u32 input, output; - bool rotation; + u32 input; int verify_input_only; if (!mgr || !config) { SDEROT_ERR("null parameters\n"); - return -EINVAL; + return NULL; } input = config->input.format; - output = config->output.format; - rotation = (config->flags & SDE_ROTATION_90) ? true : false; verify_input_only = (config->flags & SDE_ROTATION_VERIFY_INPUT_ONLY) ? 1 : 0; in_fmt = sde_get_format_params(input); if (!in_fmt) { - SDEROT_DBG("Unrecognized input format:%u\n", input); - return -EINVAL; - } - - out_fmt = sde_get_format_params(output); - if (!out_fmt) { - SDEROT_DBG("Unrecognized output format:%u\n", output); - return -EINVAL; + if (!verify_input_only) + SDEROT_ERR("Unrecognized input format:0x%x\n", input); + return NULL; } sde_mdp_get_v_h_subsample_rate(in_fmt->chroma_sample, &in_v_subsample, &in_h_subsample); - sde_mdp_get_v_h_subsample_rate(out_fmt->chroma_sample, - &out_v_subsample, &out_h_subsample); /* Dimension of image needs to be divisible by subsample rate */ if ((config->input.height % in_v_subsample) || (config->input.width % in_h_subsample)) { - SDEROT_DBG( - "In ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n", + if (!verify_input_only) + SDEROT_ERR( + "In ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n", config->input.width, config->input.height, in_v_subsample, in_h_subsample); - return -EINVAL; + return NULL; + } + + return in_fmt; +} + +static struct sde_mdp_format_params *__verify_output_config( + struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *out_fmt; + u8 out_v_subsample, out_h_subsample; + u32 output; + int verify_input_only; + + if (!mgr || !config) { + SDEROT_ERR("null parameters\n"); + return NULL; + } + + output = config->output.format; + verify_input_only = + (config->flags & SDE_ROTATION_VERIFY_INPUT_ONLY) ? 1 : 0; + + out_fmt = sde_get_format_params(output); + if (!out_fmt) { + if (!verify_input_only) + SDEROT_ERR("Unrecognized output format:0x%x\n", output); + return NULL; } + sde_mdp_get_v_h_subsample_rate(out_fmt->chroma_sample, + &out_v_subsample, &out_h_subsample); + + /* Dimension of image needs to be divisible by subsample rate */ if ((config->output.height % out_v_subsample) || (config->output.width % out_h_subsample)) { - SDEROT_DBG( - "Out ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n", + if (!verify_input_only) + SDEROT_ERR( + "Out ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n", config->output.width, config->output.height, out_v_subsample, out_h_subsample); - if (!verify_input_only) - return -EINVAL; + return NULL; } - if (!sde_rotator_verify_format(mgr, in_fmt, - out_fmt, rotation)) { - SDEROT_DBG( - "Rot format pairing invalid, in_fmt:%d, out_fmt:%d\n", - input, output); - if (!verify_input_only) - return -EINVAL; + return out_fmt; +} + +int sde_rotator_verify_config_input(struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *in_fmt; + + in_fmt = __verify_input_config(mgr, config); + if (!in_fmt) + return -EINVAL; + + return 0; +} + +int sde_rotator_verify_config_output(struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *out_fmt; + + out_fmt = __verify_output_config(mgr, config); + if (!out_fmt) + return -EINVAL; + + return 0; +} + +int sde_rotator_verify_config_all(struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *in_fmt, *out_fmt; + bool rotation; + + if (!mgr || !config) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + rotation = (config->flags & SDE_ROTATION_90) ? true : false; + + in_fmt = __verify_input_config(mgr, config); + if (!in_fmt) + return -EINVAL; + + out_fmt = __verify_output_config(mgr, config); + if (!out_fmt) + return -EINVAL; + + if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation)) { + SDEROT_ERR( + "Rot format pairing invalid, in_fmt:0x%x, out_fmt:0x%x\n", + config->input.format, + config->output.format); + return -EINVAL; } return 0; @@ -2049,7 +2123,7 @@ static int sde_rotator_config_session(struct sde_rot_mgr *mgr, int ret = 0; struct sde_rot_perf *perf; - ret = sde_rotator_verify_config(mgr, config); + ret = sde_rotator_verify_config_all(mgr, config); if (ret) { SDEROT_ERR("Rotator verify format failed\n"); return ret; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index eca0cbefcab1..7b27497ac6ef 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -413,7 +413,13 @@ void sde_rotator_remove_request(struct sde_rot_mgr *mgr, struct sde_rot_file_private *private, struct sde_rot_entry_container *req); -int sde_rotator_verify_config(struct sde_rot_mgr *rot_dev, +int sde_rotator_verify_config_all(struct sde_rot_mgr *rot_dev, + struct sde_rotation_config *config); + +int sde_rotator_verify_config_input(struct sde_rot_mgr *rot_dev, + struct sde_rotation_config *config); + +int sde_rotator_verify_config_output(struct sde_rot_mgr *rot_dev, struct sde_rotation_config *config); int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev, diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c index cf33bc6437cc..a2da663e2046 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.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 @@ -246,11 +246,13 @@ static void sde_rot_dump_vbif_debug_bus(u32 bus_dump_flag, * sde_rot_dump_reg - helper function for dumping rotator register set content * @dump_name - register set name * @reg_dump_flag - dumping flag controlling in-log/memory dump location + * @access - access type, sde registers or vbif registers * @addr - starting address offset for dumping * @len - range of the register set * @dump_mem - output buffer for memory dump location option */ -void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag, u32 addr, +void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag, + enum sde_rot_regdump_access access, u32 addr, int len, u32 **dump_mem) { struct sde_rot_data_type *mdata = sde_rot_get_mdata(); @@ -258,6 +260,7 @@ void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag, u32 addr, u32 *dump_addr = NULL; phys_addr_t phys = 0; int i; + void __iomem *base; in_log = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG); in_mem = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM); @@ -285,14 +288,20 @@ void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag, u32 addr, } } + base = mdata->sde_io.base; + /* + * VBIF NRT base handling + */ + if (access == SDE_ROT_REGDUMP_VBIF) + base = mdata->vbif_nrt_io.base; for (i = 0; i < len; i++) { u32 x0, x4, x8, xc; - x0 = readl_relaxed(mdata->sde_io.base + addr+0x0); - x4 = readl_relaxed(mdata->sde_io.base + addr+0x4); - x8 = readl_relaxed(mdata->sde_io.base + addr+0x8); - xc = readl_relaxed(mdata->sde_io.base + addr+0xc); + x0 = readl_relaxed(base + addr+0x0); + x4 = readl_relaxed(base + addr+0x4); + x8 = readl_relaxed(base + addr+0x8); + xc = readl_relaxed(base + addr+0xc); if (in_log) pr_info("0x%08X : %08x %08x %08x %08x\n", @@ -338,6 +347,7 @@ static void sde_rot_dump_reg_all(void) } else { sde_rot_dump_reg(head->name, sde_rot_dbg_evtlog.enable_reg_dump, + head->access, head->offset, head->len, &sde_rot_dbg_evtlog.reg_dump_array[i]); } 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 347c0bef163f..63c53c188637 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.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 @@ -1216,7 +1216,8 @@ static int sde_rotator_try_fmt_vid_cap(struct file *file, config.output.format = f->fmt.pix.pixelformat; config.output.width = f->fmt.pix.width; config.output.height = f->fmt.pix.height; - ret = sde_rotator_verify_config(rot_dev->mgr, &config); + config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY; + ret = sde_rotator_verify_config_output(rot_dev->mgr, &config); sde_rot_mgr_unlock(rot_dev->mgr); if (ret) { if ((config.output.width == f->fmt.pix.width) && @@ -1233,7 +1234,7 @@ static int sde_rotator_try_fmt_vid_cap(struct file *file, } sde_rotator_format_recalc(f); - return 0; + return ret; } /* @@ -1263,7 +1264,7 @@ static int sde_rotator_try_fmt_vid_out(struct file *file, config.input.width = f->fmt.pix.width; config.input.height = f->fmt.pix.height; config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY; - ret = sde_rotator_verify_config(rot_dev->mgr, &config); + ret = sde_rotator_verify_config_input(rot_dev->mgr, &config); sde_rot_mgr_unlock(rot_dev->mgr); if (ret) { if ((config.input.width == f->fmt.pix.width) && @@ -1280,7 +1281,7 @@ static int sde_rotator_try_fmt_vid_out(struct file *file, } sde_rotator_format_recalc(f); - return 0; + return ret; } /* @@ -1510,6 +1511,7 @@ static int sde_rotator_streamon(struct file *file, if (vb2_is_streaming(vq)) { sde_rot_mgr_lock(rot_dev->mgr); sde_rotator_get_config_from_ctx(ctx, &config); + config.flags &= ~SDE_ROTATION_VERIFY_INPUT_ONLY; ret = sde_rotator_session_config(rot_dev->mgr, ctx->private, &config); sde_rot_mgr_unlock(rot_dev->mgr); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index ddf11b35a1d6..3bb8399da4bf 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -226,6 +226,8 @@ static struct sde_rot_regdump sde_rot_r3_regdump[] = { SDE_ROT_REGDUMP_WRITE }, { "SDEROT_REGDMA_RAM", SDE_ROT_REGDMA_RAM_OFFSET, 0x2000, SDE_ROT_REGDUMP_READ }, + { "SDEROT_VBIF_NRT", SDE_ROT_VBIF_NRT_OFFSET, 0x590, + SDE_ROT_REGDUMP_VBIF }, }; /* Invalid software timestamp value for initialization */ @@ -363,6 +365,11 @@ static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot) REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_FSM_STATE)); + + SDEROT_ERR( + "UBWC decode status = %x, UBWC encode status = %x\n", + SDE_ROTREG_READ(rot->mdss_base, ROT_SSPP_UBWC_ERROR_STATUS), + SDE_ROTREG_READ(rot->mdss_base, ROT_WB_UBWC_ERROR_STATUS)); } /** @@ -1681,7 +1688,8 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw, SDEROT_EVTLOG(ctx->timestamp, flags, item->input.width, item->input.height, item->output.width, item->output.height, - entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr); + entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr, + item->input.format, item->output.format); if (mdata->default_ot_rd_limit) { struct sde_mdp_set_ot_params ot_params; @@ -2077,7 +2085,7 @@ static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr, } } - fmt = sde_get_format_params(item->input.format); + fmt = sde_get_format_params(item->output.format); /* * Rotator downscale support max 4 times for UBWC format and * max 2 times for TP10/TP10_UBWC format diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h index a748b87a231a..fedade122b88 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -235,6 +235,10 @@ #define ROT_QDSS_CLK_STATUS 0x18 #define ROT_QDSS_PULSE_TRIGGER 0x20 +/* + * SDE_ROT_VBIF_NRT: + */ +#define SDE_ROT_VBIF_NRT_OFFSET 0 /* REGDMA OP Code */ #define REGDMA_OP_NOP (0 << 28) diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c index 782b0eaa3648..78d3dd9d752a 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 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 @@ -298,7 +298,7 @@ static unsigned long __calculate_vmem_plus_ab(struct vidc_bus_vote_data *d) vmem_plus = 1; dprintk(VIDC_WARN, "could not calculate vmem ab value due to core freq mismatch\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); } exit: diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index babea6824c51..b36e3739e43b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.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 @@ -1313,7 +1313,11 @@ static void cleanup_instance(struct msm_vidc_inst *inst) debugfs_remove_recursive(inst->debugfs_root); mutex_lock(&inst->pending_getpropq.lock); - WARN_ON(!list_empty(&inst->pending_getpropq.list)); + if (!list_empty(&inst->pending_getpropq.list)) { + dprintk(VIDC_ERR, + "pending_getpropq not empty\n"); + WARN_ON(VIDC_DBG_WARN_ENABLE); + } mutex_unlock(&inst->pending_getpropq.lock); } } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index 11d8621564a6..39ac6273f34e 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -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 @@ -23,6 +23,7 @@ #endif #define VIDC_DBG_TAG VIDC_DBG_LABEL ": %4s: " +#define VIDC_DBG_WARN_ENABLE (msm_vidc_debug & VIDC_INFO) /* To enable messages OR these values and * echo the result to debugfs file. diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 30d1bae48e7d..777fb52b2201 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.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 @@ -105,7 +105,11 @@ static int __tzbsp_set_video_state(enum tzbsp_video_state state); */ static inline void __strict_check(struct venus_hfi_device *device) { - WARN_ON(!mutex_is_locked(&device->lock)); + if (!mutex_is_locked(&device->lock)) { + dprintk(VIDC_WARN, + "device->lock mutex is not locked\n"); + WARN_ON(VIDC_DBG_WARN_ENABLE); + } } static inline void __set_state(struct venus_hfi_device *device, @@ -267,7 +271,7 @@ static int __acquire_regulator(struct regulator_info *rinfo) if (!regulator_is_enabled(rinfo->regulator)) { dprintk(VIDC_WARN, "Regulator is not enabled %s\n", rinfo->name); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); } return rc; @@ -617,7 +621,7 @@ static void __write_register(struct venus_hfi_device *device, if (!device->power_enabled) { dprintk(VIDC_WARN, "HFI Write register failed : Power is OFF\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return; } @@ -643,7 +647,7 @@ static int __read_register(struct venus_hfi_device *device, u32 reg) if (!device->power_enabled) { dprintk(VIDC_WARN, "HFI Read register failed : Power is OFF\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return -EINVAL; } @@ -1360,7 +1364,7 @@ static int __halt_axi(struct venus_hfi_device *device) if (!device->power_enabled) { dprintk(VIDC_WARN, "Clocks are OFF, skipping AXI HALT\n"); - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return -EINVAL; } @@ -3530,7 +3534,11 @@ static int __response_handler(struct venus_hfi_device *device) if (session_id) { struct hal_session *session = NULL; - WARN_ON(upper_32_bits((uintptr_t)*session_id) != 0); + if (upper_32_bits((uintptr_t)*session_id) != 0) { + dprintk(VIDC_WARN, + "Upper 32 bits of session_id != 0\n"); + WARN_ON(VIDC_DBG_WARN_ENABLE); + } session = __get_session(device, (u32)(uintptr_t)*session_id); if (!session) { @@ -4088,7 +4096,7 @@ static int __disable_regulator(struct regulator_info *rinfo) disable_regulator_failed: /* Bring attention to this issue */ - WARN_ON(1); + WARN_ON(VIDC_DBG_WARN_ENABLE); return rc; } diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index ea5ac972b096..590e4c1a3f52 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.c @@ -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 @@ -467,12 +467,29 @@ static int i2c_pmic_parse_dt(struct i2c_pmic *chip) return rc; } +#define MAX_I2C_RETRIES 3 +static int i2c_pmic_read(struct regmap *map, unsigned int reg, void *val, + size_t val_count) +{ + int rc, retries = 0; + + do { + rc = regmap_bulk_read(map, reg, val, val_count); + } while (rc == -ENOTCONN && retries++ < MAX_I2C_RETRIES); + + if (retries > 1) + pr_err("i2c_pmic_read failed for %d retries, rc = %d\n", + retries - 1, rc); + + return rc; +} + static int i2c_pmic_determine_initial_status(struct i2c_pmic *chip) { int rc, i; for (i = 0; i < chip->num_periphs; i++) { - rc = regmap_bulk_read(chip->regmap, + rc = i2c_pmic_read(chip->regmap, chip->periph[i].addr | INT_SET_TYPE_OFFSET, chip->periph[i].cached, IRQ_MAX_REGS); if (rc < 0) { diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c index ceef607f67c0..5ffb21b8e1e5 100644 --- a/drivers/mfd/wcd9xxx-core.c +++ b/drivers/mfd/wcd9xxx-core.c @@ -505,6 +505,7 @@ static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx) mutex_init(&wcd9xxx->io_lock); mutex_init(&wcd9xxx->xfer_lock); + mutex_init(&wcd9xxx->reset_lock); ret = wcd9xxx_bringup(wcd9xxx->dev); if (ret) { @@ -583,6 +584,7 @@ err: err_bring_up: mutex_destroy(&wcd9xxx->io_lock); mutex_destroy(&wcd9xxx->xfer_lock); + mutex_destroy(&wcd9xxx->reset_lock); return ret; } @@ -595,6 +597,7 @@ static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx) wcd9xxx_core_res_deinit(&wcd9xxx->core_res); mutex_destroy(&wcd9xxx->io_lock); mutex_destroy(&wcd9xxx->xfer_lock); + mutex_destroy(&wcd9xxx->reset_lock); if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) slim_remove_device(wcd9xxx->slim_slave); } @@ -1480,9 +1483,11 @@ static int wcd9xxx_slim_device_reset(struct slim_device *sldev) if (wcd9xxx->dev_up) return 0; + mutex_lock(&wcd9xxx->reset_lock); ret = wcd9xxx_reset(wcd9xxx->dev); if (ret) dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__); + mutex_unlock(&wcd9xxx->reset_lock); return ret; } @@ -1490,6 +1495,7 @@ static int wcd9xxx_slim_device_reset(struct slim_device *sldev) static int wcd9xxx_slim_device_up(struct slim_device *sldev) { struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev); + int ret = 0; if (!wcd9xxx) { pr_err("%s: wcd9xxx is NULL\n", __func__); @@ -1501,7 +1507,12 @@ static int wcd9xxx_slim_device_up(struct slim_device *sldev) return 0; wcd9xxx->dev_up = true; - return wcd9xxx_device_up(wcd9xxx); + + mutex_lock(&wcd9xxx->reset_lock); + ret = wcd9xxx_device_up(wcd9xxx); + mutex_unlock(&wcd9xxx->reset_lock); + + return ret; } static int wcd9xxx_slim_device_down(struct slim_device *sldev) @@ -1519,10 +1530,14 @@ static int wcd9xxx_slim_device_down(struct slim_device *sldev) return 0; wcd9xxx->dev_up = false; + + mutex_lock(&wcd9xxx->reset_lock); if (wcd9xxx->dev_down) wcd9xxx->dev_down(wcd9xxx); wcd9xxx_irq_exit(&wcd9xxx->core_res); wcd9xxx_reset_low(wcd9xxx->dev); + mutex_unlock(&wcd9xxx->reset_lock); + return 0; } diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 2bc8bdff54f1..856179b96f37 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -1,4 +1,4 @@ -/* 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 @@ -304,6 +304,7 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data) goto err_disable_irq; } + memset(status, 0, sizeof(status)); ret = regmap_bulk_read(wcd9xxx_res->wcd_core_regmap, wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE], status, num_irq_regs); diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index efb987b4a6b6..bd21f8cca2aa 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.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 @@ -559,6 +559,7 @@ static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle); static struct qseecom_handle *hdcp1_handle; static bool hdcp1_supported = true; static bool hdcp1_enc_enabled; +static struct mutex hdcp1_ta_cmd_lock; static const char *hdcp_lib_message_name(int msg_id) { @@ -805,8 +806,8 @@ static int hdcp_lib_get_version(struct hdcp_lib_handle *handle) goto exit; } - if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { - pr_err("library already loaded\n"); + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("library not loaded\n"); return rc; } @@ -901,8 +902,8 @@ static int hdcp_app_init_legacy(struct hdcp_lib_handle *handle) goto exit; } - if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { - pr_err("library already loaded\n"); + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("library not loaded\n"); goto exit; } @@ -949,8 +950,8 @@ static int hdcp_app_init(struct hdcp_lib_handle *handle) goto exit; } - if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { - pr_err("library already loaded\n"); + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("library not loaded\n"); goto exit; } @@ -1024,6 +1025,7 @@ static int hdcp_lib_library_load(struct hdcp_lib_handle *handle) goto exit; } + handle->hdcp_state |= HDCP_STATE_APP_LOADED; pr_debug("qseecom_start_app success\n"); rc = hdcp_lib_get_version(handle); @@ -1050,8 +1052,6 @@ static int hdcp_lib_library_load(struct hdcp_lib_handle *handle) pr_err("app init failed\n"); goto exit; } - - handle->hdcp_state |= HDCP_STATE_APP_LOADED; exit: return rc; } @@ -1240,8 +1240,8 @@ static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle) goto exit; } - if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) { - pr_err("txmtr already initialized\n"); + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("library not loaded\n"); goto exit; } @@ -1622,6 +1622,12 @@ static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle) rc = -EBUSY; goto exit; } + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_debug("library already loaded\n"); + rc = -EBUSY; + goto exit; + } } else { if (atomic_read(&handle->hdcp_off)) { pr_debug("hdcp2.2 session tearing down\n"); @@ -2212,6 +2218,8 @@ bool hdcp1_check_if_supported_load_app(void) if (rc) { pr_err("qseecom_start_app failed %d\n", rc); hdcp1_supported = false; + } else { + mutex_init(&hdcp1_ta_cmd_lock); } } @@ -2276,12 +2284,16 @@ int hdcp1_set_enc(bool enable) struct hdcp1_set_enc_req *set_enc_req; struct hdcp1_set_enc_rsp *set_enc_rsp; - if (!hdcp1_supported || !hdcp1_handle) - return -EINVAL; + mutex_lock(&hdcp1_ta_cmd_lock); + + if (!hdcp1_supported || !hdcp1_handle) { + rc = -EINVAL; + goto end; + } if (hdcp1_enc_enabled == enable) { pr_debug("already %s\n", enable ? "enabled" : "disabled"); - return rc; + goto end; } /* set keys and request aksv */ @@ -2299,18 +2311,21 @@ int hdcp1_set_enc(bool enable) if (rc < 0) { pr_err("qseecom cmd failed err=%d\n", rc); - return -EINVAL; + goto end; } rc = set_enc_rsp->ret; if (rc) { pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret); - return -EINVAL; + rc = -EINVAL; + goto end; } hdcp1_enc_enabled = enable; pr_debug("%s success\n", enable ? "enable" : "disable"); - return 0; +end: + mutex_unlock(&hdcp1_ta_cmd_lock); + return rc; } int hdcp_library_register(struct hdcp_register_data *data) diff --git a/drivers/misc/qcom/qdsp6v2/aac_in.c b/drivers/misc/qcom/qdsp6v2/aac_in.c index 7176c114f85b..ef963451a3f9 100644 --- a/drivers/misc/qcom/qdsp6v2/aac_in.c +++ b/drivers/misc/qcom/qdsp6v2/aac_in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -34,6 +34,8 @@ #define AAC_FORMAT_ADTS 65535 +#define MAX_SAMPLE_RATE_384K 384000 + static long aac_in_ioctl_shared(struct file *file, unsigned int cmd, void *arg) { struct q6audio_in *audio = file->private_data; @@ -233,6 +235,13 @@ static long aac_in_ioctl_shared(struct file *file, unsigned int cmd, void *arg) break; } + if (cfg->sample_rate > MAX_SAMPLE_RATE_384K) { + pr_err("%s: ERROR: invalid sample rate = %u", + __func__, cfg->sample_rate); + rc = -EINVAL; + break; + } + min_bitrate = ((cfg->sample_rate)*(cfg->channels))/2; /* This calculation should be based on AAC mode. But we cannot * get AAC mode in this setconfig. min_bitrate's logical max diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 3d346d85d45a..1653f7e1ae99 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4432,6 +4432,7 @@ int qseecom_start_app(struct qseecom_handle **handle, strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { ret = -EIO; + kfree(entry); goto err; } entry->app_arch = app_arch; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 5743588aa52b..efbecb6e1dd0 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -4068,7 +4068,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, INIT_LIST_HEAD(&md->part); md->usage = 1; - ret = mmc_init_queue(&md->queue, card, &md->lock, subname, area_type); + ret = mmc_init_queue(&md->queue, card, NULL, subname, area_type); if (ret) goto err_putdisk; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 75a51bd2fc0b..f5dbb67ba929 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -724,15 +724,13 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) if (wait) { /* - * After blk_stop_queue is called, wait for all + * After blk_cleanup_queue is called, wait for all * active_reqs to complete. * Then wait for cmdq thread to exit before calling * cmdq shutdown to avoid race between issuing * requests and shutdown of cmdq. */ - spin_lock_irqsave(q->queue_lock, flags); - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_cleanup_queue(q); if (host->cmdq_ctx.active_reqs) wait_for_completion( @@ -757,9 +755,15 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) } if (!(test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags))) { - spin_lock_irqsave(q->queue_lock, flags); - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); + if (!wait) { + /* suspend/stop the queue in case of suspend */ + spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + } else { + /* shutdown the queue in case of shutdown/reboot */ + blk_cleanup_queue(q); + } rc = down_trylock(&mq->thread_sem); if (rc && !wait) { diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 57cc6b29b2d0..9e0ccdc44d6b 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,6 +2,17 @@ # MMC core configuration # +config MMC_RING_BUFFER + bool "MMC_RING_BUFFER" + depends on MMC + default n + help + This enables the ring buffer tracing of significant + events for mmc driver to provide command history for + debugging purpose. + + If unsure, say N. + config MMC_EMBEDDED_SDIO boolean "MMC embedded SDIO device support (EXPERIMENTAL)" help diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2c25138f28b7..60781dd192ab 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,3 +10,4 @@ mmc_core-y := core.o bus.o host.o \ quirks.o slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MMC_RING_BUFFER) += ring_buffer.o diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index c894f64c2e38..a0d31ded04db 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -32,6 +32,26 @@ module_param(fail_request, charp, 0); #endif /* CONFIG_FAIL_MMC_REQUEST */ /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ +static int mmc_ring_buffer_show(struct seq_file *s, void *data) +{ + struct mmc_host *mmc = s->private; + + mmc_dump_trace_buffer(mmc, s); + return 0; +} + +static int mmc_ring_buffer_open(struct inode *inode, struct file *file) +{ + return single_open(file, mmc_ring_buffer_show, inode->i_private); +} + +static const struct file_operations mmc_ring_buffer_fops = { + .open = mmc_ring_buffer_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int mmc_ios_show(struct seq_file *s, void *data) { static const char *vdd_str[] = { @@ -368,6 +388,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) &host->cmdq_thist_enabled)) goto err_node; +#ifdef CONFIG_MMC_RING_BUFFER + if (!debugfs_create_file("ring_buffer", S_IRUSR, + root, host, &mmc_ring_buffer_fops)) + goto err_node; +#endif #ifdef CONFIG_MMC_CLKGATE if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index f6a54a8e1076..333f691a73c7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -26,6 +26,8 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/ring_buffer.h> + #include <linux/mmc/slot-gpio.h> #include "core.h" @@ -869,6 +871,7 @@ int mmc_add_host(struct mmc_host *host) mmc_add_host_debugfs(host); #endif mmc_host_clk_sysfs_init(host); + mmc_trace_init(host); err = sysfs_create_group(&host->class_dev.kobj, &clk_scaling_attr_grp); if (err) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 449514bae4f3..414877874190 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2635,6 +2635,7 @@ static int mmc_suspend(struct mmc_host *host) int err; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_suspend(host, true); if (!err) { pm_runtime_disable(&host->card->dev); @@ -2643,6 +2644,7 @@ static int mmc_suspend(struct mmc_host *host) trace_mmc_suspend(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -2718,6 +2720,7 @@ static int mmc_resume(struct mmc_host *host) int err = 0; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_resume(host); pm_runtime_set_active(&host->card->dev); @@ -2727,7 +2730,7 @@ static int mmc_resume(struct mmc_host *host) trace_mmc_resume(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); - + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/ring_buffer.c b/drivers/mmc/core/ring_buffer.c new file mode 100644 index 000000000000..83945e1cae40 --- /dev/null +++ b/drivers/mmc/core/ring_buffer.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/mmc/ring_buffer.h> +#include <linux/mmc/host.h> + +void mmc_stop_tracing(struct mmc_host *mmc) +{ + mmc->trace_buf.stop_tracing = true; +} + +void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) +{ + unsigned int idx; + va_list args; + char *event; + unsigned long flags; + char str[MMC_TRACE_EVENT_SZ]; + + if (unlikely(!mmc->trace_buf.data) || + unlikely(mmc->trace_buf.stop_tracing)) + return; + + /* + * Here an increment and modulus is used to keep + * index within array bounds. The cast to unsigned is + * necessary so increment and rolover wraps to 0 correctly + */ + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + mmc->trace_buf.wr_idx += 1; + idx = ((unsigned int)mmc->trace_buf.wr_idx) & + (MMC_TRACE_RBUF_NUM_EVENTS - 1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); + + /* Catch some unlikely machine specific wrap-around bug */ + if (unlikely(idx > (MMC_TRACE_RBUF_NUM_EVENTS - 1))) { + pr_err("%s: %s: Invalid idx:%d for mmc trace, tracing stopped !\n", + mmc_hostname(mmc), __func__, idx); + mmc_stop_tracing(mmc); + return; + } + + event = &mmc->trace_buf.data[idx * MMC_TRACE_EVENT_SZ]; + va_start(args, fmt); + snprintf(str, MMC_TRACE_EVENT_SZ, "<%d> %lld: %s: %s", + raw_smp_processor_id(), + ktime_to_ns(ktime_get()), + mmc_hostname(mmc), fmt); + memset(event, '\0', MMC_TRACE_EVENT_SZ); + vscnprintf(event, MMC_TRACE_EVENT_SZ, str, args); + va_end(args); +} + +void mmc_trace_init(struct mmc_host *mmc) +{ + BUILD_BUG_ON_NOT_POWER_OF_2(MMC_TRACE_RBUF_NUM_EVENTS); + + mmc->trace_buf.data = (char *) + __get_free_pages(GFP_KERNEL|__GFP_ZERO, + MMC_TRACE_RBUF_SZ_ORDER); + + if (!mmc->trace_buf.data) { + pr_err("%s: %s: Unable to allocate trace for mmc\n", + __func__, mmc_hostname(mmc)); + return; + } + + spin_lock_init(&mmc->trace_buf.trace_lock); + mmc->trace_buf.wr_idx = -1; +} + +void mmc_trace_free(struct mmc_host *mmc) +{ + if (mmc->trace_buf.data) + free_pages((unsigned long)mmc->trace_buf.data, + MMC_TRACE_RBUF_SZ_ORDER); +} + +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s) +{ + unsigned int idx, cur_idx; + unsigned int N = MMC_TRACE_RBUF_NUM_EVENTS - 1; + char *event; + unsigned long flags; + + if (!mmc->trace_buf.data) + return; + + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + idx = ((unsigned int)mmc->trace_buf.wr_idx) & N; + cur_idx = (idx + 1) & N; + + do { + event = &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "%s", (char *)event); + else + pr_err("%s", (char *)event); + cur_idx = (cur_idx + 1) & N; + if (cur_idx == idx) { + event = + &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "latest_event: %s", + (char *)event); + else + pr_err("latest_event: %s", (char *)event); + break; + } + } while (1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 7b84030ffe92..7e7d7eb4da2a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1222,11 +1222,13 @@ static int mmc_sd_suspend(struct mmc_host *host) { int err; + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_sd_suspend(host); if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); } + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -1292,12 +1294,14 @@ static int mmc_sd_resume(struct mmc_host *host) { int err = 0; + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_sd_resume(host); pm_runtime_set_active(&host->card->dev); pm_runtime_mark_last_busy(&host->card->dev); } pm_runtime_enable(&host->card->dev); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5fedab49cf34..13a2f2d14d12 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -998,6 +998,7 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) */ static int mmc_sdio_suspend(struct mmc_host *host) { + MMC_TRACE(host, "%s: Enter\n", __func__); mmc_claim_host(host); if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) @@ -1013,7 +1014,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) } mmc_release_host(host); - + MMC_TRACE(host, "%s: Exit\n", __func__); return 0; } @@ -1024,6 +1025,7 @@ static int mmc_sdio_resume(struct mmc_host *host) BUG_ON(!host); BUG_ON(!host->card); + MMC_TRACE(host, "%s: Enter\n", __func__); /* Basic card reinitialization. */ mmc_claim_host(host); @@ -1079,6 +1081,7 @@ static int mmc_sdio_resume(struct mmc_host *host) host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_WAKE_SDIO_IRQ; + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 52427815722b..d712f29da9f1 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.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 @@ -198,6 +198,14 @@ static void cmdq_dumpregs(struct cmdq_host *cq_host) { struct mmc_host *mmc = cq_host->mmc; + MMC_TRACE(mmc, + "%s: 0x0C=0x%08x 0x10=0x%08x 0x14=0x%08x 0x18=0x%08x 0x28=0x%08x 0x2C=0x%08x 0x30=0x%08x 0x34=0x%08x 0x54=0x%08x 0x58=0x%08x 0x5C=0x%08x 0x48=0x%08x\n", + __func__, cmdq_readl(cq_host, CQCTL), cmdq_readl(cq_host, CQIS), + cmdq_readl(cq_host, CQISTE), cmdq_readl(cq_host, CQISGE), + cmdq_readl(cq_host, CQTDBR), cmdq_readl(cq_host, CQTCN), + cmdq_readl(cq_host, CQDQS), cmdq_readl(cq_host, CQDPT), + cmdq_readl(cq_host, CQTERRI), cmdq_readl(cq_host, CQCRI), + cmdq_readl(cq_host, CQCRA), cmdq_readl(cq_host, CQCRDCT)); pr_err(DRV_NAME ": ========== REGISTER DUMP (%s)==========\n", mmc_hostname(mmc)); @@ -426,6 +434,7 @@ static int cmdq_enable(struct mmc_host *mmc) pm_ref_count: cmdq_runtime_pm_put(cq_host); out: + MMC_TRACE(mmc, "%s: CQ enabled err: %d\n", __func__, err); return err; } @@ -443,6 +452,7 @@ static void cmdq_disable_nosync(struct mmc_host *mmc, bool soft) cq_host->enabled = false; mmc_host_set_cq_disable(mmc); + MMC_TRACE(mmc, "%s: CQ disabled\n", __func__); } static void cmdq_disable(struct mmc_host *mmc, bool soft) @@ -525,6 +535,12 @@ static void cmdq_prep_task_desc(struct mmc_request *mrq, REL_WRITE(!!(req_flags & REL_WR)) | BLK_COUNT(mrq->cmdq_req->data.blocks) | BLK_ADDR((u64)mrq->cmdq_req->blk_addr); + + MMC_TRACE(mrq->host, + "%s: Task: 0x%08x | Args: 0x%08x | cnt: 0x%08x\n", __func__, + lower_32_bits(*data), + upper_32_bits(*data), + mrq->cmdq_req->data.blocks); } static int cmdq_dma_map(struct mmc_host *host, struct mmc_request *mrq) @@ -665,6 +681,11 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc, dataddr = (__le64 __force *)(desc + 4); dataddr[0] = cpu_to_le64((u64)mrq->cmd->arg); cmdq_log_task_desc_history(cq_host, *task_desc, true); + MMC_TRACE(mrq->host, + "%s: DCMD: Task: 0x%08x | Args: 0x%08x\n", + __func__, + lower_32_bits(*task_desc), + upper_32_bits(*task_desc)); } static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq) @@ -743,6 +764,7 @@ ring_doorbell: cmdq_dumpregs(cq_host); BUG_ON(1); } + MMC_TRACE(mmc, "%s: tag: %d\n", __func__, tag); cmdq_writel(cq_host, 1 << tag, CQTDBR); /* Commit the doorbell write immediately */ wmb(); @@ -785,6 +807,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) if (!status && !err) return IRQ_NONE; + MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n", + __func__, status, err); if (err || (status & CQIS_RED)) { err_info = cmdq_readl(cq_host, CQTERRI); @@ -920,7 +944,9 @@ skip_cqterri: /* complete the corresponding mrq */ pr_debug("%s: completing tag -> %lu\n", mmc_hostname(mmc), tag); - cmdq_finish_data(mmc, tag); + MMC_TRACE(mmc, "%s: completing tag -> %lu\n", + __func__, tag); + cmdq_finish_data(mmc, tag); } } @@ -997,6 +1023,8 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) retries--; continue; } else { + MMC_TRACE(mmc, "%s: halt done , retries: %d\n", + __func__, retries); /* halt done: re-enable legacy interrupts */ if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, @@ -1014,6 +1042,7 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) cq_host->ops->set_data_timeout(mmc, 0xf); if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, true); + MMC_TRACE(mmc, "%s: unhalt done\n", __func__); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT, CQCTL); } diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index abf2ae2020c9..2ef459582aae 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -102,7 +102,7 @@ int sdhci_msm_ice_init(struct sdhci_host *host) struct sdhci_msm_host *msm_host = pltfm_host->priv; int err = 0; - if (msm_host->ice.vops->config) { + if (msm_host->ice.vops->init) { err = msm_host->ice.vops->init(msm_host->ice.pdev, msm_host, sdhci_msm_ice_error_cb); @@ -148,9 +148,10 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, req = mrq->req; if (req) { lba = req->__sector; - if (msm_host->ice.vops->config) { - err = msm_host->ice.vops->config(msm_host->ice.pdev, - req, &ice_set); + if (msm_host->ice.vops->config_start) { + err = msm_host->ice.vops->config_start( + msm_host->ice.pdev, + req, &ice_set, false); if (err) { pr_err("%s: ice config failed %d\n", mmc_hostname(host->mmc), err); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 203daf3bd5eb..466e0a2c8483 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2,7 +2,7 @@ * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform * driver source file * - * 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 @@ -3293,6 +3293,11 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) if (host->cq_host) sdhci_msm_cmdq_dump_debug_ram(host); + MMC_TRACE(host->mmc, "Data cnt: 0x%08x | Fifo cnt: 0x%08x\n", + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_DATA_CNT), + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_FIFO_CNT)); pr_info("Data cnt: 0x%08x | Fifo cnt: 0x%08x | Int sts: 0x%08x\n", sdhci_msm_readl_relaxed(host, msm_host_offset->CORE_MCI_DATA_CNT), diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 08822464d82f..3fd564388720 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -111,6 +111,17 @@ static void sdhci_dump_state(struct sdhci_host *host) static void sdhci_dumpregs(struct sdhci_host *host) { + MMC_TRACE(host->mmc, + "%s: 0x04=0x%08x 0x06=0x%08x 0x0E=0x%08x 0x30=0x%08x 0x34=0x%08x 0x38=0x%08x\n", + __func__, + sdhci_readw(host, SDHCI_BLOCK_SIZE), + sdhci_readw(host, SDHCI_BLOCK_COUNT), + sdhci_readw(host, SDHCI_COMMAND), + sdhci_readl(host, SDHCI_INT_STATUS), + sdhci_readl(host, SDHCI_INT_ENABLE), + sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); + mmc_stop_tracing(host->mmc); + pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); @@ -1013,6 +1024,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) /* Set the DMA boundary value and block size */ sdhci_set_blk_size_reg(host, data->blksz, SDHCI_DEFAULT_BOUNDARY_ARG); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + MMC_TRACE(host->mmc, + "%s: 0x28=0x%08x 0x3E=0x%08x 0x06=0x%08x\n", __func__, + sdhci_readb(host, SDHCI_HOST_CONTROL), + sdhci_readw(host, SDHCI_HOST_CONTROL2), + sdhci_readw(host, SDHCI_BLOCK_COUNT)); } static void sdhci_set_transfer_mode(struct sdhci_host *host, @@ -1071,6 +1087,9 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, mode |= SDHCI_TRNS_DMA; sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); + MMC_TRACE(host->mmc, "%s: 0x00=0x%08x 0x0C=0x%08x\n", __func__, + sdhci_readw(host, SDHCI_ARGUMENT2), + sdhci_readw(host, SDHCI_TRANSFER_MODE)); } static void sdhci_finish_data(struct sdhci_host *host) @@ -1082,6 +1101,8 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; + MMC_TRACE(host->mmc, "%s: 0x24=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_PRESENT_STATE)); if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); @@ -1210,6 +1231,11 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (cmd->data) host->data_start_time = ktime_get(); trace_mmc_cmd_rw_start(cmd->opcode, cmd->arg, cmd->flags); + MMC_TRACE(host->mmc, + "%s: updated 0x8=0x%08x 0xC=0x%08x 0xE=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_ARGUMENT), + sdhci_readw(host, SDHCI_TRANSFER_MODE), + sdhci_readw(host, SDHCI_COMMAND)); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); @@ -1231,8 +1257,14 @@ static void sdhci_finish_command(struct sdhci_host *host) sdhci_readb(host, SDHCI_RESPONSE + (3-i)*4-1); } + MMC_TRACE(host->mmc, + "%s: resp 0: 0x%08x resp 1: 0x%08x resp 2: 0x%08x resp 3: 0x%08x\n", + __func__, host->cmd->resp[0], host->cmd->resp[1], + host->cmd->resp[2], host->cmd->resp[3]); } else { host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); + MMC_TRACE(host->mmc, "%s: resp 0: 0x%08x\n", + __func__, host->cmd->resp[0]); } } @@ -3169,6 +3201,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } + MMC_TRACE(host->mmc, + "%s: intmask: 0x%x\n", __func__, intmask); + if (intmask & SDHCI_INT_AUTO_CMD_ERR) host->auto_cmd_err_sts = sdhci_readw(host, SDHCI_AUTO_CMD_ERR); diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e7205546fa6b..a0dd6bd8165c 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -16,7 +16,6 @@ */ #include "hif.h" -#include "pci.h" #include "ce.h" #include "debug.h" @@ -63,56 +62,56 @@ static inline void ath10k_ce_dest_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); } static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS); } static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); } static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS); } static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS); } static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); + ar->bus_write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); } static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32((ar), + u32 ctrl1_addr = ar->bus_read32((ar), (ce_ctrl_addr) + CE_CTRL1_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, (ctrl1_addr & ~CE_CTRL1_DMAX_LENGTH_MASK) | CE_CTRL1_DMAX_LENGTH_SET(n)); } @@ -121,9 +120,9 @@ static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + u32 ctrl1_addr = ar->bus_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, (ctrl1_addr & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n)); } @@ -132,9 +131,9 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + u32 ctrl1_addr = ar->bus_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, (ctrl1_addr & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n)); } @@ -142,30 +141,30 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_DRRI_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + CURRENT_DRRI_ADDRESS); } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, u32 addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); + ar->bus_write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); } static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, (addr & ~SRC_WATERMARK_HIGH_MASK) | SRC_WATERMARK_HIGH_SET(n)); } @@ -174,9 +173,9 @@ static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, (addr & ~SRC_WATERMARK_LOW_MASK) | SRC_WATERMARK_LOW_SET(n)); } @@ -185,9 +184,9 @@ static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, (addr & ~DST_WATERMARK_HIGH_MASK) | DST_WATERMARK_HIGH_SET(n)); } @@ -196,9 +195,9 @@ static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, (addr & ~DST_WATERMARK_LOW_MASK) | DST_WATERMARK_LOW_SET(n)); } @@ -206,50 +205,50 @@ static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, static inline void ath10k_ce_copy_complete_inter_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, + u32 host_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + HOST_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, host_ie_addr | HOST_IE_COPY_COMPLETE_MASK); } static inline void ath10k_ce_copy_complete_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, + u32 host_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + HOST_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, host_ie_addr & ~HOST_IE_COPY_COMPLETE_MASK); } static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, + u32 host_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + HOST_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, host_ie_addr & ~CE_WATERMARK_MASK); } static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, + u32 misc_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + MISC_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, misc_ie_addr | CE_ERROR_MASK); } static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, + u32 misc_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + MISC_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, misc_ie_addr & ~CE_ERROR_MASK); } @@ -257,7 +256,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int mask) { - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); + ar->bus_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); } /* @@ -267,7 +266,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, */ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, - u32 buffer, + dma_addr_t buffer, unsigned int nbytes, unsigned int transfer_id, unsigned int flags) @@ -325,11 +324,10 @@ exit: void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *src_ring = pipe->src_ring; u32 ctrl_addr = pipe->ctrl_addr; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ar->ce_lock); /* * This function must be called only if there is an incomplete @@ -351,19 +349,18 @@ void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, - u32 buffer, + dma_addr_t buffer, unsigned int nbytes, unsigned int transfer_id, unsigned int flags) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, buffer, nbytes, transfer_id, flags); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -371,14 +368,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int delta; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, pipe->src_ring->write_index, pipe->src_ring->sw_index - 1); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return delta; } @@ -386,21 +382,20 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; unsigned int sw_index = dest_ring->sw_index; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ar->ce_lock); return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); } -int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) +int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, + dma_addr_t paddr) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; @@ -409,7 +404,7 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); u32 ctrl_addr = pipe->ctrl_addr; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ar->ce_lock); if ((pipe->id != 5) && CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) @@ -439,15 +434,15 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) dest_ring->write_index = write_index; } -int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) +int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, + dma_addr_t paddr) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -510,14 +505,13 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, unsigned int *nbytesp) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = ath10k_ce_completed_recv_next_nolock(ce_state, per_transfer_contextp, nbytesp); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -532,7 +526,6 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, unsigned int write_index; int ret; struct ath10k *ar; - struct ath10k_pci *ar_pci; dest_ring = ce_state->dest_ring; @@ -540,9 +533,8 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, return -EIO; ar = ce_state->ar; - ar_pci = ath10k_pci_priv(ar); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); nentries_mask = dest_ring->nentries_mask; sw_index = dest_ring->sw_index; @@ -570,7 +562,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, ret = -EIO; } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -638,7 +630,6 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, unsigned int write_index; int ret; struct ath10k *ar; - struct ath10k_pci *ar_pci; src_ring = ce_state->src_ring; @@ -646,9 +637,8 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, return -EIO; ar = ce_state->ar; - ar_pci = ath10k_pci_priv(ar); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); nentries_mask = src_ring->nentries_mask; sw_index = src_ring->sw_index; @@ -679,7 +669,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, ret = -EIO; } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -688,13 +678,12 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = ath10k_ce_completed_send_next_nolock(ce_state, per_transfer_contextp); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -707,17 +696,17 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, */ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); u32 ctrl_addr = ce_state->ctrl_addr; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); /* Clear the copy-complete interrupts that will be handled here. */ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, HOST_IS_COPY_COMPLETE_MASK); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); if (ce_state->recv_cb) ce_state->recv_cb(ce_state); @@ -725,7 +714,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) if (ce_state->send_cb) ce_state->send_cb(ce_state); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); /* * Misc CE interrupts are not being handled, but still need @@ -733,7 +722,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) */ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); } /* @@ -799,22 +788,22 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) void ath10k_ce_enable_interrupts(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ce_id; /* Skip the last copy engine, CE7 the diagnostic window, as that * uses polling and isn't initialized for interrupts. */ for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) - ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]); + ath10k_ce_per_engine_handler_adjust( + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id)); } static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); struct ath10k_ce_ring *src_ring = ce_state->src_ring; u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); @@ -850,8 +839,8 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); @@ -1040,8 +1029,8 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); int ret; /* @@ -1097,8 +1086,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); if (ce_state->src_ring) { dma_free_coherent(ar->dev, diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index dfc098606bee..3c6dba648574 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -46,11 +46,20 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask #define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb +#ifndef CONFIG_ATH10K_SNOC struct ce_desc { __le32 addr; __le16 nbytes; __le16 flags; /* %CE_DESC_FLAGS_ */ }; +#else +struct ce_desc { + __le64 addr; + u16 nbytes; /* length in register map */ + u16 flags; /* fw_metadata_high */ + u32 toeplitz_hash_result; +}; +#endif struct ath10k_ce_ring { /* Number of entries in this ring; must be power of 2 */ @@ -144,7 +153,7 @@ struct ce_attr; */ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_send_context, - u32 buffer, + dma_addr_t buffer, unsigned int nbytes, /* 14 bits */ unsigned int transfer_id, @@ -152,7 +161,7 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, - u32 buffer, + dma_addr_t buffer, unsigned int nbytes, unsigned int transfer_id, unsigned int flags); @@ -164,8 +173,10 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); /*==================Recv=======================*/ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe); -int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr); -int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr); +int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, + dma_addr_t paddr); +int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, + dma_addr_t paddr); void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries); /* recv flags */ @@ -263,6 +274,7 @@ struct ce_attr { void (*recv_cb)(struct ath10k_ce_pipe *); }; +#ifndef CONFIG_ATH10K_SNOC #define SR_BA_ADDRESS 0x0000 #define SR_SIZE_ADDRESS 0x0004 #define DR_BA_ADDRESS 0x0008 @@ -383,6 +395,190 @@ struct ce_attr { #define DST_WATERMARK_HIGH_RESET 0 #define DST_WATERMARK_ADDRESS 0x0050 +#else +#define WCN3990_CE0_SR_BA_LOW (0x00240000) +#define WCN3990_CE1_SR_BA_LOW (0x00241000) +#define WCN3990_CE2_SR_BA_LOW (0x00242000) +#define WCN3990_CE3_SR_BA_LOW (0x00243000) +#define WCN3990_CE4_SR_BA_LOW (0x00244000) +#define WCN3990_CE5_SR_BA_LOW (0x00245000) +#define WCN3990_CE6_SR_BA_LOW (0x00246000) +#define WCN3990_CE7_SR_BA_LOW (0x00247000) +#define WCN3990_CE8_SR_BA_LOW (0x00248000) +#define WCN3990_CE9_SR_BA_LOW (0x00249000) +#define WCN3990_CE10_SR_BA_LOW (0x0024A000) +#define WCN3990_CE11_SR_BA_LOW (0x0024B000) +#define WCN3990_CE0_DR_BA_LOW (0x0024000C) +#define WNC3990_CE0_DR_SIZE (0x00240014) +#define WCN3990_CE0_CE_CTRL1 (0x00240018) +#define WCN3990_CE0_HOST_IE (0x0024002C) +#define WCN3990_CE0_HOST_IS (0x00240030) +#define WCN3990_CE0_MISC_IE (0x00240034) +#define WCN3990_CE0_MISC_IS (0x00240038) +#define WCN3990_CE0_SRC_WR_INDEX (0x0024003C) +#define WCN3990_CE0_CURRENT_SRRI (0x00240044) +#define WCN3990_CE0_CURRENT_DRRI (0x00240048) +#define WCN3990_CE0_SRC_WATERMARK (0x0024004C) +#define WCN3990_CE0_DST_WATERMARK (0x00240050) +#define WCN3990_CE0_SR_SIZE (0x00240008) +#define HOST_IE_COPY_COMPLETE_MASK (0x00000001) +#define WCN3990_CE_WRAPPER_HOST_INTERRUPT_SUMMARY 0x0024C000 +#define WCN3990_CE_WRAPPER_INDEX_BASE_LOW 0x0024C004 +#define WCN3990_CE_WRAPPER_INDEX_BASE_HIGH 0x0024C008 +#define CE_CTRL1_IDX_UPD_EN 0x00080000 + +#define WCN3990_CE_WRAPPER_BASE_ADDRESS \ + WCN3990_CE_WRAPPER_HOST_INTERRUPT_SUMMARY +#define WCN3990_CE0_BASE_ADDRESS \ + WCN3990_CE0_SR_BA_LOW +#define WCN3990_CE1_BASE_ADDRESS \ + WCN3990_CE1_SR_BA_LOW +#define WCN3990_CE2_BASE_ADDRESS \ + WCN3990_CE2_SR_BA_LOW +#define WCN3990_CE3_BASE_ADDRESS \ + WCN3990_CE3_SR_BA_LOW +#define WCN3990_CE4_BASE_ADDRESS \ + WCN3990_CE4_SR_BA_LOW +#define WCN3990_CE5_BASE_ADDRESS \ + WCN3990_CE5_SR_BA_LOW +#define WCN3990_CE6_BASE_ADDRESS \ + WCN3990_CE6_SR_BA_LOW +#define WCN3990_CE7_BASE_ADDRESS \ + WCN3990_CE7_SR_BA_LOW +#define WCN3990_CE8_BASE_ADDRESS \ + WCN3990_CE8_SR_BA_LOW +#define WCN3990_CE9_BASE_ADDRESS \ + WCN3990_CE9_SR_BA_LOW +#define WCN3990_CE10_BASE_ADDRESS \ + WCN3990_CE10_SR_BA_LOW +#define WCN3990_CE11_BASE_ADDRESS \ + WCN3990_CE11_SR_BA_LOW + +#define SR_BA_ADDRESS (WCN3990_CE0_SR_BA_LOW\ + - WCN3990_CE0_BASE_ADDRESS) +#define SR_SIZE_ADDRESS (WCN3990_CE0_SR_SIZE \ + - WCN3990_CE0_BASE_ADDRESS) +#define DR_BA_ADDRESS (WCN3990_CE0_DR_BA_LOW\ + - WCN3990_CE0_BASE_ADDRESS) +#define DR_SIZE_ADDRESS (WNC3990_CE0_DR_SIZE\ + - WCN3990_CE0_BASE_ADDRESS) +#define WCN3990_CE_DDR_ADDRESS_FOR_RRI_LOW \ + (WCN3990_CE_WRAPPER_INDEX_BASE_LOW - WCN3990_CE_WRAPPER_BASE_ADDRESS) + +#define WCN3990_CE_DDR_ADDRESS_FOR_RRI_HIGH \ + (WCN3990_CE_WRAPPER_INDEX_BASE_HIGH - WCN3990_CE_WRAPPER_BASE_ADDRESS) + +#define CE_RRI_LOW (WCN3990_CE_WRAPPER_BASE_ADDRESS \ + + WCN3990_CE_DDR_ADDRESS_FOR_RRI_LOW) + +#define CE_RRI_HIGH (WCN3990_CE_WRAPPER_BASE_ADDRESS \ + + WCN3990_CE_DDR_ADDRESS_FOR_RRI_HIGH) + +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MSB 18 +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 18 + +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00040000 +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ + (((0 | (x)) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) + +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MSB 16 +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 + +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_GET(x) \ + (((x) & CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) >> \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ + (((0 | (x)) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) + +#define CE_CTRL1_DMAX_LENGTH_MSB 0 +#define CE_CTRL1_DMAX_LENGTH_LSB 0 + +#define CE_CTRL1_DMAX_LENGTH_MASK 0x0000FFFF +#define CE_CTRL1_DMAX_LENGTH_GET(x) \ + (((x) & CE_CTRL1_DMAX_LENGTH_MASK) >> CE_CTRL1_DMAX_LENGTH_LSB) +#define CE_CTRL1_DMAX_LENGTH_SET(x) \ + (((0 | (x)) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) + +#define CE_CTRL1_ADDRESS (WCN3990_CE0_CE_CTRL1 \ + - WCN3990_CE0_BASE_ADDRESS) + +#define HOST_IE_ADDRESS (WCN3990_CE0_HOST_IE\ + - WCN3990_CE0_BASE_ADDRESS) + +#define HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define HOST_IS_ADDRESS (WCN3990_CE0_HOST_IS \ + - WCN3990_CE0_BASE_ADDRESS) +#define MISC_IE_ADDRESS (WCN3990_CE0_MISC_IE \ + - WCN3990_CE0_BASE_ADDRESS) + +#define MISC_IS_AXI_ERR_MASK 0x00000100 +#define MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define MISC_IS_ADDRESS (WCN3990_CE0_MISC_IS \ + - WCN3990_CE0_BASE_ADDRESS) + +#define SR_WR_INDEX_ADDRESS 0x3C +#define DST_WR_INDEX_ADDRESS 0x40 + +#define CURRENT_SRRI_ADDRESS (WCN3990_CE0_CURRENT_SRRI\ + - WCN3990_CE0_BASE_ADDRESS) +#define CURRENT_DRRI_ADDRESS (WCN3990_CE0_CURRENT_DRRI\ + - WCN3990_CE0_BASE_ADDRESS) + +#define SRC_WATERMARK_LOW_MSB 0 +#define SRC_WATERMARK_LOW_LSB 16 + +#define SRC_WATERMARK_LOW_MASK 0xffff0000 +#define SRC_WATERMARK_LOW_GET(x) \ + (((x) & SRC_WATERMARK_LOW_MASK) >> SRC_WATERMARK_LOW_LSB) +#define SRC_WATERMARK_LOW_SET(x) \ + (((0 | (x)) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) + +#define SRC_WATERMARK_LOW_RESET 0 +#define SRC_WATERMARK_HIGH_MSB 15 +#define SRC_WATERMARK_HIGH_LSB 0 +#define SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define SRC_WATERMARK_HIGH_GET(x) \ + (((x) & SRC_WATERMARK_HIGH_MASK) >> SRC_WATERMARK_HIGH_LSB) +#define SRC_WATERMARK_HIGH_SET(x) \ + (((0 | (x)) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) + +#define SRC_WATERMARK_HIGH_RESET 0 +#define SRC_WATERMARK_ADDRESS (WCN3990_CE0_SRC_WATERMARK\ + - WCN3990_CE0_BASE_ADDRESS) + +#define DST_WATERMARK_LOW_LSB 16 +#define DST_WATERMARK_LOW_MASK 0xffff0000 +#define DST_WATERMARK_LOW_SET(x) \ + (((0 | (x)) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_LOW_RESET 0 +#define DST_WATERMARK_HIGH_MSB 15 +#define DST_WATERMARK_HIGH_LSB 0 +#define DST_WATERMARK_HIGH_MASK 0x0000ffff +#define DST_WATERMARK_HIGH_GET(x) \ + (((x) & DST_WATERMARK_HIGH_MASK) >> DST_WATERMARK_HIGH_LSB) +#define DST_WATERMARK_HIGH_SET(x) \ + (((0 | (x)) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_HIGH_RESET 0 +#define DST_WATERMARK_ADDRESS (WCN3990_CE0_DST_WATERMARK \ + - WCN3990_CE0_BASE_ADDRESS) + +#define BITS0_TO_31(val) ((uint32_t)((uint64_t)(val)\ + & (uint64_t)(0xFFFFFFFF))) +#define BITS32_TO_35(val) ((uint32_t)(((uint64_t)(val)\ + & (uint64_t)(0xF00000000)) >> 32)) +#endif + static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; @@ -425,7 +621,7 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) #define CE_INTERRUPT_SUMMARY(ar) \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \ - ath10k_pci_read32((ar), CE_WRAPPER_BASE_ADDRESS + \ + ar->bus_read32((ar), CE_WRAPPER_BASE_ADDRESS + \ CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)) #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 21ae8d663e67..bf77ac66c79e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1560,10 +1560,22 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } +/* WAR: WCN3990 fw loading is done by PIL, assign WMI/HTT version */ +static inline void init_fw_param(struct ath10k *ar, + struct ath10k_fw_file *fw_file) +{ + if (QCA_REV_WCN3990(ar)) { + fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_HL_1_0; + fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV; + } +} + static int ath10k_core_init_firmware_features(struct ath10k *ar) { struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file; + init_fw_param(ar, &ar->normal_mode_fw.fw_file); + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) && !test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) { ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); @@ -1666,6 +1678,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: ar->max_num_peers = TARGET_TLV_NUM_PEERS; ar->max_num_stations = TARGET_TLV_NUM_STATIONS; ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; @@ -1712,6 +1725,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1; break; case ATH10K_FW_WMI_OP_VERSION_TLV: + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV; break; case ATH10K_FW_WMI_OP_VERSION_10_4: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 521f1c55c19e..9eede4266721 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -74,6 +74,7 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, ATH10K_BUS_AHB, + ATH10K_BUS_SNOC, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -83,6 +84,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) return "pci"; case ATH10K_BUS_AHB: return "ahb"; + case ATH10K_BUS_SNOC: + return "snoc"; } return "unknown"; @@ -778,7 +781,7 @@ struct ath10k { } scan; struct { - struct ieee80211_supported_band sbands[NUM_NL80211_BANDS]; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; } mac; /* should never be NULL; needed for regular htt rx */ @@ -912,6 +915,10 @@ struct ath10k { struct net_device napi_dev; struct napi_struct napi; + void (*bus_write32)(void *ar, u32 offset, u32 value); + u32 (*bus_read32)(void *ar, u32 offset); + spinlock_t ce_lock; /* lock for CE access */ + void *ce_states; /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index c458fa96a6d4..b1db01a167ac 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -38,6 +38,7 @@ enum ath10k_debug_mask { ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_PCI_PS = 0x00004000, ATH10K_DBG_AHB = 0x00008000, + ATH10K_DBG_SNOC = 0x00009000, ATH10K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index b2566b06e1e1..9e79d52e18cf 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -74,9 +74,9 @@ struct ath10k_hif_ops { u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); - u32 (*read32)(struct ath10k *ar, u32 address); + u32 (*read32)(void *ar, u32 address); - void (*write32)(struct ath10k *ar, u32 address, u32 value); + void (*write32)(void *ar, u32 address, u32 value); /* Power up the device and enter BMI transfer mode for FW download */ int (*power_up)(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 961ef0626680..ed6ac39cd49d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -27,6 +27,7 @@ #define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX #define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) +#define HTT_RX_RING_FILL_LEVEL_DUAL_MAC (HTT_RX_RING_SIZE - 1) /* when under memory pressure rx ring refill may fail and needs a retry */ #define HTT_RX_RING_REFILL_RETRY_MS 50 @@ -471,7 +472,15 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) */ htt->rx_ring.size = HTT_RX_RING_SIZE; htt->rx_ring.size_mask = htt->rx_ring.size - 1; - htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; + + switch (ar->hw_rev) { + case ATH10K_HW_WCN3990: + htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC; + break; + default: + htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; + break; + } if (!is_power_of_2(htt->rx_ring.size)) { ath10k_warn(ar, "htt rx ring size is not power of 2\n"); diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 675e75d66db2..4332a27dfa9a 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -138,6 +138,32 @@ const struct ath10k_hw_regs qca4019_regs = { .pcie_intr_clr_address = 0x00000010, }; +const struct ath10k_hw_regs wcn3990_regs = { + .rtc_soc_base_address = 0x00000000, + .rtc_wmac_base_address = 0x00000000, + .soc_core_base_address = 0x00000000, + .ce_wrapper_base_address = 0x0024C000, + .soc_global_reset_address = 0x00000008, + .ce0_base_address = 0x00240000, + .ce1_base_address = 0x00241000, + .ce2_base_address = 0x00242000, + .ce3_base_address = 0x00243000, + .ce4_base_address = 0x00244000, + .ce5_base_address = 0x00245000, + .ce6_base_address = 0x00246000, + .ce7_base_address = 0x00247000, + .ce8_base_address = 0x00248000, + .ce9_base_address = 0x00249000, + .ce10_base_address = 0x0024A000, + .ce11_base_address = 0x0024B000, + .soc_chip_id_address = 0x000000f0, + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00000100, + .ce_wrap_intr_sum_host_msi_lsb = 0x0000000c, + .ce_wrap_intr_sum_host_msi_mask = 0x00fff000, + .pcie_intr_fw_mask = 0x00100000, +}; + const struct ath10k_hw_values qca988x_values = { .rtc_state_val_on = 3, .ce_count = 8, @@ -181,6 +207,15 @@ const struct ath10k_hw_values qca4019_values = { .ce_desc_meta_data_lsb = 4, }; +const struct ath10k_hw_values wcn3990_values = { + .rtc_state_val_on = 5, + .ce_count = 12, + .msi_assign_ce_max = 12, + .num_target_ce_config_wlan = 12, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 6038b7486f1d..b7d9c23e17fa 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -184,6 +184,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_TLV = 4, ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, ATH10K_FW_WMI_OP_VERSION_10_4 = 6, + ATH10K_FW_WMI_OP_VERSION_HL_1_0 = 7, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, @@ -224,12 +225,14 @@ enum ath10k_hw_rev { ATH10K_HW_QCA9377, ATH10K_HW_QCA4019, ATH10K_HW_QCA9887, + ATH10K_HW_WCN3990, }; struct ath10k_hw_regs { u32 rtc_soc_base_address; u32 rtc_wmac_base_address; u32 soc_core_base_address; + u32 soc_global_reset_address; u32 ce_wrapper_base_address; u32 ce0_base_address; u32 ce1_base_address; @@ -239,6 +242,10 @@ struct ath10k_hw_regs { u32 ce5_base_address; u32 ce6_base_address; u32 ce7_base_address; + u32 ce8_base_address; + u32 ce9_base_address; + u32 ce10_base_address; + u32 ce11_base_address; u32 soc_reset_control_si0_rst_mask; u32 soc_reset_control_ce_rst_mask; u32 soc_chip_id_address; @@ -256,6 +263,7 @@ extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; extern const struct ath10k_hw_regs qca99x0_regs; extern const struct ath10k_hw_regs qca4019_regs; +extern const struct ath10k_hw_regs wcn3990_regs; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -271,6 +279,7 @@ extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca99x0_values; extern const struct ath10k_hw_values qca9888_values; extern const struct ath10k_hw_values qca4019_values; +extern const struct ath10k_hw_values wcn3990_values; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); @@ -283,6 +292,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, #define QCA_REV_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984) #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377) #define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019) +#define QCA_REV_WCN3990(ar) ((ar)->hw_rev == ATH10K_HW_WCN3990) /* Known peculiarities: * - raw appears in nwifi decap, raw and nwifi appear in ethernet decap @@ -516,6 +526,11 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +/* Target specific defines for WMI-HL-1.0 firmware */ +#define TARGET_HL_10_TLV_NUM_PEERS 14 +#define TARGET_HL_10_TLV_AST_SKID_LIMIT 6 +#define TARGET_HL_10_TLV_NUM_WDS_ENTRIES 2 + /* Diagnostic Window */ #define CE_DIAG_PIPE 7 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 76297d69f1ed..7a5bfeea8f3d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -531,7 +531,7 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) enum wmi_phy_mode phymode = MODE_UNKNOWN; switch (chandef->chan->band) { - case NL80211_BAND_2GHZ: + case IEEE80211_BAND_2GHZ: switch (chandef->width) { case NL80211_CHAN_WIDTH_20_NOHT: if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM) @@ -554,7 +554,7 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) break; } break; - case NL80211_BAND_5GHZ: + case IEEE80211_BAND_5GHZ: switch (chandef->width) { case NL80211_CHAN_WIDTH_20_NOHT: phymode = MODE_11A; @@ -2122,7 +2122,7 @@ static void ath10k_peer_assoc_h_rates(struct ath10k *ar, struct cfg80211_chan_def def; const struct ieee80211_supported_band *sband; const struct ieee80211_rate *rates; - enum nl80211_band band; + enum ieee80211_band band; u32 ratemask; u8 rate; int i; @@ -2182,7 +2182,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct cfg80211_chan_def def; - enum nl80211_band band; + enum ieee80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; int i, n; @@ -2406,7 +2406,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct cfg80211_chan_def def; - enum nl80211_band band; + enum ieee80211_band band; const u16 *vht_mcs_mask; u8 ampdu_factor; @@ -2424,7 +2424,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, arg->peer_flags |= ar->wmi.peer_flags->vht; - if (def.chan->band == NL80211_BAND_2GHZ) + if (def.chan->band == IEEE80211_BAND_2GHZ) arg->peer_flags |= ar->wmi.peer_flags->vht_2g; arg->peer_vht_caps = vht_cap->cap; @@ -2493,7 +2493,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta) { - return sta->supp_rates[NL80211_BAND_2GHZ] >> + return sta->supp_rates[IEEE80211_BAND_2GHZ] >> ATH10K_MAC_FIRST_OFDM_RATE_IDX; } @@ -2504,7 +2504,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, { struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct cfg80211_chan_def def; - enum nl80211_band band; + enum ieee80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; enum wmi_phy_mode phymode = MODE_UNKNOWN; @@ -2517,7 +2517,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; switch (band) { - case NL80211_BAND_2GHZ: + case IEEE80211_BAND_2GHZ: if (sta->vht_cap.vht_supported && !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) { if (sta->bandwidth == IEEE80211_STA_RX_BW_40) @@ -2537,7 +2537,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, } break; - case NL80211_BAND_5GHZ: + case IEEE80211_BAND_5GHZ: /* * Check VHT first. */ @@ -2915,7 +2915,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) { struct ieee80211_hw *hw = ar->hw; struct ieee80211_supported_band **bands; - enum nl80211_band band; + enum ieee80211_band band; struct ieee80211_channel *channel; struct wmi_scan_chan_list_arg arg = {0}; struct wmi_channel_arg *ch; @@ -2927,7 +2927,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); bands = hw->wiphy->bands; - for (band = 0; band < NUM_NL80211_BANDS; band++) { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!bands[band]) continue; @@ -2946,7 +2946,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) return -ENOMEM; ch = arg.channels; - for (band = 0; band < NUM_NL80211_BANDS; band++) { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!bands[band]) continue; @@ -2984,7 +2984,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) /* FIXME: why use only legacy modes, why not any * HT/VHT modes? Would that even make any * difference? */ - if (channel->band == NL80211_BAND_2GHZ) + if (channel->band == IEEE80211_BAND_2GHZ) ch->mode = MODE_11G; else ch->mode = MODE_11A; @@ -3899,16 +3899,12 @@ void __ath10k_scan_finish(struct ath10k *ar) break; case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: - if (!ar->scan.is_roc) { - struct cfg80211_scan_info info = { - .aborted = (ar->scan.state == - ATH10K_SCAN_ABORTING), - }; - - ieee80211_scan_completed(ar->hw, &info); - } else if (ar->scan.roc_notify) { + if (!ar->scan.is_roc) + ieee80211_scan_completed(ar->hw, + (ar->scan.state == + ATH10K_SCAN_ABORTING)); + else if (ar->scan.roc_notify) ieee80211_remain_on_channel_expired(ar->hw); - } /* fall through */ case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; @@ -4370,11 +4366,11 @@ static void ath10k_mac_setup_ht_vht_cap(struct ath10k *ar) vht_cap = ath10k_create_vht_cap(ar); if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) { - band = &ar->mac.sbands[NL80211_BAND_2GHZ]; + band = &ar->mac.sbands[IEEE80211_BAND_2GHZ]; band->ht_cap = ht_cap; } if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) { - band = &ar->mac.sbands[NL80211_BAND_5GHZ]; + band = &ar->mac.sbands[IEEE80211_BAND_5GHZ]; band->ht_cap = ht_cap; band->vht_cap = vht_cap; } @@ -5722,7 +5718,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) struct ath10k_sta *arsta; struct ieee80211_sta *sta; struct cfg80211_chan_def def; - enum nl80211_band band; + enum ieee80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; u32 changed, bw, nss, smps; @@ -6562,14 +6558,14 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, mutex_lock(&ar->conf_mutex); - sband = hw->wiphy->bands[NL80211_BAND_2GHZ]; + sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { idx -= sband->n_channels; sband = NULL; } if (!sband) - sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; + sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; if (!sband || idx >= sband->n_channels) { ret = -ENOENT; @@ -6594,7 +6590,7 @@ exit: static bool ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar, - enum nl80211_band band, + enum ieee80211_band band, const struct cfg80211_bitrate_mask *mask) { int num_rates = 0; @@ -6613,7 +6609,7 @@ ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar, static bool ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar, - enum nl80211_band band, + enum ieee80211_band band, const struct cfg80211_bitrate_mask *mask, int *nss) { @@ -6662,7 +6658,7 @@ ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar, static int ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar, - enum nl80211_band band, + enum ieee80211_band band, const struct cfg80211_bitrate_mask *mask, u8 *rate, u8 *nss) { @@ -6763,7 +6759,7 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif, static bool ath10k_mac_can_set_bitrate_mask(struct ath10k *ar, - enum nl80211_band band, + enum ieee80211_band band, const struct cfg80211_bitrate_mask *mask) { int i; @@ -6815,7 +6811,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct cfg80211_chan_def def; struct ath10k *ar = arvif->ar; - enum nl80211_band band; + enum ieee80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; u8 rate; @@ -7479,7 +7475,7 @@ static const struct ieee80211_ops ath10k_ops = { }; #define CHAN2G(_channel, _freq, _flags) { \ - .band = NL80211_BAND_2GHZ, \ + .band = IEEE80211_BAND_2GHZ, \ .hw_value = (_channel), \ .center_freq = (_freq), \ .flags = (_flags), \ @@ -7488,7 +7484,7 @@ static const struct ieee80211_ops ath10k_ops = { } #define CHAN5G(_channel, _freq, _flags) { \ - .band = NL80211_BAND_5GHZ, \ + .band = IEEE80211_BAND_5GHZ, \ .hw_value = (_channel), \ .center_freq = (_freq), \ .flags = (_flags), \ @@ -7819,7 +7815,7 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } - band = &ar->mac.sbands[NL80211_BAND_2GHZ]; + band = &ar->mac.sbands[IEEE80211_BAND_2GHZ]; band->n_channels = ARRAY_SIZE(ath10k_2ghz_channels); band->channels = channels; @@ -7831,7 +7827,7 @@ int ath10k_mac_register(struct ath10k *ar) band->bitrates = ath10k_g_rates; } - ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; } if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) { @@ -7843,12 +7839,12 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } - band = &ar->mac.sbands[NL80211_BAND_5GHZ]; + band = &ar->mac.sbands[IEEE80211_BAND_5GHZ]; band->n_channels = ARRAY_SIZE(ath10k_5ghz_channels); band->channels = channels; band->n_bitrates = ath10k_a_rates_size; band->bitrates = ath10k_a_rates; - ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band; } ath10k_mac_setup_ht_vht_cap(ar); @@ -7959,6 +7955,7 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); break; case ATH10K_FW_WMI_OP_VERSION_TLV: + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { ar->hw->wiphy->iface_combinations = ath10k_tlv_qcs_if_comb; @@ -8045,8 +8042,8 @@ err_dfs_detector_exit: ar->dfs_detector->exit(ar->dfs_detector); err_free: - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); + kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); + kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); SET_IEEE80211_DEV(ar->hw, NULL); return ret; @@ -8059,8 +8056,8 @@ void ath10k_mac_unregister(struct ath10k *ar) if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) ar->dfs_detector->exit(ar->dfs_detector); - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); + kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); + kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); SET_IEEE80211_DEV(ar->hw, NULL); } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 9fbeb7e5ab2d..0c250f8d45ce 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -669,14 +669,14 @@ static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset) return val; } -inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) +inline void ath10k_pci_write32(void *ar, u32 offset, u32 value) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ar_pci->bus_ops->write32(ar, offset, value); } -inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) +inline u32 ath10k_pci_read32(void *ar, u32 offset) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -3246,6 +3246,16 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar->id.subsystem_vendor = pdev->subsystem_vendor; ar->id.subsystem_device = pdev->subsystem_device; + spin_lock_init(&ar_pci->ce_lock); + spin_lock_init(&ar_pci->ps_lock); + + ar->bus_write32 = ath10k_pci_write32; + ar->bus_read32 = ath10k_pci_read32; + ar->ce_lock = ar_pci->ce_lock; + ar->ce_states = ar_pci->ce_states; + + setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, + (unsigned long)ar); setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer, (unsigned long)ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 9854ad56b2de..06d0bd3993d3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -263,11 +263,11 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 -void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value); +void ath10k_pci_write32(void *ar, u32 offset, u32 value); void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val); void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val); -u32 ath10k_pci_read32(struct ath10k *ar, u32 offset); +u32 ath10k_pci_read32(void *ar, u32 offset); u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr); u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr); diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 034e7a54c5b2..6260f11d4e32 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -205,12 +205,25 @@ struct rx_attention { * descriptor. */ +#ifndef CONFIG_ATH10K_SNOC struct rx_frag_info { u8 ring0_more_count; u8 ring1_more_count; u8 ring2_more_count; u8 ring3_more_count; } __packed; +#else +struct rx_frag_info { + u8 ring0_more_count; + u8 ring1_more_count; + u8 ring2_more_count; + u8 ring3_more_count; + u8 ring4_more_count; + u8 ring5_more_count; + u8 ring6_more_count; + u8 ring7_more_count; +} __packed; +#endif /* * ring0_more_count @@ -465,11 +478,23 @@ struct rx_msdu_start_qca99x0 { __le32 info2; /* %RX_MSDU_START_INFO2_ */ } __packed; +#ifdef CONFIG_ATH10K_SNOC +struct rx_msdu_start_wcn3990 { + __le32 info3; +} __packed; +#else +struct rx_msdu_start_wcn3990 { +} __packed; +#endif + struct rx_msdu_start { struct rx_msdu_start_common common; union { struct rx_msdu_start_qca99x0 qca99x0; } __packed; + union { + struct rx_msdu_start_wcn3990 wcn3990; + } __packed; } __packed; /* @@ -589,10 +614,18 @@ struct rx_msdu_end_qca99x0 { __le32 info2; } __packed; +struct rx_msdu_end_wcn3990 { + __le32 rule_indication_0; + __le32 rule_indication_1; + __le32 rule_indication_2; + __le32 rule_indication_3; +} __packed; + struct rx_msdu_end { struct rx_msdu_end_common common; union { struct rx_msdu_end_qca99x0 qca99x0; + struct rx_msdu_end_wcn3990 wcn3990; } __packed; } __packed; @@ -953,8 +986,13 @@ struct rx_ppdu_end_qca6174 { struct rx_pkt_end { __le32 info0; /* %RX_PKT_END_INFO0_ */ +#ifndef CONFIG_ATH10K_SNOC __le32 phy_timestamp_1; __le32 phy_timestamp_2; +#else + __le64 phy_timestamp_1; + __le64 phy_timestamp_2; +#endif } __packed; #define RX_LOCATION_INFO0_RTT_FAC_LEGACY_MASK 0x00003fff @@ -990,6 +1028,9 @@ struct rx_pkt_end { struct rx_location_info { __le32 rx_location_info0; /* %RX_LOCATION_INFO0_ */ __le32 rx_location_info1; /* %RX_LOCATION_INFO1_ */ +#ifdef CONFIG_ATH10K_SNOC + __le32 rx_location_info2; /* %RX_LOCATION_INFO2_ */ +#endif } __packed; enum rx_phy_ppdu_end_info0 { @@ -1080,6 +1121,25 @@ struct rx_ppdu_end_qca9984 { __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +struct rx_timing_offset { + __le32 timing_offset; + __le32 reserved; +}; + +struct rx_ppdu_end_wcn3990 { + __le32 reserved_info_0; + __le32 reserved_info_1; + __le32 rx_antenna_info; + __le32 rx_coex_info; + __le32 rx_mpdu_cnt_info; + __le32 rx_bb_length; + __le64 phy_timestamp_tx; + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + struct rx_timing_offset rx_timing_offset; + struct rx_location_info rx_location_info; +} __packed; + struct rx_ppdu_end { struct rx_ppdu_end_common common; union { @@ -1087,6 +1147,7 @@ struct rx_ppdu_end { struct rx_ppdu_end_qca6174 qca6174; struct rx_ppdu_end_qca99x0 qca99x0; struct rx_ppdu_end_qca9984 qca9984; + struct rx_ppdu_end_wcn3990 wcn3990; } __packed; } __packed; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index e64f59300a7c..7a8f9cfd8253 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -937,7 +937,12 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]; reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]; - svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; + if (QCA_REV_WCN3990(ar)) { + svc_bmap = (__le32 *)(skb->data + + WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET); + } else { + svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; + } mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT]; if (!ev || !reg || !svc_bmap || !mem_reqs) { @@ -1400,7 +1405,18 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); - cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); + if (QCA_REV_WCN3990(ar)) { + cfg->num_peers = __cpu_to_le32(TARGET_HL_10_TLV_NUM_PEERS); + cfg->ast_skid_limit = + __cpu_to_le32(TARGET_HL_10_TLV_AST_SKID_LIMIT); + cfg->num_wds_entries = + __cpu_to_le32(TARGET_HL_10_TLV_NUM_WDS_ENTRIES); + } else { + cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); + cfg->ast_skid_limit = __cpu_to_le32(0x10); + cfg->num_wds_entries = __cpu_to_le32(0x20); + } + if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) { cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); @@ -1412,7 +1428,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_peer_keys = __cpu_to_le32(2); cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); - cfg->ast_skid_limit = __cpu_to_le32(0x10); cfg->tx_chain_mask = __cpu_to_le32(0x7); cfg->rx_chain_mask = __cpu_to_le32(0x7); cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); @@ -1428,7 +1443,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_mcast_table_elems = __cpu_to_le32(0); cfg->mcast2ucast_mode = __cpu_to_le32(0); cfg->tx_dbg_log_size = __cpu_to_le32(0x400); - cfg->num_wds_entries = __cpu_to_le32(0x20); cfg->dma_burst_size = __cpu_to_le32(0); cfg->mac_aggr_delim = __cpu_to_le32(0); cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0); @@ -3562,7 +3576,78 @@ static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { .pmf = WMI_TLV_PEER_PMF, }; -/************/ +static const struct wmi_ops wmi_hl_1_0_ops = { + .rx = ath10k_wmi_tlv_op_rx, + .map_svc = wmi_hl_1_0_svc_map, + .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, + .pull_phyerr_hdr = ath10k_wmi_tlv_op_pull_phyerr_ev_hdr, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, + .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, + .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev, + .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev, + .get_txbf_conf_scheme = ath10k_wmi_tlv_txbf_conf_scheme, + .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param, + .gen_init = ath10k_wmi_tlv_op_gen_init, + .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key, + .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf, + .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param, + .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc, + .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, + .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, + .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, + .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, + .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, + .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, + .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, + .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable, + .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event, + .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind, + .gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern, + .gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern, + .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state, + .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, + .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, + .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, +}; + +void ath10k_wmi_hl_1_0_attach(struct ath10k *ar) +{ + ar->wmi.cmd = &wmi_tlv_cmd_map; + ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; + ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; + ar->wmi.ops = &wmi_hl_1_0_ops; +} + /* TLV init */ /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index b8aa6000573c..496fee5d489b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -889,6 +889,7 @@ enum wmi_tlv_tag { WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT, WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM, WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR, + WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET = 176, WMI_TLV_TAG_MAX }; @@ -966,6 +967,125 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, }; +enum wmi_hl_10_service { + WMI_HL_10_SERVICE_BEACON_OFFLOAD = 0, + WMI_HL_10_SERVICE_SCAN_OFFLOAD, + WMI_HL_10_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_HL_10_SERVICE_BCN_MISS_OFFLOAD, + WMI_HL_10_SERVICE_STA_PWRSAVE, + WMI_HL_10_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_HL_10_SERVICE_AP_UAPSD, + WMI_HL_10_SERVICE_AP_DFS, + WMI_HL_10_SERVICE_11AC, + WMI_HL_10_SERVICE_BLOCKACK, + WMI_HL_10_SERVICE_PHYERR, + WMI_HL_10_SERVICE_BCN_FILTER, + WMI_HL_10_SERVICE_RTT, + WMI_HL_10_SERVICE_WOW, + WMI_HL_10_SERVICE_RATECTRL_CACHE, + WMI_HL_10_SERVICE_IRAM_TIDS, + WMI_HL_10_SERVICE_ARPNS_OFFLOAD, + WMI_HL_10_SERVICE_NLO, + WMI_HL_10_SERVICE_GTK_OFFLOAD, + WMI_HL_10_SERVICE_SCAN_SCH, + WMI_HL_10_SERVICE_CSA_OFFLOAD, + WMI_HL_10_SERVICE_CHATTER, + WMI_HL_10_SERVICE_COEX_FREQAVOID, + WMI_HL_10_SERVICE_PACKET_POWER_SAVE, + WMI_HL_10_SERVICE_FORCE_FW_HANG, + WMI_HL_10_SERVICE_GPIO, + WMI_HL_10_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_HL_10_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_HL_10_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_HL_10_SERVICE_STA_KEEP_ALIVE, + WMI_HL_10_SERVICE_TX_ENCAP, + WMI_HL_10_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_HL_10_SERVICE_EARLY_RX, + WMI_HL_10_SERVICE_STA_SMPS, + WMI_HL_10_SERVICE_FWTEST, + WMI_HL_10_SERVICE_STA_WMMAC, + WMI_HL_10_SERVICE_TDLS, + WMI_HL_10_SERVICE_BURST, + WMI_HL_10_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_HL_10_SERVICE_ADAPTIVE_OCS, + WMI_HL_10_SERVICE_BA_SSN_SUPPORT, + WMI_HL_10_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_HL_10_SERVICE_WLAN_HB, + WMI_HL_10_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_HL_10_SERVICE_BATCH_SCAN, + WMI_HL_10_SERVICE_QPOWER, + WMI_HL_10_SERVICE_PLMREQ, + WMI_HL_10_SERVICE_THERMAL_MGMT, + WMI_HL_10_SERVICE_RMC, + WMI_HL_10_SERVICE_MHF_OFFLOAD, + WMI_HL_10_SERVICE_COEX_SAR, + WMI_HL_10_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_HL_10_SERVICE_NAN, + WMI_HL_10_SERVICE_L1SS_STAT, + WMI_HL_10_SERVICE_ESTIMATE_LINKSPEED, + WMI_HL_10_SERVICE_OBSS_SCAN, + WMI_HL_10_SERVICE_TDLS_OFFCHAN, + WMI_HL_10_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_HL_10_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_HL_10_SERVICE_IBSS_PWRSAVE, + WMI_HL_10_SERVICE_LPASS, + WMI_HL_10_SERVICE_EXTSCAN, + WMI_HL_10_SERVICE_D0WOW, + WMI_HL_10_SERVICE_HSOFFLOAD, + WMI_HL_10_SERVICE_ROAM_HO_OFFLOAD, + WMI_HL_10_SERVICE_RX_FULL_REORDER, + WMI_HL_10_SERVICE_DHCP_OFFLOAD, + WMI_HL_10_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_HL_10_SERVICE_MDNS_OFFLOAD, + WMI_HL_10_SERVICE_SAP_AUTH_OFFLOAD, + WMI_HL_10_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT, + WMI_HL_10_SERVICE_OCB, + WMI_HL_10_SERVICE_AP_ARPNS_OFFLOAD, + WMI_HL_10_SERVICE_PER_BAND_CHAINMASK_SUPPORT, + WMI_HL_10_SERVICE_PACKET_FILTER_OFFLOAD, + WMI_HL_10_SERVICE_MGMT_TX_HTT, + WMI_HL_10_SERVICE_MGMT_TX_WMI, + WMI_HL_10_SERVICE_EXT_MSG, + WMI_HL_10_SERVICE_MAWC, + WMI_HL_10_SERVICE_PEER_ASSOC_CONF, + WMI_HL_10_SERVICE_EGAP, + WMI_HL_10_SERVICE_STA_PMF_OFFLOAD, + WMI_HL_10_SERVICE_UNIFIED_WOW_CAPABILITY, + WMI_HL_10_SERVICE_ENHANCED_PROXY_STA, + WMI_HL_10_SERVICE_ATF, + WMI_HL_10_SERVICE_COEX_GPIO, + WMI_HL_10_SERVICE_AUX_SPECTRAL_INTF, + WMI_HL_10_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_HL_10_SERVICE_BSS_CHANNEL_INFO_64, + WMI_HL_10_SERVICE_ENTERPRISE_MESH, + WMI_HL_10_SERVICE_RESTRT_CHNL_SUPPORT, + WMI_HL_10_SERVICE_BPF_OFFLOAD, + WMI_HL_10_SERVICE_SYNC_DELETE_CMDS, + WMI_HL_10_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_HL_10_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_HL_10_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES, + WMI_HL_10_SERVICE_NAN_DATA, + WMI_HL_10_SERVICE_NAN_RTT, + WMI_HL_10_SERVICE_11AX, + WMI_HL_10_SERVICE_DEPRECATED_REPLACE, + WMI_HL_10_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, + WMI_HL_10_SERVICE_ENHANCED_MCAST_FILTER, + WMI_HL_10_SERVICE_PERIODIC_CHAN_STAT_SUPPORT, + WMI_HL_10_SERVICE_MESH_11S, + WMI_HL_10_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT, + WMI_HL_10_SERVICE_VDEV_RX_FILTER, + WMI_HL_10_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT, + WMI_HL_10_SERVICE_MARK_FIRST_WAKEUP_PACKET, + WMI_HL_10_SERVICE_MULTIPLE_MCAST_FILTER_SET, + WMI_HL_10_SERVICE_HOST_MANAGED_RX_REORDER, + WMI_HL_10_SERVICE_FLASH_RDWR_SUPPORT, + WMI_HL_10_SERVICE_WLAN_STATS_REPORT, + WMI_HL_10_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT, + WMI_HL_10_SERVICE_DFS_PHYERR_OFFLOAD, + WMI_HL_10_MAX_SERVICE = 128, + WMI_HL_10_MAX_EXT_SERVICE +}; + #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ ((svc_id) < (len) && \ __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \ @@ -978,6 +1098,63 @@ enum wmi_tlv_service { } while (0) static inline void +wmi_hl_1_0_svc_map(const __le32 *in, unsigned long *out, size_t len) +{ + SVCMAP(WMI_HL_10_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_SERVICE_ROAM_SCAN_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_HL_10_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_HL_10_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_HL_10_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_HL_10_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_HL_10_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_HL_10_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_HL_10_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_HL_10_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_HL_10_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_HL_10_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_HL_10_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_HL_10_SERVICE_ARPNS_OFFLOAD, + WMI_SERVICE_ARPNS_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_NLO, + WMI_SERVICE_NLO, len); + SVCMAP(WMI_HL_10_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_HL_10_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_HL_10_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_HL_10_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_HL_10_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_HL_10_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_HL_10_SERVICE_RX_FULL_REORDER, + WMI_SERVICE_RX_FULL_REORDER, len); +} + +static inline void wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) { SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD, @@ -1182,6 +1359,14 @@ struct wmi_tlv_svc_rdy_ev { __le32 max_num_scan_chans; __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */ struct wmi_tlv_hw_bd_info hw_bd_info[5]; +#ifdef CONFIG_ATH10K_SNOC + __le32 max_supported_macs; + __le32 wmi_fw_sub_feat_caps; + __le32 num_dbs_hw_modes; + __le32 txrx_chainmask; + __le32 default_dbs_hw_mode_index; + __le32 num_msdu_desc; +#endif } __packed; struct wmi_tlv_rdy_ev { @@ -1641,5 +1826,5 @@ struct wmi_tlv_tx_pause_ev { } __packed; void ath10k_wmi_tlv_attach(struct ath10k *ar); - +void ath10k_wmi_hl_1_0_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 54df425bb0fc..f7ada7147136 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2320,9 +2320,9 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) * of mgmt rx. */ if (channel >= 1 && channel <= 14) { - status->band = NL80211_BAND_2GHZ; + status->band = IEEE80211_BAND_2GHZ; } else if (channel >= 36 && channel <= 165) { - status->band = NL80211_BAND_5GHZ; + status->band = IEEE80211_BAND_5GHZ; } else { /* Shouldn't happen unless list of advertised channels to * mac80211 has been changed. @@ -2332,7 +2332,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) return 0; } - if (phy_mode == MODE_11B && status->band == NL80211_BAND_5GHZ) + if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ) ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); sband = &ar->mac.sbands[status->band]; @@ -2387,7 +2387,7 @@ static int freq_to_idx(struct ath10k *ar, int freq) struct ieee80211_supported_band *sband; int band, ch, idx = 0; - for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { sband = ar->hw->wiphy->bands[band]; if (!sband) continue; @@ -8196,6 +8196,9 @@ int ath10k_wmi_attach(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_TLV: ath10k_wmi_tlv_attach(ar); break; + case ATH10K_FW_WMI_OP_VERSION_HL_1_0: + ath10k_wmi_hl_1_0_attach(ar); + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: ath10k_err(ar, "unsupported WMI op version: %d\n", diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index a680a970b7f7..e4281438c04f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1657,13 +1657,14 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_sta *ista; int ret = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d184e682e636..5cc0ddc254eb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1860,14 +1860,16 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static int ath9k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); bool flush = false; int ret = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; mutex_lock(&sc->mutex); diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 19d3d64416bf..4d1527a2e292 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1413,10 +1413,12 @@ static void carl9170_ampdu_work(struct work_struct *work) static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; struct carl9170_sta_tid *tid_info; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 7c169abdbafe..a27279c2c695 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -857,12 +857,14 @@ static int wcn36xx_resume(struct ieee80211_hw *hw) static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct wcn36xx *wcn = hw->priv; struct wcn36xx_sta *sta_priv = NULL; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 8983b5f125c3..0a3928a8fe90 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -754,6 +754,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { netif_carrier_on(ndev); + wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); @@ -1273,6 +1274,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, wil->pbss = pbss; netif_carrier_on(ndev); + wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go); if (rc) @@ -1288,6 +1290,7 @@ err_bcast: wmi_pcp_stop(wil); err_pcp_start: netif_carrier_off(ndev); + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); out: mutex_unlock(&wil->mutex); return rc; @@ -1394,6 +1397,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "%s()\n", __func__); netif_carrier_off(ndev); + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fa061daa56d7..eb1fd9dd09ba 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -270,6 +270,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, wil_bcast_fini(wil); wil_update_net_queues_bh(wil, NULL, true); netif_carrier_off(ndev); + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); if (test_bit(wil_status_fwconnected, wil->status)) { clear_bit(wil_status_fwconnected, wil->status); @@ -553,6 +554,12 @@ out_wmi_wq: return -EAGAIN; } +void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) +{ + if (wil->platform_ops.bus_request) + wil->platform_ops.bus_request(wil->platform_handle, kbps); +} + /** * wil6210_disconnect - disconnect one connection * @wil: driver context @@ -1068,9 +1075,7 @@ int __wil_up(struct wil6210_priv *wil) napi_enable(&wil->napi_tx); set_bit(wil_status_napi_en, wil->status); - if (wil->platform_ops.bus_request) - wil->platform_ops.bus_request(wil->platform_handle, - WIL_MAX_BUS_REQUEST_KBPS); + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); return 0; } @@ -1094,8 +1099,7 @@ int __wil_down(struct wil6210_priv *wil) set_bit(wil_status_resetting, wil->status); - if (wil->platform_ops.bus_request) - wil->platform_ops.bus_request(wil->platform_handle, 0); + wil6210_bus_request(wil, 0); wil_disable_irq(wil); if (test_and_clear_bit(wil_status_napi_en, wil->status)) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index cc20517a4726..b9727ebe79ac 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -39,6 +39,7 @@ extern bool debug_fw; #define WIL_FW_NAME "wil6210.fw" /* code */ #define WIL_FW2_NAME "wil6210.brd" /* board & radio parameters */ +#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ /** @@ -892,7 +893,7 @@ int wmi_aoa_meas(struct wil6210_priv *wil, const void *mac_addr, u8 chan, u8 type); int wmi_abort_scan(struct wil6210_priv *wil); void wil_abort_scan(struct wil6210_priv *wil, bool sync); - +void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps); void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, u16 reason_code, bool from_event); void wil_probe_client_flush(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 24f42e3a6d92..09595349f24b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -566,6 +566,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { if (rc) { netif_carrier_off(ndev); + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); wil_err(wil, "%s: cfg80211_connect_result with failure\n", __func__); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index bec2dc1ca2e4..61ae2768132a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -818,13 +818,15 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int brcms_ops_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct brcms_info *wl = hw->priv; struct scb *scb = &wl->wlc->pri_scb; int status; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u8 buf_size = params->buf_size; if (WARN_ON(scb->magic != SCB_MAGIC)) return -EIDRM; diff --git a/drivers/net/wireless/cw1200/sta.h b/drivers/net/wireless/cw1200/sta.h index bebb3379017f..a0bacaa39b31 100644 --- a/drivers/net/wireless/cw1200/sta.h +++ b/drivers/net/wireless/cw1200/sta.h @@ -109,9 +109,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, u32 changed); int cw1200_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); void cw1200_suspend_resume(struct cw1200_common *priv, struct wsm_suspend_resume *arg); diff --git a/drivers/net/wireless/iwlegacy/4965.h b/drivers/net/wireless/iwlegacy/4965.h index 8ab8706f9422..e432715e02d8 100644 --- a/drivers/net/wireless/iwlegacy/4965.h +++ b/drivers/net/wireless/iwlegacy/4965.h @@ -182,9 +182,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 * ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 0cd95120bc78..d59769e858f4 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1817,10 +1817,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + switch (action) { case IEEE80211_AMPDU_TX_START: ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index f715eee39851..e70dd9523911 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -334,11 +334,13 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value) static int mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, - bool amsdu) + struct ieee80211_ampdu_params *params) { struct mt7601u_dev *dev = hw->priv; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; WARN_ON(msta->wcid.idx > GROUP_WCID(0)); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 30e3aaae32e2..088429d0a634 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5421,11 +5421,13 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, static int mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { - + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 buf_size = params->buf_size; int i, rc = 0; struct mwl8k_priv *priv = hw->priv; struct mwl8k_ampdu_stream *stream; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 6aed923a709a..7d820c395375 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5375,13 +5375,13 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static int rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, - bool amsdu) + struct ieee80211_ampdu_params *params) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; u8 ampdu_factor, ampdu_density; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; switch (action) { case IEEE80211_AMPDU_TX_START: diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index c925a4dff599..a4527880b2b7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1371,11 +1371,13 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw, static int rtl_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; switch (action) { case IEEE80211_AMPDU_TX_START: diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index b5bcc933a2a6..4df992de7d07 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -659,29 +659,24 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, * informs the f/w regarding this. * @hw: Pointer to the ieee80211_hw structure. * @vif: Pointer to the ieee80211_vif structure. - * @action: ieee80211_ampdu_mlme_action enum. - * @sta: Pointer to the ieee80211_sta structure. - * @tid: Traffic identifier. - * @ssn: Pointer to ssn value. - * @buf_size: Buffer size (for kernel version > 2.6.38). - * @amsdu: is AMSDU in AMPDU allowed + * @params: Pointer to A-MPDU action parameters * * Return: status: 0 on success, negative error code on failure. */ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - unsigned short tid, - unsigned short *ssn, - unsigned char buf_size, - bool amsdu) + struct ieee80211_ampdu_params *params) { int status = -EOPNOTSUPP; struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; u16 seq_no = 0; u8 ii = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 buf_size = params->buf_size; for (ii = 0; ii < RSI_MAX_VIFS; ii++) { if (vif == adapter->vifs[ii]) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9733b31a780d..69c1c09687a3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -7935,10 +7935,11 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) EXPORT_SYMBOL_GPL(rt2800_get_tsf); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv; int ret = 0; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 440790b92b19..83f1a44fb9b4 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -218,9 +218,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params); u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); int rt2800_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ec7f6af3fab2..30165ea0fa25 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5261,14 +5261,16 @@ out: static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; u8 hlid, *ba_bitmap; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, tid); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index a617c9e8e11f..fd241f6b62da 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.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 @@ -362,8 +362,13 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt, notify->chan_user_data = ch_ctx->props.chan_user_data; notify->evt_id = evt->code; notify->bytes_xfered = evt->len; - if (callback) + if (callback) { + if (atomic_read(&ch_ctx->poll_mode)) { + GSIERR("Calling client callback in polling mode\n"); + WARN_ON(1); + } ch_ctx->props.xfer_cb(notify); + } } static void gsi_process_evt_re(struct gsi_evt_ctx *ctx, @@ -459,12 +464,12 @@ check_again: ctx->ring.rp = rp; while (ctx->ring.rp_local != rp) { ++cntr; - gsi_process_evt_re(ctx, ¬ify, true); if (ctx->props.exclusive && atomic_read(&ctx->chan->poll_mode)) { cntr = 0; break; } + gsi_process_evt_re(ctx, ¬ify, true); } gsi_ring_evt_doorbell(ctx); if (cntr != 0) @@ -1586,15 +1591,21 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, return -GSI_STATUS_INVALID_PARAMS; } - if (props->evt_ring_hdl != ~0 && - atomic_read(&gsi_ctx->evtr[props->evt_ring_hdl].chan_ref_cnt) && - gsi_ctx->evtr[props->evt_ring_hdl].props.exclusive) { - GSIERR("evt ring=%lu already in exclusive use chan_hdl=%p\n", + if (props->evt_ring_hdl != ~0) { + if (props->evt_ring_hdl >= GSI_EVT_RING_MAX) { + GSIERR("invalid evt ring=%lu\n", props->evt_ring_hdl); + return -GSI_STATUS_INVALID_PARAMS; + } + + if (atomic_read( + &gsi_ctx->evtr[props->evt_ring_hdl].chan_ref_cnt) && + gsi_ctx->evtr[props->evt_ring_hdl].props.exclusive) { + GSIERR("evt ring=%lu exclusively used by chan_hdl=%p\n", props->evt_ring_hdl, chan_hdl); - return -GSI_STATUS_UNSUPPORTED_OP; + return -GSI_STATUS_UNSUPPORTED_OP; + } } - ctx = &gsi_ctx->chan[props->ch_id]; if (ctx->allocated) { GSIERR("chan %d already allocated\n", props->ch_id); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 09ec8458fcad..1e79fd954969 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3774,6 +3774,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, ipa_ctx->ipa_wrapper_size = resource_p->ipa_mem_size; ipa_ctx->ipa_hw_type = resource_p->ipa_hw_type; ipa_ctx->ipa_hw_mode = resource_p->ipa_hw_mode; + ipa_ctx->ipa_uc_monitor_holb = + resource_p->ipa_uc_monitor_holb; ipa_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge; ipa_ctx->ipa_bam_remote_mode = resource_p->ipa_bam_remote_mode; ipa_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt; @@ -4316,6 +4318,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE; ipa_drv_res->ipa_hw_type = 0; ipa_drv_res->ipa_hw_mode = 0; + ipa_drv_res->ipa_uc_monitor_holb = false; ipa_drv_res->ipa_bam_remote_mode = false; ipa_drv_res->modem_cfg_emb_pipe_flt = false; ipa_drv_res->ipa_wdi2 = false; @@ -4340,6 +4343,14 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, IPADBG(": found ipa_drv_res->ipa_hw_mode = %d", ipa_drv_res->ipa_hw_mode); + /* Check ipa_uc_monitor_holb enabled or disabled */ + ipa_drv_res->ipa_uc_monitor_holb = + of_property_read_bool(pdev->dev.of_node, + "qcom,ipa-uc-monitor-holb"); + IPADBG(": ipa uc monitor holb = %s\n", + ipa_drv_res->ipa_uc_monitor_holb + ? "Enabled" : "Disabled"); + /* Get IPA WAN / LAN RX pool sizes */ result = of_property_read_u32(pdev->dev.of_node, "qcom,wan-rx-ring-size", diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index 7ce51fccb822..8d2213f30ec2 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.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 @@ -1272,8 +1272,9 @@ static ssize_t ipa_read_wdi(struct file *file, char __user *ubuf, "RX num_db=%u\n" "RX num_unexpected_db=%u\n" "RX num_pkts_in_dis_uninit_state=%u\n" - "num_ic_inj_vdev_change=%u\n" - "num_ic_inj_fw_desc_change=%u\n" + "RX num_ic_inj_vdev_change=%u\n" + "RX num_ic_inj_fw_desc_change=%u\n" + "RX num_qmb_int_handled=%u\n" "RX reserved1=%u\n" "RX reserved2=%u\n", stats.rx_ch_stats.max_outstanding_pkts, @@ -1295,6 +1296,7 @@ static ssize_t ipa_read_wdi(struct file *file, char __user *ubuf, stats.rx_ch_stats.num_pkts_in_dis_uninit_state, stats.rx_ch_stats.num_ic_inj_vdev_change, stats.rx_ch_stats.num_ic_inj_fw_desc_change, + stats.rx_ch_stats.num_qmb_int_handled, stats.rx_ch_stats.reserved1, stats.rx_ch_stats.reserved2); cnt += nbytes; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 2c2a9c617b16..b45e748b66a6 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -47,7 +47,7 @@ #define IPA_QMAP_HEADER_LENGTH (4) #define IPA_DL_CHECKSUM_LENGTH (8) #define IPA_NUM_DESC_PER_SW_TX (2) -#define IPA_GENERIC_RX_POOL_SZ 1000 +#define IPA_GENERIC_RX_POOL_SZ 192 #define IPA_UC_FINISH_MAX 6 #define IPA_UC_WAIT_MIN_SLEEP 1000 #define IPA_UC_WAII_MAX_SLEEP 1200 @@ -1174,6 +1174,7 @@ struct ipa_context { u32 ipa_rx_min_timeout_usec; u32 ipa_rx_max_timeout_usec; u32 ipa_polling_iteration; + bool ipa_uc_monitor_holb; }; /** @@ -1229,6 +1230,7 @@ struct ipa_plat_drv_res { bool tethered_flow_control; u32 ipa_rx_polling_sleep_msec; u32 ipa_polling_iteration; + bool ipa_uc_monitor_holb; }; struct ipa_mem_partition { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c index 13db6b08ba9d..3dd2eb093317 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.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 @@ -768,8 +768,12 @@ int ipa_uc_monitor_holb(enum ipa_client_type ipa_client, bool enable) int ep_idx; int ret; - /* HOLB monitoring is applicable only to 2.6L. */ - if (ipa_ctx->ipa_hw_type != IPA_HW_v2_6L) { + /* + * HOLB monitoring is applicable to 2.6L. + * And also could be enabled from dtsi node. + */ + if (ipa_ctx->ipa_hw_type != IPA_HW_v2_6L || + !ipa_ctx->ipa_uc_monitor_holb) { IPADBG("Not applicable on this target\n"); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c index 6dc194f97656..5bda4cb9ed2b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c @@ -477,6 +477,9 @@ int ipa2_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats) RX_STATS(num_db); RX_STATS(num_unexpected_db); RX_STATS(num_pkts_in_dis_uninit_state); + RX_STATS(num_ic_inj_vdev_change); + RX_STATS(num_ic_inj_fw_desc_change); + RX_STATS(num_qmb_int_handled); RX_STATS(reserved1); RX_STATS(reserved2); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index e3d20422d591..2cd8d5c975f4 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -195,7 +195,7 @@ static const int ep_mapping[3][IPA_CLIENT_MAX] = { [IPA_2_6L][IPA_CLIENT_HSIC1_PROD] = -1, - [IPA_2_6L][IPA_CLIENT_WLAN1_PROD] = -1, + [IPA_2_6L][IPA_CLIENT_WLAN1_PROD] = 18, [IPA_2_6L][IPA_CLIENT_HSIC2_PROD] = -1, [IPA_2_6L][IPA_CLIENT_USB2_PROD] = -1, [IPA_2_6L][IPA_CLIENT_HSIC3_PROD] = -1, @@ -228,16 +228,16 @@ static const int ep_mapping[3][IPA_CLIENT_MAX] = { [IPA_2_6L][IPA_CLIENT_TEST4_PROD] = 14, [IPA_2_6L][IPA_CLIENT_HSIC1_CONS] = -1, - [IPA_2_6L][IPA_CLIENT_WLAN1_CONS] = -1, + [IPA_2_6L][IPA_CLIENT_WLAN1_CONS] = 17, [IPA_2_6L][IPA_CLIENT_HSIC2_CONS] = -1, [IPA_2_6L][IPA_CLIENT_USB2_CONS] = -1, - [IPA_2_6L][IPA_CLIENT_WLAN2_CONS] = -1, + [IPA_2_6L][IPA_CLIENT_WLAN2_CONS] = 16, [IPA_2_6L][IPA_CLIENT_HSIC3_CONS] = -1, [IPA_2_6L][IPA_CLIENT_USB3_CONS] = -1, - [IPA_2_6L][IPA_CLIENT_WLAN3_CONS] = -1, + [IPA_2_6L][IPA_CLIENT_WLAN3_CONS] = 15, [IPA_2_6L][IPA_CLIENT_HSIC4_CONS] = -1, [IPA_2_6L][IPA_CLIENT_USB4_CONS] = -1, - [IPA_2_6L][IPA_CLIENT_WLAN4_CONS] = -1, + [IPA_2_6L][IPA_CLIENT_WLAN4_CONS] = 19, [IPA_2_6L][IPA_CLIENT_HSIC5_CONS] = -1, [IPA_2_6L][IPA_CLIENT_USB_CONS] = 0, [IPA_2_6L][IPA_CLIENT_USB_DPL_CONS] = 10, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 25e5e3b74f26..17e6973b807f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.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 @@ -1356,8 +1356,9 @@ static ssize_t ipa3_read_wdi(struct file *file, char __user *ubuf, "RX num_db=%u\n" "RX num_unexpected_db=%u\n" "RX num_pkts_in_dis_uninit_state=%u\n" - "num_ic_inj_vdev_change=%u\n" - "num_ic_inj_fw_desc_change=%u\n" + "RX num_ic_inj_vdev_change=%u\n" + "RX num_ic_inj_fw_desc_change=%u\n" + "RX num_qmb_int_handled=%u\n" "RX reserved1=%u\n" "RX reserved2=%u\n", stats.rx_ch_stats.max_outstanding_pkts, @@ -1379,6 +1380,7 @@ static ssize_t ipa3_read_wdi(struct file *file, char __user *ubuf, stats.rx_ch_stats.num_pkts_in_dis_uninit_state, stats.rx_ch_stats.num_ic_inj_vdev_change, stats.rx_ch_stats.num_ic_inj_fw_desc_change, + stats.rx_ch_stats.num_qmb_int_handled, stats.rx_ch_stats.reserved1, stats.rx_ch_stats.reserved2); cnt += nbytes; 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 bf794faa7f6a..3086311b5c2a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,8 @@ #define QMI_SEND_STATS_REQ_TIMEOUT_MS 5000 #define QMI_SEND_REQ_TIMEOUT_MS 60000 +#define QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS 1000 + static struct qmi_handle *ipa3_svc_handle; static void ipa3_a5_svc_recv_msg(struct work_struct *work); static DECLARE_DELAYED_WORK(work_recv_msg, ipa3_a5_svc_recv_msg); @@ -713,7 +715,8 @@ int ipa3_qmi_enable_force_clear_datapath_send( &req_desc, req, sizeof(*req), - &resp_desc, &resp, sizeof(resp), 0); + &resp_desc, &resp, sizeof(resp), + QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS); if (rc < 0) { IPAWANERR("send req failed %d\n", rc); return rc; @@ -758,7 +761,8 @@ int ipa3_qmi_disable_force_clear_datapath_send( &req_desc, req, sizeof(*req), - &resp_desc, &resp, sizeof(resp), 0); + &resp_desc, &resp, sizeof(resp), + QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS); if (rc < 0) { IPAWANERR("send req failed %d\n", rc); return rc; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 41bb8651f69c..24b61880f95d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.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 @@ -472,6 +472,9 @@ int ipa3_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats) RX_STATS(num_db); RX_STATS(num_unexpected_db); RX_STATS(num_pkts_in_dis_uninit_state); + RX_STATS(num_ic_inj_vdev_change); + RX_STATS(num_ic_inj_fw_desc_change); + RX_STATS(num_qmb_int_handled); RX_STATS(reserved1); RX_STATS(reserved2); @@ -1353,6 +1356,33 @@ uc_timeout: return result; } +static int ipa3_wait_for_prod_empty(void) +{ + int i; + u32 rx_door_bell_value; + + for (i = 0; i < IPA_UC_FINISH_MAX; i++) { + rx_door_bell_value = ipahal_read_reg_mn( + IPA_UC_MAILBOX_m_n, + IPA_HW_WDI_RX_MBOX_START_INDEX / 32, + IPA_HW_WDI_RX_MBOX_START_INDEX % 32); + IPADBG("(%d)rx_DB(%u)rp(%u),comp_wp(%u)\n", + i, + rx_door_bell_value, + *ipa3_ctx->uc_ctx.rdy_ring_rp_va, + *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va); + if (*ipa3_ctx->uc_ctx.rdy_ring_rp_va != + *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va) { + usleep_range(IPA_UC_WAIT_MIN_SLEEP, + IPA_UC_WAII_MAX_SLEEP); + } else { + return 0; + } + } + + return -ETIME; +} + /** * ipa3_disable_wdi_pipe() - WDI client disable * @clnt_hdl: [in] opaque client handle assigned by IPA to client @@ -1368,9 +1398,9 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) union IpaHwWdiCommonChCmdData_t disable; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; u32 prod_hdl; - int i; - u32 rx_door_bell_value; + u32 source_pipe_bitmask = 0; + bool disable_force_clear = false; if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || ipa3_ctx->ep[clnt_hdl].valid == 0) { @@ -1406,16 +1436,8 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) * holb on IPA Producer pipe */ if (IPA_CLIENT_IS_PROD(ep->client)) { - /* enable force clear */ IPADBG("Stopping PROD channel - hdl=%d clnt=%d\n", clnt_hdl, ep->client); - source_pipe_bitmask = 1 << - ipa3_get_ep_mapping(ep->client); - result = ipa3_enable_force_clear(clnt_hdl, false, - source_pipe_bitmask); - if (result) - goto uc_timeout; - /* remove delay on wlan-prod pipe*/ memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl)); ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); @@ -1439,30 +1461,34 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) * rdy_comp_ring_wp_pa on WDI2.0 */ if (ipa3_ctx->ipa_wdi2) { - for (i = 0; i < IPA_UC_FINISH_MAX; i++) { - rx_door_bell_value = ipahal_read_reg_mn( - IPA_UC_MAILBOX_m_n, - IPA_HW_WDI_RX_MBOX_START_INDEX/32, - IPA_HW_WDI_RX_MBOX_START_INDEX % 32); - IPADBG("(%d)rx_DB(%u)rp(%u),comp_wp(%u)\n", - i, - rx_door_bell_value, - *ipa3_ctx->uc_ctx.rdy_ring_rp_va, - *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va); - if (*ipa3_ctx->uc_ctx.rdy_ring_rp_va != - *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va) { - usleep_range(IPA_UC_WAIT_MIN_SLEEP, - IPA_UC_WAII_MAX_SLEEP); + result = ipa3_wait_for_prod_empty(); + if (result) { + IPADBG("prod not empty\n"); + /* + * In case ipa_uc still haven't processed all + * pending descriptors, ask modem to drain + */ + source_pipe_bitmask = 1 << + ipa3_get_ep_mapping(ep->client); + result = ipa3_enable_force_clear(clnt_hdl, + false, source_pipe_bitmask); + if (result) { + IPAERR("failed to force clear %d\n", + result); } else { - break; + disable_force_clear = true; + } + + /* + * In case ipa_uc still haven't processed all + * pending descriptors, we have to assert + */ + result = ipa3_wait_for_prod_empty(); + if (result) { + IPAERR("prod still not empty\n"); + ipa_assert(); } } - /* - * In case ipa_uc still haven't processed all - * pending descriptors, we have to assert - */ - if (i == IPA_UC_FINISH_MAX) - ipa_assert(); } } @@ -1482,8 +1508,8 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); ep_cfg_ctrl.ipa_ep_delay = true; ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); - /* disable force clear */ - ipa3_disable_force_clear(clnt_hdl); + if (disable_force_clear) + ipa3_disable_force_clear(clnt_hdl); } IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); ep->uc_offload_state &= ~IPA_WDI_ENABLED; diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index b7fc68a6efdd..7f97d7c6bab7 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.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,6 +26,10 @@ #include <soc/qcom/memory_dump.h> #include <linux/regulator/consumer.h> #include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/cpumask.h> +#include <linux/cpufreq.h> +#include <linux/sched/core_ctl.h> #include "wil_platform.h" #include "msm_11ad.h" @@ -54,6 +58,8 @@ #define DISABLE_PCIE_L1_MASK 0xFFFFFFFD #define PCIE20_CAP_LINKCTRLSTATUS 0x80 +#define WIGIG_MIN_CPU_BOOST_KBPS 150000 + struct device; static const char * const gpio_en_name = "qcom,wigig-en"; @@ -113,6 +119,11 @@ struct msm11ad_ctx { struct msm11ad_vreg vddio; struct msm11ad_clk rf_clk3; struct msm11ad_clk rf_clk3_pin; + + /* cpu boost support */ + bool use_cpu_boost; + bool is_cpu_boosted; + struct cpumask boost_cpu; }; static LIST_HEAD(dev_list); @@ -823,6 +834,36 @@ out_rc: return rc; } +static void msm_11ad_init_cpu_boost(struct msm11ad_ctx *ctx) +{ + unsigned int minfreq = 0, maxfreq = 0, freq; + int i, boost_cpu; + + for_each_possible_cpu(i) { + freq = cpufreq_quick_get_max(i); + if (freq > maxfreq) { + maxfreq = freq; + boost_cpu = i; + } + if (!minfreq || freq < minfreq) + minfreq = freq; + } + + if (minfreq != maxfreq) { + /* + * use first big core for boost, to be compatible with WLAN + * which assigns big cores from the last index + */ + ctx->use_cpu_boost = true; + cpumask_clear(&ctx->boost_cpu); + cpumask_set_cpu(boost_cpu, &ctx->boost_cpu); + dev_info(ctx->dev, "CPU boost: will use core %d\n", boost_cpu); + } else { + ctx->use_cpu_boost = false; + dev_info(ctx->dev, "CPU boost disabled, uniform topology\n"); + } +} + static int msm_11ad_probe(struct platform_device *pdev) { struct msm11ad_ctx *ctx; @@ -998,6 +1039,8 @@ static int msm_11ad_probe(struct platform_device *pdev) goto out_rc; } + msm_11ad_init_cpu_boost(ctx); + /* report */ dev_info(ctx->dev, "msm_11ad discovered. %p {\n" " gpio_en = %d\n" @@ -1074,6 +1117,34 @@ static struct platform_driver msm_11ad_driver = { }; module_platform_driver(msm_11ad_driver); +static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx) +{ + /* + * There is a very small window where user space can change the + * affinity after we changed it here and before setting the + * NO_BALANCING flag. Retry this several times as a workaround. + */ + int retries = 5, rc; + struct irq_desc *desc; + + while (retries > 0) { + irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0); + rc = irq_set_affinity_hint(ctx->pcidev->irq, &ctx->boost_cpu); + if (rc) + dev_warn(ctx->dev, + "Failed set affinity, rc=%d\n", rc); + irq_modify_status(ctx->pcidev->irq, 0, IRQ_NO_BALANCING); + desc = irq_to_desc(ctx->pcidev->irq); + if (cpumask_equal(desc->irq_common_data.affinity, + &ctx->boost_cpu)) + break; + retries--; + } + + if (!retries) + dev_warn(ctx->dev, "failed to set CPU boost affinity\n"); +} + /* hooks for the wil6210 driver */ static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */) { @@ -1102,6 +1173,35 @@ static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */) "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n", kbps, vote, rc); + if (ctx->use_cpu_boost) { + bool was_boosted = ctx->is_cpu_boosted; + bool needs_boost = (kbps >= WIGIG_MIN_CPU_BOOST_KBPS); + + if (was_boosted != needs_boost) { + if (needs_boost) { + rc = core_ctl_set_boost(true); + if (rc) { + dev_err(ctx->dev, + "Failed enable boost rc=%d\n", + rc); + goto out; + } + msm_11ad_set_boost_affinity(ctx); + dev_dbg(ctx->dev, "CPU boost enabled\n"); + } else { + rc = core_ctl_set_boost(false); + if (rc) + dev_err(ctx->dev, + "Failed disable boost rc=%d\n", + rc); + irq_modify_status(ctx->pcidev->irq, + IRQ_NO_BALANCING, 0); + dev_dbg(ctx->dev, "CPU boost disabled\n"); + } + ctx->is_cpu_boosted = needs_boost; + } + } +out: return rc; } diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 864152ca463d..dbda0b6a9c9a 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1249,11 +1249,9 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) if (!chg->external_vconn) { rc = smblib_read(chg, RID_CC_CONTROL_7_0_REG, &stat); - if (rc < 0) { + if (rc < 0) smblib_err(chg, "Couldn't read RID_CC_CONTROL_7_0 rc=%d\n", rc); - return rc; - } /* check if VCONN is enabled on either CC pin */ if (stat & VCONN_EN_CC_MASK) { @@ -1262,7 +1260,6 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); - return rc; } } @@ -1362,17 +1359,48 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg, int smblib_get_prop_batt_status(struct smb_charger *chg, union power_supply_propval *val) { + union power_supply_propval pval = {0, }; + bool usb_online, dc_online; u8 stat; int rc; + rc = smblib_get_prop_usb_online(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb online property rc=%d\n", + rc); + return rc; + } + usb_online = (bool)pval.intval; + + rc = smblib_get_prop_dc_online(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get dc online property rc=%d\n", + rc); + return rc; + } + dc_online = (bool)pval.intval; + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", rc); return rc; } - stat = stat & BATTERY_CHARGER_STATUS_MASK; + + if (!usb_online && !dc_online) { + switch (stat) { + case TERMINATE_CHARGE: + case INHIBIT_CHARGE: + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + default: + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + break; + } + return rc; + } + switch (stat) { case TRICKLE_CHARGE: case PRE_CHARGE: @@ -2351,6 +2379,12 @@ 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, diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 70d935e9d1df..c836e780fc86 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -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 @@ -39,6 +39,9 @@ #define DEAD_TIME_MASK GENMASK(7, 4) #define HIGH_DEAD_TIME_MASK GENMASK(7, 4) +#define SMB2CHG_DC_TM_SREFGEN (DCIN_BASE + 0xE2) +#define STACKED_DIODE_EN_BIT BIT(2) + enum { OOB_COMP_WA_BIT = BIT(0), }; @@ -410,6 +413,7 @@ static enum power_supply_property smb138x_parallel_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, + POWER_SUPPLY_PROP_MODEL_NAME, }; static int smb138x_parallel_get_prop(struct power_supply *psy, @@ -456,6 +460,9 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: rc = smblib_get_prop_charger_temp_max(chg, val); break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = "smb138x"; + break; default: pr_err("parallel power supply get prop %d not supported\n", prop); @@ -1212,6 +1219,13 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } + /* enable stacked diode */ + rc = smblib_write(chg, SMB2CHG_DC_TM_SREFGEN, STACKED_DIODE_EN_BIT); + if (rc < 0) { + pr_err("Couldn't enable stacked diode rc=%d\n", rc); + return rc; + } + rc = smb138x_init_parallel_psy(chip); if (rc < 0) { pr_err("Couldn't initialize parallel psy rc=%d\n", rc); diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index 1ac9791b467b..1070a34073e4 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -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 @@ -453,45 +453,24 @@ done: } /** - * cpr3_msm8996_mmss_apply_closed_loop_offset_voltages() - modify the - * closed-loop voltage adjustments by the amounts that are needed - * for this fuse combo + * cpr3_msm8996_mmss_adjust_target_quotients() - adjust the target quotients + * for each corner according to device tree values and fuse values * @vreg: Pointer to the CPR3 regulator - * @volt_adjust: Array of closed-loop voltage adjustment values of length - * vreg->corner_count which is further adjusted based upon - * offset voltage fuse values. * * Return: 0 on success, errno on failure */ -static int cpr3_msm8996_mmss_apply_closed_loop_offset_voltages( - struct cpr3_regulator *vreg, int *volt_adjust) +static int cpr3_msm8996_mmss_adjust_target_quotients( + struct cpr3_regulator *vreg) { struct cpr3_msm8996_mmss_fuses *fuse = vreg->platform_fuses; const struct cpr3_fuse_param (*offset_param)[2]; - u32 *corner_map; int *volt_offset; - int rc = 0, i, fuse_len; - - if (!of_find_property(vreg->of_node, - "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) { - /* No closed-loop offset required. */ - return 0; - } + int i, fuse_len, rc = 0; - corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map), - GFP_KERNEL); volt_offset = kcalloc(vreg->fuse_corner_count, sizeof(*volt_offset), GFP_KERNEL); - if (!corner_map || !volt_offset) { - rc = -ENOMEM; - goto done; - } - - rc = cpr3_parse_corner_array_property(vreg, - "qcom,cpr-fused-closed-loop-voltage-adjustment-map", - 1, corner_map); - if (rc) - goto done; + if (!volt_offset) + return -ENOMEM; offset_param = cpr3_ctrl_is_msm8998(vreg->thread->ctrl) ? msm8998_mmss_offset_voltage_param @@ -507,223 +486,11 @@ static int cpr3_msm8996_mmss_apply_closed_loop_offset_voltages( i, volt_offset[i]); } - for (i = 0; i < vreg->corner_count; i++) { - if (corner_map[i] == 0) { - continue; - } else if (corner_map[i] > vreg->fuse_corner_count) { - cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n", - i, corner_map[i]); - rc = -EINVAL; - goto done; - } - - volt_adjust[i] += volt_offset[corner_map[i] - 1]; - } + rc = cpr3_adjust_target_quotients(vreg, volt_offset); + if (rc) + cpr3_err(vreg, "adjust target quotients failed, rc=%d\n", rc); -done: - kfree(corner_map); kfree(volt_offset); - - return rc; -} - -/** - * cpr3_mmss_enforce_inc_quotient_monotonicity() - Ensure that target quotients - * increase monotonically from lower to higher corners - * @vreg: Pointer to the CPR3 regulator - * - * Return: 0 on success, errno on failure - */ -static void cpr3_mmss_enforce_inc_quotient_monotonicity( - struct cpr3_regulator *vreg) -{ - int i, j; - - for (i = 1; i < vreg->corner_count; i++) { - for (j = 0; j < CPR3_RO_COUNT; j++) { - if (vreg->corner[i].target_quot[j] - && vreg->corner[i].target_quot[j] - < vreg->corner[i - 1].target_quot[j]) { - cpr3_debug(vreg, "corner %d RO%u target quot=%u < corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", - i, j, - vreg->corner[i].target_quot[j], - i - 1, j, - vreg->corner[i - 1].target_quot[j], - i, j, - vreg->corner[i - 1].target_quot[j]); - vreg->corner[i].target_quot[j] - = vreg->corner[i - 1].target_quot[j]; - } - } - } -} - -/** - * cpr3_mmss_enforce_dec_quotient_monotonicity() - Ensure that target quotients - * decrease monotonically from higher to lower corners - * @vreg: Pointer to the CPR3 regulator - * - * Return: 0 on success, errno on failure - */ -static void cpr3_mmss_enforce_dec_quotient_monotonicity( - struct cpr3_regulator *vreg) -{ - int i, j; - - for (i = vreg->corner_count - 2; i >= 0; i--) { - for (j = 0; j < CPR3_RO_COUNT; j++) { - if (vreg->corner[i + 1].target_quot[j] - && vreg->corner[i].target_quot[j] - > vreg->corner[i + 1].target_quot[j]) { - cpr3_debug(vreg, "corner %d RO%u target quot=%u > corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", - i, j, - vreg->corner[i].target_quot[j], - i + 1, j, - vreg->corner[i + 1].target_quot[j], - i, j, - vreg->corner[i + 1].target_quot[j]); - vreg->corner[i].target_quot[j] - = vreg->corner[i + 1].target_quot[j]; - } - } - } -} - -/** - * _cpr3_mmss_adjust_target_quotients() - adjust the target quotients for each - * corner of the regulator according to input adjustment and - * scaling arrays - * @vreg: Pointer to the CPR3 regulator - * @volt_adjust: Pointer to an array of closed-loop voltage adjustments - * with units of microvolts. The array must have - * vreg->corner_count number of elements. - * @ro_scale: Pointer to a flattened 2D array of RO scaling factors. - * The array must have an inner dimension of CPR3_RO_COUNT - * and an outer dimension of vreg->corner_count - * @label: Null terminated string providing a label for the type - * of adjustment. - * - * Return: true if any corners received a positive voltage adjustment (> 0), - * else false - */ -static bool _cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, - const int *volt_adjust, const int *ro_scale, const char *label) -{ - int i, j, quot_adjust; - bool is_increasing = false; - u32 prev_quot; - - for (i = 0; i < vreg->corner_count; i++) { - for (j = 0; j < CPR3_RO_COUNT; j++) { - if (vreg->corner[i].target_quot[j]) { - quot_adjust = cpr3_quot_adjustment( - ro_scale[i * CPR3_RO_COUNT + j], - volt_adjust[i]); - if (quot_adjust) { - prev_quot = vreg->corner[i]. - target_quot[j]; - vreg->corner[i].target_quot[j] - += quot_adjust; - cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n", - i, j, label, prev_quot, - vreg->corner[i].target_quot[j], - volt_adjust[i]); - } - } - } - if (volt_adjust[i] > 0) - is_increasing = true; - } - - return is_increasing; -} - -/** - * cpr3_mmss_adjust_target_quotients() - adjust the target quotients for each - * corner according to device tree values and fuse values - * @vreg: Pointer to the CPR3 regulator - * - * Return: 0 on success, errno on failure - */ -static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg) -{ - int i, rc; - int *volt_adjust, *ro_scale; - bool explicit_adjustment, fused_adjustment, is_increasing; - - explicit_adjustment = of_find_property(vreg->of_node, - "qcom,cpr-closed-loop-voltage-adjustment", NULL); - fused_adjustment = of_find_property(vreg->of_node, - "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL); - - if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) { - /* No adjustment required. */ - return 0; - } else if (!of_find_property(vreg->of_node, - "qcom,cpr-ro-scaling-factor", NULL)) { - cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n"); - return -EINVAL; - } - - volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust), - GFP_KERNEL); - ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT, - sizeof(*ro_scale), GFP_KERNEL); - if (!volt_adjust || !ro_scale) { - rc = -ENOMEM; - goto done; - } - - rc = cpr3_parse_corner_array_property(vreg, - "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale); - if (rc) { - cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n", - rc); - goto done; - } - - for (i = 0; i < vreg->corner_count; i++) - memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT], - sizeof(*ro_scale) * CPR3_RO_COUNT); - - if (explicit_adjustment) { - rc = cpr3_parse_corner_array_property(vreg, - "qcom,cpr-closed-loop-voltage-adjustment", - 1, volt_adjust); - if (rc) { - cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", - rc); - goto done; - } - - _cpr3_mmss_adjust_target_quotients(vreg, volt_adjust, ro_scale, - "from DT"); - cpr3_mmss_enforce_inc_quotient_monotonicity(vreg); - } - - if (fused_adjustment) { - memset(volt_adjust, 0, - sizeof(*volt_adjust) * vreg->corner_count); - - rc = cpr3_msm8996_mmss_apply_closed_loop_offset_voltages(vreg, - volt_adjust); - if (rc) { - cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n", - rc); - goto done; - } - - is_increasing = _cpr3_mmss_adjust_target_quotients(vreg, - volt_adjust, ro_scale, "from fuse"); - if (is_increasing) - cpr3_mmss_enforce_inc_quotient_monotonicity(vreg); - else - cpr3_mmss_enforce_dec_quotient_monotonicity(vreg); - } - -done: - kfree(volt_adjust); - kfree(ro_scale); return rc; } @@ -1112,7 +879,7 @@ static int cpr3_mmss_init_thread(struct cpr3_thread *thread) return rc; } - rc = cpr3_mmss_adjust_target_quotients(vreg); + rc = cpr3_msm8996_mmss_adjust_target_quotients(vreg); if (rc) { cpr3_err(vreg, "unable to adjust target quotients, rc=%d\n", rc); diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index 2e997b526b90..f0230b8ae2e5 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.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 @@ -904,6 +904,8 @@ int cpr3_apm_init(struct cpr3_controller *ctrl); int cpr3_mem_acc_init(struct cpr3_regulator *vreg); void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg); void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg); +int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + int *fuse_volt_adjust); #else @@ -1084,6 +1086,12 @@ static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg) { } +static inline int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + int *fuse_volt_adjust) +{ + return 0; +} + #endif /* CONFIG_REGULATOR_CPR3 */ #endif /* __REGULATOR_CPR_REGULATOR_H__ */ diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 7f712d4f6ee4..0a1a1c56bd16 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -2147,3 +2147,259 @@ void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg) corner->ceiling_volt, corner->open_loop_volt); } } + +/** + * cpr3_apply_closed_loop_offset_voltages() - modify the closed-loop voltage + * adjustments by the amounts that are needed for this + * fuse combo + * @vreg: Pointer to the CPR3 regulator + * @volt_adjust: Array of closed-loop voltage adjustment values of length + * vreg->corner_count which is further adjusted based upon + * offset voltage fuse values. + * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length + * vreg->fuse_corner_count. + * + * Return: 0 on success, errno on failure + */ +static int cpr3_apply_closed_loop_offset_voltages(struct cpr3_regulator *vreg, + int *volt_adjust, int *fuse_volt_adjust) +{ + u32 *corner_map; + int rc = 0, i; + + if (!of_find_property(vreg->of_node, + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) { + /* No closed-loop offset required. */ + return 0; + } + + corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map), + GFP_KERNEL); + if (!corner_map) + return -ENOMEM; + + rc = cpr3_parse_corner_array_property(vreg, + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", + 1, corner_map); + if (rc) + goto done; + + for (i = 0; i < vreg->corner_count; i++) { + if (corner_map[i] == 0) { + continue; + } else if (corner_map[i] > vreg->fuse_corner_count) { + cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n", + i, corner_map[i]); + rc = -EINVAL; + goto done; + } + + volt_adjust[i] += fuse_volt_adjust[corner_map[i] - 1]; + } + +done: + kfree(corner_map); + return rc; +} + +/** + * cpr3_enforce_inc_quotient_monotonicity() - Ensure that target quotients + * increase monotonically from lower to higher corners + * @vreg: Pointer to the CPR3 regulator + * + * Return: 0 on success, errno on failure + */ +static void cpr3_enforce_inc_quotient_monotonicity(struct cpr3_regulator *vreg) +{ + int i, j; + + for (i = 1; i < vreg->corner_count; i++) { + for (j = 0; j < CPR3_RO_COUNT; j++) { + if (vreg->corner[i].target_quot[j] + && vreg->corner[i].target_quot[j] + < vreg->corner[i - 1].target_quot[j]) { + cpr3_debug(vreg, "corner %d RO%u target quot=%u < corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", + i, j, + vreg->corner[i].target_quot[j], + i - 1, j, + vreg->corner[i - 1].target_quot[j], + i, j, + vreg->corner[i - 1].target_quot[j]); + vreg->corner[i].target_quot[j] + = vreg->corner[i - 1].target_quot[j]; + } + } + } +} + +/** + * cpr3_enforce_dec_quotient_monotonicity() - Ensure that target quotients + * decrease monotonically from higher to lower corners + * @vreg: Pointer to the CPR3 regulator + * + * Return: 0 on success, errno on failure + */ +static void cpr3_enforce_dec_quotient_monotonicity(struct cpr3_regulator *vreg) +{ + int i, j; + + for (i = vreg->corner_count - 2; i >= 0; i--) { + for (j = 0; j < CPR3_RO_COUNT; j++) { + if (vreg->corner[i + 1].target_quot[j] + && vreg->corner[i].target_quot[j] + > vreg->corner[i + 1].target_quot[j]) { + cpr3_debug(vreg, "corner %d RO%u target quot=%u > corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", + i, j, + vreg->corner[i].target_quot[j], + i + 1, j, + vreg->corner[i + 1].target_quot[j], + i, j, + vreg->corner[i + 1].target_quot[j]); + vreg->corner[i].target_quot[j] + = vreg->corner[i + 1].target_quot[j]; + } + } + } +} + +/** + * _cpr3_adjust_target_quotients() - adjust the target quotients for each + * corner of the regulator according to input adjustment and + * scaling arrays + * @vreg: Pointer to the CPR3 regulator + * @volt_adjust: Pointer to an array of closed-loop voltage adjustments + * with units of microvolts. The array must have + * vreg->corner_count number of elements. + * @ro_scale: Pointer to a flattened 2D array of RO scaling factors. + * The array must have an inner dimension of CPR3_RO_COUNT + * and an outer dimension of vreg->corner_count + * @label: Null terminated string providing a label for the type + * of adjustment. + * + * Return: true if any corners received a positive voltage adjustment (> 0), + * else false + */ +static bool _cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + const int *volt_adjust, const int *ro_scale, const char *label) +{ + int i, j, quot_adjust; + bool is_increasing = false; + u32 prev_quot; + + for (i = 0; i < vreg->corner_count; i++) { + for (j = 0; j < CPR3_RO_COUNT; j++) { + if (vreg->corner[i].target_quot[j]) { + quot_adjust = cpr3_quot_adjustment( + ro_scale[i * CPR3_RO_COUNT + j], + volt_adjust[i]); + if (quot_adjust) { + prev_quot = vreg->corner[i]. + target_quot[j]; + vreg->corner[i].target_quot[j] + += quot_adjust; + cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n", + i, j, label, prev_quot, + vreg->corner[i].target_quot[j], + volt_adjust[i]); + } + } + } + if (volt_adjust[i] > 0) + is_increasing = true; + } + + return is_increasing; +} + +/** + * cpr3_adjust_target_quotients() - adjust the target quotients for each + * corner according to device tree values and fuse values + * @vreg: Pointer to the CPR3 regulator + * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length + * vreg->fuse_corner_count. This parameter could be null + * pointer when no fused adjustments are needed. + * + * Return: 0 on success, errno on failure + */ +int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg, + int *fuse_volt_adjust) +{ + int i, rc; + int *volt_adjust, *ro_scale; + bool explicit_adjustment, fused_adjustment, is_increasing; + + explicit_adjustment = of_find_property(vreg->of_node, + "qcom,cpr-closed-loop-voltage-adjustment", NULL); + fused_adjustment = of_find_property(vreg->of_node, + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL); + + if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) { + /* No adjustment required. */ + return 0; + } else if (!of_find_property(vreg->of_node, + "qcom,cpr-ro-scaling-factor", NULL)) { + cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n"); + return -EINVAL; + } + + volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust), + GFP_KERNEL); + ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT, + sizeof(*ro_scale), GFP_KERNEL); + if (!volt_adjust || !ro_scale) { + rc = -ENOMEM; + goto done; + } + + rc = cpr3_parse_corner_array_property(vreg, + "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale); + if (rc) { + cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n", + rc); + goto done; + } + + for (i = 0; i < vreg->corner_count; i++) + memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT], + sizeof(*ro_scale) * CPR3_RO_COUNT); + + if (explicit_adjustment) { + rc = cpr3_parse_corner_array_property(vreg, + "qcom,cpr-closed-loop-voltage-adjustment", + 1, volt_adjust); + if (rc) { + cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", + rc); + goto done; + } + + _cpr3_adjust_target_quotients(vreg, volt_adjust, ro_scale, + "from DT"); + cpr3_enforce_inc_quotient_monotonicity(vreg); + } + + if (fused_adjustment && fuse_volt_adjust) { + memset(volt_adjust, 0, + sizeof(*volt_adjust) * vreg->corner_count); + + rc = cpr3_apply_closed_loop_offset_voltages(vreg, volt_adjust, + fuse_volt_adjust); + if (rc) { + cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n", + rc); + goto done; + } + + is_increasing = _cpr3_adjust_target_quotients(vreg, volt_adjust, + ro_scale, "from fuse"); + if (is_increasing) + cpr3_enforce_inc_quotient_monotonicity(vreg); + else + cpr3_enforce_dec_quotient_monotonicity(vreg); + } + +done: + kfree(volt_adjust); + kfree(ro_scale); + return rc; +} diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c index 2843f71745fc..f8e3ea40ddac 100644 --- a/drivers/regulator/cpr4-mmss-ldo-regulator.c +++ b/drivers/regulator/cpr4-mmss-ldo-regulator.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 @@ -417,6 +417,45 @@ done: } /** + * cpr4_sdm660_mmss_adjust_target_quotients() - adjust the target quotients for + * each corner according to device tree values and fuse values + * @vreg: Pointer to the CPR3 regulator + * + * Return: 0 on success, errno on failure + */ +static int cpr4_sdm660_mmss_adjust_target_quotients(struct cpr3_regulator *vreg) +{ + struct cpr4_sdm660_mmss_fuses *fuse = vreg->platform_fuses; + const struct cpr3_fuse_param (*offset_param)[2]; + int *volt_offset; + int i, fuse_len, rc = 0; + + volt_offset = kcalloc(vreg->fuse_corner_count, sizeof(*volt_offset), + GFP_KERNEL); + if (!volt_offset) + return -ENOMEM; + + offset_param = sdm660_mmss_offset_voltage_param; + for (i = 0; i < vreg->fuse_corner_count; i++) { + fuse_len = offset_param[i][0].bit_end + 1 + - offset_param[i][0].bit_start; + volt_offset[i] = cpr3_convert_open_loop_voltage_fuse( + 0, SDM660_MMSS_OFFSET_FUSE_STEP_VOLT, + fuse->offset_voltage[i], fuse_len); + if (volt_offset[i]) + cpr3_info(vreg, "fuse_corner[%d] offset=%7d uV\n", + i, volt_offset[i]); + } + + rc = cpr3_adjust_target_quotients(vreg, volt_offset); + if (rc) + cpr3_err(vreg, "adjust target quotients failed, rc=%d\n", rc); + + kfree(volt_offset); + return rc; +} + +/** * cpr4_mmss_print_settings() - print out MMSS CPR configuration settings into * the kernel log for debugging purposes * @vreg: Pointer to the CPR3 regulator @@ -489,6 +528,13 @@ static int cpr4_mmss_init_thread(struct cpr3_thread *thread) return rc; } + rc = cpr4_sdm660_mmss_adjust_target_quotients(vreg); + if (rc) { + cpr3_err(vreg, "unable to adjust target quotients, rc=%d\n", + rc); + return rc; + } + rc = cpr4_sdm660_mmss_calculate_open_loop_voltages(vreg); if (rc) { cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n", diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 8dbe3080873c..40c62c355188 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.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 @@ -333,7 +333,7 @@ enum ibb_mode { IBB_HW_SW_CONTROL, }; -static const int ibb_discharge_resistor_table[] = { +static const int ibb_dischg_res_table[] = { 300, 64, 32, @@ -946,38 +946,27 @@ static int qpnp_ibb_soft_start_ctl_v1(struct qpnp_labibb *labibb, rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-discharge-resistor", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(ibb_dischg_res_table); val++) { + if (ibb_dischg_res_table[val] == tmp) + break; + } - if (rc < 0) { - pr_err("qcom,qpnp-ibb-discharge-resistor is missing, rc = %d\n", - rc); - return rc; - } - - if (labibb->mode == QPNP_LABIBB_AMOLED_MODE) { - /* - * AMOLED mode needs ibb discharge resistor to be - * configured for 300KOhm - */ - if (tmp < ibb_discharge_resistor_table[0]) - tmp = ibb_discharge_resistor_table[0]; - } - - for (val = 0; val < ARRAY_SIZE(ibb_discharge_resistor_table); val++) - if (ibb_discharge_resistor_table[val] == tmp) - break; + if (val == ARRAY_SIZE(ibb_dischg_res_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-discharge-resistor\n"); + return -EINVAL; + } - if (val == ARRAY_SIZE(ibb_discharge_resistor_table)) { - pr_err("Invalid value in qcom,qpnp-ibb-discharge-resistor\n"); - return -EINVAL; + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_SOFT_START_CTL, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_IBB_SOFT_START_CTL, rc); + return rc; + } } - rc = qpnp_labibb_write(labibb, labibb->ibb_base + - REG_IBB_SOFT_START_CTL, &val, 1); - if (rc < 0) - pr_err("write to register %x failed rc = %d\n", - REG_IBB_SOFT_START_CTL, rc); - - return rc; + return 0; } static int qpnp_ibb_soft_start_ctl_v2(struct qpnp_labibb *labibb, @@ -2643,7 +2632,8 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, return rc; } - if (labibb->mode == QPNP_LABIBB_AMOLED_MODE) { + if (labibb->mode == QPNP_LABIBB_AMOLED_MODE && + labibb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) { /* * default to 1.5 times current gain if * user doesn't specify the current-sense @@ -2684,7 +2674,7 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, val = (labibb->standalone) ? 0 : LAB_IBB_EN_RDY_EN; rc = qpnp_labibb_sec_write(labibb, labibb->lab_base, - REG_LAB_IBB_EN_RDY, val); + REG_LAB_IBB_EN_RDY, val); if (rc < 0) { pr_err("qpnp_lab_sec_write register %x failed rc = %d\n", @@ -3331,7 +3321,7 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, struct regulator_init_data *init_data; struct regulator_desc *rdesc = &labibb->ibb_vreg.rdesc; struct regulator_config cfg = {}; - u8 val, ibb_enable_ctl; + u8 val, ibb_enable_ctl, index; u32 tmp; if (!of_node) { @@ -3407,7 +3397,8 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, * before by the bootloader. */ if (labibb->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) - labibb->swire_control = val & IBB_ENABLE_CTL_SWIRE_RDY; + labibb->swire_control = ibb_enable_ctl & + IBB_ENABLE_CTL_SWIRE_RDY; if (ibb_enable_ctl & (IBB_ENABLE_CTL_SWIRE_RDY | IBB_ENABLE_CTL_MODULE_EN)) { @@ -3460,11 +3451,11 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return rc; } - labibb->ibb_vreg.pwrup_dly = ibb_pwrup_dly_table[ - (val & - IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK)]; - labibb->ibb_vreg.pwrdn_dly = ibb_pwrdn_dly_table[val & - IBB_PWRUP_PWRDN_CTL_1_DLY2_MASK]; + index = (val & IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK) >> + IBB_PWRUP_PWRDN_CTL_1_DLY1_SHIFT; + labibb->ibb_vreg.pwrup_dly = ibb_pwrup_dly_table[index]; + index = val & IBB_PWRUP_PWRDN_CTL_1_DLY2_MASK; + labibb->ibb_vreg.pwrdn_dly = ibb_pwrdn_dly_table[index]; labibb->ibb_vreg.vreg_enabled = 1; } else { @@ -3829,9 +3820,10 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) } } dev_set_drvdata(&pdev->dev, labibb); - pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d\n", + pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n", labibb->lab_vreg.vreg_enabled, - labibb->ibb_vreg.vreg_enabled); + labibb->ibb_vreg.vreg_enabled, + labibb->swire_control); return 0; diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c index dd52b74b11b6..587538cca474 100644 --- a/drivers/regulator/qpnp-oledb-regulator.c +++ b/drivers/regulator/qpnp-oledb-regulator.c @@ -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 @@ -152,6 +152,8 @@ struct qpnp_oledb { struct qpnp_oledb_fast_precharge_ctl fast_prechg_ctl; u32 base; + u8 mod_enable; + u8 ext_pinctl_state; int current_voltage; int default_voltage; int vout_mv; @@ -162,10 +164,8 @@ struct qpnp_oledb { int nlimit_enable; int sc_en; int sc_dbnc_time; - bool mod_enable; bool swire_control; bool ext_pin_control; - bool ext_pinctl_state; bool dynamic_ext_pinctl_config; bool pbs_control; }; @@ -292,12 +292,15 @@ static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev) * Disable ext-pin-ctl after display-supply is turned off. This is to * avoid glitches on the external pin. */ - if (oledb->ext_pin_control && oledb->dynamic_ext_pinctl_config) { - rc = qpnp_oledb_masked_write(oledb, oledb->base + + if (oledb->ext_pin_control) { + if (oledb->dynamic_ext_pinctl_config) { + rc = qpnp_oledb_masked_write(oledb, oledb->base + OLEDB_EXT_PIN_CTL, OLEDB_EXT_PIN_CTL_BIT, 0); - if (rc < 0) { - pr_err("Failed to write EXT_PIN_CTL rc=%d\n", rc); - return rc; + if (rc < 0) { + pr_err("Failed to write EXT_PIN_CTL rc=%d\n", + rc); + return rc; + } } pr_debug("ext-pin-ctrl mode disabled\n"); } else { @@ -635,14 +638,14 @@ static int qpnp_oledb_hw_init(struct qpnp_oledb *oledb) } rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_MODULE_ENABLE, - (u8 *)&oledb->mod_enable, 1); + &oledb->mod_enable, 1); if (rc < 0) { pr_err("Failed to read MODULE_ENABLE rc=%d\n", rc); return rc; } rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_EXT_PIN_CTL, - (u8 *)&oledb->ext_pinctl_state, 1); + &oledb->ext_pinctl_state, 1); if (rc < 0) { pr_err("Failed to read EXT_PIN_CTL rc=%d\n", rc); return rc; @@ -652,7 +655,12 @@ static int qpnp_oledb_hw_init(struct qpnp_oledb *oledb) if (rc < 0) return rc; - if (!((val & OLEDB_EXT_PIN_CTL_BIT) || oledb->mod_enable)) { + /* + * Go through if the module is not enabled either through + * external pin control or SPMI interface. + */ + if (!((oledb->ext_pinctl_state & OLEDB_EXT_PIN_CTL_BIT) + || oledb->mod_enable)) { if (oledb->warmup_delay != -EINVAL) { for (i = 0; i < ARRAY_SIZE(oledb_warmup_dly_ns); i++) { if (oledb->warmup_delay == diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 070d27df6b49..85f82b2251c1 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -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 @@ -14,6 +14,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/blkdev.h> +#include <linux/spinlock.h> #include <crypto/ice.h> #include "ufs-qcom-ice.h" @@ -168,6 +169,7 @@ out: static void ufs_qcom_ice_cfg_work(struct work_struct *work) { + unsigned long flags; struct ice_data_setting ice_set; struct ufs_qcom_host *qcom_host = container_of(work, struct ufs_qcom_host, ice_cfg_work); @@ -185,12 +187,17 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work) qcom_host->ice.vops->config_start(qcom_host->ice.pdev, qcom_host->req_pending, &ice_set, false); + spin_lock_irqsave(&qcom_host->ice_work_lock, flags); + qcom_host->req_pending = NULL; + spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); + /* * Resume with requests processing. We assume config_start has been * successful, but even if it wasn't we still must resume in order to * allow for the request to be retried. */ ufshcd_scsi_unblock_requests(qcom_host->hba); + } /** @@ -246,6 +253,7 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, struct ice_data_setting ice_set; char cmd_op = cmd->cmnd[0]; int err; + unsigned long flags; if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { dev_dbg(qcom_host->hba->dev, "%s: ice device is not enabled\n", @@ -272,14 +280,36 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", __func__); - qcom_host->req_pending = cmd->request; - if (schedule_work(&qcom_host->ice_cfg_work)) + + spin_lock_irqsave( + &qcom_host->ice_work_lock, flags); + + if (!qcom_host->req_pending) { ufshcd_scsi_block_requests( qcom_host->hba); + qcom_host->req_pending = cmd->request; + if (!schedule_work( + &qcom_host->ice_cfg_work)) { + qcom_host->req_pending = NULL; + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + ufshcd_scsi_unblock_requests( + qcom_host->hba); + return err; + } + } + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, flags); + } else { - dev_err(qcom_host->hba->dev, - "%s: error in ice_vops->config %d\n", - __func__, err); + if (err != -EBUSY) + dev_err(qcom_host->hba->dev, + "%s: error in ice_vops->config %d\n", + __func__, err); } return err; @@ -320,6 +350,7 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, unsigned int bypass = 0; struct request *req; char cmd_op; + unsigned long flags; if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { dev_dbg(dev, "%s: ice device is not enabled\n", __func__); @@ -365,12 +396,43 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, * request processing. */ if (err == -EAGAIN) { - qcom_host->req_pending = req; - if (schedule_work(&qcom_host->ice_cfg_work)) + + dev_dbg(qcom_host->hba->dev, + "%s: scheduling task for ice setup\n", + __func__); + + spin_lock_irqsave( + &qcom_host->ice_work_lock, flags); + + if (!qcom_host->req_pending) { ufshcd_scsi_block_requests( + qcom_host->hba); + qcom_host->req_pending = cmd->request; + if (!schedule_work( + &qcom_host->ice_cfg_work)) { + qcom_host->req_pending = NULL; + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + ufshcd_scsi_unblock_requests( qcom_host->hba); + return err; + } + } + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, flags); + + } else { + if (err != -EBUSY) + dev_err(qcom_host->hba->dev, + "%s: error in ice_vops->config %d\n", + __func__, err); } - goto out; + + return err; } } diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 2b0731b8358c..03b222d8be93 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, 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 @@ -1981,6 +1981,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) /* Make a two way bind between the qcom host and the hba */ host->hba = hba; + spin_lock_init(&host->ice_work_lock); + ufshcd_set_variant(hba, host); err = ufs_qcom_ice_get_dev(host); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 394de8302fd2..74d8a7a30ad6 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.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 @@ -370,6 +370,7 @@ struct ufs_qcom_host { u32 dbg_print_en; struct ufs_qcom_testbus testbus; + spinlock_t ice_work_lock; struct work_struct ice_cfg_work; struct request *req_pending; }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 1e6db2a76fa5..d4acc3c911f5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -48,6 +48,7 @@ #include "ufshci.h" #include "ufs_quirks.h" #include "ufs-debugfs.h" +#include "ufs-qcom.h" #define CREATE_TRACE_POINTS #include <trace/events/ufs.h> @@ -2884,11 +2885,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) "%s: failed to compose upiu %d\n", __func__, err); - lrbp->cmd = NULL; - clear_bit_unlock(tag, &hba->lrb_in_use); - ufshcd_release_all(hba); - ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); - goto out; + lrbp->cmd = NULL; + clear_bit_unlock(tag, &hba->lrb_in_use); + ufshcd_release_all(hba); + ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); + goto out; } err = ufshcd_map_sg(lrbp); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 281e83d90970..86e29199b2b1 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -625,6 +625,14 @@ config MSM_ADSP_LOADER for the platforms that use APRv2. Say M if you want to enable this module. +config MSM_CDSP_LOADER + tristate "CDSP loader support" + help + Enable CDSP image loader. + The CDSP loader brings CDSP out of reset + during boot. + Say M if you want to enable this module. + config MSM_PERFORMANCE tristate "msm_performance driver to support perflock request" help diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 84f346385f18..f2d2aece6846 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.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 @@ -51,7 +51,7 @@ #define RPM_MAX_TOC_ENTRIES 20 #define RPM_FIFO_ADDR_ALIGN_BYTES 3 #define TRACER_PKT_FEATURE BIT(2) - +#define DEFERRED_CMDS_THRESHOLD 25 /** * enum command_types - definition of the types of commands sent/received * @VERSION_CMD: Version and feature set supported @@ -181,6 +181,7 @@ struct mailbox_config_info { * processing. * @deferred_cmds: List of deferred commands that need to be * processed in process context. + * @deferred_cmds_cnt: Number of deferred commands in queue. * @num_pw_states: Size of @ramp_time_us. * @ramp_time_us: Array of ramp times in microseconds where array * index position represents a power state. @@ -218,6 +219,7 @@ struct edge_info { bool in_ssr; spinlock_t rx_lock; struct list_head deferred_cmds; + uint32_t deferred_cmds_cnt; uint32_t num_pw_states; unsigned long *ramp_time_us; struct mailbox_config_info *mailbox; @@ -768,6 +770,7 @@ static bool queue_cmd(struct edge_info *einfo, void *cmd, void *data) d_cmd->param2 = _cmd->param2; d_cmd->data = data; list_add_tail(&d_cmd->list_node, &einfo->deferred_cmds); + einfo->deferred_cmds_cnt++; queue_kthread_work(&einfo->kworker, &einfo->kwork); return true; } @@ -877,10 +880,15 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) if (einfo->in_ssr) break; + if (atomic_ctx && !einfo->intentless && + einfo->deferred_cmds_cnt >= DEFERRED_CMDS_THRESHOLD) + break; + if (!atomic_ctx && !list_empty(&einfo->deferred_cmds)) { d_cmd = list_first_entry(&einfo->deferred_cmds, struct deferred_cmd, list_node); list_del(&d_cmd->list_node); + einfo->deferred_cmds_cnt--; cmd.id = d_cmd->id; cmd.param1 = d_cmd->param1; cmd.param2 = d_cmd->param2; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 44d086656a12..873416944b19 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1661,10 +1661,8 @@ static int icnss_driver_event_server_arrive(void *data) if (ret < 0) goto err_setup_msa; - ret = wlfw_dynamic_feature_mask_send_sync_msg(penv, - dynamic_feature_mask); - if (ret < 0) - goto err_setup_msa; + wlfw_dynamic_feature_mask_send_sync_msg(penv, + dynamic_feature_mask); icnss_init_vph_monitor(penv); @@ -2068,7 +2066,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, icnss_pr_info("Modem went down, state: %lx\n", priv->state); - event_data = kzalloc(sizeof(*data), GFP_KERNEL); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); @@ -2143,7 +2141,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data, priv->state); - event_data = kzalloc(sizeof(*data), GFP_KERNEL); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index 5726c3277456..76f9ed046120 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,6 +38,7 @@ static void mem_share_svc_recv_msg(struct work_struct *work); static DECLARE_DELAYED_WORK(work_recv_msg, mem_share_svc_recv_msg); static struct workqueue_struct *mem_share_svc_workqueue; static uint64_t bootup_request; +static bool ramdump_event; static void *memshare_ramdump_dev[MAX_CLIENTS]; static struct device *memshare_dev[MAX_CLIENTS]; @@ -337,18 +338,25 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, bootup_request++; break; + case SUBSYS_RAMDUMP_NOTIFICATION: + ramdump_event = 1; + break; + case SUBSYS_BEFORE_POWERUP: - if (_cmd) + if (_cmd) { notifdata = (struct notif_data *) _cmd; - else + } else { + ramdump_event = 0; break; + } - if (notifdata->enable_ramdump) { + if (notifdata->enable_ramdump && ramdump_event) { pr_info("memshare: %s, Ramdump collection is enabled\n", __func__); ret = mem_share_do_ramdump(); if (ret) pr_err("Ramdump collection failed\n"); + ramdump_event = 0; } break; diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index 9c4d89ac704d..d3f44ab75f67 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -1222,12 +1222,18 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d cached heap exceeds size\n", num); BUG(); } - if (hdr->host0 == SMEM_COMM_HOST && hdr->host1 == SMEM_COMM_HOST) { - comm_partition.partition_num = num; - comm_partition.offset = entry->offset; - comm_partition.size_cacheline = entry->size_cacheline; - SMEM_INFO("Common Partition %d offset:%x\n", num, - entry->offset); + if (is_comm_partition) { + if (hdr->host0 == SMEM_COMM_HOST + && hdr->host1 == SMEM_COMM_HOST) { + comm_partition.partition_num = num; + comm_partition.offset = entry->offset; + comm_partition.size_cacheline = entry->size_cacheline; + SMEM_INFO("Common Partition %d offset:%x\n", num, + entry->offset); + } else { + LOG_ERR("Smem Comm partition hosts don't match TOC\n"); + WARN_ON(1); + } return; } if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) { diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile index f3505bab1a34..8c5b0d0e81c8 100644 --- a/drivers/soc/qcom/qdsp6v2/Makefile +++ b/drivers/soc/qcom/qdsp6v2/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o obj-$(CONFIG_MSM_QDSP6_SSR) += audio_ssr.o obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.o obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += audio_notifier.o +obj-$(CONFIG_MSM_CDSP_LOADER) += cdsp-loader.o diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c new file mode 100644 index 000000000000..0b801c5cd7dd --- /dev/null +++ b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2012-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 + * 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/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/sysfs.h> +#include <soc/qcom/subsystem_restart.h> + +#define BOOT_CMD 1 +#define IMAGE_UNLOAD_CMD 0 + +#define CDSP_SUBSYS_DOWN 0 +#define CDSP_SUBSYS_LOADED 1 + +static ssize_t cdsp_boot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); + +struct cdsp_loader_private { + void *pil_h; + struct kobject *boot_cdsp_obj; + struct attribute_group *attr_group; +}; + +static struct kobj_attribute cdsp_boot_attribute = + __ATTR(boot, 0220, NULL, cdsp_boot_store); + +static struct attribute *attrs[] = { + &cdsp_boot_attribute.attr, + NULL, +}; + +static u32 cdsp_state = CDSP_SUBSYS_DOWN; +static struct platform_device *cdsp_private; +static void cdsp_loader_unload(struct platform_device *pdev); + +static int cdsp_loader_do(struct platform_device *pdev) +{ + + struct cdsp_loader_private *priv = NULL; + + int rc = 0; + const char *img_name; + + if (!pdev) { + dev_err(&pdev->dev, "%s: Platform device null\n", __func__); + goto fail; + } + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, + "%s: Device tree information missing\n", __func__); + + goto fail; + } + + rc = of_property_read_string(pdev->dev.of_node, + "qcom,proc-img-to-load", + &img_name); + + if (rc) + goto fail; + + if (!strcmp(img_name, "cdsp")) { + /* cdsp_state always returns "0".*/ + if (cdsp_state == CDSP_SUBSYS_DOWN) { + priv = platform_get_drvdata(pdev); + if (!priv) { + dev_err(&pdev->dev, + " %s: Private data get failed\n", __func__); + goto fail; + } + + priv->pil_h = subsystem_get("cdsp"); + if (IS_ERR(priv->pil_h)) { + dev_err(&pdev->dev, "%s: pil get failed,\n", + __func__); + goto fail; + } + + /* Set the state of the CDSP.*/ + cdsp_state = CDSP_SUBSYS_LOADED; + } else if (cdsp_state == CDSP_SUBSYS_LOADED) { + dev_dbg(&pdev->dev, + "%s: CDSP state = %x\n", __func__, cdsp_state); + } + + dev_dbg(&pdev->dev, "%s: CDSP image is loaded\n", __func__); + return rc; + } + +fail: + dev_err(&pdev->dev, "%s: CDSP image loading failed\n", __func__); + return rc; +} + + +static ssize_t cdsp_boot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + int boot = 0, ret = 0; + + ret = sscanf(buf, "%du", &boot); + + if (ret != 1) + pr_debug("%s: invalid arguments for cdsp_loader.\n", __func__); + + if (boot == BOOT_CMD) { + pr_debug("%s: going to call cdsp_loader_do\n", __func__); + cdsp_loader_do(cdsp_private); + } else if (boot == IMAGE_UNLOAD_CMD) { + pr_debug("%s: going to call adsp_unloader\n", __func__); + cdsp_loader_unload(cdsp_private); + } + return count; +} + +static void cdsp_loader_unload(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + + if (!priv) + return; + + if (priv->pil_h) { + dev_dbg(&pdev->dev, "%s: calling subsystem put\n", __func__); + subsystem_put(priv->pil_h); + priv->pil_h = NULL; + } +} + +static int cdsp_loader_init_sysfs(struct platform_device *pdev) +{ + int ret = -EINVAL; + struct cdsp_loader_private *priv = NULL; + + cdsp_private = NULL; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + return ret; + } + + platform_set_drvdata(pdev, priv); + + priv->pil_h = NULL; + priv->boot_cdsp_obj = NULL; + priv->attr_group = devm_kzalloc(&pdev->dev, + sizeof(*(priv->attr_group)), + GFP_KERNEL); + if (!priv->attr_group) { + dev_err(&pdev->dev, "%s: malloc attr_group failed\n", + __func__); + ret = -ENOMEM; + goto error_return; + } + + priv->attr_group->attrs = attrs; + + priv->boot_cdsp_obj = kobject_create_and_add("boot_cdsp", kernel_kobj); + if (!priv->boot_cdsp_obj) { + dev_err(&pdev->dev, "%s: sysfs create and add failed\n", + __func__); + ret = -ENOMEM; + goto error_return; + } + + ret = sysfs_create_group(priv->boot_cdsp_obj, priv->attr_group); + if (ret) { + dev_err(&pdev->dev, "%s: sysfs create group failed %d\n", + __func__, ret); + goto error_return; + } + + cdsp_private = pdev; + + return 0; + +error_return: + + if (priv->boot_cdsp_obj) { + kobject_del(priv->boot_cdsp_obj); + priv->boot_cdsp_obj = NULL; + } + + return ret; +} + +static int cdsp_loader_remove(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + + if (!priv) + return 0; + + if (priv->pil_h) { + subsystem_put(priv->pil_h); + priv->pil_h = NULL; + } + + if (priv->boot_cdsp_obj) { + sysfs_remove_group(priv->boot_cdsp_obj, priv->attr_group); + kobject_del(priv->boot_cdsp_obj); + priv->boot_cdsp_obj = NULL; + } + + return 0; +} + +static int cdsp_loader_probe(struct platform_device *pdev) +{ + int ret = cdsp_loader_init_sysfs(pdev); + + if (ret != 0) { + dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__); + return ret; + } + + return 0; +} + +static const struct of_device_id cdsp_loader_dt_match[] = { + { .compatible = "qcom,cdsp-loader" }, + { } +}; +MODULE_DEVICE_TABLE(of, cdsp_loader_dt_match); + +static struct platform_driver cdsp_loader_driver = { + .driver = { + .name = "cdsp-loader", + .owner = THIS_MODULE, + .of_match_table = cdsp_loader_dt_match, + }, + .probe = cdsp_loader_probe, + .remove = cdsp_loader_remove, +}; + +static int __init cdsp_loader_init(void) +{ + return platform_driver_register(&cdsp_loader_driver); +} +module_init(cdsp_loader_init); + +static void __exit cdsp_loader_exit(void) +{ + platform_driver_unregister(&cdsp_loader_driver); +} +module_exit(cdsp_loader_exit); + +MODULE_DESCRIPTION("CDSP Loader module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index e7307c46a895..8a501d4d0615 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -215,7 +215,7 @@ static void send_ind_ack(struct work_struct *work) if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) pr_err("QMI request failed 0x%x\n", QMI_RESP_BIT_SHIFT(resp.resp.error)); - pr_debug("Indication ACKed for transid %d, service %s, instance %d!\n", + pr_info("Indication ACKed for transid %d, service %s, instance %d!\n", data->ind_msg.transaction_id, data->ind_msg.service_path, data->instance_id); } @@ -240,7 +240,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, return; } - pr_debug("Indication received from %s, state: 0x%x, trans-id: %d\n", + pr_info("Indication received from %s, state: 0x%x, trans-id: %d\n", ind_msg.service_name, ind_msg.curr_state, ind_msg.transaction_id); diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 27e66dc5d204..1ceded4db79f 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -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 @@ -25,8 +25,10 @@ #include "sound/wcd-dsp-glink.h" #define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink" -#define WDSP_MAX_WRITE_SIZE (512 * 1024) +#define WDSP_MAX_WRITE_SIZE (256 * 1024) #define WDSP_MAX_READ_SIZE (4 * 1024) +#define WDSP_MAX_NO_OF_INTENTS (20) +#define WDSP_MAX_NO_OF_CHANNELS (10) #define MINOR_NUMBER_COUNT 1 #define WDSP_EDGE "wdsp" @@ -532,15 +534,30 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, payload = (u8 *)pkt->payload; no_of_channels = pkt->no_of_channels; + if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) { + dev_info(wpriv->dev, "%s: no_of_channels = %d are limited to %d\n", + __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS); + no_of_channels = WDSP_MAX_NO_OF_CHANNELS; + } ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *), GFP_KERNEL); if (!ch) { ret = -ENOMEM; goto done; } + wpriv->ch = ch; + wpriv->no_of_channels = no_of_channels; for (i = 0; i < no_of_channels; i++) { ch_cfg = (struct wdsp_glink_ch_cfg *)payload; + + if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) { + dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n", + __func__, ch_cfg->no_of_intents); + ret = -EINVAL; + goto err_ch_mem; + } + ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) + (sizeof(u32) * ch_cfg->no_of_intents); ch_size = sizeof(struct wdsp_glink_ch) + @@ -564,8 +581,6 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk); init_waitqueue_head(&ch[i]->ch_connect_wait); } - wpriv->ch = ch; - wpriv->no_of_channels = no_of_channels; INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk); @@ -746,15 +761,17 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, goto done; } - dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count); - - if (count > WDSP_MAX_WRITE_SIZE) { - dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_WRITE_SIZE\n", + if ((count < sizeof(struct wdsp_write_pkt)) || + (count > WDSP_MAX_WRITE_SIZE)) { + dev_err(wpriv->dev, "%s: Invalid count = %zd\n", __func__, count); - count = WDSP_MAX_WRITE_SIZE; + ret = -EINVAL; + goto done; } - tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf); + dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count); + + tx_buf_size = WDSP_MAX_WRITE_SIZE + sizeof(struct wdsp_glink_tx_buf); tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); if (!tx_buf) { ret = -ENOMEM; @@ -772,6 +789,13 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, wpkt = (struct wdsp_write_pkt *)tx_buf->buf; switch (wpkt->pkt_type) { case WDSP_REG_PKT: + if (count <= (sizeof(struct wdsp_write_pkt) + + sizeof(struct wdsp_reg_pkt))) { + dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", + __func__, count); + ret = -EINVAL; + goto free_buf; + } ret = wdsp_glink_ch_info_init(wpriv, (struct wdsp_reg_pkt *)wpkt->payload); if (IS_ERR_VALUE(ret)) @@ -794,6 +818,13 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, kfree(tx_buf); break; case WDSP_CMD_PKT: + if (count <= (sizeof(struct wdsp_write_pkt) + + sizeof(struct wdsp_cmd_pkt))) { + dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", + __func__, count); + ret = -EINVAL; + goto free_buf; + } mutex_lock(&wpriv->glink_mutex); if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) { mutex_unlock(&wpriv->glink_mutex); diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 7aa04a4fa156..b81348ceb469 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -45,8 +45,6 @@ #include <linux/msm-bus-board.h> #include "spi_qsd.h" -#define SPI_MAX_BYTES_PER_WORD (4) - static int msm_spi_pm_resume_runtime(struct device *device); static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); @@ -440,12 +438,10 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) u32 data_in; int i; int shift; - int read_bytes = (dd->pack_words ? - SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO); if (dd->read_buf) { - for (i = 0; (i < read_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->rx_bytes_remaining; i++) { /* The data format depends on bytes_per_word: 4 bytes: 0x12345678 @@ -458,8 +454,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) dd->rx_bytes_remaining--; } } else { - if (dd->rx_bytes_remaining >= read_bytes) - dd->rx_bytes_remaining -= read_bytes; + if (dd->rx_bytes_remaining >= dd->bytes_per_word) + dd->rx_bytes_remaining -= dd->bytes_per_word; else dd->rx_bytes_remaining = 0; } @@ -556,7 +552,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n) if (n != (*config & SPI_CFG_N)) *config = (*config & ~SPI_CFG_N) | n; - if (dd->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { if (dd->read_buf == NULL) *config |= SPI_NO_INPUT; if (dd->write_buf == NULL) @@ -621,34 +617,25 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw) static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words) { /* - * For FIFO mode: - * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0 - * - Set the READ/WRITE_COUNT registers to 0 (infinite mode) - * or num bytes (finite mode) if less than fifo worth of data. - * For Block mode: - * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes. - * - Set the READ/WRITE_COUNT registers to 0. + * n_words cannot exceed fifo_size, and only one READ COUNT + * interrupt is generated per transaction, so for transactions + * larger than fifo size READ COUNT must be disabled. + * For those transactions we usually move to Data Mover mode. */ - if (dd->tx_mode != SPI_BAM_MODE) { - if (dd->tx_mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) - msm_spi_set_write_count(dd, n_words); - else - msm_spi_set_write_count(dd, 0); - writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); - } else - writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT); - - if (dd->rx_mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) - writel_relaxed(n_words, - dd->base + SPI_MX_READ_COUNT); - else - writel_relaxed(0, - dd->base + SPI_MX_READ_COUNT); + if (dd->mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) { + writel_relaxed(n_words, + dd->base + SPI_MX_READ_COUNT); + msm_spi_set_write_count(dd, n_words); + } else { + writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); + msm_spi_set_write_count(dd, 0); + } + if (dd->qup_ver == SPI_QUP_VERSION_BFAM) { + /* must be zero for FIFO */ writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); - } else - writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT); + writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); + } } else { /* must be zero for BAM and DMOV */ writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); @@ -895,7 +882,7 @@ xfr_err: static int msm_spi_bam_next_transfer(struct msm_spi *dd) { - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) return 0; if (dd->tx_bytes_remaining > 0) { @@ -914,7 +901,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd) static int msm_spi_dma_send_next(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_next_transfer(dd); return ret; } @@ -945,38 +932,32 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); - writel_relaxed(op, dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); if (op & SPI_OP_INPUT_SERVICE_FLAG) { + writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG, + dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); ret |= msm_spi_input_irq(irq, dev_id); } if (op & SPI_OP_OUTPUT_SERVICE_FLAG) { + writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG, + dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); ret |= msm_spi_output_irq(irq, dev_id); } - if (dd->tx_mode != SPI_BAM_MODE) { - if (!dd->rx_done) { - if (dd->rx_bytes_remaining == 0) - dd->rx_done = true; - } - if (!dd->tx_done) { - if (!dd->tx_bytes_remaining && - (op & SPI_OP_IP_FIFO_NOT_EMPTY)) { - dd->tx_done = true; - } - } - } - if (dd->tx_done && dd->rx_done) { - msm_spi_set_state(dd, SPI_OP_STATE_RESET); - dd->tx_done = false; - dd->rx_done = false; + if (dd->done) { complete(&dd->rx_transfer_complete); complete(&dd->tx_transfer_complete); + dd->done = 0; } return ret; } @@ -987,23 +968,17 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id) dd->stat_rx++; - if (dd->rx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; - if (dd->rx_mode == SPI_FIFO_MODE) { + if (dd->mode == SPI_FIFO_MODE) { while ((readl_relaxed(dd->base + SPI_OPERATIONAL) & SPI_OP_IP_FIFO_NOT_EMPTY) && (dd->rx_bytes_remaining > 0)) { msm_spi_read_word_from_fifo(dd); } - } else if (dd->rx_mode == SPI_BLOCK_MODE) { - int count = 0; - - while (dd->rx_bytes_remaining && - (count < dd->input_block_size)) { - msm_spi_read_word_from_fifo(dd); - count += SPI_MAX_BYTES_PER_WORD; - } + if (dd->rx_bytes_remaining == 0) + msm_spi_complete(dd); } return IRQ_HANDLED; @@ -1014,20 +989,18 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd) u32 word; u8 byte; int i; - int write_bytes = - (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); word = 0; if (dd->write_buf) { - for (i = 0; (i < write_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->tx_bytes_remaining; i++) { dd->tx_bytes_remaining--; byte = *dd->write_buf++; word |= (byte << (BITS_PER_BYTE * i)); } } else - if (dd->tx_bytes_remaining > write_bytes) - dd->tx_bytes_remaining -= write_bytes; + if (dd->tx_bytes_remaining > dd->bytes_per_word) + dd->tx_bytes_remaining -= dd->bytes_per_word; else dd->tx_bytes_remaining = 0; dd->write_xfr_cnt++; @@ -1039,22 +1012,11 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd) { int count = 0; - if (dd->tx_mode == SPI_FIFO_MODE) { - while ((dd->tx_bytes_remaining > 0) && - (count < dd->input_fifo_size) && - !(readl_relaxed(dd->base + SPI_OPERATIONAL) - & SPI_OP_OUTPUT_FIFO_FULL)) { - msm_spi_write_word_to_fifo(dd); - count++; - } - } - - if (dd->tx_mode == SPI_BLOCK_MODE) { - while (dd->tx_bytes_remaining && - (count < dd->output_block_size)) { - msm_spi_write_word_to_fifo(dd); - count += SPI_MAX_BYTES_PER_WORD; - } + while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) && + !(readl_relaxed(dd->base + SPI_OPERATIONAL) & + SPI_OP_OUTPUT_FIFO_FULL)) { + msm_spi_write_word_to_fifo(dd); + count++; } } @@ -1064,11 +1026,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id) dd->stat_tx++; - if (dd->tx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; /* Output FIFO is empty. Transmit any outstanding write data. */ - if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE)) + if (dd->mode == SPI_FIFO_MODE) msm_spi_write_rmn_to_fifo(dd); return IRQ_HANDLED; @@ -1144,7 +1106,7 @@ error: static int msm_spi_dma_map_buffers(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_map_buffers(dd); return ret; } @@ -1173,7 +1135,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd) static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd) { - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) msm_spi_bam_unmap_buffers(dd); } @@ -1235,11 +1197,9 @@ static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { - dd->tx_mode = SPI_BAM_MODE; - dd->rx_mode = SPI_BAM_MODE; + dd->mode = SPI_BAM_MODE; } else { - dd->rx_mode = SPI_FIFO_MODE; - dd->tx_mode = SPI_FIFO_MODE; + dd->mode = SPI_FIFO_MODE; dd->read_len = dd->cur_transfer->len; dd->write_len = dd->cur_transfer->len; } @@ -1255,19 +1215,14 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd) spi_iom = readl_relaxed(dd->base + SPI_IO_MODES); /* Set input and output transfer mode: FIFO, DMOV, or BAM */ spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE); - spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT)); - spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT)); - /* Always enable packing for all % 8 bits_per_word */ - if (dd->cur_transfer->bits_per_word && - ((dd->cur_transfer->bits_per_word == 8) || - (dd->cur_transfer->bits_per_word == 16) || - (dd->cur_transfer->bits_per_word == 32))) { + spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT)); + spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT)); + /* Turn on packing for data mover */ + if (dd->mode == SPI_BAM_MODE) spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN; - dd->pack_words = true; - } else { + else { spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN); spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN; - dd->pack_words = false; } /*if (dd->mode == SPI_BAM_MODE) { @@ -1325,7 +1280,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd) { /* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status * change in BAM mode */ - u32 mask = (dd->tx_mode == SPI_BAM_MODE) ? + u32 mask = (dd->mode == SPI_BAM_MODE) ? QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG : 0; writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK); @@ -1366,8 +1321,6 @@ static int msm_spi_process_transfer(struct msm_spi *dd) dd->rx_bytes_remaining = dd->cur_msg_len; dd->read_buf = dd->cur_transfer->rx_buf; dd->write_buf = dd->cur_transfer->tx_buf; - dd->tx_done = false; - dd->rx_done = false; init_completion(&dd->tx_transfer_complete); init_completion(&dd->rx_transfer_complete); if (dd->cur_transfer->bits_per_word) @@ -1398,12 +1351,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_transfer_mode(dd, bpw, read_count); msm_spi_set_mx_counts(dd, read_count); - if (dd->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { ret = msm_spi_dma_map_buffers(dd); if (ret < 0) { pr_err("Mapping DMA buffers\n"); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; return ret; } } @@ -1417,11 +1368,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) the first. Restricting this to one write avoids contention issues and race conditions between this thread and the int handler */ - if (dd->tx_mode != SPI_BAM_MODE) { + if (dd->mode == SPI_FIFO_MODE) { if (msm_spi_prepare_for_write(dd)) goto transfer_end; msm_spi_start_write(dd, read_count); - } else { + } else if (dd->mode == SPI_BAM_MODE) { if ((msm_spi_bam_begin_transfer(dd)) < 0) { dev_err(dd->dev, "%s: BAM transfer setup failed\n", __func__); @@ -1437,11 +1388,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) * might fire before the first word is written resulting in a * possible race condition. */ - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) { dev_warn(dd->dev, "%s: Failed to set QUP to run-state. Mode:%d", - __func__, dd->tx_mode); + __func__, dd->mode); goto transfer_end; } @@ -1471,11 +1422,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_udelay(dd->xfrs_delay_usec); transfer_end: - if ((dd->tx_mode == SPI_BAM_MODE) && status) + if ((dd->mode == SPI_BAM_MODE) && status) msm_spi_bam_flush(dd); msm_spi_dma_unmap_buffers(dd); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); if (!dd->cur_transfer->cs_change) @@ -2403,8 +2353,7 @@ static int init_resources(struct platform_device *pdev) pclk_enabled = 0; dd->transfer_pending = 0; - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; rc = msm_spi_request_irq(dd, pdev, master); if (rc) diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index e8e6cdce1a02..53ec1e600594 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.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 @@ -113,8 +113,6 @@ #define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12) /* SPI_OPERATIONAL fields */ -#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000 -#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000 #define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800 #define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400 #define SPI_OP_INPUT_SERVICE_FLAG 0x00000200 @@ -316,8 +314,7 @@ struct msm_spi { bool transfer_pending; wait_queue_head_t continue_suspend; /* DMA data */ - enum msm_spi_mode tx_mode; - enum msm_spi_mode rx_mode; + enum msm_spi_mode mode; bool use_dma; int tx_dma_chan; int tx_dma_crci; @@ -349,8 +346,7 @@ struct msm_spi { #endif struct msm_spi_platform_data *pdata; /* Platform data */ /* When set indicates multiple transfers in a single message */ - bool rx_done; - bool tx_done; + bool done; u32 cur_msg_len; /* Used in FIFO mode to keep track of the transfer being processed */ struct spi_transfer *cur_tx_transfer; @@ -368,7 +364,6 @@ struct msm_spi { struct pinctrl_state *pins_active; struct pinctrl_state *pins_sleep; bool is_init_complete; - bool pack_words; }; /* Forward declaration */ @@ -522,8 +517,7 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) static inline void msm_spi_complete(struct msm_spi *dd) { - dd->tx_done = true; - dd->rx_done = true; + dd->done = 1; } static inline void msm_spi_enable_error_flags(struct msm_spi *dd) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index bc0e0184a917..1e252febc783 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -156,6 +156,7 @@ struct dwc3_msm { struct clk *xo_clk; struct clk *core_clk; long core_clk_rate; + long core_clk_rate_hs; struct clk *iface_clk; struct clk *sleep_clk; struct clk *utmi_clk; @@ -195,6 +196,7 @@ struct dwc3_msm { struct power_supply *usb_psy; struct work_struct vbus_draw_work; bool in_host_mode; + enum usb_device_speed max_rh_port_speed; unsigned int tx_fifo_size; bool vbus_active; bool suspend; @@ -342,6 +344,23 @@ static inline void dwc3_msm_write_readback(void *base, u32 offset, __func__, val, offset); } +static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc) +{ + int i, num_ports; + u32 reg; + + reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); + num_ports = HCS_MAX_PORTS(reg); + + for (i = 0; i < num_ports; i++) { + reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); + if ((reg & PORT_CONNECT) && DEV_SUPERSPEED(reg)) + return true; + } + + return false; +} + static bool dwc3_msm_is_host_superspeed(struct dwc3_msm *mdwc) { int i, num_ports; @@ -2128,6 +2147,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) static int dwc3_msm_resume(struct dwc3_msm *mdwc) { int ret; + long core_clk_rate; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__); @@ -2175,7 +2195,15 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) clk_prepare_enable(mdwc->iface_clk); if (mdwc->noc_aggr_clk) clk_prepare_enable(mdwc->noc_aggr_clk); - clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); + + core_clk_rate = mdwc->core_clk_rate; + if (mdwc->in_host_mode && mdwc->max_rh_port_speed == USB_SPEED_HIGH) { + core_clk_rate = mdwc->core_clk_rate_hs; + dev_dbg(mdwc->dev, "%s: set hs core clk rate %ld\n", __func__, + core_clk_rate); + } + + clk_set_rate(mdwc->core_clk, core_clk_rate); clk_prepare_enable(mdwc->core_clk); /* set Memory core: ON, Memory periphery: ON */ @@ -2496,6 +2524,11 @@ static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc) if (ret) dev_err(mdwc->dev, "fail to set core_clk freq:%d\n", ret); + if (of_property_read_u32(mdwc->dev->of_node, "qcom,core-clk-rate-hs", + (u32 *)&mdwc->core_clk_rate_hs)) { + dev_dbg(mdwc->dev, "USB core-clk-rate-hs is not present\n"); + mdwc->core_clk_rate_hs = mdwc->core_clk_rate; + } mdwc->core_reset = devm_reset_control_get(mdwc->dev, "core_reset"); if (IS_ERR(mdwc->core_reset)) { @@ -2723,6 +2756,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; struct device *dev = &pdev->dev; + union power_supply_propval pval = {0}; struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; @@ -3016,10 +3050,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) */ mdwc->lpm_flags = MDWC3_POWER_COLLAPSE | MDWC3_SS_PHY_SUSPEND; atomic_set(&dwc->in_lpm, 1); - pm_runtime_set_suspended(mdwc->dev); pm_runtime_set_autosuspend_delay(mdwc->dev, 1000); pm_runtime_use_autosuspend(mdwc->dev); - pm_runtime_enable(mdwc->dev); device_init_wakeup(mdwc->dev, 1); if (of_property_read_bool(node, "qcom,disable-dev-mode-pm")) @@ -3036,18 +3068,32 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->pm_qos_latency = 0; } + mdwc->usb_psy = power_supply_get_by_name("usb"); + if (!mdwc->usb_psy) { + dev_warn(mdwc->dev, "Could not get usb power_supply\n"); + pval.intval = -EINVAL; + } else { + power_supply_get_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + } + /* Update initial VBUS/ID state from extcon */ if (mdwc->extcon_vbus && extcon_get_cable_state_(mdwc->extcon_vbus, EXTCON_USB)) dwc3_msm_vbus_notifier(&mdwc->vbus_nb, true, mdwc->extcon_vbus); - if (mdwc->extcon_id && extcon_get_cable_state_(mdwc->extcon_id, + else if (mdwc->extcon_id && extcon_get_cable_state_(mdwc->extcon_id, EXTCON_USB_HOST)) dwc3_msm_id_notifier(&mdwc->id_nb, true, mdwc->extcon_id); + else if (!pval.intval) { + /* USB cable is not connected */ + schedule_delayed_work(&mdwc->sm_work, 0); + } else { + if (pval.intval > 0) + dev_info(mdwc->dev, "charger detection in progress\n"); + } device_create_file(&pdev->dev, &dev_attr_mode); - schedule_delayed_work(&mdwc->sm_work, 0); - host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (!dwc->is_drd && host_mode) { dev_dbg(&pdev->dev, "DWC3 in host only mode\n"); @@ -3166,10 +3212,26 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, if (udev->parent && !udev->parent->parent && udev->dev.parent->parent == &dwc->xhci->dev) { if (event == USB_DEVICE_ADD && udev->actconfig) { + if (!dwc3_msm_is_ss_rhport_connected(mdwc)) { + /* + * Core clock rate can be reduced only if root + * hub SS port is not enabled/connected. + */ + clk_set_rate(mdwc->core_clk, + mdwc->core_clk_rate_hs); + dev_dbg(mdwc->dev, + "set hs core clk rate %ld\n", + mdwc->core_clk_rate_hs); + mdwc->max_rh_port_speed = USB_SPEED_HIGH; + } else { + mdwc->max_rh_port_speed = USB_SPEED_SUPER; + } + if (udev->speed >= USB_SPEED_SUPER) max_power = udev->actconfig->desc.bMaxPower * 8; else max_power = udev->actconfig->desc.bMaxPower * 2; + dev_dbg(mdwc->dev, "%s configured bMaxPower:%d (mA)\n", dev_name(&udev->dev), max_power); @@ -3181,6 +3243,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, pval.intval = 0; power_supply_set_property(mdwc->usb_psy, POWER_SUPPLY_PROP_BOOST_CURRENT, &pval); + mdwc->max_rh_port_speed = USB_SPEED_UNKNOWN; } } @@ -3538,13 +3601,25 @@ static void dwc3_otg_sm_work(struct work_struct *w) /* Check OTG state */ switch (mdwc->otg_state) { case OTG_STATE_UNDEFINED: - /* Do nothing if no cable connected */ + /* put controller and phy in suspend if no cable connected */ if (test_bit(ID, &mdwc->inputs) && - !test_bit(B_SESS_VLD, &mdwc->inputs)) + !test_bit(B_SESS_VLD, &mdwc->inputs)) { + dbg_event(0xFF, "undef_id_!bsv", 0); + pm_runtime_set_active(mdwc->dev); + pm_runtime_enable(mdwc->dev); + pm_runtime_get_noresume(mdwc->dev); + dwc3_msm_resume(mdwc); + pm_runtime_put_sync(mdwc->dev); + dbg_event(0xFF, "Undef NoUSB", + atomic_read(&mdwc->dev->power.usage_count)); + mdwc->otg_state = OTG_STATE_B_IDLE; break; + } dbg_event(0xFF, "Exit UNDEF", 0); mdwc->otg_state = OTG_STATE_B_IDLE; + pm_runtime_set_suspended(mdwc->dev); + pm_runtime_enable(mdwc->dev); /* fall-through */ case OTG_STATE_B_IDLE: if (!test_bit(ID, &mdwc->inputs)) { diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c index fe428e8bb781..da02ad557d34 100644 --- a/drivers/usb/gadget/function/f_diag.c +++ b/drivers/usb/gadget/function/f_diag.c @@ -352,9 +352,11 @@ struct usb_diag_ch *usb_diag_open(const char *name, void *priv, ch->priv = priv; ch->notify = notify; - spin_lock_irqsave(&ch_lock, flags); - list_add_tail(&ch->list, &usb_diag_ch_list); - spin_unlock_irqrestore(&ch_lock, flags); + if (!found) { + spin_lock_irqsave(&ch_lock, flags); + list_add_tail(&ch->list, &usb_diag_ch_list); + spin_unlock_irqrestore(&ch_lock, flags); + } return ch; } @@ -828,6 +830,7 @@ static struct diag_context *diag_context_init(const char *name) struct diag_context *dev; struct usb_diag_ch *_ch; int found = 0; + unsigned long flags; pr_debug("%s\n", __func__); @@ -837,9 +840,19 @@ static struct diag_context *diag_context_init(const char *name) break; } } + if (!found) { - pr_err("%s: unable to get diag usb channel\n", __func__); - return ERR_PTR(-ENODEV); + pr_warn("%s: unable to get diag usb channel\n", __func__); + + _ch = kzalloc(sizeof(*_ch), GFP_KERNEL); + if (_ch == NULL) + return ERR_PTR(-ENOMEM); + + _ch->name = name; + + spin_lock_irqsave(&ch_lock, flags); + list_add_tail(&_ch->list, &usb_diag_ch_list); + spin_unlock_irqrestore(&ch_lock, flags); } dev = kzalloc(sizeof(*dev), GFP_KERNEL); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f3715d85aedc..97d86b6ac69b 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -454,13 +454,23 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + return; + } + spin_lock(&common->lock); bh->inreq_busy = 0; bh->state = BUF_STATE_EMPTY; @@ -473,15 +483,24 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_common *common = ep->driver_data; struct fsg_buffhd *bh = req->context; - dump_msg(common, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, bh->bulk_out_intended_length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->outreq_busy = 0; + return; + } + + dump_msg(common, "bulk-out", req->buf, req->actual); spin_lock(&common->lock); bh->outreq_busy = 0; bh->state = BUF_STATE_FULL; @@ -2471,8 +2490,14 @@ static void handle_exception(struct fsg_common *common) case FSG_STATE_CONFIG_CHANGE: do_set_interface(common, common->new_fsg); - if (common->new_fsg) + if (common->new_fsg) { + /* + * make sure delayed_status flag updated when set_alt + * returned. + */ + msleep(200); usb_composite_setup_continue(common->cdev); + } break; case FSG_STATE_EXIT: diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index 11c73f584594..061095b78c37 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -683,6 +683,7 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* we know alt == 0 */ + opts = container_of(f->fi, struct f_rndis_qc_opts, func_inst); if (intf == rndis->ctrl_id) { if (rndis->notify->driver_data) { VDBG(cdev, "reset rndis control %d\n", intf); diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c index 8ef223370827..013c54da0d0a 100644 --- a/drivers/usb/gadget/function/u_ctrl_qti.c +++ b/drivers/usb/gadget/function/u_ctrl_qti.c @@ -485,7 +485,7 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count, port->copied_from_modem++; spin_lock_irqsave(&port->lock, flags); - if (port && port->port_usb) { + if (port->port_usb) { if (port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)port->port_usb; } else { diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index bf9e0fa9950b..6c18a04f6c1c 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -1107,18 +1107,18 @@ static void bam2bam_data_resume_work(struct work_struct *w) unsigned long flags; int ret; - if (!port->port_usb->cdev) { - pr_err("!port->port_usb->cdev is NULL"); + spin_lock_irqsave(&port->port_lock, flags); + if (!port->port_usb || !port->port_usb->cdev) { + pr_err("port->port_usb or cdev is NULL"); goto exit; } if (!port->port_usb->cdev->gadget) { - pr_err("!port->port_usb->cdev->gadget is NULL"); + pr_err("port->port_usb->cdev->gadget is NULL"); goto exit; } pr_debug("%s: resume started\n", __func__); - spin_lock_irqsave(&port->port_lock, flags); gadget = port->port_usb->cdev->gadget; if (!gadget) { spin_unlock_irqrestore(&port->port_lock, flags); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index f3e17b84efff..f1360f20ffe4 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2009-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 diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 0cdf91da920c..06e4812a8bd4 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -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 @@ -281,7 +281,7 @@ struct mdss_data_type { u32 mdp_rev; struct clk *mdp_clk[MDSS_MAX_CLK]; struct regulator *fs; - struct regulator *venus; + struct regulator *core_gdsc; struct regulator *vdd_cx; u32 vdd_cx_min_uv; u32 vdd_cx_max_uv; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index f499cdfd85ef..14d998d14eeb 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * Copyright (C) 1994 Martin Schaller * * 2001 - Documented with DocBook @@ -938,6 +938,7 @@ static int __to_user_pcc_coeff_v1_7( struct mdp_pcc_data_v1_7_32 pcc_cfg_payload32; struct mdp_pcc_data_v1_7 pcc_cfg_payload; + memset(&pcc_cfg_payload32, 0, sizeof(pcc_cfg_payload32)); if (copy_from_user(&pcc_cfg_payload, pcc_cfg->cfg_payload, sizeof(struct mdp_pcc_data_v1_7))) { @@ -2133,6 +2134,7 @@ static int __to_user_pa_data_v1_7( struct mdp_pa_data_v1_7_32 pa_cfg_payload32; struct mdp_pa_data_v1_7 pa_cfg_payload; + memset(&pa_cfg_payload32, 0, sizeof(pa_cfg_payload32)); if (copy_from_user(&pa_cfg_payload, pa_v2_cfg->cfg_payload, sizeof(pa_cfg_payload))) { diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index ccf8a0d34a6c..f3c36c5c6b5a 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -56,9 +56,58 @@ struct mdss_dp_attention_node { static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv); static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata); -static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp); +static inline void mdss_dp_link_maintenance(struct mdss_dp_drv_pdata *dp, + bool lt_needed); static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp_drv); static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 events); +static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, + enum notification_status status); +static int mdss_dp_process_phy_test_pattern_request( + struct mdss_dp_drv_pdata *dp); + +static inline void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp) +{ + dp->test_data = (const struct dpcd_test_request){ 0 }; + dp->test_data.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN; + hdmi_edid_config_override(dp->panel_data.panel_info.edid_data, + false, 0); +} + +static inline bool mdss_dp_is_link_status_updated(struct mdss_dp_drv_pdata *dp) +{ + return dp->link_status.link_status_updated; +} + +static inline bool mdss_dp_is_downstream_port_status_changed( + struct mdss_dp_drv_pdata *dp) +{ + return dp->link_status.downstream_port_status_changed; +} + +static inline bool mdss_dp_is_audio_pattern_requested( + struct mdss_dp_drv_pdata *dp) +{ + return (dp->test_data.test_requested & TEST_AUDIO_PATTERN); +} + +static inline bool mdss_dp_is_link_training_requested( + struct mdss_dp_drv_pdata *dp) +{ + return (dp->test_data.test_requested == TEST_LINK_TRAINING); +} + +static inline bool mdss_dp_is_video_pattern_requested( + struct mdss_dp_drv_pdata *dp) +{ + return (dp->test_data.test_requested & TEST_VIDEO_PATTERN) + && !(dp->test_data.test_requested & TEST_AUDIO_DISABLED_VIDEO); +} + +static inline bool mdss_dp_is_phy_test_pattern_requested( + struct mdss_dp_drv_pdata *dp) +{ + return (dp->test_data.test_requested == PHY_TEST_PATTERN); +} static void mdss_dp_put_dt_clk_data(struct device *dev, struct dss_module_power *module_power) @@ -798,9 +847,11 @@ void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *dp) { struct dpcd_cap *cap; struct display_timing_desc *timing; + struct mdss_panel_info *pinfo; u32 data = 0; timing = &dp->edid.timing[0]; + pinfo = &dp->panel_data.panel_info; cap = &dp->dpcd; @@ -823,8 +874,8 @@ void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *dp) if (cap->scrambler_reset) data |= (1 << 10); - if (dp->edid.color_depth != 6) - data |= 0x100; /* Default: 8 bits */ + /* Bits per components */ + data |= (mdss_dp_bpp_to_test_bit_depth(pinfo->bpp) << 8); /* Num of Lanes */ data |= ((dp->lane_cnt - 1) << 4); @@ -840,7 +891,7 @@ void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *dp) mdss_dp_configuration_ctrl(&dp->ctrl_io, data); } -int mdss_dp_wait4train(struct mdss_dp_drv_pdata *dp_drv) +static int mdss_dp_wait4video_ready(struct mdss_dp_drv_pdata *dp_drv) { int ret = 0; @@ -882,9 +933,7 @@ static int dp_get_cable_status(struct platform_device *pdev, u32 vote) return -ENODEV; } - mutex_lock(&dp_ctrl->pd_msg_mutex); hpd = dp_ctrl->cable_connected; - mutex_unlock(&dp_ctrl->pd_msg_mutex); return hpd; } @@ -905,7 +954,7 @@ static int dp_audio_info_setup(struct platform_device *pdev, return -ENODEV; } - mdss_dp_audio_setup_sdps(&dp_ctrl->ctrl_io); + mdss_dp_audio_setup_sdps(&dp_ctrl->ctrl_io, params->num_of_channels); mdss_dp_config_audio_acr_ctrl(&dp_ctrl->ctrl_io, dp_ctrl->link_rate); mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt); mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true); @@ -983,6 +1032,55 @@ end: return ret; } +static u32 mdss_dp_get_bpp(struct mdss_dp_drv_pdata *dp) +{ + u32 bpp; + u32 bit_depth; + + /* + * Set bpp value based on whether a test video pattern is requested. + * For test pattern, the test data has the bit depth per color + * component. Otherwise, set it based on EDID. + */ + if (dp->override_config || mdss_dp_is_video_pattern_requested(dp)) + bit_depth = dp->test_data.test_bit_depth; + else + bit_depth = dp->edid.color_depth; + + if (!mdss_dp_is_test_bit_depth_valid(bit_depth)) { + pr_debug("invalid bit_depth=%d. fall back to default\n", + bit_depth); + bit_depth = DP_TEST_BIT_DEPTH_8; /* default to 24bpp */ + } + + bpp = mdss_dp_test_bit_depth_to_bpp(bit_depth); + return bpp; +} + +static u32 mdss_dp_get_colorimetry_config(struct mdss_dp_drv_pdata *dp) +{ + u32 cc; + enum dynamic_range dr; + + /* unless a video pattern CTS test is ongoing, use CEA_VESA */ + if (mdss_dp_is_video_pattern_requested(dp)) + dr = dp->test_data.test_dyn_range; + else + dr = DP_DYNAMIC_RANGE_RGB_VESA; + + /* Only RGB_VESA nd RGB_CEA supported for now */ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_CEA: + cc = BIT(3); + break; + case DP_DYNAMIC_RANGE_RGB_VESA: + default: + cc = 0; + } + + return cc; +} + static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) { struct mdss_panel_info *pinfo; @@ -993,13 +1091,17 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) DEV_ERR("invalid input\n"); return -EINVAL; } - - ret = hdmi_get_supported_mode(&timing, 0, vic); pinfo = &dp_drv->panel_data.panel_info; - if (ret || !timing.supported || !pinfo) { - DEV_ERR("%s: invalid timing data\n", __func__); - return -EINVAL; + if (vic != HDMI_VFRMT_UNKNOWN) { + ret = hdmi_get_supported_mode(&timing, 0, vic); + + if (ret || !timing.supported || !pinfo) { + DEV_ERR("%s: invalid timing data\n", __func__); + return -EINVAL; + } + } else { + pr_debug("reset panel info to zeroes\n"); } dp_drv->vic = vic; @@ -1010,14 +1112,15 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) pinfo->lcdc.h_back_porch = timing.back_porch_h; pinfo->lcdc.h_front_porch = timing.front_porch_h; pinfo->lcdc.h_pulse_width = timing.pulse_width_h; + pinfo->lcdc.h_active_low = timing.active_low_h; pinfo->lcdc.v_back_porch = timing.back_porch_v; pinfo->lcdc.v_front_porch = timing.front_porch_v; pinfo->lcdc.v_pulse_width = timing.pulse_width_v; + pinfo->lcdc.v_active_low = timing.active_low_v; pinfo->type = DP_PANEL; pinfo->pdest = DISPLAY_4; pinfo->wait_cycle = 0; - pinfo->bpp = 24; pinfo->fb_num = 1; pinfo->lcdc.border_clr = 0; /* blk */ @@ -1025,8 +1128,8 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) pinfo->lcdc.hsync_skew = 0; pinfo->is_pluggable = true; - dp_drv->bpp = pinfo->bpp; - + pinfo->bpp = mdss_dp_get_bpp(dp_drv); + pr_debug("bpp=%d\n", pinfo->bpp); pr_debug("update res. vic= %d, pclk_rate = %llu\n", dp_drv->vic, pinfo->clk_rate); @@ -1151,13 +1254,17 @@ static void mdss_dp_configure_source_params(struct mdss_dp_drv_pdata *dp, mdss_dp_fill_link_cfg(dp); mdss_dp_mainlink_ctrl(&dp->ctrl_io, true); mdss_dp_config_ctrl(dp); + mdss_dp_config_misc(dp, + mdss_dp_bpp_to_test_bit_depth(mdss_dp_get_bpp(dp)), + mdss_dp_get_colorimetry_config(dp)); mdss_dp_sw_config_msa(&dp->ctrl_io, dp->link_rate, &dp->dp_cc_io); mdss_dp_timing_cfg(&dp->ctrl_io, &dp->panel_data.panel_info); } /** - * mdss_dp_train_main_link() - initiates training of DP main link + * mdss_dp_setup_main_link() - initiates training of DP main link * @dp: Display Port Driver data + * @train: specify if link training should be done or not * * Initiates training of the DP main link and checks the state of the main * link after the training is complete. @@ -1165,64 +1272,90 @@ static void mdss_dp_configure_source_params(struct mdss_dp_drv_pdata *dp, * Return: error code. -EINVAL if any invalid data or -EAGAIN if retraining * is required. */ -static int mdss_dp_train_main_link(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_setup_main_link(struct mdss_dp_drv_pdata *dp, bool train) { int ret = 0; int ready = 0; pr_debug("enter\n"); + mdss_dp_mainlink_ctrl(&dp->ctrl_io, true); + mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON); + reinit_completion(&dp->video_comp); + + if (mdss_dp_is_phy_test_pattern_requested(dp)) + goto end; + + if (!train) + goto send_video; + + /* + * As part of previous calls, DP controller state might have + * transitioned to PUSH_IDLE. In order to start transmitting a link + * training pattern, we have to first to a DP software reset. + */ + mdss_dp_ctrl_reset(&dp->ctrl_io); ret = mdss_dp_link_train(dp); if (ret) goto end; - mdss_dp_wait4train(dp); +send_video: + /* + * Set up transfer unit values and set controller state to send + * video. + */ + mdss_dp_setup_tr_unit(&dp->ctrl_io, dp->link_rate, dp->lane_cnt, + dp->vic, &dp->panel_data.panel_info); + mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO); + mdss_dp_wait4video_ready(dp); ready = mdss_dp_mainlink_ready(dp, BIT(0)); - pr_debug("main link %s\n", ready ? "READY" : "NOT READY"); + end: return ret; } -static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv) +static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv, bool lt_needed) { int ret = 0; struct lane_mapping ln_map; /* wait until link training is completed */ - pr_debug("enter\n"); + pr_debug("enter, lt_needed=%s\n", lt_needed ? "true" : "false"); do { - if (ret == -EAGAIN) { - mdss_dp_mainlink_push_idle(&dp_drv->panel_data); - mdss_dp_off_irq(dp_drv); - } + if (ret == -EAGAIN) + mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false); mutex_lock(&dp_drv->train_mutex); + dp_init_panel_info(dp_drv, dp_drv->vic); ret = mdss_dp_get_lane_mapping(dp_drv, dp_drv->orientation, &ln_map); - if (ret) { - mutex_unlock(&dp_drv->train_mutex); - goto exit; - } + if (ret) + goto exit_loop; mdss_dp_phy_share_lane_config(&dp_drv->phy_io, dp_drv->orientation, dp_drv->dpcd.max_lane_count); - ret = mdss_dp_enable_mainlink_clocks(dp_drv); - if (ret) { - mutex_unlock(&dp_drv->train_mutex); - goto exit; + if (lt_needed) { + /* + * Diasable and re-enable the mainlink clock since the + * link clock might have been adjusted as part of the + * link maintenance. + */ + if (!mdss_dp_is_phy_test_pattern_requested(dp_drv)) + mdss_dp_disable_mainlink_clocks(dp_drv); + ret = mdss_dp_enable_mainlink_clocks(dp_drv); + if (ret) + goto exit_loop; } - mdss_dp_mainlink_reset(&dp_drv->ctrl_io); + mdss_dp_configure_source_params(dp_drv, &ln_map); reinit_completion(&dp_drv->idle_comp); - mdss_dp_configure_source_params(dp_drv, &ln_map); - dp_drv->power_on = true; if (dp_drv->psm_enabled) { @@ -1230,18 +1363,22 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv) if (ret) { pr_err("Failed to exit low power mode, rc=%d\n", ret); - goto exit; + goto exit_loop; } } - ret = mdss_dp_train_main_link(dp_drv); + ret = mdss_dp_setup_main_link(dp_drv, lt_needed); +exit_loop: mutex_unlock(&dp_drv->train_mutex); } while (ret == -EAGAIN); pr_debug("end\n"); -exit: + /* Send a connect notification */ + if (!mdss_dp_is_phy_test_pattern_requested(dp_drv)) + mdss_dp_notify_clients(dp_drv, NOTIFY_CONNECT_IRQ_HPD); + return ret; } @@ -1274,12 +1411,7 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) if (dp_drv->new_vic && (dp_drv->new_vic != dp_drv->vic)) dp_init_panel_info(dp_drv, dp_drv->new_vic); - dp_drv->link_rate = - mdss_dp_gen_link_clk(&dp_drv->panel_data.panel_info, - dp_drv->dpcd.max_lane_count); - - pr_debug("link_rate=0x%x, Max rate supported by sink=0x%x\n", - dp_drv->link_rate, dp_drv->dpcd.max_link_rate); + dp_drv->link_rate = mdss_dp_gen_link_clk(dp_drv); if (!dp_drv->link_rate) { pr_err("Unable to configure required link rate\n"); ret = -EINVAL; @@ -1289,14 +1421,10 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_phy_share_lane_config(&dp_drv->phy_io, dp_drv->orientation, dp_drv->dpcd.max_lane_count); - pr_debug("link_rate = 0x%x\n", dp_drv->link_rate); - ret = mdss_dp_enable_mainlink_clocks(dp_drv); if (ret) goto exit; - mdss_dp_mainlink_reset(&dp_drv->ctrl_io); - reinit_completion(&dp_drv->idle_comp); mdss_dp_configure_source_params(dp_drv, &ln_map); @@ -1313,7 +1441,7 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) link_training: dp_drv->power_on = true; - while (-EAGAIN == mdss_dp_train_main_link(dp_drv)) + while (-EAGAIN == mdss_dp_setup_main_link(dp_drv, true)) pr_debug("MAIN LINK TRAINING RETRY\n"); dp_drv->cont_splash = 0; @@ -1338,42 +1466,12 @@ int mdss_dp_on(struct mdss_panel_data *pdata) dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, panel_data); - return mdss_dp_on_hpd(dp_drv); -} - -static inline void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp) -{ - dp->test_data = (const struct dpcd_test_request){ 0 }; -} - -static inline bool mdss_dp_is_link_status_updated(struct mdss_dp_drv_pdata *dp) -{ - return dp->link_status.link_status_updated; -} - -static inline bool mdss_dp_is_downstream_port_status_changed( - struct mdss_dp_drv_pdata *dp) -{ - return dp->link_status.downstream_port_status_changed; -} - -static inline bool mdss_dp_is_link_training_requested( - struct mdss_dp_drv_pdata *dp) -{ - return (dp->test_data.test_requested == TEST_LINK_TRAINING); -} - -static inline bool mdss_dp_is_phy_test_pattern_requested( - struct mdss_dp_drv_pdata *dp) -{ - return (dp->test_data.test_requested == PHY_TEST_PATTERN); -} + if (dp_drv->power_on) { + pr_debug("Link already setup, return\n"); + return 0; + } -static inline bool mdss_dp_soft_hpd_reset(struct mdss_dp_drv_pdata *dp) -{ - return (mdss_dp_is_link_training_requested(dp) || - mdss_dp_is_phy_test_pattern_requested(dp)) && - dp->alt_mode.dp_status.hpd_irq; + return mdss_dp_on_hpd(dp_drv); } static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv) @@ -1389,16 +1487,13 @@ static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv) pr_debug("start\n"); mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false); - mdss_dp_audio_enable(&dp_drv->ctrl_io, false); - - /* Make sure the DP main link is disabled before clk disable */ + /* Make sure DP mainlink and audio engines are disabled */ wmb(); - mdss_dp_disable_mainlink_clocks(dp_drv); - dp_drv->power_on = false; - dp_drv->sink_info_read = false; + mdss_dp_ack_state(dp_drv, false); mutex_unlock(&dp_drv->train_mutex); + complete_all(&dp_drv->irq_comp); pr_debug("end\n"); @@ -1445,8 +1540,10 @@ static int mdss_dp_off_hpd(struct mdss_dp_drv_pdata *dp_drv) dp_drv->power_on = false; dp_drv->sink_info_read = false; + dp_init_panel_info(dp_drv, HDMI_VFRMT_UNKNOWN); mdss_dp_ack_state(dp_drv, false); + mdss_dp_reset_test_data(dp_drv); mutex_unlock(&dp_drv->train_mutex); pr_debug("DP off done\n"); @@ -1464,7 +1561,7 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return -EINVAL; } - if (mdss_dp_soft_hpd_reset(dp)) + if (dp->hpd_irq_on) return mdss_dp_off_irq(dp); else return mdss_dp_off_hpd(dp); @@ -1482,8 +1579,13 @@ static int mdss_dp_send_cable_notification( goto end; } - if (mdss_dp_is_dvi_mode(dp)) - flags |= MSM_EXT_DISP_HPD_NO_AUDIO; + flags |= MSM_EXT_DISP_HPD_VIDEO; + + if (!mdss_dp_is_dvi_mode(dp) || dp->audio_test_req) { + dp->audio_test_req = false; + + flags |= MSM_EXT_DISP_HPD_AUDIO; + } if (dp->ext_audio_data.intf_ops.hpd) ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, @@ -1493,11 +1595,6 @@ end: return ret; } -static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable) -{ - return mdss_dp_send_cable_notification(dp, enable); -} - static void mdss_dp_set_default_resolution(struct mdss_dp_drv_pdata *dp) { hdmi_edid_set_video_resolution(dp->panel_data.panel_info.edid_data, @@ -1606,6 +1703,93 @@ vreg_error: return ret; } +/** + * mdss_dp_notify_clients() - notifies DP clients of cable connection + * @dp: Display Port Driver data + * @status: HPD notification status requested + * + * This function will send a notification to display/audio clients of change + * in DP connection status. + */ +static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, + enum notification_status status) +{ + const int irq_comp_timeout = HZ * 2; + int ret = 0; + + mutex_lock(&dp->pd_msg_mutex); + if (status == dp->hpd_notification_status) { + pr_debug("No change in status %s --> %s\n", + mdss_dp_notification_status_to_string(status), + mdss_dp_notification_status_to_string( + dp->hpd_notification_status)); + goto end; + } + + switch (status) { + case NOTIFY_CONNECT_IRQ_HPD: + if (dp->hpd_notification_status != NOTIFY_DISCONNECT_IRQ_HPD) + goto invalid_request; + /* Follow the same programming as for NOTIFY_CONNECT */ + mdss_dp_host_init(&dp->panel_data); + mdss_dp_send_cable_notification(dp, true); + break; + case NOTIFY_CONNECT: + if ((dp->hpd_notification_status == NOTIFY_CONNECT_IRQ_HPD) || + (dp->hpd_notification_status == + NOTIFY_DISCONNECT_IRQ_HPD)) + goto invalid_request; + mdss_dp_host_init(&dp->panel_data); + mdss_dp_send_cable_notification(dp, true); + break; + case NOTIFY_DISCONNECT: + mdss_dp_send_cable_notification(dp, false); + break; + case NOTIFY_DISCONNECT_IRQ_HPD: + if (dp->hpd_notification_status == NOTIFY_DISCONNECT) + goto invalid_request; + + mdss_dp_send_cable_notification(dp, false); + if (!IS_ERR_VALUE(ret) && ret) { + reinit_completion(&dp->irq_comp); + ret = wait_for_completion_timeout(&dp->irq_comp, + irq_comp_timeout); + if (ret <= 0) { + pr_warn("irq_comp timed out\n"); + ret = -EINVAL; + } else { + ret = 0; + } + } + break; + default: + pr_err("Invalid notification status = %d\n", status); + ret = -EINVAL; + break; + } + + goto end; + +invalid_request: + pr_err("Invalid request %s --> %s\n", + mdss_dp_notification_status_to_string( + dp->hpd_notification_status), + mdss_dp_notification_status_to_string(status)); + ret = -EINVAL; + +end: + if (!ret) { + pr_debug("Successfully sent notification %s --> %s\n", + mdss_dp_notification_status_to_string( + dp->hpd_notification_status), + mdss_dp_notification_status_to_string(status)); + dp->hpd_notification_status = status; + } + + mutex_unlock(&dp->pd_msg_mutex); + return ret; +} + static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp) { int ret; @@ -1613,6 +1797,8 @@ static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp) if (dp->sink_info_read) return 0; + pr_debug("start\n"); + mdss_dp_dpcd_cap_read(dp); ret = mdss_dp_edid_read(dp); @@ -1620,20 +1806,35 @@ static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp) pr_debug("edid read error, setting default resolution\n"); mdss_dp_set_default_resolution(dp); - goto end; + goto notify; } ret = hdmi_edid_parser(dp->panel_data.panel_info.edid_data); if (ret) { pr_err("edid parse failed\n"); - goto end; + goto notify; } dp->sink_info_read = true; -end: - mdss_dp_update_cable_status(dp, true); - mdss_dp_notify_clients(dp, true); +notify: + /* Check if there is a PHY_TEST_PATTERN request when we get HPD high. + * Update the DP driver with the test parameters including link rate, + * lane count, voltage level, and pre-emphasis level. Do not notify + * the userspace of the connection, just power on the DP controller + * and mainlink with the new settings. + */ + if (mdss_dp_is_phy_test_pattern_requested(dp)) { + pr_info("PHY_TEST_PATTERN requested by sink\n"); + mdss_dp_process_phy_test_pattern_request(dp); + pr_info("skip client notification\n"); + goto end; + } + + mdss_dp_notify_clients(dp, NOTIFY_CONNECT); + +end: + pr_debug("end\n"); return ret; } @@ -1676,6 +1877,13 @@ end: return rc; } +static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv) +{ + return dp_drv->hdcp.feature_enabled && + (dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) && + dp_drv->hdcp.ops; +} + static void mdss_dp_hdcp_cb_work(struct work_struct *work) { struct mdss_dp_drv_pdata *dp; @@ -1688,6 +1896,13 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work) dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work); base = dp->base; + + if (dp->hdcp_status == HDCP_STATE_AUTHENTICATING && + mdss_dp_is_audio_pattern_requested(dp)) { + pr_debug("no hdcp for audio tests\n"); + return; + } + hdcp_auth_state = (dp_read(base + DP_HDCP_STATUS) >> 20) & 0x3; pr_debug("hdcp auth state %d\n", hdcp_auth_state); @@ -1874,7 +2089,7 @@ static ssize_t mdss_dp_sysfs_rda_s3d_mode(struct device *dev, static bool mdss_dp_is_test_ongoing(struct mdss_dp_drv_pdata *dp) { - return dp->hpd_irq_clients_notified; + return (dp->hpd_notification_status == NOTIFY_DISCONNECT_IRQ_HPD); } /** @@ -1916,7 +2131,7 @@ static int mdss_dp_psm_config(struct mdss_dp_drv_pdata *dp, bool enable) mdss_dp_mainlink_push_idle(&dp->panel_data); mdss_dp_off_irq(dp); } else { - mdss_dp_notify_clients(dp, false); + mdss_dp_notify_clients(dp, NOTIFY_DISCONNECT); } } else { /* @@ -1928,10 +2143,10 @@ static int mdss_dp_psm_config(struct mdss_dp_drv_pdata *dp, bool enable) * to user modules. */ if (mdss_dp_is_test_ongoing(dp)) { - mdss_dp_link_retraining(dp); + mdss_dp_link_maintenance(dp, true); } else { mdss_dp_host_init(&dp->panel_data); - mdss_dp_notify_clients(dp, true); + mdss_dp_notify_clients(dp, NOTIFY_CONNECT); } } @@ -1993,7 +2208,7 @@ static ssize_t mdss_dp_rda_psm(struct device *dev, static ssize_t mdss_dp_wta_hpd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int hpd; + int hpd, rc; ssize_t ret = strnlen(buf, PAGE_SIZE); struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); @@ -2003,9 +2218,10 @@ static ssize_t mdss_dp_wta_hpd(struct device *dev, goto end; } - ret = kstrtoint(buf, 10, &hpd); - if (ret) { - pr_err("kstrtoint failed. ret=%d\n", (int)ret); + rc = kstrtoint(buf, 10, &hpd); + if (rc) { + pr_err("kstrtoint failed. ret=%d\n", rc); + ret = rc; goto end; } @@ -2020,7 +2236,7 @@ static ssize_t mdss_dp_wta_hpd(struct device *dev, dp_send_events(dp, EV_USBPD_DISCOVER_MODES); } } else if (!dp->hpd && dp->power_on) { - mdss_dp_notify_clients(dp, false); + mdss_dp_notify_clients(dp, NOTIFY_DISCONNECT); } end: return ret; @@ -2043,6 +2259,233 @@ static ssize_t mdss_dp_rda_hpd(struct device *dev, return ret; } +static int mdss_dp_parse_config_value(char const *buf, char const *name, + u32 *val) +{ + int ret = 0; + char *buf1; + char *token; + + buf1 = strnstr(buf, name, PAGE_SIZE); + if (buf1) { + buf1 = buf1 + strlen(name); + token = strsep(&buf1, " "); + ret = kstrtou32(token, 10, val); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", (int)ret); + goto end; + } + pr_debug("parsed %s(%d)\n", name, *val); + } else { + ret = -EINVAL; + } + +end: + return ret; +} + +static ssize_t mdss_dp_wta_config(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u32 val; + u32 bit_depth; + int ret; + char const *bpp_key = "bpp="; + char const *pattern_type_key = "pattern_type="; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + pr_err("invalid data\n"); + ret = -EINVAL; + goto end; + } + + ret = mdss_dp_parse_config_value(buf, bpp_key, &val); + if (ret) { + pr_debug("%s config not found\n", bpp_key); + goto pattern_type; + } + + bit_depth = mdss_dp_bpp_to_test_bit_depth(val); + if (!mdss_dp_is_test_bit_depth_valid(bit_depth)) { + pr_err("invalid bpp = %d\n", val); + } else { + dp->test_data.test_bit_depth = bit_depth; + if (val != 0) + dp->override_config = true; + else + dp->override_config = false; + pr_debug("bpp=%d, test_bit_depth=%d\n", val, + dp->test_data.test_bit_depth); + } + +pattern_type: + ret = mdss_dp_parse_config_value(buf, pattern_type_key, &val); + if (ret) { + pr_debug("%s config not found\n", pattern_type_key); + goto end; + } + + if (!mdss_dp_is_test_video_pattern_valid(val)) { + pr_err("invalid test video pattern = %d\n", val); + } else { + dp->test_data.test_video_pattern = val; + pr_debug("test_video_pattern=%d (%s)\n", + dp->test_data.test_video_pattern, + mdss_dp_test_video_pattern_to_string( + dp->test_data.test_video_pattern)); + } + +end: + return count; +} + +static ssize_t mdss_dp_rda_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + u32 bpp; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + pr_err("invalid input\n"); + return -EINVAL; + } + + bpp = mdss_dp_get_bpp(dp); + ret = snprintf(buf, PAGE_SIZE, "bpp=%d\npattern_type=%d\n", + bpp, dp->test_data.test_video_pattern); + + pr_debug("bpp: %d pattern_type=%d (%s)\n", + bpp, dp->test_data.test_video_pattern, + mdss_dp_test_video_pattern_to_string( + dp->test_data.test_video_pattern)); + + return ret; +} + +static ssize_t mdss_dp_wta_frame_crc(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + u32 val; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + char const *ctl_crc_key = "ctl_crc_en="; + char const *sink_crc_key = "sink_crc_en="; + bool ctl_crc_en, sink_crc_en; + + if (!dp) { + pr_err("invalid data\n"); + goto end; + } + + if (!dp->power_on) { + pr_err("DP controller not powered on\n"); + goto end; + } + + ret = mdss_dp_parse_config_value(buf, ctl_crc_key, &val); + if (ret) { + pr_debug("%s config not found\n", ctl_crc_key); + goto sink_crc; + } + ctl_crc_en = val ? true : false; + mdss_dp_config_ctl_frame_crc(dp, ctl_crc_en); + +sink_crc: + ret = mdss_dp_parse_config_value(buf, sink_crc_key, &val); + if (ret) { + pr_debug("%s config not found\n", sink_crc_key); + goto end; + } + sink_crc_en = val ? true : false; + mdss_dp_aux_config_sink_frame_crc(dp, sink_crc_en); + +end: + return count; +} + +static ssize_t mdss_dp_print_crc_values(struct mdss_dp_drv_pdata *dp, + char *buf, ssize_t len) +{ + char line[] = "------------------------------"; + + mdss_dp_read_ctl_frame_crc(dp); + mdss_dp_aux_read_sink_frame_crc(dp); + + return snprintf(buf, PAGE_SIZE, + "\t\t|R_Cr\t\t|G_y\t\t|B_Cb\n%s%s\nctl(%s)\t|0x%08x\t|0x%08x\t|0x%08x\nsink(%s)\t|0x%08x\t|0x%08x\t|0x%08x\n", + line, line, dp->ctl_crc.en ? "enabled" : "disabled", + dp->ctl_crc.r_cr, dp->ctl_crc.g_y, dp->ctl_crc.b_cb, + dp->sink_crc.en ? "enabled" : "disabled", + dp->sink_crc.r_cr, dp->sink_crc.g_y, dp->sink_crc.b_cb); +} + +static ssize_t mdss_dp_rda_frame_crc(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (!dp->power_on) { + pr_err("DP controller not powered on\n"); + return 0; + } + + ret = mdss_dp_print_crc_values(dp, buf, PAGE_SIZE); + + return ret; +} + +static ssize_t mdss_dp_wta_hdcp_feature(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u32 hdcp; + int rc; + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + pr_err("invalid data\n"); + ret = -EINVAL; + goto end; + } + + rc = kstrtoint(buf, 10, &hdcp); + if (rc) { + pr_err("kstrtoint failed. ret=%d\n", rc); + ret = rc; + goto end; + } + + dp->hdcp.feature_enabled = !!hdcp; + pr_debug("hdcp=%d\n", dp->hdcp.feature_enabled); +end: + return ret; +} + +static ssize_t mdss_dp_rda_hdcp_feature(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev); + + if (!dp) { + pr_err("invalid input\n"); + return -EINVAL; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", dp->hdcp.feature_enabled); + pr_debug("hdcp: %d\n", dp->hdcp.feature_enabled); + + return ret; +} + static DEVICE_ATTR(connected, S_IRUGO, mdss_dp_rda_connected, NULL); static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, mdss_dp_sysfs_rda_s3d_mode, mdss_dp_sysfs_wta_s3d_mode); @@ -2050,13 +2493,21 @@ static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, mdss_dp_rda_hpd, mdss_dp_wta_hpd); static DEVICE_ATTR(psm, S_IRUGO | S_IWUSR, mdss_dp_rda_psm, mdss_dp_wta_psm); - +static DEVICE_ATTR(config, S_IRUGO | S_IWUSR, mdss_dp_rda_config, + mdss_dp_wta_config); +static DEVICE_ATTR(frame_crc, S_IRUGO | S_IWUSR, mdss_dp_rda_frame_crc, + mdss_dp_wta_frame_crc); +static DEVICE_ATTR(hdcp_feature, S_IRUGO | S_IWUSR, mdss_dp_rda_hdcp_feature, + mdss_dp_wta_hdcp_feature); static struct attribute *mdss_dp_fs_attrs[] = { &dev_attr_connected.attr, &dev_attr_s3d_mode.attr, &dev_attr_hpd.attr, &dev_attr_psm.attr, + &dev_attr_config.attr, + &dev_attr_frame_crc.attr, + &dev_attr_hdcp_feature.attr, NULL, }; @@ -2124,6 +2575,11 @@ static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp) return; } + if (!dp->hdcp.feature_enabled) { + pr_debug("feature not enabled\n"); + return; + } + /* check first if hdcp2p2 is supported */ fd = dp->hdcp.hdcp2; if (fd) @@ -2153,13 +2609,6 @@ static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp) } } -static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv) -{ - return dp_drv->hdcp.feature_enabled && - (dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) && - dp_drv->hdcp.ops; -} - static int mdss_dp_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -2235,21 +2684,6 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, return rc; } -static int mdss_dp_remove(struct platform_device *pdev) -{ - struct mdss_dp_drv_pdata *dp_drv = NULL; - - dp_drv = platform_get_drvdata(pdev); - dp_hdcp2p2_deinit(dp_drv->hdcp.data); - - iounmap(dp_drv->ctrl_io.base); - dp_drv->ctrl_io.base = NULL; - iounmap(dp_drv->phy_io.base); - dp_drv->phy_io.base = NULL; - - return 0; -} - static int mdss_dp_device_register(struct mdss_dp_drv_pdata *dp_drv) { int ret; @@ -2360,81 +2794,105 @@ static void mdss_dp_do_link_train(struct mdss_dp_drv_pdata *dp) mdss_dp_link_train(dp); } -static void mdss_dp_event_work(struct work_struct *work) +static int mdss_dp_event_thread(void *data) { - struct mdss_dp_drv_pdata *dp = NULL; unsigned long flag; u32 todo = 0, config; - if (!work) { - pr_err("invalid work structure\n"); - return; - } - - dp = container_of(work, struct mdss_dp_drv_pdata, work); - - spin_lock_irqsave(&dp->event_lock, flag); - todo = dp->current_event; - dp->current_event = 0; - spin_unlock_irqrestore(&dp->event_lock, flag); + struct mdss_dp_event_data *ev_data; + struct mdss_dp_event *ev; + struct mdss_dp_drv_pdata *dp = NULL; - pr_debug("todo=%s\n", mdss_dp_ev_event_to_string(todo)); + if (!data) + return -EINVAL; - switch (todo) { - case EV_EDID_READ: - mdss_dp_edid_read(dp); - break; - case EV_DPCD_CAP_READ: - mdss_dp_dpcd_cap_read(dp); - break; - case EV_DPCD_STATUS_READ: - mdss_dp_dpcd_status_read(dp); - break; - case EV_LINK_TRAIN: - mdss_dp_do_link_train(dp); - break; - case EV_VIDEO_READY: - mdss_dp_video_ready(dp); - break; - case EV_IDLE_PATTERNS_SENT: - mdss_dp_idle_patterns_sent(dp); - break; - case EV_USBPD_ATTENTION: - mdss_dp_handle_attention(dp); - break; - case EV_USBPD_DISCOVER_MODES: - usbpd_send_svdm(dp->pd, USB_C_DP_SID, USBPD_SVDM_DISCOVER_MODES, - SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0); - break; - case EV_USBPD_ENTER_MODE: - usbpd_send_svdm(dp->pd, USB_C_DP_SID, USBPD_SVDM_ENTER_MODE, - SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); - break; - case EV_USBPD_EXIT_MODE: - usbpd_send_svdm(dp->pd, USB_C_DP_SID, USBPD_SVDM_EXIT_MODE, - SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); - break; - case EV_USBPD_DP_STATUS: - config = 0x1; /* DFP_D connected */ - usbpd_send_svdm(dp->pd, USB_C_DP_SID, DP_VDM_STATUS, - SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); - break; - case EV_USBPD_DP_CONFIGURE: - config = mdss_dp_usbpd_gen_config_pkt(dp); - usbpd_send_svdm(dp->pd, USB_C_DP_SID, DP_VDM_CONFIGURE, - SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); - break; - default: - pr_err("Unknown event:%d\n", todo); + ev_data = (struct mdss_dp_event_data *)data; + init_waitqueue_head(&ev_data->event_q); + spin_lock_init(&ev_data->event_lock); + + while (!kthread_should_stop()) { + wait_event(ev_data->event_q, + (ev_data->pndx != ev_data->gndx) || + kthread_should_stop()); + spin_lock_irqsave(&ev_data->event_lock, flag); + ev = &(ev_data->event_list[ev_data->gndx++]); + todo = ev->id; + dp = ev->dp; + ev->id = 0; + ev_data->gndx %= MDSS_DP_EVENT_Q_MAX; + spin_unlock_irqrestore(&ev_data->event_lock, flag); + + pr_debug("todo=%s\n", mdss_dp_ev_event_to_string(todo)); + + switch (todo) { + case EV_EDID_READ: + mdss_dp_edid_read(dp); + break; + case EV_DPCD_CAP_READ: + mdss_dp_dpcd_cap_read(dp); + break; + case EV_DPCD_STATUS_READ: + mdss_dp_dpcd_status_read(dp); + break; + case EV_LINK_TRAIN: + mdss_dp_do_link_train(dp); + break; + case EV_VIDEO_READY: + mdss_dp_video_ready(dp); + break; + case EV_IDLE_PATTERNS_SENT: + mdss_dp_idle_patterns_sent(dp); + break; + case EV_USBPD_ATTENTION: + mdss_dp_handle_attention(dp); + break; + case EV_USBPD_DISCOVER_MODES: + usbpd_send_svdm(dp->pd, USB_C_DP_SID, + USBPD_SVDM_DISCOVER_MODES, + SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0); + break; + case EV_USBPD_ENTER_MODE: + usbpd_send_svdm(dp->pd, USB_C_DP_SID, + USBPD_SVDM_ENTER_MODE, + SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); + break; + case EV_USBPD_EXIT_MODE: + usbpd_send_svdm(dp->pd, USB_C_DP_SID, + USBPD_SVDM_EXIT_MODE, + SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); + break; + case EV_USBPD_DP_STATUS: + config = 0x1; /* DFP_D connected */ + usbpd_send_svdm(dp->pd, USB_C_DP_SID, DP_VDM_STATUS, + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); + break; + case EV_USBPD_DP_CONFIGURE: + config = mdss_dp_usbpd_gen_config_pkt(dp); + usbpd_send_svdm(dp->pd, USB_C_DP_SID, DP_VDM_CONFIGURE, + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); + break; + default: + pr_err("Unknown event:%d\n", todo); + } } + + return 0; } -static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 events) +static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 event) { - spin_lock(&dp->event_lock); - dp->current_event = events; - queue_work(dp->workq, &dp->work); - spin_unlock(&dp->event_lock); + struct mdss_dp_event *ev; + struct mdss_dp_event_data *ev_data = &dp->dp_event; + + pr_debug("event=%s\n", mdss_dp_ev_event_to_string(event)); + + spin_lock(&ev_data->event_lock); + ev = &ev_data->event_list[ev_data->pndx++]; + ev->id = event; + ev->dp = dp; + ev_data->pndx %= MDSS_DP_EVENT_Q_MAX; + wake_up(&ev_data->event_q); + spin_unlock(&ev_data->event_lock); } irqreturn_t dp_isr(int irq, void *ptr) @@ -2470,10 +2928,10 @@ irqreturn_t dp_isr(int irq, void *ptr) } if (isr2 & EDP_INTR_READY_FOR_VIDEO) - dp_send_events(dp, EV_VIDEO_READY); + mdss_dp_video_ready(dp); if (isr2 & EDP_INTR_IDLE_PATTERNs_SENT) - dp_send_events(dp, EV_IDLE_PATTERNS_SENT); + mdss_dp_idle_patterns_sent(dp); if (isr1 && dp->aux_cmd_busy) { /* clear DP_AUX_TRANS_CTRL */ @@ -2488,7 +2946,7 @@ irqreturn_t dp_isr(int irq, void *ptr) dp_aux_native_handler(dp, isr1); } - if (dp->hdcp.ops && dp->hdcp.ops->isr) { + if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) { if (dp->hdcp.ops->isr(dp->hdcp.data)) pr_err("dp_hdcp_isr failed\n"); } @@ -2496,17 +2954,32 @@ irqreturn_t dp_isr(int irq, void *ptr) return IRQ_HANDLED; } +static void mdss_dp_event_cleanup(struct mdss_dp_drv_pdata *dp) +{ + destroy_workqueue(dp->workq); + + if (dp->ev_thread == current) + return; + + kthread_stop(dp->ev_thread); +} + static int mdss_dp_event_setup(struct mdss_dp_drv_pdata *dp) { - spin_lock_init(&dp->event_lock); + dp->ev_thread = kthread_run(mdss_dp_event_thread, + (void *)&dp->dp_event, "mdss_dp_event"); + if (IS_ERR(dp->ev_thread)) { + pr_err("unable to start event thread\n"); + return PTR_ERR(dp->ev_thread); + } + dp->workq = create_workqueue("mdss_dp_hpd"); if (!dp->workq) { pr_err("%s: Error creating workqueue\n", __func__); return -EPERM; } - INIT_WORK(&dp->work, mdss_dp_event_work); INIT_DELAYED_WORK(&dp->hdcp_cb_work, mdss_dp_hdcp_cb_work); INIT_LIST_HEAD(&dp->attention_head); return 0; @@ -2541,7 +3014,18 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr) pr_debug("cable disconnected\n"); mdss_dp_update_cable_status(dp_drv, false); dp_drv->alt_mode.current_state = UNKNOWN_STATE; - mdss_dp_notify_clients(dp_drv, false); + + /** + * Manually turn off the DP controller if we are in PHY + * testing mode. + */ + if (mdss_dp_is_phy_test_pattern_requested(dp_drv)) { + pr_info("turning off DP controller for PHY testing\n"); + mdss_dp_mainlink_push_idle(&dp_drv->panel_data); + mdss_dp_off_hpd(dp_drv); + } else { + mdss_dp_notify_clients(dp_drv, NOTIFY_DISCONNECT); + } } static int mdss_dp_validate_callback(u8 cmd, @@ -2598,54 +3082,22 @@ static inline void mdss_dp_send_test_response(struct mdss_dp_drv_pdata *dp) } /** - * mdss_dp_hpd_irq_notify_clients() - notifies DP clients of HPD IRQ tear down + * mdss_dp_link_maintenance() - initiates link maintenanace * @dp: Display Port Driver data + * @lt_needed: link retraining needed * - * This function will send a notification to display/audio clients of DP tear - * down during an HPD IRQ. This happens only if HPD IRQ is toggled, - * in which case the user space proceeds with shutdown of DP driver, including - * mainlink disable, and pushing the controller into idle state. - */ -static int mdss_dp_hpd_irq_notify_clients(struct mdss_dp_drv_pdata *dp) -{ - const int irq_comp_timeout = HZ * 2; - int ret = 0; - - if (dp->hpd_irq_toggled) { - dp->hpd_irq_clients_notified = true; - - ret = mdss_dp_notify_clients(dp, false); - - if (!IS_ERR_VALUE(ret) && ret) { - reinit_completion(&dp->irq_comp); - ret = wait_for_completion_timeout(&dp->irq_comp, - irq_comp_timeout); - if (ret <= 0) { - pr_warn("irq_comp timed out\n"); - ret = -EINVAL; - } else { - ret = 0; - } - } - } - - return 0; -} - -/** - * mdss_dp_link_retraining() - initiates link retraining - * @dp: Display Port Driver data - * - * This function will initiate link retraining by first notifying + * This function will perform link maintenance by first notifying * DP clients and triggering DP shutdown, and then enabling DP after - * notification is done successfully. + * notification is done successfully. It will perform link retraining + * if specified. */ -static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp) +static inline void mdss_dp_link_maintenance(struct mdss_dp_drv_pdata *dp, + bool lt_needed) { - if (mdss_dp_hpd_irq_notify_clients(dp)) + if (mdss_dp_notify_clients(dp, NOTIFY_DISCONNECT_IRQ_HPD)) return; - mdss_dp_on_irq(dp); + mdss_dp_on_irq(dp, lt_needed); } /** @@ -2670,7 +3122,7 @@ static int mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp) mdss_dp_aux_channel_eq_done(dp), mdss_dp_aux_clock_recovery_done(dp)); - mdss_dp_link_retraining(dp); + mdss_dp_link_maintenance(dp, true); return 0; } @@ -2701,7 +3153,7 @@ static int mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp) dp->test_data.test_lane_count; dp->link_rate = dp->test_data.test_link_rate; - mdss_dp_link_retraining(dp); + mdss_dp_link_maintenance(dp, true); return 0; } @@ -2722,38 +3174,109 @@ static int mdss_dp_process_phy_test_pattern_request( if (!mdss_dp_is_phy_test_pattern_requested(dp)) return -EINVAL; - mdss_dp_send_test_response(dp); - test_link_rate = dp->test_data.test_link_rate; test_lane_count = dp->test_data.test_lane_count; - pr_info("%s link rate = 0x%x, lane count = 0x%x\n", - mdss_dp_get_test_name(TEST_LINK_TRAINING), - test_link_rate, test_lane_count); + if (!mdss_dp_aux_is_link_rate_valid(test_link_rate) || + !mdss_dp_aux_is_lane_count_valid(test_lane_count)) { + pr_info("Invalid params: link rate = 0x%x, lane count = 0x%x\n", + test_link_rate, test_lane_count); + return -EINVAL; + } + + pr_debug("start\n"); + + if (dp->power_on) { + pr_info("turning off DP controller for PHY testing\n"); + mdss_dp_mainlink_push_idle(&dp->panel_data); + /* + * The global reset will need DP link ralated clocks to be + * running. Add the global reset just before disabling the + * link clocks and core clocks. + */ + mdss_dp_ctrl_reset(&dp->ctrl_io); + mdss_dp_off_irq(dp); + } /** - * Retrain the mainlink if there is a change in link rate or lane - * count. + * Set the timing information to 1920x1080p60. This resolution will be + * used when enabling the pixel clock. */ - if (mdss_dp_aux_is_link_rate_valid(test_link_rate) && - mdss_dp_aux_is_lane_count_valid(test_lane_count) && - ((dp->dpcd.max_lane_count != test_lane_count) || - (dp->link_rate != test_link_rate))) { + dp_init_panel_info(dp, HDMI_VFRMT_1920x1080p60_16_9); - pr_info("updated link rate or lane count, retraining.\n"); + pr_info("Current: link rate = 0x%x, lane count = 0x%x\n", + dp->dpcd.max_lane_count, + dp->link_rate); - dp->dpcd.max_lane_count = dp->test_data.test_lane_count; - dp->link_rate = dp->test_data.test_link_rate; + pr_info("Requested: link rate = 0x%x, lane count = 0x%x\n", + dp->test_data.test_link_rate, + dp->test_data.test_lane_count); - mdss_dp_link_retraining(dp); - } + dp->dpcd.max_lane_count = dp->test_data.test_lane_count; + dp->link_rate = dp->test_data.test_link_rate; - mdss_dp_config_ctrl(dp); + mdss_dp_on_irq(dp, true); + /** + * Read the updated values for voltage and pre-emphasis levels and + * then program the DP controller PHY accordingly. + */ + mdss_dp_aux_parse_vx_px(dp); mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(dp); mdss_dp_phy_send_test_pattern(dp); + mdss_dp_send_test_response(dp); + + pr_debug("end\n"); + + return 0; +} + +/** + * mdss_dp_process_audio_pattern_request() - process new audio pattern request + * @dp: Display Port Driver data + * + * This function will handle a new audio pattern request that is initiated by + * the sink. This is acheieved by sending the necessary secondary data packets + * to the sink. It is expected that any simulatenous requests for video + * patterns will be handled before the audio pattern is sent to the sink. + */ +static int mdss_dp_process_audio_pattern_request(struct mdss_dp_drv_pdata *dp) +{ + if (!mdss_dp_is_audio_pattern_requested(dp)) + return -EINVAL; + + if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) { + cancel_delayed_work(&dp->hdcp_cb_work); + dp->hdcp.ops->off(dp->hdcp.data); + } + + pr_debug("sampling_rate=%s, channel_count=%d, pattern_type=%s\n", + mdss_dp_get_audio_sample_rate( + dp->test_data.test_audio_sampling_rate), + dp->test_data.test_audio_channel_count, + mdss_dp_get_audio_test_pattern( + dp->test_data.test_audio_pattern_type)); + + pr_debug("audio_period: ch1=0x%x, ch2=0x%x, ch3=0x%x, ch4=0x%x\n", + dp->test_data.test_audio_period_ch_1, + dp->test_data.test_audio_period_ch_2, + dp->test_data.test_audio_period_ch_3, + dp->test_data.test_audio_period_ch_4); + + pr_debug("audio_period: ch5=0x%x, ch6=0x%x, ch7=0x%x, ch8=0x%x\n", + dp->test_data.test_audio_period_ch_5, + dp->test_data.test_audio_period_ch_6, + dp->test_data.test_audio_period_ch_7, + dp->test_data.test_audio_period_ch_8); + + if (dp->ext_audio_data.intf_ops.hpd) + dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, + dp->ext_audio_data.type, 1, MSM_EXT_DISP_HPD_AUDIO); + + dp->audio_test_req = true; + return 0; } @@ -2777,6 +3300,81 @@ static int mdss_dp_process_downstream_port_status_change( return mdss_dp_edid_read(dp); } +static bool mdss_dp_video_pattern_test_lt_needed(struct mdss_dp_drv_pdata *dp) +{ + char new_link_rate; + + /* + * Link re-training for video format change is only needed if: + * 1. Link rate changes + * 2. Lane count changes + * For now, assume that lane count is not going to change + */ + new_link_rate = mdss_dp_gen_link_clk(dp); + pr_debug("new link rate = 0x%x, current link rate = 0x%x\n", + new_link_rate, dp->link_rate); + if (new_link_rate != dp->link_rate) { + dp->link_rate = new_link_rate; + return true; + } + + return false; +} + +/** + * mdss_dp_process_video_pattern_request() - process new video pattern request + * @dp: Display Port Driver data + * + * This function will handle a new video pattern request that are initiated by + * the sink. This is acheieved by first sending a disconnect notification to + * the sink followed by a subsequent connect notification to the user modules, + * where it is expected that the user modules would draw the required test + * pattern. + */ +static int mdss_dp_process_video_pattern_request(struct mdss_dp_drv_pdata *dp) +{ + bool lt_needed; + struct hdmi_edid_override_data ov_data = {0, 0, 1, + HDMI_VFRMT_640x480p59_4_3}; + bool ov_res = false; + + if (!mdss_dp_is_video_pattern_requested(dp)) + goto end; + + pr_info("%s: bit depth=%d(%d bpp) pattern=%s\n", + mdss_dp_get_test_name(TEST_VIDEO_PATTERN), + dp->test_data.test_bit_depth, + mdss_dp_test_bit_depth_to_bpp(dp->test_data.test_bit_depth), + mdss_dp_test_video_pattern_to_string( + dp->test_data.test_video_pattern)); + + if (dp->test_data.test_h_width == 640) { + pr_debug("Set resolution to 640x480p59"); + if (dp->vic != HDMI_VFRMT_640x480p59_4_3) { + ov_res = true; + dp->vic = HDMI_VFRMT_640x480p59_4_3; + } + hdmi_edid_config_override(dp->panel_data.panel_info.edid_data, + true, &ov_data); + } + + dp_init_panel_info(dp, dp->vic); + lt_needed = ov_res | mdss_dp_video_pattern_test_lt_needed(dp); + + pr_debug("Link training needed: %s", lt_needed ? "yes" : "no"); + + mdss_dp_link_maintenance(dp, lt_needed); + + if (mdss_dp_is_audio_pattern_requested(dp)) + goto end; + + mdss_dp_send_test_response(dp); + + return 0; +end: + return -EINVAL; +} + /** * mdss_dp_process_hpd_irq_high() - handle HPD IRQ transition to HIGH * @dp: Display Port Driver data @@ -2789,14 +3387,22 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) { int ret = 0; + pr_debug("start\n"); + dp->hpd_irq_on = true; + mdss_dp_reset_test_data(dp); + mdss_dp_aux_parse_sink_status_field(dp); ret = mdss_dp_process_link_training_request(dp); if (!ret) goto exit; + ret = mdss_dp_process_phy_test_pattern_request(dp); + if (!ret) + goto exit; + ret = mdss_dp_process_link_status_update(dp); if (!ret) goto exit; @@ -2805,41 +3411,19 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) if (!ret) goto exit; - ret = mdss_dp_process_phy_test_pattern_request(dp); + ret = mdss_dp_process_video_pattern_request(dp); if (!ret) goto exit; - pr_debug("done\n"); -exit: - mdss_dp_reset_test_data(dp); - - return ret; -} -/** - * mdss_dp_process_hpd_irq_low() - handle HPD IRQ transition to LOW - * @dp: Display Port Driver data - * - * This function will handle the HPD IRQ state transitions from HIGH to LOW, - * indicating the end of a test request. - */ -static int mdss_dp_process_hpd_irq_low(struct mdss_dp_drv_pdata *dp) -{ - if (!dp->hpd_irq_clients_notified) - return -EINVAL; + ret = mdss_dp_process_audio_pattern_request(dp); + if (!ret) + goto exit; - pr_debug("enter: HPD IRQ low\n"); + pr_debug("done\n"); +exit: dp->hpd_irq_on = false; - dp->hpd_irq_clients_notified = false; - - mdss_dp_update_cable_status(dp, false); - mdss_dp_mainlink_push_idle(&dp->panel_data); - mdss_dp_off_hpd(dp); - - mdss_dp_reset_test_data(dp); - - pr_debug("done\n"); - return 0; + return ret; } static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, @@ -2900,6 +3484,7 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, case DP_VDM_CONFIGURE: dp_drv->alt_mode.current_state |= DP_CONFIGURE_DONE; pr_debug("Configure: config USBPD to DP done\n"); + mdss_dp_usbpd_ext_dp_status(&dp_drv->alt_mode.dp_status); mdss_dp_host_init(&dp_drv->panel_data); @@ -2914,22 +3499,16 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) { - dp_drv->hpd_irq_toggled = dp_drv->hpd_irq_on != - dp_drv->alt_mode.dp_status.hpd_irq; - if (dp_drv->alt_mode.dp_status.hpd_irq) { pr_debug("Attention: hpd_irq high\n"); - if (dp_drv->hdcp.ops && dp_drv->hdcp.ops->cp_irq) { + if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->cp_irq) { if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data)) return; } if (!mdss_dp_process_hpd_irq_high(dp_drv)) return; - } else if (dp_drv->hpd_irq_toggled) { - if (!mdss_dp_process_hpd_irq_low(dp_drv)) - return; } if (!dp_drv->alt_mode.dp_status.hpd_high) { @@ -2940,16 +3519,23 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) dp_drv->hdcp.ops->off(dp_drv->hdcp.data); } - mdss_dp_update_cable_status(dp_drv, false); - mdss_dp_notify_clients(dp_drv, false); + mdss_dp_notify_clients(dp_drv, NOTIFY_DISCONNECT); pr_debug("Attention: Notified clients\n"); + + /** + * Manually turn off the DP controller if we are in PHY + * testing mode. + */ + if (mdss_dp_is_phy_test_pattern_requested(dp_drv)) { + pr_info("turning off DP controller for PHY testing\n"); + mdss_dp_mainlink_push_idle(&dp_drv->panel_data); + mdss_dp_off_hpd(dp_drv); + } return; } pr_debug("Attention: HPD high\n"); - mdss_dp_update_cable_status(dp_drv, true); - dp_drv->alt_mode.current_state |= DP_STATUS_DONE; if (dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE) { @@ -2963,6 +3549,7 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp) { int i = 0; + pr_debug("start\n"); while (!list_empty_careful(&dp->attention_head)) { struct mdss_dp_attention_node *node; @@ -2983,8 +3570,11 @@ static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp) dp->alt_mode.dp_status.response = vdo; mdss_dp_usbpd_ext_dp_status(&dp->alt_mode.dp_status); mdss_dp_process_attention(dp); + + pr_debug("done processing item %d in the list\n", i); }; + pr_debug("exit\n"); } static int mdss_dp_usbpd_setup(struct mdss_dp_drv_pdata *dp_drv) @@ -3063,6 +3653,11 @@ static int mdss_dp_probe(struct platform_device *pdev) mutex_init(&dp_drv->attention_lock); mutex_init(&dp_drv->hdcp_mutex); spin_lock_init(&dp_drv->lock); + mutex_init(&dp_drv->aux_mutex); + mutex_init(&dp_drv->train_mutex); + init_completion(&dp_drv->aux_comp); + init_completion(&dp_drv->idle_comp); + init_completion(&dp_drv->video_comp); if (mdss_dp_usbpd_setup(dp_drv)) { pr_err("Error usbpd setup!\n"); @@ -3202,6 +3797,22 @@ static inline bool dp_is_stream_shareable(struct mdss_dp_drv_pdata *dp_drv) return ret; } +static int mdss_dp_remove(struct platform_device *pdev) +{ + struct mdss_dp_drv_pdata *dp_drv = NULL; + + dp_drv = platform_get_drvdata(pdev); + dp_hdcp2p2_deinit(dp_drv->hdcp.data); + + mdss_dp_event_cleanup(dp_drv); + iounmap(dp_drv->ctrl_io.base); + dp_drv->ctrl_io.base = NULL; + iounmap(dp_drv->phy_io.base); + dp_drv->phy_io.base = NULL; + + return 0; +} + static const struct of_device_id msm_mdss_dp_dt_match[] = { {.compatible = "qcom,mdss-dp"}, {} diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index b7a8583e5864..bf74a8a4d7df 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -269,6 +269,32 @@ struct dpcd_test_request { u32 test_link_rate; u32 test_lane_count; u32 phy_test_pattern_sel; + u32 test_video_pattern; + u32 test_bit_depth; + u32 test_dyn_range; + u32 test_h_total; + u32 test_v_total; + u32 test_h_start; + u32 test_v_start; + u32 test_hsync_pol; + u32 test_hsync_width; + u32 test_vsync_pol; + u32 test_vsync_width; + u32 test_h_width; + u32 test_v_height; + u32 test_rr_d; + u32 test_rr_n; + u32 test_audio_sampling_rate; + u32 test_audio_channel_count; + u32 test_audio_pattern_type; + u32 test_audio_period_ch_1; + u32 test_audio_period_ch_2; + u32 test_audio_period_ch_3; + u32 test_audio_period_ch_4; + u32 test_audio_period_ch_5; + u32 test_audio_period_ch_6; + u32 test_audio_period_ch_7; + u32 test_audio_period_ch_8; u32 response; }; @@ -376,6 +402,28 @@ struct dp_hdcp { bool feature_enabled; }; +struct mdss_dp_event { + struct mdss_dp_drv_pdata *dp; + u32 id; +}; + +#define MDSS_DP_EVENT_Q_MAX 4 + +struct mdss_dp_event_data { + wait_queue_head_t event_q; + u32 pndx; + u32 gndx; + struct mdss_dp_event event_list[MDSS_DP_EVENT_Q_MAX]; + spinlock_t event_lock; +}; + +struct mdss_dp_crc_data { + bool en; + u32 r_cr; + u32 g_y; + u32 b_cb; +}; + struct mdss_dp_drv_pdata { /* device driver */ int (*on) (struct mdss_panel_data *pdata); @@ -402,6 +450,7 @@ struct mdss_dp_drv_pdata { bool sink_info_read; bool hpd; bool psm_enabled; + bool audio_test_req; /* dp specific */ unsigned char *base; @@ -413,8 +462,11 @@ struct mdss_dp_drv_pdata { struct dss_io_data hdcp_io; int base_size; unsigned char *mmss_cc_base; + bool override_config; u32 mask1; u32 mask2; + struct mdss_dp_crc_data ctl_crc; + struct mdss_dp_crc_data sink_crc; struct mdss_panel_data panel_data; struct mdss_util_intf *mdss_util; @@ -451,7 +503,6 @@ struct mdss_dp_drv_pdata { /* aux */ struct completion aux_comp; - struct completion train_comp; struct completion idle_comp; struct completion video_comp; struct completion irq_comp; @@ -478,18 +529,15 @@ struct mdss_dp_drv_pdata { char tu_desired; char valid_boundary; char delay_start; - u32 bpp; struct dp_statistic dp_stat; bool hpd_irq_on; - bool hpd_irq_toggled; - bool hpd_irq_clients_notified; + u32 hpd_notification_status; + + struct mdss_dp_event_data dp_event; + struct task_struct *ev_thread; - /* event */ struct workqueue_struct *workq; - struct work_struct work; struct delayed_work hdcp_cb_work; - u32 current_event; - spinlock_t event_lock; spinlock_t lock; struct switch_dev sdev; struct kobject *kobj; @@ -512,6 +560,55 @@ enum dp_lane_count { DP_LANE_COUNT_4 = 4, }; +enum audio_pattern_type { + AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00, + AUDIO_TEST_PATTERN_SAWTOOTH = 0x01, +}; + +static inline char *mdss_dp_get_audio_test_pattern(u32 pattern) +{ + switch (pattern) { + case AUDIO_TEST_PATTERN_OPERATOR_DEFINED: + return DP_ENUM_STR(AUDIO_TEST_PATTERN_OPERATOR_DEFINED); + case AUDIO_TEST_PATTERN_SAWTOOTH: + return DP_ENUM_STR(AUDIO_TEST_PATTERN_SAWTOOTH); + default: + return "unknown"; + } +} + +enum audio_sample_rate { + AUDIO_SAMPLE_RATE_32_KHZ = 0x00, + AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01, + AUDIO_SAMPLE_RATE_48_KHZ = 0x02, + AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03, + AUDIO_SAMPLE_RATE_96_KHZ = 0x04, + AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05, + AUDIO_SAMPLE_RATE_192_KHZ = 0x06, +}; + +static inline char *mdss_dp_get_audio_sample_rate(u32 rate) +{ + switch (rate) { + case AUDIO_SAMPLE_RATE_32_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_32_KHZ); + case AUDIO_SAMPLE_RATE_44_1_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_44_1_KHZ); + case AUDIO_SAMPLE_RATE_48_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_48_KHZ); + case AUDIO_SAMPLE_RATE_88_2_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_88_2_KHZ); + case AUDIO_SAMPLE_RATE_96_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_96_KHZ); + case AUDIO_SAMPLE_RATE_176_4_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_176_4_KHZ); + case AUDIO_SAMPLE_RATE_192_KHZ: + return DP_ENUM_STR(AUDIO_SAMPLE_RATE_192_KHZ); + default: + return "unknown"; + } +} + enum phy_test_pattern { PHY_TEST_PATTERN_NONE, PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING, @@ -608,17 +705,22 @@ static inline char *mdss_dp_get_test_response(u32 test_response) enum test_type { UNKNOWN_TEST = 0, - TEST_LINK_TRAINING = BIT(0), - PHY_TEST_PATTERN = BIT(3), - TEST_EDID_READ = BIT(2), + TEST_LINK_TRAINING = 0x1, + TEST_VIDEO_PATTERN = 0x2, + PHY_TEST_PATTERN = 0x8, + TEST_EDID_READ = 0x4, + TEST_AUDIO_PATTERN = 32, + TEST_AUDIO_DISABLED_VIDEO = 64, }; static inline char *mdss_dp_get_test_name(u32 test_requested) { switch (test_requested) { case TEST_LINK_TRAINING: return DP_ENUM_STR(TEST_LINK_TRAINING); + case TEST_VIDEO_PATTERN: return DP_ENUM_STR(TEST_VIDEO_PATTERN); case PHY_TEST_PATTERN: return DP_ENUM_STR(PHY_TEST_PATTERN); case TEST_EDID_READ: return DP_ENUM_STR(TEST_EDID_READ); + case TEST_AUDIO_PATTERN: return DP_ENUM_STR(TEST_AUDIO_PATTERN); default: return "unknown"; } } @@ -661,11 +763,252 @@ static inline char *mdss_dp_ev_event_to_string(int event) return DP_ENUM_STR(EV_IDLE_PATTERNS_SENT); case EV_VIDEO_READY: return DP_ENUM_STR(EV_VIDEO_READY); + case EV_USBPD_DISCOVER_MODES: + return DP_ENUM_STR(EV_USBPD_DISCOVER_MODES); + case EV_USBPD_ENTER_MODE: + return DP_ENUM_STR(EV_USBPD_ENTER_MODE); + case EV_USBPD_DP_STATUS: + return DP_ENUM_STR(EV_USBPD_DP_STATUS); + case EV_USBPD_DP_CONFIGURE: + return DP_ENUM_STR(EV_USBPD_DP_CONFIGURE); + case EV_USBPD_CC_PIN_POLARITY: + return DP_ENUM_STR(EV_USBPD_CC_PIN_POLARITY); + case EV_USBPD_EXIT_MODE: + return DP_ENUM_STR(EV_USBPD_EXIT_MODE); + case EV_USBPD_ATTENTION: + return DP_ENUM_STR(EV_USBPD_ATTENTION); + default: + return "unknown"; + } +} + +enum dynamic_range { + DP_DYNAMIC_RANGE_RGB_VESA = 0x00, + DP_DYNAMIC_RANGE_RGB_CEA = 0x01, + DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF, +}; + +static inline char *mdss_dp_dynamic_range_to_string(u32 dr) +{ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_VESA: + return DP_ENUM_STR(DP_DYNAMIC_RANGE_RGB_VESA); + case DP_DYNAMIC_RANGE_RGB_CEA: + return DP_ENUM_STR(DP_DYNAMIC_RANGE_RGB_CEA); + case DP_DYNAMIC_RANGE_UNKNOWN: + default: + return "unknown"; + } +} + +/** + * mdss_dp_is_dynamic_range_valid() - validates the dynamic range + * @bit_depth: the dynamic range value to be checked + * + * Returns true if the dynamic range value is supported. + */ +static inline bool mdss_dp_is_dynamic_range_valid(u32 dr) +{ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_VESA: + case DP_DYNAMIC_RANGE_RGB_CEA: + return true; + default: + return false; + } +} + +enum test_bit_depth { + DP_TEST_BIT_DEPTH_6 = 0x00, + DP_TEST_BIT_DEPTH_8 = 0x01, + DP_TEST_BIT_DEPTH_10 = 0x02, + DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF, +}; + +static inline char *mdss_dp_test_bit_depth_to_string(u32 tbd) +{ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + return DP_ENUM_STR(DP_TEST_BIT_DEPTH_6); + case DP_TEST_BIT_DEPTH_8: + return DP_ENUM_STR(DP_TEST_BIT_DEPTH_8); + case DP_TEST_BIT_DEPTH_10: + return DP_ENUM_STR(DP_TEST_BIT_DEPTH_10); + case DP_TEST_BIT_DEPTH_UNKNOWN: + default: + return "unknown"; + } +} + +/** + * mdss_dp_is_test_bit_depth_valid() - validates the bit depth requested + * @bit_depth: bit depth requested by the sink + * + * Returns true if the requested bit depth is supported. + */ +static inline bool mdss_dp_is_test_bit_depth_valid(u32 tbd) +{ + /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + case DP_TEST_BIT_DEPTH_8: + case DP_TEST_BIT_DEPTH_10: + return true; + default: + return false; + } +} + +/** + * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp + * @tbd: test bit depth + * + * Returns the bits per pixel (bpp) to be used corresponding to the + * git bit depth value. This function assumes that bit depth has + * already been validated. + */ +static inline u32 mdss_dp_test_bit_depth_to_bpp(enum test_bit_depth tbd) +{ + u32 bpp; + + /* + * Few simplistic rules and assumptions made here: + * 1. Bit depth is per color component + * 2. If bit depth is unknown return 0 + * 3. Assume 3 color components + */ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + bpp = 18; + break; + case DP_TEST_BIT_DEPTH_8: + bpp = 24; + break; + case DP_TEST_BIT_DEPTH_10: + bpp = 30; + break; + case DP_TEST_BIT_DEPTH_UNKNOWN: + default: + bpp = 0; + } + + return bpp; +} + +/** + * mdss_dp_bpp_to_test_bit_depth() - convert bpp to test bit depth + * &bpp: the bpp to be converted + * + * Return the bit depth per color component to used with the video + * test pattern data based on the bits per pixel value. + */ +static inline u32 mdss_dp_bpp_to_test_bit_depth(u32 bpp) +{ + enum test_bit_depth tbd; + + /* + * Few simplistic rules and assumptions made here: + * 1. Test bit depth is bit depth per color component + * 2. Assume 3 color components + */ + switch (bpp) { + case 18: + tbd = DP_TEST_BIT_DEPTH_6; + break; + case 24: + tbd = DP_TEST_BIT_DEPTH_8; + break; + case 30: + tbd = DP_TEST_BIT_DEPTH_10; + break; + default: + tbd = DP_TEST_BIT_DEPTH_UNKNOWN; + break; + } + + return tbd; +} + +enum test_video_pattern { + DP_TEST_VIDEO_PATTERN_NONE = 0x00, + DP_TEST_VIDEO_PATTERN_COLOR_RAMPS = 0x01, + DP_TEST_VIDEO_PATTERN_BW_VERT_LINES = 0x02, + DP_TEST_VIDEO_PATTERN_COLOR_SQUARE = 0x03, +}; + +static inline char *mdss_dp_test_video_pattern_to_string(u32 test_video_pattern) +{ + switch (test_video_pattern) { + case DP_TEST_VIDEO_PATTERN_NONE: + return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_NONE); + case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS: + return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_RAMPS); + case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES: + return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_BW_VERT_LINES); + case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE: + return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_SQUARE); default: return "unknown"; } } +/** + * mdss_dp_is_test_video_pattern_valid() - validates the video pattern + * @pattern: video pattern requested by the sink + * + * Returns true if the requested video pattern is supported. + */ +static inline bool mdss_dp_is_test_video_pattern_valid(u32 pattern) +{ + switch (pattern) { + case DP_TEST_VIDEO_PATTERN_NONE: + case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS: + case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES: + case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE: + return true; + default: + return false; + } +} + +enum notification_status { + NOTIFY_UNKNOWN, + NOTIFY_CONNECT, + NOTIFY_DISCONNECT, + NOTIFY_CONNECT_IRQ_HPD, + NOTIFY_DISCONNECT_IRQ_HPD, +}; + +static inline char const *mdss_dp_notification_status_to_string( + enum notification_status status) +{ + switch (status) { + case NOTIFY_UNKNOWN: + return DP_ENUM_STR(NOTIFY_UNKNOWN); + case NOTIFY_CONNECT: + return DP_ENUM_STR(NOTIFY_CONNECT); + case NOTIFY_DISCONNECT: + return DP_ENUM_STR(NOTIFY_DISCONNECT); + case NOTIFY_CONNECT_IRQ_HPD: + return DP_ENUM_STR(NOTIFY_CONNECT_IRQ_HPD); + case NOTIFY_DISCONNECT_IRQ_HPD: + return DP_ENUM_STR(NOTIFY_DISCONNECT_IRQ_HPD); + default: + return "unknown"; + } +} + +static inline void mdss_dp_reset_frame_crc_data(struct mdss_dp_crc_data *crc) +{ + if (!crc) + return; + + crc->r_cr = 0; + crc->g_y = 0; + crc->b_cb = 0; + crc->en = false; +} + void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp); void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp); @@ -681,7 +1024,7 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep); void mdss_dp_sink_power_down(struct mdss_dp_drv_pdata *ep); void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up); void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep); -char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt); +char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp); int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state); int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable); void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep); @@ -694,5 +1037,9 @@ bool mdss_dp_aux_is_lane_count_valid(u32 lane_count); int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len); void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl( struct mdss_dp_drv_pdata *dp); +int mdss_dp_aux_read_sink_frame_crc(struct mdss_dp_drv_pdata *dp); +int mdss_dp_aux_config_sink_frame_crc(struct mdss_dp_drv_pdata *dp, + bool enable); +int mdss_dp_aux_parse_vx_px(struct mdss_dp_drv_pdata *ep); #endif /* MDSS_DP_H */ diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index fa1af0d392e7..ca07e80d6613 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 2014, 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -466,10 +466,8 @@ void dp_extract_edid_video_support(struct edp_edid *edid, char *buf) edid->video_intf = *bp & 0x0f; /* 6, 8, 10, 12, 14 and 16 bit per component */ edid->color_depth = ((*bp & 0x70) >> 4); /* color bit depth */ - if (edid->color_depth) { - edid->color_depth *= 2; - edid->color_depth += 4; - } + /* decrement to match with the test_bit_depth enum definition */ + edid->color_depth--; pr_debug("Digital Video intf=%d color_depth=%d\n", edid->video_intf, edid->color_depth); } else { @@ -501,12 +499,14 @@ void dp_extract_edid_feature(struct edp_edid *edid, char *buf) edid->dpm, edid->color_format); }; -char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt) +char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp) { const u32 encoding_factx10 = 8; const u32 ln_to_link_ratio = 10; u32 min_link_rate, reminder = 0; char calc_link_rate = 0; + struct mdss_panel_info *pinfo = &dp->panel_data.panel_info; + char lane_cnt = dp->dpcd.max_lane_count; pr_debug("clk_rate=%llu, bpp= %d, lane_cnt=%d\n", pinfo->clk_rate, pinfo->bpp, lane_cnt); @@ -545,6 +545,11 @@ char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt) calc_link_rate = DP_LINK_RATE_540; } + pr_debug("calc_link_rate=0x%x, Max rate supported by sink=0x%x\n", + dp->link_rate, dp->dpcd.max_link_rate); + if (calc_link_rate > dp->dpcd.max_link_rate) + calc_link_rate = dp->dpcd.max_link_rate; + pr_debug("calc_link_rate = 0x%x\n", calc_link_rate); return calc_link_rate; } @@ -1112,6 +1117,84 @@ bool mdss_dp_aux_is_lane_count_valid(u32 lane_count) (lane_count == DP_LANE_COUNT_4); } +int mdss_dp_aux_parse_vx_px(struct mdss_dp_drv_pdata *ep) +{ + char *bp; + char data; + struct edp_buf *rp; + int rlen; + int const param_len = 0x1; + int const addr1 = 0x206; + int const addr2 = 0x207; + int ret = 0; + u32 v0, p0, v1, p1, v2, p2, v3, p3; + + pr_info("Parsing DPCP for updated voltage and pre-emphasis levels\n"); + + rlen = dp_aux_read_buf(ep, addr1, param_len, 0); + if (rlen < param_len) { + pr_err("failed reading lanes 0/1\n"); + ret = -EINVAL; + goto end; + } + + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + pr_info("lanes 0/1 (Byte 0x206): 0x%x\n", data); + + v0 = data & 0x3; + data = data >> 2; + p0 = data & 0x3; + data = data >> 2; + + v1 = data & 0x3; + data = data >> 2; + p1 = data & 0x3; + data = data >> 2; + + rlen = dp_aux_read_buf(ep, addr2, param_len, 0); + if (rlen < param_len) { + pr_err("failed reading lanes 2/3\n"); + ret = -EINVAL; + goto end; + } + + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + pr_info("lanes 2/3 (Byte 0x207): 0x%x\n", data); + + v2 = data & 0x3; + data = data >> 2; + p2 = data & 0x3; + data = data >> 2; + + v3 = data & 0x3; + data = data >> 2; + p3 = data & 0x3; + data = data >> 2; + + pr_info("vx: 0=%d, 1=%d, 2=%d, 3=%d\n", v0, v1, v2, v3); + pr_info("px: 0=%d, 1=%d, 2=%d, 3=%d\n", p0, p1, p2, p3); + + /** + * Update the voltage and pre-emphasis levels as per DPCD request + * vector. + */ + pr_info("Current: v_level = 0x%x, p_level = 0x%x\n", + ep->v_level, ep->p_level); + pr_info("Requested: v_level = 0x%x, p_level = 0x%x\n", v0, p0); + ep->v_level = v0; + ep->p_level = p0; + + pr_info("Success\n"); +end: + return ret; +} + /** * dp_parse_link_training_params() - parses link training parameters from DPCD * @ep: Display Port Driver data @@ -1212,6 +1295,236 @@ static void dp_sink_parse_sink_count(struct mdss_dp_drv_pdata *ep) ep->sink_count.count, ep->sink_count.cp_ready); } +static int dp_get_test_period(struct mdss_dp_drv_pdata *ep, int const addr) +{ + int ret = 0; + char *bp; + char data; + struct edp_buf *rp; + int rlen; + int const test_parameter_len = 0x1; + int const max_audio_period = 0xA; + + /* TEST_AUDIO_PERIOD_CH_XX */ + rlen = dp_aux_read_buf(ep, addr, test_parameter_len, 0); + if (rlen < test_parameter_len) { + pr_err("failed to read test_audio_period (0x%x)\n", addr); + ret = -EINVAL; + goto exit; + } + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + /* Period - Bits 3:0 */ + data = data & 0xF; + if ((int)data > max_audio_period) { + pr_err("invalid test_audio_period_ch_1 = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + ret = data; + +exit: + return ret; +} + +static int dp_parse_audio_channel_test_period(struct mdss_dp_drv_pdata *ep) +{ + int ret = 0; + int const test_audio_period_ch_1_addr = 0x273; + int const test_audio_period_ch_2_addr = 0x274; + int const test_audio_period_ch_3_addr = 0x275; + int const test_audio_period_ch_4_addr = 0x276; + int const test_audio_period_ch_5_addr = 0x277; + int const test_audio_period_ch_6_addr = 0x278; + int const test_audio_period_ch_7_addr = 0x279; + int const test_audio_period_ch_8_addr = 0x27A; + + /* TEST_AUDIO_PERIOD_CH_1 (Byte 0x273) */ + ret = dp_get_test_period(ep, test_audio_period_ch_1_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_1 = ret; + pr_debug("test_audio_period_ch_1 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_2 (Byte 0x274) */ + ret = dp_get_test_period(ep, test_audio_period_ch_2_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_2 = ret; + pr_debug("test_audio_period_ch_2 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */ + ret = dp_get_test_period(ep, test_audio_period_ch_3_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_3 = ret; + pr_debug("test_audio_period_ch_3 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_4 (Byte 0x276) */ + ret = dp_get_test_period(ep, test_audio_period_ch_4_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_4 = ret; + pr_debug("test_audio_period_ch_4 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_5 (Byte 0x277) */ + ret = dp_get_test_period(ep, test_audio_period_ch_5_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_5 = ret; + pr_debug("test_audio_period_ch_5 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_6 (Byte 0x278) */ + ret = dp_get_test_period(ep, test_audio_period_ch_6_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_6 = ret; + pr_debug("test_audio_period_ch_6 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_7 (Byte 0x279) */ + ret = dp_get_test_period(ep, test_audio_period_ch_7_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_7 = ret; + pr_debug("test_audio_period_ch_7 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_8 (Byte 0x27A) */ + ret = dp_get_test_period(ep, test_audio_period_ch_8_addr); + if (ret == -EINVAL) + goto exit; + + ep->test_data.test_audio_period_ch_8 = ret; + pr_debug("test_audio_period_ch_8 = 0x%x\n", ret); + + +exit: + return ret; +} + +static int dp_parse_audio_pattern_type(struct mdss_dp_drv_pdata *ep) +{ + int ret = 0; + char *bp; + char data; + struct edp_buf *rp; + int rlen; + int const test_parameter_len = 0x1; + int const test_audio_pattern_type_addr = 0x272; + int const max_audio_pattern_type = 0x1; + + /* Read the requested audio pattern type (Byte 0x272). */ + rlen = dp_aux_read_buf(ep, test_audio_pattern_type_addr, + test_parameter_len, 0); + if (rlen < test_parameter_len) { + pr_err("failed to read test audio mode data\n"); + ret = -EINVAL; + goto exit; + } + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + /* Audio Pattern Type - Bits 7:0 */ + if ((int)data > max_audio_pattern_type) { + pr_err("invalid audio pattern type = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + ep->test_data.test_audio_pattern_type = data; + pr_debug("audio pattern type = %s\n", + mdss_dp_get_audio_test_pattern(data)); + +exit: + return ret; +} + +static int dp_parse_audio_mode(struct mdss_dp_drv_pdata *ep) +{ + int ret = 0; + char *bp; + char data; + struct edp_buf *rp; + int rlen; + int const test_parameter_len = 0x1; + int const test_audio_mode_addr = 0x271; + int const max_audio_sampling_rate = 0x6; + int const max_audio_channel_count = 0x8; + int sampling_rate = 0x0; + int channel_count = 0x0; + + /* Read the requested audio mode (Byte 0x271). */ + rlen = dp_aux_read_buf(ep, test_audio_mode_addr, + test_parameter_len, 0); + if (rlen < test_parameter_len) { + pr_err("failed to read test audio mode data\n"); + ret = -EINVAL; + goto exit; + } + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + /* Sampling Rate - Bits 3:0 */ + sampling_rate = data & 0xF; + if (sampling_rate > max_audio_sampling_rate) { + pr_err("sampling rate (0x%x) greater than max (0x%x)\n", + sampling_rate, max_audio_sampling_rate); + ret = -EINVAL; + goto exit; + } + + /* Channel Count - Bits 7:4 */ + channel_count = ((data & 0xF0) >> 4) + 1; + if (channel_count > max_audio_channel_count) { + pr_err("channel_count (0x%x) greater than max (0x%x)\n", + channel_count, max_audio_channel_count); + ret = -EINVAL; + goto exit; + } + + ep->test_data.test_audio_sampling_rate = sampling_rate; + ep->test_data.test_audio_channel_count = channel_count; + pr_debug("sampling_rate = %s, channel_count = 0x%x\n", + mdss_dp_get_audio_sample_rate(sampling_rate), channel_count); + +exit: + return ret; +} + +/** + * dp_parse_audio_pattern_params() - parses audio pattern parameters from DPCD + * @ep: Display Port Driver data + * + * Returns 0 if it successfully parses the audio test pattern parameters. + */ +static int dp_parse_audio_pattern_params(struct mdss_dp_drv_pdata *ep) +{ + int ret = 0; + + ret = dp_parse_audio_mode(ep); + if (ret) + goto exit; + + ret = dp_parse_audio_pattern_type(ep); + if (ret) + goto exit; + + ret = dp_parse_audio_channel_test_period(ep); + +exit: + return ret; +} /** * dp_parse_phy_test_params() - parses the phy test parameters * @ep: Display Port Driver data @@ -1227,7 +1540,6 @@ static int dp_parse_phy_test_params(struct mdss_dp_drv_pdata *ep) int rlen; int const param_len = 0x1; int const phy_test_pattern_addr = 0x248; - int const dpcd_version_1_2 = 0x12; int ret = 0; rlen = dp_aux_read_buf(ep, phy_test_pattern_addr, param_len, 0); @@ -1241,11 +1553,6 @@ static int dp_parse_phy_test_params(struct mdss_dp_drv_pdata *ep) bp = rp->data; data = *bp++; - if (ep->dpcd.major == dpcd_version_1_2) - data = data & 0x7; - else - data = data & 0x3; - ep->test_data.phy_test_pattern_sel = data; pr_debug("phy_test_pattern_sel = %s\n", @@ -1258,6 +1565,256 @@ end: return ret; } +static int dp_parse_test_timing_params1(struct mdss_dp_drv_pdata *ep, + int const addr, int const len, u32 *val) +{ + char *bp; + struct edp_buf *rp; + int rlen; + + if (len < 2) + return -EINVAL; + + /* Read the requested video test pattern (Byte 0x221). */ + rlen = dp_aux_read_buf(ep, addr, len, 0); + if (rlen < len) { + pr_err("failed to read 0x%x\n", addr); + return -EINVAL; + } + rp = &ep->rxp; + bp = rp->data; + + *val = bp[1] | (bp[0] << 8); + + return 0; +} + +static int dp_parse_test_timing_params2(struct mdss_dp_drv_pdata *ep, + int const addr, int const len, u32 *val1, u32 *val2) +{ + char *bp; + struct edp_buf *rp; + int rlen; + + if (len < 2) + return -EINVAL; + + /* Read the requested video test pattern (Byte 0x221). */ + rlen = dp_aux_read_buf(ep, addr, len, 0); + if (rlen < len) { + pr_err("failed to read 0x%x\n", addr); + return -EINVAL; + } + rp = &ep->rxp; + bp = rp->data; + + *val1 = (bp[0] & BIT(7)) >> 7; + *val2 = bp[1] | ((bp[0] & 0x7F) << 8); + + return 0; +} + +static int dp_parse_test_timing_params3(struct mdss_dp_drv_pdata *ep, + int const addr, u32 *val) +{ + char *bp; + struct edp_buf *rp; + int rlen; + + /* Read the requested video test pattern (Byte 0x221). */ + rlen = dp_aux_read_buf(ep, addr, 1, 0); + if (rlen < 1) { + pr_err("failed to read 0x%x\n", addr); + return -EINVAL; + } + rp = &ep->rxp; + bp = rp->data; + *val = bp[0]; + + return 0; +} + +/** + * dp_parse_video_pattern_params() - parses video pattern parameters from DPCD + * @ep: Display Port Driver data + * + * Returns 0 if it successfully parses the video test pattern and the test + * bit depth requested by the sink and, and if the values parsed are valid. + */ +static int dp_parse_video_pattern_params(struct mdss_dp_drv_pdata *ep) +{ + int ret = 0; + char *bp; + char data; + struct edp_buf *rp; + int rlen; + u32 dyn_range; + int const test_parameter_len = 0x1; + int const test_video_pattern_addr = 0x221; + int const test_misc_addr = 0x232; + + /* Read the requested video test pattern (Byte 0x221). */ + rlen = dp_aux_read_buf(ep, test_video_pattern_addr, + test_parameter_len, 0); + if (rlen < test_parameter_len) { + pr_err("failed to read test video pattern\n"); + ret = -EINVAL; + goto exit; + } + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + if (!mdss_dp_is_test_video_pattern_valid(data)) { + pr_err("invalid test video pattern = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + ep->test_data.test_video_pattern = data; + pr_debug("test video pattern = 0x%x (%s)\n", + ep->test_data.test_video_pattern, + mdss_dp_test_video_pattern_to_string( + ep->test_data.test_video_pattern)); + + /* Read the requested color bit depth and dynamic range (Byte 0x232) */ + rlen = dp_aux_read_buf(ep, test_misc_addr, test_parameter_len, 0); + if (rlen < test_parameter_len) { + pr_err("failed to read test bit depth\n"); + ret = -EINVAL; + goto exit; + } + rp = &ep->rxp; + bp = rp->data; + data = *bp++; + + /* Dynamic Range */ + dyn_range = (data & BIT(3)) >> 3; + if (!mdss_dp_is_dynamic_range_valid(dyn_range)) { + pr_err("invalid test dynamic range = 0x%x", dyn_range); + ret = -EINVAL; + goto exit; + } + ep->test_data.test_dyn_range = dyn_range; + pr_debug("test dynamic range = 0x%x (%s)\n", + ep->test_data.test_dyn_range, + mdss_dp_dynamic_range_to_string(ep->test_data.test_dyn_range)); + + /* Color bit depth */ + data &= (BIT(5) | BIT(6) | BIT(7)); + data >>= 5; + if (!mdss_dp_is_test_bit_depth_valid(data)) { + pr_err("invalid test bit depth = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + ep->test_data.test_bit_depth = data; + pr_debug("test bit depth = 0x%x (%s)\n", + ep->test_data.test_bit_depth, + mdss_dp_test_bit_depth_to_string(ep->test_data.test_bit_depth)); + + /* resolution timing params */ + ret = dp_parse_test_timing_params1(ep, 0x222, 2, + &ep->test_data.test_h_total); + if (ret) { + pr_err("failed to parse test_h_total (0x222)\n"); + goto exit; + } + pr_debug("TEST_H_TOTAL = %d\n", ep->test_data.test_h_total); + + ret = dp_parse_test_timing_params1(ep, 0x224, 2, + &ep->test_data.test_v_total); + if (ret) { + pr_err("failed to parse test_v_total (0x224)\n"); + goto exit; + } + pr_debug("TEST_V_TOTAL = %d\n", ep->test_data.test_v_total); + + ret = dp_parse_test_timing_params1(ep, 0x226, 2, + &ep->test_data.test_h_start); + if (ret) { + pr_err("failed to parse test_h_start (0x226)\n"); + goto exit; + } + pr_debug("TEST_H_START = %d\n", ep->test_data.test_h_start); + + ret = dp_parse_test_timing_params1(ep, 0x228, 2, + &ep->test_data.test_v_start); + if (ret) { + pr_err("failed to parse test_v_start (0x228)\n"); + goto exit; + } + pr_debug("TEST_V_START = %d\n", ep->test_data.test_v_start); + + ret = dp_parse_test_timing_params2(ep, 0x22A, 2, + &ep->test_data.test_hsync_pol, + &ep->test_data.test_hsync_width); + if (ret) { + pr_err("failed to parse (0x22A)\n"); + goto exit; + } + pr_debug("TEST_HSYNC_POL = %d\n", ep->test_data.test_hsync_pol); + pr_debug("TEST_HSYNC_WIDTH = %d\n", ep->test_data.test_hsync_width); + + ret = dp_parse_test_timing_params2(ep, 0x22C, 2, + &ep->test_data.test_vsync_pol, + &ep->test_data.test_vsync_width); + if (ret) { + pr_err("failed to parse (0x22C)\n"); + goto exit; + } + pr_debug("TEST_VSYNC_POL = %d\n", ep->test_data.test_vsync_pol); + pr_debug("TEST_VSYNC_WIDTH = %d\n", ep->test_data.test_vsync_width); + + ret = dp_parse_test_timing_params1(ep, 0x22E, 2, + &ep->test_data.test_h_width); + if (ret) { + pr_err("failed to parse test_h_width (0x22E)\n"); + goto exit; + } + pr_debug("TEST_H_WIDTH = %d\n", ep->test_data.test_h_width); + + ret = dp_parse_test_timing_params1(ep, 0x230, 2, + &ep->test_data.test_v_height); + if (ret) { + pr_err("failed to parse test_v_height (0x230)\n"); + goto exit; + } + pr_debug("TEST_V_HEIGHT = %d\n", ep->test_data.test_v_height); + + ret = dp_parse_test_timing_params3(ep, 0x233, &ep->test_data.test_rr_d); + ep->test_data.test_rr_d &= BIT(0); + if (ret) { + pr_err("failed to parse test_rr_d (0x233)\n"); + goto exit; + } + pr_debug("TEST_REFRESH_DENOMINATOR = %d\n", ep->test_data.test_rr_d); + + ret = dp_parse_test_timing_params3(ep, 0x234, &ep->test_data.test_rr_n); + if (ret) { + pr_err("failed to parse test_rr_n (0x234)\n"); + goto exit; + } + pr_debug("TEST_REFRESH_NUMERATOR = %d\n", ep->test_data.test_rr_n); + +exit: + return ret; +} + +/** + * mdss_dp_is_video_audio_test_requested() - checks for audio/video test request + * @test: test requested by the sink + * + * Returns true if the requested test is a permitted audio/video test. + */ +static bool mdss_dp_is_video_audio_test_requested(u32 test) +{ + return (test == TEST_VIDEO_PATTERN) || + (test == (TEST_AUDIO_PATTERN | TEST_VIDEO_PATTERN)) || + (test == TEST_AUDIO_PATTERN) || + (test == (TEST_AUDIO_PATTERN | TEST_AUDIO_DISABLED_VIDEO)); +} /** * dp_is_test_supported() - checks if test requested by sink is supported @@ -1269,7 +1826,8 @@ static bool dp_is_test_supported(u32 test_requested) { return (test_requested == TEST_LINK_TRAINING) || (test_requested == TEST_EDID_READ) || - (test_requested == PHY_TEST_PATTERN); + (test_requested == PHY_TEST_PATTERN) || + mdss_dp_is_video_audio_test_requested(test_requested); } /** @@ -1289,6 +1847,7 @@ static void dp_sink_parse_test_request(struct mdss_dp_drv_pdata *ep) int const test_parameter_len = 0x1; int const device_service_irq_addr = 0x201; int const test_request_addr = 0x218; + char buf[4]; /** * Read the device service IRQ vector (Byte 0x201) to determine @@ -1330,23 +1889,31 @@ static void dp_sink_parse_test_request(struct mdss_dp_drv_pdata *ep) return; } - pr_debug("%s requested\n", mdss_dp_get_test_name(data)); + pr_debug("%s (0x%x) requested\n", mdss_dp_get_test_name(data), data); ep->test_data.test_requested = data; - switch (ep->test_data.test_requested) { - case PHY_TEST_PATTERN: + if (ep->test_data.test_requested == PHY_TEST_PATTERN) { ret = dp_parse_phy_test_params(ep); if (ret) - break; - case TEST_LINK_TRAINING: + goto end; ret = dp_parse_link_training_params(ep); - break; - default: - pr_debug("test 0x%x not supported\n", - ep->test_data.test_requested); - return; } + if (ep->test_data.test_requested == TEST_LINK_TRAINING) + ret = dp_parse_link_training_params(ep); + + if (mdss_dp_is_video_audio_test_requested( + ep->test_data.test_requested)) { + ret = dp_parse_video_pattern_params(ep); + if (ret) + goto end; + ret = dp_parse_audio_pattern_params(ep); + } +end: + /* clear the test request IRQ */ + buf[0] = 1; + dp_aux_write_buf(ep, test_request_addr, buf, 1, 0); + /** * Send a TEST_ACK if all test parameters are valid, otherwise send * a TEST_NACK. @@ -1568,7 +2135,7 @@ char vm_voltage_swing[4][4] = { {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ }; -static void dp_aux_set_voltage_and_pre_emphasis_lvl( +void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl( struct mdss_dp_drv_pdata *dp) { u32 value0 = 0; @@ -1605,45 +2172,13 @@ static void dp_aux_set_voltage_and_pre_emphasis_lvl( QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL, value1); - pr_debug("value0=0x%x value1=0x%x", + pr_debug("host PHY settings: value0=0x%x value1=0x%x", value0, value1); dp_lane_set_write(dp, dp->v_level, dp->p_level); } } -/** - * mdss_dp_aux_update_voltage_and_pre_emphasis_lvl() - updates DP PHY settings - * @ep: Display Port Driver data - * - * Updates the DP PHY with the requested voltage swing and pre-emphasis - * levels if they are different from the current settings. - */ -void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl( - struct mdss_dp_drv_pdata *dp) -{ - int const num_bytes = 6; - struct dpcd_link_status *status = &dp->link_status; - - /* Read link status for updated voltage and pre-emphasis levels. */ - mdss_dp_aux_link_status_read(dp, num_bytes); - - pr_info("Current: v_level = %d, p_level = %d\n", - dp->v_level, dp->p_level); - pr_info("Requested: v_level = %d, p_level = %d\n", - status->req_voltage_swing[0], - status->req_pre_emphasis[0]); - - if ((status->req_voltage_swing[0] != dp->v_level) || - (status->req_pre_emphasis[0] != dp->p_level)) { - dp->v_level = status->req_voltage_swing[0]; - dp->p_level = status->req_pre_emphasis[0]; - - dp_aux_set_voltage_and_pre_emphasis_lvl(dp); - } - - pr_debug("end\n"); -} static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) { int tries, old_v_level; @@ -1653,10 +2188,14 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) pr_debug("Entered++"); + dp_write(ep->base + DP_STATE_CTRL, 0x0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + dp_host_train_set(ep, 0x01); /* train_1 */ dp_cap_lane_rate_set(ep); dp_train_pattern_set_write(ep, 0x21); /* train_1 */ - dp_aux_set_voltage_and_pre_emphasis_lvl(ep); - dp_host_train_set(ep, 0x01); /* train_1 */ + mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(ep); tries = 0; old_v_level = ep->v_level; @@ -1687,7 +2226,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) } dp_sink_train_set_adjust(ep); - dp_aux_set_voltage_and_pre_emphasis_lvl(ep); + mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(ep); } return ret; @@ -1708,11 +2247,15 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) else pattern = 0x02; + dp_write(ep->base + DP_STATE_CTRL, 0x0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + dp_host_train_set(ep, pattern); + mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(ep); dp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */ do { - dp_host_train_set(ep, pattern); - usleep_time = ep->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time); @@ -1723,14 +2266,14 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) break; } - tries++; if (tries > maximum_retries) { ret = -1; break; } + tries++; dp_sink_train_set_adjust(ep); - dp_aux_set_voltage_and_pre_emphasis_lvl(ep); + mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(ep); } while (1); return ret; @@ -1787,25 +2330,20 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp) ret = dp_aux_chan_ready(dp); if (ret) { pr_err("LINK Train failed: aux chan NOT ready\n"); - complete(&dp->train_comp); return ret; } - dp_write(dp->base + DP_MAINLINK_CTRL, 0x1); - - mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON); - dp->v_level = 0; /* start from default level */ dp->p_level = 0; mdss_dp_config_ctrl(dp); mdss_dp_state_ctrl(&dp->ctrl_io, 0); - dp_clear_training_pattern(dp); ret = dp_start_link_train_1(dp); if (ret < 0) { if (!dp_link_rate_down_shift(dp)) { pr_debug("retry with lower rate\n"); + dp_clear_training_pattern(dp); return -EAGAIN; } else { pr_err("Training 1 failed\n"); @@ -1816,10 +2354,15 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp) pr_debug("Training 1 completed successfully\n"); + dp_write(dp->base + DP_STATE_CTRL, 0x0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + ret = dp_start_link_train_2(dp); if (ret < 0) { if (!dp_link_rate_down_shift(dp)) { pr_debug("retry with lower rate\n"); + dp_clear_training_pattern(dp); return -EAGAIN; } else { pr_err("Training 2 failed\n"); @@ -1830,19 +2373,13 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp) pr_debug("Training 2 completed successfully\n"); + dp_write(dp->base + DP_STATE_CTRL, 0x0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + clear: dp_clear_training_pattern(dp); - if (ret != -EINVAL) { - mdss_dp_config_misc_settings(&dp->ctrl_io, - &dp->panel_data.panel_info); - mdss_dp_setup_tr_unit(&dp->ctrl_io, dp->link_rate, - dp->lane_cnt, dp->vic, - &dp->panel_data.panel_info); - mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO); - pr_debug("State_ctrl set to SEND_VIDEO\n"); - } - complete(&dp->train_comp); return ret; } @@ -1885,15 +2422,129 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep) } +/** + * mdss_dp_aux_config_sink_frame_crc() - enable/disable per frame CRC calc + * @dp: Display Port Driver data + * @enable: true - start CRC calculation, false - stop CRC calculation + * + * Program the sink DPCD register 0x270 to start/stop CRC calculation. + * This would take effect with the next frame. + */ +int mdss_dp_aux_config_sink_frame_crc(struct mdss_dp_drv_pdata *dp, + bool enable) +{ + int rlen; + struct edp_buf *rp; + u8 *bp; + u8 buf[4]; + u8 crc_supported; + u32 const test_sink_addr = 0x270; + u32 const test_sink_misc_addr = 0x246; + + if (dp->sink_crc.en == enable) { + pr_debug("sink crc already %s\n", + enable ? "enabled" : "disabled"); + return 0; + } + + rlen = dp_aux_read_buf(dp, test_sink_misc_addr, 1, 0); + if (rlen < 1) { + pr_err("failed to TEST_SINK_ADDR\n"); + return -EPERM; + } + rp = &dp->rxp; + bp = rp->data; + crc_supported = bp[0] & BIT(5); + pr_debug("crc supported=%s\n", crc_supported ? "true" : "false"); + + if (!crc_supported) { + pr_err("sink does not support CRC generation\n"); + return -EINVAL; + } + + buf[0] = enable ? 1 : 0; + dp_aux_write_buf(dp, test_sink_addr, buf, BIT(0), 0); + + if (!enable) + mdss_dp_reset_frame_crc_data(&dp->sink_crc); + dp->sink_crc.en = enable; + pr_debug("TEST_SINK_START (CRC calculation) %s\n", + enable ? "enabled" : "disabled"); + + return 0; +} + +/** + * mdss_dp_aux_read_sink_frame_crc() - read frame CRC values from the sink + * @dp: Display Port Driver data + */ +int mdss_dp_aux_read_sink_frame_crc(struct mdss_dp_drv_pdata *dp) +{ + int rlen; + struct edp_buf *rp; + u8 *bp; + u32 addr, len; + struct mdss_dp_crc_data *crc = &dp->sink_crc; + + addr = 0x270; /* TEST_SINK */ + len = 1; /* one byte */ + rlen = dp_aux_read_buf(dp, addr, len, 0); + if (rlen < len) { + pr_err("failed to read TEST SINK\n"); + return -EPERM; + } + rp = &dp->rxp; + bp = rp->data; + if (!(bp[0] & BIT(0))) { + pr_err("Sink side CRC calculation not enabled, TEST_SINK=0x%08x\n", + (u32)bp[0]); + return -EINVAL; + } + + addr = 0x240; /* TEST_CRC_R_Cr */ + len = 2; /* 2 bytes */ + rlen = dp_aux_read_buf(dp, addr, len, 0); + if (rlen < len) { + pr_err("failed to read TEST_CRC_R_Cr\n"); + return -EPERM; + } + rp = &dp->rxp; + bp = rp->data; + crc->r_cr = bp[0] | (bp[1] << 8); + + addr = 0x242; /* TEST_CRC_G_Y */ + len = 2; /* 2 bytes */ + rlen = dp_aux_read_buf(dp, addr, len, 0); + if (rlen < len) { + pr_err("failed to read TEST_CRC_G_Y\n"); + return -EPERM; + } + rp = &dp->rxp; + bp = rp->data; + crc->g_y = bp[0] | (bp[1] << 8); + + addr = 0x244; /* TEST_CRC_B_Cb */ + len = 2; /* 2 bytes */ + rlen = dp_aux_read_buf(dp, addr, len, 0); + if (rlen < len) { + pr_err("failed to read TEST_CRC_B_Cb\n"); + return -EPERM; + } + rp = &dp->rxp; + bp = rp->data; + crc->b_cb = bp[0] | (bp[1] << 8); + + pr_debug("r_cr=0x%08x\t g_y=0x%08x\t b_cb=0x%08x\n", + crc->r_cr, crc->g_y, crc->b_cb); + + return 0; +} + void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep) { - mutex_init(&ep->aux_mutex); - mutex_init(&ep->train_mutex); - init_completion(&ep->aux_comp); - init_completion(&ep->train_comp); - init_completion(&ep->idle_comp); - init_completion(&ep->video_comp); - complete(&ep->train_comp); /* make non block at first time */ + reinit_completion(&ep->aux_comp); + reinit_completion(&ep->idle_comp); + reinit_completion(&ep->video_comp); complete(&ep->video_comp); /* make non block at first time */ dp_buf_init(&ep->txp, ep->txbuf, sizeof(ep->txbuf)); diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c index 73b9ad65482f..3bcacf945761 100644 --- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c @@ -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 @@ -370,6 +370,8 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) dp_hdcp2p2_set_interrupts(ctrl, false); + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); + /* notify DP about HDCP failure */ ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTH_FAIL); @@ -625,6 +627,12 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work) return; } + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || + atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("invalid hdcp state\n"); + return; + } + cdata.context = ctrl->lib_ctx; if (ctrl->sink_rx_status & ctrl->abort_mask) { @@ -685,6 +693,13 @@ static int dp_hdcp2p2_cp_irq(void *input) return -EINVAL; } + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || + atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("invalid hdcp state\n"); + rc = -EINVAL; + goto error; + } + ctrl->sink_rx_status = 0; rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data, &ctrl->sink_rx_status); diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c index a7f42ba8c261..1dcf83f094c1 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.c +++ b/drivers/video/fbdev/msm/mdss_dp_util.c @@ -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 @@ -202,6 +202,45 @@ void mdss_dp_configuration_ctrl(struct dss_io_data *ctrl_io, u32 data) writel_relaxed(data, ctrl_io->base + DP_CONFIGURATION_CTRL); } +void mdss_dp_config_ctl_frame_crc(struct mdss_dp_drv_pdata *dp, bool enable) +{ + if (dp->ctl_crc.en == enable) { + pr_debug("CTL crc already %s\n", + enable ? "enabled" : "disabled"); + return; + } + + writel_relaxed(BIT(8), dp->ctrl_io.base + MMSS_DP_TIMING_ENGINE_EN); + if (!enable) + mdss_dp_reset_frame_crc_data(&dp->ctl_crc); + dp->ctl_crc.en = enable; + + pr_debug("CTL crc %s\n", enable ? "enabled" : "disabled"); +} + +int mdss_dp_read_ctl_frame_crc(struct mdss_dp_drv_pdata *dp) +{ + u32 data; + u32 crc_rg = 0; + struct mdss_dp_crc_data *crc = &dp->ctl_crc; + + data = readl_relaxed(dp->ctrl_io.base + MMSS_DP_TIMING_ENGINE_EN); + if (!(data & BIT(8))) { + pr_debug("frame CRC calculation not enabled\n"); + return -EPERM; + } + + crc_rg = readl_relaxed(dp->ctrl_io.base + MMSS_DP_PSR_CRC_RG); + crc->r_cr = crc_rg & 0xFFFF; + crc->g_y = crc_rg >> 16; + crc->b_cb = readl_relaxed(dp->ctrl_io.base + MMSS_DP_PSR_CRC_B); + + pr_debug("r_cr=0x%08x\t g_y=0x%08x\t b_cb=0x%08x\n", + crc->r_cr, crc->g_y, crc->b_cb); + + return 0; +} + /* DP state controller*/ void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data) { @@ -735,7 +774,9 @@ void mdss_dp_timing_cfg(struct dss_io_data *ctrl_io, data = pinfo->lcdc.v_pulse_width; data <<= 16; + data |= (pinfo->lcdc.v_active_low << 31); data |= pinfo->lcdc.h_pulse_width; + data |= (pinfo->lcdc.h_active_low << 15); /* DP_HSYNC_VSYNC_WIDTH_POLARITY */ writel_relaxed(data, ctrl_io->base + DP_HSYNC_VSYNC_WIDTH_POLARITY); @@ -765,28 +806,15 @@ void mdss_dp_sw_config_msa(struct dss_io_data *ctrl_io, writel_relaxed(nvid, ctrl_io->base + DP_SOFTWARE_NVID); } -void mdss_dp_config_misc_settings(struct dss_io_data *ctrl_io, - struct mdss_panel_info *pinfo) +void mdss_dp_config_misc(struct mdss_dp_drv_pdata *dp, u32 bd, u32 cc) { - u32 bpp = pinfo->bpp; - u32 misc_val = 0x0; - - switch (bpp) { - case 18: - misc_val |= (0x0 << 5); - break; - case 30: - misc_val |= (0x2 << 5); - break; - case 24: - default: - misc_val |= (0x1 << 5); - } + u32 misc_val = cc; + misc_val |= (bd << 5); misc_val |= BIT(0); /* Configure clock to synchronous mode */ pr_debug("Misc settings = 0x%x\n", misc_val); - writel_relaxed(misc_val, ctrl_io->base + DP_MISC1_MISC0); + writel_relaxed(misc_val, dp->ctrl_io.base + DP_MISC1_MISC0); } void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate, @@ -1113,7 +1141,8 @@ static u8 mdss_dp_calculate_parity_byte(u32 data) return parityByte; } -static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io) +static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io, + u32 num_of_channels) { u32 value = 0; u32 new_value = 0; @@ -1131,7 +1160,7 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 2 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); - new_value = 0x0; + new_value = value; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); @@ -1141,7 +1170,7 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); - new_value = 0x01; + new_value = num_of_channels - 1; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); @@ -1179,7 +1208,7 @@ static void mdss_dp_audio_setup_audio_timestamp_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_1); - new_value = (0x0 | (0x12 << 2)); + new_value = (0x0 | (0x11 << 2)); parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); @@ -1216,7 +1245,7 @@ static void mdss_dp_audio_setup_audio_infoframe_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_1); - new_value = (0x0 | (0x12 << 2)); + new_value = (0x0 | (0x11 << 2)); parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); @@ -1309,7 +1338,7 @@ static void mdss_dp_audio_setup_isrc_sdp(struct dss_io_data *ctrl_io) writel_relaxed(0x0, ctrl_io->base + MMSS_DP_AUDIO_ISRC_4); } -void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io) +void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io, u32 num_of_channels) { u32 sdp_cfg = 0; u32 sdp_cfg2 = 0; @@ -1335,7 +1364,7 @@ void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io) writel_relaxed(sdp_cfg2, ctrl_io->base + MMSS_DP_SDP_CFG2); - mdss_dp_audio_setup_audio_stream_sdp(ctrl_io); + mdss_dp_audio_setup_audio_stream_sdp(ctrl_io, num_of_channels); mdss_dp_audio_setup_audio_timestamp_sdp(ctrl_io); mdss_dp_audio_setup_audio_infoframe_sdp(ctrl_io); mdss_dp_audio_setup_copy_management_sdp(ctrl_io); @@ -1366,7 +1395,7 @@ void mdss_dp_set_safe_to_exit_level(struct dss_io_data *ctrl_io, } mainlink_levels = readl_relaxed(ctrl_io->base + DP_MAINLINK_LEVELS); - mainlink_levels &= 0xFF0; + mainlink_levels &= 0xFE0; mainlink_levels |= safe_to_exit_level; pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n", @@ -1406,28 +1435,17 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp) return; } - /* Disable mainlink */ - writel_relaxed(0x0, io->base + DP_MAINLINK_CTRL); - - /* Reset mainlink */ - mdss_dp_mainlink_reset(io); - - /* Enable mainlink */ - writel_relaxed(0x0, io->base + DP_MAINLINK_CTRL); - /* Initialize DP state control */ - mdss_dp_state_ctrl(io, 0x00); + writel_relaxed(0x0, io->base + DP_STATE_CTRL); pr_debug("phy_test_pattern_sel = %s\n", mdss_dp_get_phy_test_pattern(phy_test_pattern_sel)); switch (phy_test_pattern_sel) { case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING: - mdss_dp_state_ctrl(io, BIT(0)); + writel_relaxed(0x1, io->base + DP_STATE_CTRL); break; case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: - value = readl_relaxed(io->base + - DP_HBR2_COMPLIANCE_SCRAMBLER_RESET); value &= ~(1 << 16); writel_relaxed(value, io->base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET); @@ -1438,7 +1456,7 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp) mdss_dp_state_ctrl(io, BIT(4)); break; case PHY_TEST_PATTERN_PRBS7: - mdss_dp_state_ctrl(io, BIT(5)); + writel_relaxed(0x20, io->base + DP_STATE_CTRL); break; case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN: mdss_dp_state_ctrl(io, BIT(6)); @@ -1453,9 +1471,7 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp) DP_TEST_80BIT_CUSTOM_PATTERN_REG2); break; case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN: - value = readl_relaxed(io->base + - DP_HBR2_COMPLIANCE_SCRAMBLER_RESET); - value |= BIT(16); + value = BIT(16); writel_relaxed(value, io->base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET); value |= 0xFC; @@ -1469,4 +1485,8 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp) phy_test_pattern_sel); return; } + + value = 0x0; + value = readl_relaxed(io->base + DP_MAINLINK_READY); + pr_info("DP_MAINLINK_READY = 0x%x\n", value); } diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index fcb9a77db67c..cb62d145960f 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -65,6 +65,7 @@ #define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4) #define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8) +#define MMSS_DP_MISC1_MISC0 (0x0000042C) #define MMSS_DP_AUDIO_TIMING_GEN (0x00000480) #define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484) #define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488) @@ -73,6 +74,9 @@ #define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494) #define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498) +#define MMSS_DP_PSR_CRC_RG (0x00000554) +#define MMSS_DP_PSR_CRC_B (0x00000558) + #define MMSS_DP_AUDIO_CFG (0x00000600) #define MMSS_DP_AUDIO_STATUS (0x00000604) #define MMSS_DP_AUDIO_PKT_CTRL (0x00000608) @@ -135,6 +139,8 @@ #define MMSS_DP_GENERIC1_8 (0x00000748) #define MMSS_DP_GENERIC1_9 (0x0000074C) +#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10) + /*DP PHY Register offsets */ #define DP_PHY_REVISION_ID0 (0x00000000) #define DP_PHY_REVISION_ID1 (0x00000004) @@ -285,8 +291,7 @@ void mdss_dp_switch_usb3_phy_to_dp_mode(struct dss_io_data *tcsr_reg_io); void mdss_dp_assert_phy_reset(struct dss_io_data *ctrl_io, bool assert); void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate, u8 ln_cnt, u32 res, struct mdss_panel_info *pinfo); -void mdss_dp_config_misc_settings(struct dss_io_data *ctrl_io, - struct mdss_panel_info *pinfo); +void mdss_dp_config_misc(struct mdss_dp_drv_pdata *dp, u32 bd, u32 cc); void mdss_dp_phy_aux_setup(struct dss_io_data *phy_io); void mdss_dp_hpd_configure(struct dss_io_data *ctrl_io, bool enable); void mdss_dp_aux_ctrl(struct dss_io_data *ctrl_io, bool enable); @@ -312,7 +317,7 @@ void mdss_dp_phy_share_lane_config(struct dss_io_data *phy_io, u8 orientation, u8 ln_cnt); void mdss_dp_config_audio_acr_ctrl(struct dss_io_data *ctrl_io, char link_rate); -void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io); +void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io, u32 num_of_channels); void mdss_dp_audio_enable(struct dss_io_data *ctrl_io, bool enable); void mdss_dp_audio_select_core(struct dss_io_data *ctrl_io); void mdss_dp_audio_set_sample_rate(struct dss_io_data *ctrl_io, @@ -321,5 +326,7 @@ void mdss_dp_set_safe_to_exit_level(struct dss_io_data *ctrl_io, uint32_t lane_cnt); int mdss_dp_aux_read_rx_status(struct mdss_dp_drv_pdata *dp, u8 *rx_status); void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp); +void mdss_dp_config_ctl_frame_crc(struct mdss_dp_drv_pdata *dp, bool enable); +int mdss_dp_read_ctl_frame_crc(struct mdss_dp_drv_pdata *dp); #endif /* __DP_UTIL_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 19e3eadfc1b2..51745a9a59ac 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2507,6 +2507,23 @@ static struct device_node *mdss_dsi_get_fb_node_cb(struct platform_device *pdev) return fb_node; } +static void mdss_dsi_timing_db_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, + int enable) +{ + if (!ctrl || !ctrl->timing_db_mode || + (ctrl->shared_data->hw_rev < MDSS_DSI_HW_REV_201)) + return; + + mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, + MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_ON); + MIPI_OUTP((ctrl->ctrl_base + 0x1e8), enable); + wmb(); /* ensure timing db is disabled */ + MIPI_OUTP((ctrl->ctrl_base + 0x1e4), enable); + wmb(); /* ensure timing flush is disabled */ + mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, + MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF); +} + static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -2680,6 +2697,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, &ctrl_pdata->dba_work, HZ); } break; + case MDSS_EVENT_DSI_TIMING_DB_CTRL: + mdss_dsi_timing_db_ctrl(ctrl_pdata, (int)(unsigned long)arg); + break; default: pr_debug("%s: unhandled event=%d\n", __func__, event); break; diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 0574410868bf..df24352ff87d 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -58,6 +58,7 @@ #define MDSS_DSI_HW_REV_104_1 0x10040001 /* 8996 */ #define MDSS_DSI_HW_REV_104_2 0x10040002 /* 8937 */ #define MDSS_DSI_HW_REV_200 0x20000000 /* cobalt */ +#define MDSS_DSI_HW_REV_201 0x20010000 /* 660 */ #define MDSS_DSI_HW_REV_STEP_0 0x0 #define MDSS_DSI_HW_REV_STEP_1 0x1 @@ -487,6 +488,8 @@ struct mdss_dsi_ctrl_pdata { struct dsi_panel_cmds post_dms_on_cmds; struct dsi_panel_cmds post_panel_on_cmds; struct dsi_panel_cmds off_cmds; + struct dsi_panel_cmds lp_on_cmds; + struct dsi_panel_cmds lp_off_cmds; struct dsi_panel_cmds status_cmds; u32 *status_valid_params; u32 *status_cmds_rlen; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 7f6cad3de18e..7cc9ce6e034d 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -160,6 +160,27 @@ int mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0, return mdss_dsi_cmdlist_put(ctrl, &cmdreq); } +static void mdss_dsi_panel_apply_settings(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_panel_cmds *pcmds) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + if ((pinfo->dcs_cmd_by_left) && (ctrl->ndx != DSI_CTRL_LEFT)) + return; + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = pcmds->cmds; + cmdreq.cmds_cnt = pcmds->cmd_cnt; + cmdreq.flags = CMD_REQ_COMMIT; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + + mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + + static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_panel_cmds *pcmds, u32 flags) { @@ -660,6 +681,38 @@ end: return 0; } +static int mdss_dsi_panel_apply_display_setting(struct mdss_panel_data *pdata, + u32 mode) +{ + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + struct dsi_panel_cmds *lp_on_cmds; + struct dsi_panel_cmds *lp_off_cmds; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + lp_on_cmds = &ctrl->lp_on_cmds; + lp_off_cmds = &ctrl->lp_off_cmds; + + /* Apply display settings for low-persistence mode */ + if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_ON) && + (lp_on_cmds->cmd_cnt)) + mdss_dsi_panel_apply_settings(ctrl, lp_on_cmds); + else if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_OFF) && + (lp_on_cmds->cmd_cnt)) + mdss_dsi_panel_apply_settings(ctrl, lp_off_cmds); + else + return -EINVAL; + + pr_debug("%s: Persistence mode %d applied\n", __func__, mode); + return 0; +} + static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, int mode) { @@ -822,6 +875,10 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) if (ctrl->ds_registered) mdss_dba_utils_video_on(pinfo->dba_data, pinfo); + + /* Ensure low persistence mode is set as before */ + mdss_dsi_panel_apply_display_setting(pdata, pinfo->persist_mode); + end: pr_debug("%s:-\n", __func__); return ret; @@ -2046,6 +2103,12 @@ static int mdss_dsi_parse_panel_features(struct device_node *np, __func__, __LINE__); } + mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_on_cmds, + "qcom,mdss-dsi-lp-mode-on", NULL); + + mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_off_cmds, + "qcom,mdss-dsi-lp-mode-off", NULL); + return 0; } @@ -2796,12 +2859,15 @@ int mdss_dsi_panel_init(struct device_node *node, pinfo->dynamic_switch_pending = false; pinfo->is_lpm_mode = false; pinfo->esd_rdy = false; + pinfo->persist_mode = false; ctrl_pdata->on = mdss_dsi_panel_on; ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on; ctrl_pdata->off = mdss_dsi_panel_off; ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config; ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl; + ctrl_pdata->panel_data.apply_display_setting = + mdss_dsi_panel_apply_display_setting; ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; return 0; diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index f20248e13cf8..a183fd7cd247 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1,8 +1,8 @@ /* * Core MDSS framebuffer driver. * + * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated - * Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -589,8 +589,8 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, "primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n" "is_cec_supported=%d\nis_pingpong_split=%d\n" "dfps_porch_mode=%d\npu_roi_cnt=%d\ndual_dsi=%d\n" - "is_hdr_enabled=%d\n" - "peak_brightness=%d\nblackness_level=%d\n" + "is_hdr_enabled=%d\npeak_brightness=%d\n" + "blackness_level=%d\naverage_brightness=%d\n" "white_chromaticity_x=%d\nwhite_chromaticity_y=%d\n" "red_chromaticity_x=%d\nred_chromaticity_y=%d\n" "green_chromaticity_x=%d\ngreen_chromaticity_y=%d\n" @@ -612,6 +612,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, is_panel_split(mfd), pinfo->hdr_properties.hdr_enabled, pinfo->hdr_properties.peak_brightness, pinfo->hdr_properties.blackness_level, + pinfo->hdr_properties.avg_brightness, pinfo->hdr_properties.display_primaries[0], pinfo->hdr_properties.display_primaries[1], pinfo->hdr_properties.display_primaries[2], @@ -823,6 +824,74 @@ static ssize_t mdss_fb_get_dfps_mode(struct device *dev, return ret; } +static ssize_t mdss_fb_change_persist_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdss_panel_info *pinfo = NULL; + struct mdss_panel_data *pdata; + int ret = 0; + u32 persist_mode; + + if (!mfd || !mfd->panel_info) { + pr_err("%s: Panel info is NULL!\n", __func__); + return len; + } + + pinfo = mfd->panel_info; + + if (kstrtouint(buf, 0, &persist_mode)) { + pr_err("kstrtouint buf error!\n"); + return len; + } + + mutex_lock(&mfd->mdss_sysfs_lock); + if (mdss_panel_is_power_off(mfd->panel_power_state)) { + pinfo->persist_mode = persist_mode; + goto end; + } + + mutex_lock(&mfd->bl_lock); + + pdata = dev_get_platdata(&mfd->pdev->dev); + if ((pdata) && (pdata->apply_display_setting)) + ret = pdata->apply_display_setting(pdata, persist_mode); + + mutex_unlock(&mfd->bl_lock); + + if (!ret) { + pr_debug("%s: Persist mode %d\n", __func__, persist_mode); + pinfo->persist_mode = persist_mode; + } + +end: + mutex_unlock(&mfd->mdss_sysfs_lock); + + return len; +} + +static ssize_t mdss_fb_get_persist_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdss_panel_data *pdata; + struct mdss_panel_info *pinfo; + int ret; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("no panel connected!\n"); + return -EINVAL; + } + pinfo = &pdata->panel_info; + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", pinfo->persist_mode); + + return ret; +} + static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL); static DEVICE_ATTR(msm_fb_split, S_IRUGO | S_IWUSR, mdss_fb_show_split, mdss_fb_store_split); @@ -841,6 +910,8 @@ static DEVICE_ATTR(msm_fb_dfps_mode, S_IRUGO | S_IWUSR, mdss_fb_get_dfps_mode, mdss_fb_change_dfps_mode); static DEVICE_ATTR(measured_fps, S_IRUGO | S_IWUSR | S_IWGRP, mdss_fb_get_fps_info, NULL); +static DEVICE_ATTR(msm_fb_persist_mode, S_IRUGO | S_IWUSR, + mdss_fb_get_persist_mode, mdss_fb_change_persist_mode); static struct attribute *mdss_fb_attrs[] = { &dev_attr_msm_fb_type.attr, &dev_attr_msm_fb_split.attr, @@ -853,6 +924,7 @@ static struct attribute *mdss_fb_attrs[] = { &dev_attr_msm_fb_panel_status.attr, &dev_attr_msm_fb_dfps_mode.attr, &dev_attr_measured_fps.attr, + &dev_attr_msm_fb_persist_mode.attr, NULL, }; @@ -1203,6 +1275,7 @@ static int mdss_fb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&mfd->file_list); mutex_init(&mfd->bl_lock); + mutex_init(&mfd->mdss_sysfs_lock); mutex_init(&mfd->switch_lock); fbi_list[fbi_list_index++] = fbi; @@ -1971,6 +2044,8 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info) return ret; } + mutex_lock(&mfd->mdss_sysfs_lock); + if (mfd->op_enable == 0) { if (blank_mode == FB_BLANK_UNBLANK) mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON; @@ -1980,7 +2055,9 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info) mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1; else mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF; - return 0; + + ret = 0; + goto end; } pr_debug("mode: %d\n", blank_mode); @@ -1997,7 +2074,12 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info) if (pdata->panel_disable_mode) mdss_mdp_enable_panel_disable_mode(mfd, false); - return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); + ret = mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); + +end: + mutex_unlock(&mfd->mdss_sysfs_lock); + + return ret; } static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd) diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 1487c4e7f6e2..111d7cfc7c9a 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.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 @@ -310,6 +310,7 @@ struct msm_fb_data_type { bool allow_bl_update; u32 bl_level_scaled; struct mutex bl_lock; + struct mutex mdss_sysfs_lock; bool ipc_resume; struct platform_device *pdev; @@ -427,6 +428,12 @@ static inline bool mdss_fb_is_power_on_lp(struct msm_fb_data_type *mfd) return mdss_panel_is_power_on_lp(mfd->panel_power_state); } +static inline bool mdss_fb_is_power_on_ulp(struct msm_fb_data_type *mfd) +{ + return mdss_panel_is_power_on_ulp(mfd->panel_power_state); +} + + static inline bool mdss_fb_is_hdmi_primary(struct msm_fb_data_type *mfd) { return (mfd && (mfd->index == 0) && diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c index 08307fe8eb16..834726e84bda 100644 --- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c +++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -643,7 +643,8 @@ static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp) /* Wait for HDCP keys to be checked and validated */ rc = readl_poll_timeout(io->base + reg_set->status, link0_status, ((link0_status >> reg_set->keys_offset) & 0x7) - == HDCP_KEYS_STATE_VALID, + == HDCP_KEYS_STATE_VALID || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { pr_err("key not ready\n"); @@ -658,7 +659,8 @@ static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp) /* Wait for An0 and An1 bit to be ready */ rc = readl_poll_timeout(io->base + reg_set->status, link0_status, - (link0_status & (BIT(8) | BIT(9))), + (link0_status & (BIT(8) | BIT(9))) || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { pr_err("An not ready\n"); @@ -668,6 +670,9 @@ static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp) /* As per hardware recommendations, wait before reading An */ msleep(20); error: + if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + rc = -EINVAL; + return rc; } @@ -820,7 +825,8 @@ static int hdcp_1x_verify_r0(struct hdcp_1x *hdcp) /* Wait for HDCP R0 computation to be completed */ rc = readl_poll_timeout(io->base + reg_set->status, link0_status, - link0_status & BIT(reg_set->r0_offset), + (link0_status & BIT(reg_set->r0_offset)) || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { pr_err("R0 not ready\n"); @@ -862,10 +868,14 @@ static int hdcp_1x_verify_r0(struct hdcp_1x *hdcp) DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]); rc = readl_poll_timeout(io->base + reg_set->status, - link0_status, link0_status & BIT(12), + link0_status, (link0_status & BIT(12)) || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), r0_read_delay_us, r0_read_timeout_us); } while (rc && --r0_retry); error: + if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + rc = -EINVAL; + return rc; } @@ -1092,9 +1102,9 @@ static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp) */ if (i && !((i + 1) % 64)) { rc = readl_poll_timeout(io->base + reg_set->sha_status, - sha_status, sha_status & BIT(0), - HDCP_POLL_SLEEP_US, - HDCP_POLL_TIMEOUT_US); + sha_status, (sha_status & BIT(0)) || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { pr_err("block not done\n"); goto error; @@ -1108,7 +1118,8 @@ static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp) /* Now wait for HDCP_SHA_COMP_DONE */ rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status, - sha_status & BIT(4), + (sha_status & BIT(4)) || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { pr_err("V computation not done\n"); @@ -1117,13 +1128,17 @@ static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp) /* Wait for V_MATCHES */ rc = readl_poll_timeout(io->base + reg_set->status, status, - status & BIT(reg_set->v_offset), + (status & BIT(reg_set->v_offset)) || + !hdcp_1x_state(HDCP_STATE_AUTHENTICATING), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { pr_err("V mismatch\n"); rc = -EINVAL; } error: + if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + rc = -EINVAL; + return rc; } @@ -1273,8 +1288,6 @@ static void hdcp_1x_update_auth_status(struct hdcp_1x *hdcp) if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) { hdcp_1x_cache_topology(hdcp); hdcp_1x_notify_topology(hdcp); - } else { - hdcp1_set_enc(false); } if (hdcp->init_data.notify_status && @@ -1459,9 +1472,6 @@ void hdcp_1x_off(void *input) return; } - if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) - hdcp1_set_enc(false); - /* * Disable HDCP interrupts. * Also, need to set the state to inactive here so that any ongoing @@ -1482,11 +1492,13 @@ void hdcp_1x_off(void *input) * No more reauthentiaction attempts will be scheduled since we * set the currect state to inactive. */ - rc = cancel_delayed_work(&hdcp->hdcp_auth_work); + rc = cancel_delayed_work_sync(&hdcp->hdcp_auth_work); if (rc) pr_debug("%s: Deleted hdcp auth work\n", HDCP_STATE_NAME); + hdcp1_set_enc(false); + reg = DSS_REG_R(io, reg_set->reset); DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 3adf04214d87..3d8fe2ceebac 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -122,13 +122,6 @@ struct hdmi_edid_sink_caps { bool ind_view_support; }; -struct hdmi_edid_override_data { - int scramble; - int sink_mode; - int format; - int vic; -}; - struct hdmi_edid_ctrl { u8 pt_scan_info; u8 it_scan_info; @@ -1607,9 +1600,14 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, (timing.refresh_rate % 100) / 10, timing.refresh_rate % 10); - rc = hdmi_get_video_id_code(&timing, NULL); - if (rc < 0) - rc = hdmi_set_resv_timing_info(&timing); + /* + * Always add resolutions parsed from DTD in the reserved + * timing info. This can avoid matching resolutions that have + * a non-integral fps denominators with corresponding + * resolutions that have an integral fps denominator. + * For example - 640x480p@59.94Hz --> 640x480p@60Hz + */ + rc = hdmi_set_resv_timing_info(&timing); } else { rc = -EINVAL; } @@ -1983,7 +1981,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl) { u8 i = 0, offset = 0, std_blk = 0; u32 video_format = HDMI_VFRMT_640x480p60_4_3; - u32 has480p = false; u8 len = 0; u8 num_of_cea_blocks; u8 *data_buf; @@ -2046,9 +2043,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl) video_format == HDMI_VFRMT_2880x576p50_16_9 || video_format == HDMI_VFRMT_1920x1250i50_16_9) has50hz_mode = true; - - if (video_format == HDMI_VFRMT_640x480p60_4_3) - has480p = true; } } @@ -2067,9 +2061,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl) hdmi_edid_add_sink_video_format(edid_ctrl, video_format); - if (video_format == HDMI_VFRMT_640x480p60_4_3) - has480p = true; - /* Make a note of the preferred video format */ if (i == 0) sink_data->preferred_video_format = @@ -2091,7 +2082,7 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl) desc_offset = edid_blk1[0x02]; if (desc_offset < (EDID_BLOCK_SIZE - EDID_DTD_LEN)) { i = 0; - while (!edid_blk1[desc_offset]) { + while ((i < 4) && edid_blk1[desc_offset]) { hdmi_edid_detail_desc(edid_ctrl, edid_blk1+desc_offset, &video_format); @@ -2103,8 +2094,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl) hdmi_edid_add_sink_video_format(edid_ctrl, video_format); - if (video_format == HDMI_VFRMT_640x480p60_4_3) - has480p = true; /* Make a note of the preferred video format */ if (i == 0) { @@ -2192,15 +2181,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl) if (!rc) pr_debug("%s: 3D formats in VSD\n", __func__); } - - /* - * Need to add default 640 by 480 timings, in case not described - * in the EDID structure. - * All DTV sink devices should support this mode - */ - if (!has480p) - hdmi_edid_add_sink_video_format(edid_ctrl, - HDMI_VFRMT_640x480p60_4_3); } /* hdmi_edid_get_display_mode */ u32 hdmi_edid_get_raw_data(void *input, u8 *buf, u32 size) @@ -2498,6 +2478,11 @@ bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode) struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; struct hdmi_edid_sink_data *sink_data; + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return false; + } + sink_data = &edid_ctrl->sink_data; for (i = 0; i < sink_data->num_of_elements; ++i) { if (sink_data->disp_mode_list[i].video_format != video_mode) @@ -2610,6 +2595,31 @@ void hdmi_edid_set_video_resolution(void *input, u32 resolution, bool reset) } } /* hdmi_edid_set_video_resolution */ +void hdmi_edid_config_override(void *input, bool enable, + struct hdmi_edid_override_data *data) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + struct hdmi_edid_override_data *ov_data = &edid_ctrl->override_data; + + if ((!edid_ctrl) || (enable && !data)) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + edid_ctrl->edid_override = enable; + pr_debug("EDID override %s\n", enable ? "enabled" : "disabled"); + + if (enable) { + ov_data->scramble = data->scramble; + ov_data->sink_mode = data->sink_mode; + ov_data->format = data->format; + ov_data->vic = data->vic; + pr_debug("%s: Override data: scramble=%d sink_mode=%d format=%d vic=%d\n", + __func__, ov_data->scramble, ov_data->sink_mode, + ov_data->format, ov_data->vic); + } +} + void hdmi_edid_deinit(void *input) { struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 5ee77fcf2066..16efb6ee4014 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,6 +44,20 @@ struct hdmi_edid_hdr_data { u32 min_luminance; }; +/* + * struct hdmi_override_data - Resolution Override Data + * @scramble - scrambler enable + * @sink_mode - 0 for DVI and 1 for HDMI + * @format - pixel format (refer to msm_hdmi_modes.h) + * @vic - resolution code + */ +struct hdmi_edid_override_data { + int scramble; + int sink_mode; + int format; + int vic; +}; + int hdmi_edid_parser(void *edid_ctrl); u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size); u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution); @@ -63,5 +77,7 @@ u8 hdmi_edid_get_deep_color(void *edid_ctrl); u32 hdmi_edid_get_max_pclk(void *edid_ctrl); void hdmi_edid_get_hdr_data(void *edid_ctrl, struct hdmi_edid_hdr_data **hdr_data); +void hdmi_edid_config_override(void *input, bool enable, + struct hdmi_edid_override_data *data); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index ce5c8c412c99..eadb90f3ce88 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -689,7 +689,6 @@ static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl) if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { pr_err("hdcp is off\n"); - rc = -EINVAL; goto exit; } hdmi_ddc_config(ddc_ctrl); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 67813ca9cd37..abc56f5f352d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -421,8 +421,10 @@ static inline void hdmi_tx_send_cable_notification( if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) { u32 flags = 0; - if (hdmi_tx_is_dvi_mode(hdmi_ctrl)) - flags |= MSM_EXT_DISP_HPD_NO_AUDIO; + flags |= MSM_EXT_DISP_HPD_VIDEO; + + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) + flags |= MSM_EXT_DISP_HPD_AUDIO; hdmi_ctrl->ext_audio_data.intf_ops.hpd(hdmi_ctrl->ext_pdev, hdmi_ctrl->ext_audio_data.type, val, flags); @@ -1608,14 +1610,18 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) } if (hdmi_tx_is_panel_on(hdmi_ctrl)) { - DEV_DBG("%s: Reauthenticating\n", __func__); - rc = hdmi_ctrl->hdcp_ops->reauthenticate( - hdmi_ctrl->hdcp_data); - if (rc) - DEV_ERR("%s: HDCP reauth failed. rc=%d\n", - __func__, rc); + pr_debug("%s: Reauthenticating\n", __func__); + if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_data) { + rc = hdmi_ctrl->hdcp_ops->reauthenticate( + hdmi_ctrl->hdcp_data); + if (rc) + pr_err("%s: HDCP reauth failed. rc=%d\n", + __func__, rc); + } else + pr_err("%s: NULL HDCP Ops and Data\n", + __func__); } else { - DEV_DBG("%s: Not reauthenticating. Cable not conn\n", + pr_debug("%s: Not reauthenticating. Cable not conn\n", __func__); } @@ -2282,7 +2288,8 @@ static void hdmi_tx_update_hdcp_info(struct hdmi_tx_ctrl *hdmi_ctrl) if (hdmi_ctrl->hdcp14_present) { fd = hdmi_tx_get_fd(HDMI_TX_FEAT_HDCP); - ops = hdcp_1x_start(fd); + if (fd) + ops = hdcp_1x_start(fd); } } @@ -2325,6 +2332,31 @@ static void hdmi_tx_update_deep_color(struct hdmi_tx_ctrl *hdmi_ctrl) } } +static void hdmi_tx_update_hdr_info(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct mdss_panel_info *pinfo = &hdmi_ctrl->panel_data.panel_info; + struct mdss_panel_hdr_properties *hdr_prop = &pinfo->hdr_properties; + struct hdmi_edid_hdr_data *hdr_data = NULL; + + /* CEA-861.3 4.2 */ + hdr_prop->hdr_enabled = hdmi_tx_is_hdr_supported(hdmi_ctrl); + /* no display primaries in EDID, so skip it */ + memset(hdr_prop->display_primaries, 0, + sizeof(hdr_prop->display_primaries)); + + hdmi_edid_get_hdr_data(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), &hdr_data); + + if (hdr_prop->hdr_enabled) { + hdr_prop->peak_brightness = hdr_data->max_luminance * 10000; + if (hdr_data->avg_luminance != 0) + hdr_prop->avg_brightness = 50 * + (BIT(0) << (int)(hdr_data->avg_luminance / 32)); + hdr_prop->blackness_level = (hdr_data->min_luminance * + hdr_data->min_luminance * + hdr_data->max_luminance * 100) / 65025; + } +} + static void hdmi_tx_hpd_int_work(struct work_struct *work) { struct hdmi_tx_ctrl *hdmi_ctrl = NULL; @@ -2353,6 +2385,7 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) if (!retry && rc) pr_warn_ratelimited("%s: EDID read failed\n", __func__); hdmi_tx_update_deep_color(hdmi_ctrl); + hdmi_tx_update_hdr_info(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, true); } else { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 89890bcf68df..102c2f994646 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -555,6 +555,9 @@ int msm_hdmi_get_timing_info( case HDMI_VFRMT_3840x2160p60_64_27: MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p60_64_27); break; + case HDMI_VFRMT_640x480p59_4_3: + MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_640x480p59_4_3); + break; default: ret = hdmi_get_resv_timing_info(mode, id); } diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 7ed4b5404868..fbbcc16f48b5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1,7 +1,7 @@ /* * MDSS MDP Interface (used by framebuffer core) * - * Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This software is licensed under the terms of the GNU General Public @@ -1794,11 +1794,13 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) return -EINVAL; } - mdata->venus = devm_regulator_get_optional(&mdata->pdev->dev, - "gdsc-venus"); - if (IS_ERR_OR_NULL(mdata->venus)) { - mdata->venus = NULL; - pr_debug("unable to get venus gdsc regulator\n"); + mdata->core_gdsc = devm_regulator_get_optional(&mdata->pdev->dev, + "gdsc-core"); + if (IS_ERR_OR_NULL(mdata->core_gdsc)) { + mdata->core_gdsc = NULL; + pr_err("unable to get core gdsc regulator\n"); + } else { + pr_debug("core gdsc regulator found\n"); } mdata->fs_ena = false; @@ -2370,10 +2372,10 @@ void mdss_mdp_footswitch_ctrl_splash(int on) if (on) { mdata->handoff_pending = true; pr_debug("Enable MDP FS for splash.\n"); - if (mdata->venus) { - ret = regulator_enable(mdata->venus); + if (mdata->core_gdsc) { + ret = regulator_enable(mdata->core_gdsc); if (ret) - pr_err("venus failed to enable\n"); + pr_err("core_gdsc failed to enable\n"); } ret = regulator_enable(mdata->fs); @@ -2387,8 +2389,8 @@ void mdss_mdp_footswitch_ctrl_splash(int on) mdss_bus_bandwidth_ctrl(false); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); regulator_disable(mdata->fs); - if (mdata->venus) - regulator_disable(mdata->venus); + if (mdata->core_gdsc) + regulator_disable(mdata->core_gdsc); mdata->handoff_pending = false; } } else { @@ -5059,6 +5061,7 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on) { int ret; int active_cnt = 0; + bool footswitch_suspend = false; if (!mdata->fs) return; @@ -5069,12 +5072,21 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on) if (on) { if (!mdata->fs_ena) { pr_debug("Enable MDP FS\n"); - if (mdata->venus) { - ret = regulator_enable(mdata->venus); + if (mdata->core_gdsc) { + ret = regulator_enable(mdata->core_gdsc); if (ret) - pr_err("venus failed to enable\n"); + pr_err("core_gdsc failed to enable\n"); } + /* + * Advise RPM to not turn MMSS GDSC off, this will + * ensure that GDSC off is maintained during Active + * display and during Idle display + */ + if (mdss_has_quirk(mdata, + MDSS_QUIRK_MMSS_GDSC_COLLAPSE)) + mdss_rpm_set_msg_ram(true); + ret = regulator_enable(mdata->fs); if (ret) pr_warn("Footswitch failed to enable\n"); @@ -5092,13 +5104,6 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on) active_cnt = atomic_read(&mdata->active_intf_cnt); if (active_cnt != 0) { /* - * Advise RPM to not turn MMSS GDSC off during - * idle case. - */ - if (mdss_has_quirk(mdata, - MDSS_QUIRK_MMSS_GDSC_COLLAPSE)) - mdss_rpm_set_msg_ram(true); - /* * Turning off GDSC while overlays are still * active. */ @@ -5109,14 +5114,8 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on) pr_debug("idle pc. active overlays=%d\n", active_cnt); } else { - /* - * Advise RPM to turn MMSS GDSC off during - * suspend case - */ - if (mdss_has_quirk(mdata, - MDSS_QUIRK_MMSS_GDSC_COLLAPSE)) - mdss_rpm_set_msg_ram(false); + footswitch_suspend = true; mdss_mdp_cx_ctrl(mdata, false); mdss_mdp_batfet_ctrl(mdata, false); mdss_mdp_memory_retention_ctrl( @@ -5127,8 +5126,21 @@ static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on) if (mdata->en_svs_high) mdss_mdp_config_cx_voltage(mdata, false); regulator_disable(mdata->fs); - if (mdata->venus) - regulator_disable(mdata->venus); + if (mdata->core_gdsc) + regulator_disable(mdata->core_gdsc); + + if (footswitch_suspend) { + /* + * Advise RPM to turn MMSS GDSC off during + * suspend case, do this after the MDSS GDSC + * regulator OFF, so we can ensure that MMSS + * GDSC will go OFF after the MDSS GDSC + * regulator + */ + if (mdss_has_quirk(mdata, + MDSS_QUIRK_MMSS_GDSC_COLLAPSE)) + mdss_rpm_set_msg_ram(false); + } } mdata->fs_ena = false; } diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index d3d332d780d5..cb9cc08140f0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1,5 +1,5 @@ /* - * 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 @@ -124,6 +124,7 @@ #define DS_ENHANCER_UPDATE BIT(5) #define DS_VALIDATE BIT(6) #define DS_DIRTY_UPDATE BIT(7) +#define DS_PU_ENABLE BIT(8) /** * Destination Scaler DUAL mode overfetch pixel count @@ -386,6 +387,7 @@ struct mdss_mdp_destination_scaler { u16 last_mixer_height; u32 flags; struct mdp_scale_data_v2 scaler; + struct mdss_rect panel_roi; }; @@ -1169,6 +1171,14 @@ static inline int is_dest_scaling_enable(struct mdss_mdp_mixer *mixer) mixer && mixer->ds && (mixer->ds->flags & DS_ENABLE)); } +static inline int is_dest_scaling_pu_enable(struct mdss_mdp_mixer *mixer) +{ + if (is_dest_scaling_enable(mixer)) + return (mixer->ds->flags & DS_PU_ENABLE); + + return 0; +} + static inline u32 get_ds_input_width(struct mdss_mdp_mixer *mixer) { struct mdss_mdp_destination_scaler *ds; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index f397aca8ad3a..ffbf156e9eed 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.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 @@ -4434,6 +4434,13 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int power_state) goto end; } + /* + * reset the play_cnt, after the cmd_stop + * this will ensure pipes are reconfiged + * after every panel power state change + */ + ctl->play_cnt = 0; + if (mdss_panel_is_power_on(power_state)) { pr_debug("panel is not off, leaving ctl power on\n"); goto end; @@ -4450,8 +4457,6 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int power_state) mdss_mdp_reset_mixercfg(ctl); - ctl->play_cnt = 0; - end: if (!ret) { ctl->power_state = power_state; @@ -4575,7 +4580,8 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl, bool is_recovery) if (mixer) { mdss_mdp_pipe_reset(mixer, is_recovery); - if (is_dual_lm_single_display(ctl->mfd)) + if (is_dual_lm_single_display(ctl->mfd) && + ctl->mixer_right) mdss_mdp_pipe_reset(ctl->mixer_right, is_recovery); } @@ -4652,7 +4658,15 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, previous_frame_pu_type = mdss_mdp_get_pu_type(ctl); if (ctl->mixer_left) { mdss_mdp_set_mixer_roi(ctl->mixer_left, l_roi); - ctl->roi = ctl->mixer_left->roi; + if (is_dest_scaling_enable(ctl->mixer_left)) + ctl->roi = ctl->mixer_left->ds->panel_roi; + else + ctl->roi = ctl->mixer_left->roi; + + pr_debug("ctl->mixer_left: [%d %d %d %d] ds:%d\n", + ctl->roi.x, ctl->roi.y, + ctl->roi.w, ctl->roi.h, + is_dest_scaling_enable(ctl->mixer_left)); } if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) { @@ -4660,20 +4674,43 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, if (sctl && sctl->mixer_left) { mdss_mdp_set_mixer_roi(sctl->mixer_left, r_roi); - sctl->roi = sctl->mixer_left->roi; + if (is_dest_scaling_enable(sctl->mixer_left)) + sctl->roi = sctl->mixer_left->ds->panel_roi; + else + sctl->roi = sctl->mixer_left->roi; + + pr_debug("sctl->mixer_left: [%d %d %d %d] ds:%d\n", + sctl->roi.x, sctl->roi.y, + sctl->roi.w, sctl->roi.h, + is_dest_scaling_enable(sctl->mixer_left)); + } } else if (is_dual_lm_single_display(ctl->mfd) && ctl->mixer_right) { mdss_mdp_set_mixer_roi(ctl->mixer_right, r_roi); /* in this case, CTL_ROI is a union of left+right ROIs. */ - ctl->roi.w += ctl->mixer_right->roi.w; + if (is_dest_scaling_enable(ctl->mixer_right)) + ctl->roi.w += ctl->mixer_right->ds->panel_roi.w; + else + ctl->roi.w += ctl->mixer_right->roi.w; /* right_only, update roi.x as per CTL ROI guidelines */ if (ctl->mixer_left && !ctl->mixer_left->valid_roi) { - ctl->roi = ctl->mixer_right->roi; - ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + - ctl->mixer_right->roi.x; + if (is_dest_scaling_enable(ctl->mixer_right)) { + ctl->roi = ctl->mixer_right->ds->panel_roi; + ctl->roi.x = + get_ds_output_width(ctl->mixer_left) + + ctl->mixer_right->ds->panel_roi.x; + } else { + ctl->roi = ctl->mixer_right->roi; + ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + + ctl->mixer_right->roi.x; + } + pr_debug("ctl->mixer_right_only : [%d %d %d %d] ds:%d\n", + ctl->roi.x, ctl->roi.y, + ctl->roi.w, ctl->roi.h, + is_dest_scaling_enable(ctl->mixer_right)); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index c249cac87b8a..b7f27b818eda 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -51,8 +51,10 @@ struct mdss_mdp_cmd_ctx { u32 current_pp_num; /* * aux_pp_num will be set only when topology is using split-lm. - * aux_pp_num will be used only when MDSS_QUIRK_DSC_RIGHT_ONLY_PU - * quirk is set and on following partial updates. + * aux_pp_num will be used + * if right-only update on DUAL_LM_SINGLE_DISPLAY with 3D Mux + * or if MDSS_QUIRK_DSC_RIGHT_ONLY_PU quirk is set + * and on following partial updates. * * right-only update on DUAL_LM_SINGLE_DISPLAY with DSC_MERGE * right-only update on DUAL_LM_DUAL_DISPLAY with DSC @@ -119,14 +121,32 @@ static int mdss_mdp_setup_vsync(struct mdss_mdp_cmd_ctx *ctx, bool enable); static bool __mdss_mdp_cmd_is_aux_pp_needed(struct mdss_data_type *mdata, struct mdss_mdp_ctl *mctl) { - return (mdata && mctl && mctl->is_master && - mdss_has_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU) && - is_dsc_compression(&mctl->panel_data->panel_info) && - ((mctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) || - ((mctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) && - (mctl->panel_data->panel_info.dsc_enc_total == 1))) && - !mctl->mixer_left->valid_roi && - mctl->mixer_right->valid_roi); + bool mux3d, merge, quirk, rightonly; + + if (!mdata || !mctl || !mctl->is_master) + return false; + + /* + * aux_pp_num will be used: + * if right-only update on DUAL_LM_SINGLE_DISPLAY with 3D Mux + * or if MDSS_QUIRK_DSC_RIGHT_ONLY_PU quirk is set + * and on following partial updates. + * + * right-only update on DUAL_LM_SINGLE_DISPLAY with DSC_MERGE + * right-only update on DUAL_LM_DUAL_DISPLAY with DSC + */ + mux3d = ((mctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) && + (mctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE)); + merge = ((mctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) && + (mctl->panel_data->panel_info.dsc_enc_total == 1)); + quirk = (mdss_has_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU) && + is_dsc_compression(&mctl->panel_data->panel_info) && + ((mctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) || + merge)); + rightonly = !mctl->mixer_left->valid_roi && + mctl->mixer_right->valid_roi; + + return ((mux3d || quirk) && rightonly); } static bool __mdss_mdp_cmd_is_panel_power_off(struct mdss_mdp_cmd_ctx *ctx) @@ -337,6 +357,87 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer, return 0; } +/** + * mdss_mdp_cmd_autorefresh_pp_done() - pp done irq callback for autorefresh + * @arg: void pointer to the controller context. + * + * This function is the pp_done interrupt callback while disabling + * autorefresh. This function does not modify the kickoff count (koff_cnt). + */ +static void mdss_mdp_cmd_autorefresh_pp_done(void *arg) +{ + struct mdss_mdp_ctl *ctl = arg; + struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; + + if (!ctx) { + pr_err("%s: invalid ctx\n", __func__); + return; + } + + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, + ctx->current_pp_num); + mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, + ctx->current_pp_num, NULL, NULL); + + MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->current_pp_num); + complete_all(&ctx->autorefresh_ppdone); + + pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d cnt=%d\n", __func__, + ctl->num, ctl->intf_num, ctx->current_pp_num, + atomic_read(&ctx->koff_cnt)); +} + +static void mdss_mdp_cmd_wait4_autorefresh_pp(struct mdss_mdp_ctl *ctl) +{ + int rc; + u32 val, line_out, intr_type = MDSS_MDP_IRQ_TYPE_PING_PONG_COMP; + char __iomem *pp_base = ctl->mixer_left->pingpong_base; + struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; + + line_out = mdss_mdp_pingpong_read(pp_base, MDSS_MDP_REG_PP_LINE_COUNT); + + MDSS_XLOG(ctl->num, line_out, ctl->mixer_left->roi.h); + pr_debug("ctl:%d line_out:%d\n", ctl->num, line_out); + + if (!ctx) { + pr_err("%s: invalid ctx\n", __func__); + return; + } + + if (line_out < ctl->mixer_left->roi.h) { + reinit_completion(&ctx->autorefresh_ppdone); + + /* enable ping pong done */ + mdss_mdp_set_intr_callback(intr_type, ctx->current_pp_num, + mdss_mdp_cmd_autorefresh_pp_done, ctl); + mdss_mdp_irq_enable(intr_type, ctx->current_pp_num); + + /* wait for ping pong done */ + rc = wait_for_completion_timeout(&ctx->autorefresh_ppdone, + KOFF_TIMEOUT); + if (rc <= 0) { + val = mdss_mdp_pingpong_read(pp_base, + MDSS_MDP_REG_PP_LINE_COUNT); + if (val == ctl->mixer_left->roi.h) { + mdss_mdp_irq_clear(ctl->mdata, + MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, + ctx->current_pp_num); + mdss_mdp_irq_disable_nosync(intr_type, + ctx->current_pp_num); + mdss_mdp_set_intr_callback(intr_type, + ctx->current_pp_num, NULL, NULL); + } else { + pr_err("timedout waiting for ctl%d autorefresh pp done\n", + ctl->num); + MDSS_XLOG(0xbad3); + MDSS_XLOG_TOUT_HANDLER("mdp", + "vbif", "dbg_bus", "vbif_dbg_bus", + "panic"); + } + } + } +} + static bool __disable_rd_ptr_from_te(char __iomem *pingpong_base) { u32 cfg; @@ -410,7 +511,10 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, rd_ptr_disabled = __disable_rd_ptr_from_te(mixer->pingpong_base); - /* 2. disable autorefresh */ + /* 2. wait for previous transfer to finish */ + mdss_mdp_cmd_wait4_autorefresh_pp(ctl); + + /* 3. disable autorefresh */ if (is_pingpong_split(ctl->mfd)) __disable_autorefresh( mdata->slave_pingpong_base); @@ -427,7 +531,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, __disable_autorefresh(mixer->pingpong_base); pr_debug("%s: disabling auto refresh\n", __func__); - /* 2. re-enable rd pointer from te (if was enabled) */ + /* 4. re-enable rd pointer from te (if was enabled) */ if (rd_ptr_disabled) __enable_rd_ptr_from_te(mixer->pingpong_base); @@ -1475,36 +1579,6 @@ static int mdss_mdp_cmd_update_lineptr(struct mdss_mdp_ctl *ctl, bool enable) return 0; } -/** - * mdss_mdp_cmd_autorefresh_pp_done() - pp done irq callback for autorefresh - * @arg: void pointer to the controller context. - * - * This function is the pp_done interrupt callback while disabling - * autorefresh. This function does not modify the kickoff count (koff_cnt). - */ -static void mdss_mdp_cmd_autorefresh_pp_done(void *arg) -{ - struct mdss_mdp_ctl *ctl = arg; - struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; - - if (!ctx) { - pr_err("%s: invalid ctx\n", __func__); - return; - } - - mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, - ctx->current_pp_num); - mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, - ctx->current_pp_num, NULL, NULL); - - MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->current_pp_num); - complete_all(&ctx->autorefresh_ppdone); - - pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d cnt=%d\n", __func__, - ctl->num, ctl->intf_num, ctx->current_pp_num, - atomic_read(&ctx->koff_cnt)); -} - static void pingpong_done_work(struct work_struct *work) { u32 status; @@ -2488,51 +2562,6 @@ static void mdss_mdp_cmd_post_programming(struct mdss_mdp_ctl *mctl) } } -static void mdss_mdp_cmd_wait4_autorefresh_pp(struct mdss_mdp_ctl *ctl) -{ - int rc; - u32 val, line_out, intr_type = MDSS_MDP_IRQ_TYPE_PING_PONG_COMP; - char __iomem *pp_base = ctl->mixer_left->pingpong_base; - struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; - - line_out = mdss_mdp_pingpong_read(pp_base, MDSS_MDP_REG_PP_LINE_COUNT); - - MDSS_XLOG(ctl->num, line_out, ctl->mixer_left->roi.h); - - if (line_out < ctl->mixer_left->roi.h) { - reinit_completion(&ctx->autorefresh_ppdone); - - /* enable ping pong done */ - mdss_mdp_set_intr_callback(intr_type, ctx->current_pp_num, - mdss_mdp_cmd_autorefresh_pp_done, ctl); - mdss_mdp_irq_enable(intr_type, ctx->current_pp_num); - - /* wait for ping pong done */ - rc = wait_for_completion_timeout(&ctx->autorefresh_ppdone, - KOFF_TIMEOUT); - if (rc <= 0) { - val = mdss_mdp_pingpong_read(pp_base, - MDSS_MDP_REG_PP_LINE_COUNT); - if (val == ctl->mixer_left->roi.h) { - mdss_mdp_irq_clear(ctl->mdata, - MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, - ctx->current_pp_num); - mdss_mdp_irq_disable_nosync(intr_type, - ctx->current_pp_num); - mdss_mdp_set_intr_callback(intr_type, - ctx->current_pp_num, NULL, NULL); - } else { - pr_err("timedout waiting for ctl%d autorefresh pp done\n", - ctl->num); - MDSS_XLOG(0xbad3); - MDSS_XLOG_TOUT_HANDLER("mdp", - "vbif", "dbg_bus", "vbif_dbg_bus", - "panic"); - } - } - } -} - static void mdss_mdp_cmd_autorefresh_done(void *arg) { struct mdss_mdp_ctl *ctl = arg; @@ -3236,6 +3265,8 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state) (void *)&ctx->intf_mdp_callback, CTL_INTF_EVENT_FLAG_DEFAULT); + mdss_mdp_tearcheck_enable(ctl, true); + ctx->intf_stopped = 0; if (sctx) sctx->intf_stopped = 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 5d5515a91572..4efa38093557 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.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 @@ -1521,6 +1521,11 @@ exit_dfps: pr_err("Error in dfps_wait: %d\n", rc); } + /* Disable interface timing double buffer */ + rc = mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_DSI_TIMING_DB_CTRL, + (void *) (unsigned long) 0, + CTL_INTF_EVENT_FLAG_DEFAULT); } else { pr_err("intf %d panel, unknown FPS mode\n", ctl->intf_num); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c index 9bebd72dce61..e1d2a947a77f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.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 @@ -521,6 +521,10 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl, * updating img_width with buffer->planes[0].stride */ fmt = mdss_mdp_get_format_params(buffer->format); + if (!fmt) { + pr_err("invalid format for cwb\n"); + return -EINVAL; + } mdss_mdp_get_plane_sizes(fmt, ctx->img_width, buffer->height, &ps, 0, 0); diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 5a7f8e7e95b4..0eb82dd8371d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.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 @@ -67,6 +67,36 @@ static inline void *u64_to_ptr(uint64_t address) return (void *)(uintptr_t)address; } +static inline struct mdp_destination_scaler_data *__dest_scaler_next( + struct mdp_destination_scaler_data *ds_data, int ds_count) +{ + struct mdp_destination_scaler_data *ds_data_r = ds_data; + size_t offset; + + /* + * Advanced to next ds_data structure from commit if + * there is more than 1 for source split usecase. + */ + if (ds_count > 1) { + ds_data_r = ds_data + 1; + + /* + * To check for binary compatibility with old user mode + * driver which does not have ROI support in destination + * scalar. + */ + if ((ds_data_r->dest_scaler_ndx != 1) && + (ds_data_r->lm_height != ds_data->lm_height)) { + offset = offsetof(struct mdp_destination_scaler_data, + panel_roi); + ds_data_r = (struct mdp_destination_scaler_data *)( + (void *)ds_data + offset); + } + } + + return ds_data_r; +} + static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) { struct mdss_data_type *mdata = ctl->mdata; @@ -94,6 +124,9 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) ctl->mixer_right->roi = (struct mdss_rect) { 0, 0, ctl->mixer_right->width, ctl->mixer_right->height }; + if (split_ctl) + split_ctl->mixer_left->roi = + ctl->mixer_right->roi; /* * Disable destination scaler by resetting the control @@ -143,6 +176,46 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) } } +static int __dest_scaler_panel_roi_update( + struct mdp_destination_scaler_data *ds_data, + struct mdss_mdp_destination_scaler *ds) +{ + if (ds_data->flags & MDP_DESTSCALER_ROI_ENABLE) { + /* + * Updating PANEL ROI info, used in partial update + */ + if ((ds_data->panel_roi.w > ds->scaler.dst_width) || + (ds_data->panel_roi.h > + ds->scaler.dst_height) || + (ds_data->panel_roi.w == 0) || + (ds_data->panel_roi.h == 0)) { + pr_err("Invalid panel ROI parameter for dest-scaler-%d: [%d %d %d %d]\n", + ds_data->dest_scaler_ndx, + ds_data->panel_roi.x, + ds_data->panel_roi.y, + ds_data->panel_roi.w, + ds_data->panel_roi.h); + ds->flags &= ~DS_PU_ENABLE; + return -EINVAL; + } + ds->panel_roi.x = ds_data->panel_roi.x; + ds->panel_roi.y = ds_data->panel_roi.y; + ds->panel_roi.w = ds_data->panel_roi.w; + ds->panel_roi.h = ds_data->panel_roi.h; + ds->flags |= DS_PU_ENABLE; + pr_debug("dest-scaler[%d] panel_roi update: [%d,%d,%d,%d]\n", + ds->num, + ds_data->panel_roi.x, ds_data->panel_roi.y, + ds_data->panel_roi.w, ds_data->panel_roi.h); + MDSS_XLOG(ds->num, ds_data->panel_roi.x, ds_data->panel_roi.y, + ds_data->panel_roi.w, ds_data->panel_roi.h); + } else { + ds->flags &= ~DS_PU_ENABLE; + } + + return 0; +} + static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data, struct mdss_mdp_destination_scaler *ds, u32 max_input_width, u32 max_output_width) @@ -188,6 +261,9 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data, ds->src_height = ds_data->lm_height; } + if (__dest_scaler_panel_roi_update(ds_data, ds)) + return -EINVAL; + if (ds_data->flags == 0) { pr_debug("Disabling destination scaler-%d\n", ds_data->dest_scaler_ndx); @@ -235,13 +311,7 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl, } if (ctl->mixer_right && ctl->mixer_right->ds) { - /* - * Advanced to next ds_data structure from commit if - * there is more than 1 for split display usecase. - */ - if (ds_count > 1) - ds_data++; - + ds_data = __dest_scaler_next(ds_data, ds_count); pinfo = &ctl->panel_data->panel_info; if ((ds_data->lm_width > get_panel_xres(pinfo)) || (ds_data->lm_height > get_panel_yres(pinfo)) || @@ -317,14 +387,17 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, int ret = 0; struct mdss_data_type *mdata; struct mdss_mdp_ctl *ctl; + struct mdss_mdp_ctl *sctl; struct mdss_mdp_destination_scaler *ds_left = NULL; struct mdss_mdp_destination_scaler *ds_right = NULL; struct mdss_panel_info *pinfo; u32 scaler_width, scaler_height; + struct mdp_destination_scaler_data *ds_data_r = NULL; if (ds_data) { mdata = mfd_to_mdata(mfd); ctl = mfd_to_ctl(mfd); + sctl = mdss_mdp_get_split_ctl(ctl); if (ctl->mixer_left) ds_left = ctl->mixer_left->ds; @@ -332,6 +405,9 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ctl->mixer_right) ds_right = ctl->mixer_right->ds; + if (sctl && sctl->mixer_left && ds_right) + sctl->mixer_left->ds = ds_right; + switch (ds_mode) { case DS_DUAL_MODE: if (!ds_left || !ds_right) { @@ -346,13 +422,28 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; - ret = __dest_scaler_data_setup(&ds_data[1], ds_right, + ds_data_r = __dest_scaler_next(ds_data, 2); + ret = __dest_scaler_data_setup(ds_data_r, ds_right, mdata->max_dest_scaler_input_width - MDSS_MDP_DS_OVERFETCH_SIZE, mdata->max_dest_scaler_output_width); if (ret) goto reset_mixer; + if ((ds_right->flags & DS_PU_ENABLE) && sctl) { + pinfo = &ctl->panel_data->panel_info; + if (ds_right->panel_roi.x >= + get_panel_xres(pinfo)) { + ds_right->panel_roi.x -= + get_panel_xres(pinfo); + } else { + pr_err("SCTL DS right roi.x:%d < left panel width:%d\n", + ds_right->panel_roi.x, + get_panel_xres(pinfo)); + goto reset_mixer; + } + } + ds_left->flags &= ~(DS_LEFT|DS_RIGHT); ds_left->flags |= DS_DUAL_MODE; ds_right->flags &= ~(DS_LEFT|DS_RIGHT); @@ -377,6 +468,17 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + /* + * For Partial update usecase, it is possible switching + * from Left+Right mode to Left only mode. So make sure + * cleanup the DS_RIGHT flags. + */ + if (ds_right) { + ds_right->flags &= + ~(DS_DUAL_MODE|DS_ENABLE|DS_PU_ENABLE); + ds_right->flags |= DS_VALIDATE; + } + MDSS_XLOG(ds_left->num, ds_left->src_width, ds_left->src_height, ds_left->flags); break; @@ -396,6 +498,26 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + if (ds_left) { + ds_left->flags &= + ~(DS_DUAL_MODE|DS_ENABLE|DS_PU_ENABLE); + ds_left->flags |= DS_VALIDATE; + } + + if ((ds_right->flags & DS_PU_ENABLE) && sctl) { + pinfo = &ctl->panel_data->panel_info; + if (ds_right->panel_roi.x >= + get_panel_xres(pinfo)) { + ds_right->panel_roi.x -= + get_panel_xres(pinfo); + } else { + pr_err("SCTL DS-right-only roi.x:%d < Left panel width:%d\n", + ds_right->panel_roi.x, + get_panel_xres(pinfo)); + goto reset_mixer; + } + } + MDSS_XLOG(ds_right->num, ds_right->src_width, ds_right->src_height, ds_right->flags); break; @@ -418,11 +540,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, pinfo = &ctl->panel_data->panel_info; scaler_width = 0; scaler_height = 0; - if (ds_left && ds_left->flags) { + if (ds_left && (ds_left->flags & DS_ENABLE)) { scaler_width += ds_left->scaler.dst_width; scaler_height = ds_left->scaler.dst_height; } - if (ds_right && ds_right->flags) { + if (ds_right && (ds_right->flags & DS_ENABLE)) { scaler_width += ds_right->scaler.dst_width; scaler_height = ds_right->scaler.dst_height; } @@ -1674,7 +1796,12 @@ static int __validate_secure_session(struct mdss_overlay_private *mdp5_data) pr_debug("pipe count:: secure display:%d non-secure:%d secure-vid:%d,secure-cam:%d\n", sd_pipes, nonsd_pipes, secure_vid_pipes, secure_cam_pipes); - if ((sd_pipes || mdss_get_sd_client_cnt()) && + if (mdss_get_sd_client_cnt() && !mdp5_data->sd_enabled) { + pr_err("Secure session already enabled for other client\n"); + return -EINVAL; + } + + if ((sd_pipes) && (nonsd_pipes || secure_vid_pipes || secure_cam_pipes)) { pr_err("non-secure layer validation request during secure display session\n"); @@ -2726,7 +2853,8 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd, return -ENODEV; } - if (mdss_fb_is_power_off(mfd)) { + if (mdss_fb_is_power_off(mfd) || + mdss_fb_is_power_on_ulp(mfd)) { pr_err("display interface is in off state fb:%d\n", mfd->index); return -EPERM; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index c6fc10833d7f..9864d611e8e4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.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 @@ -1930,6 +1930,39 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe) pipe->restore_roi = false; } +static void __restore_dest_scaler_roi(struct mdss_mdp_ctl *ctl) +{ + struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; + struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + + if (is_dest_scaling_pu_enable(ctl->mixer_left)) { + ctl->mixer_left->ds->panel_roi.x = 0; + ctl->mixer_left->ds->panel_roi.y = 0; + ctl->mixer_left->ds->panel_roi.w = get_panel_xres(pinfo); + ctl->mixer_left->ds->panel_roi.h = get_panel_yres(pinfo); + + if ((ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) && + sctl) { + if (ctl->panel_data->next) + pinfo = &ctl->panel_data->next->panel_info; + sctl->mixer_left->ds->panel_roi.x = 0; + sctl->mixer_left->ds->panel_roi.y = 0; + sctl->mixer_left->ds->panel_roi.w = + get_panel_xres(pinfo); + sctl->mixer_left->ds->panel_roi.h = + get_panel_yres(pinfo); + } else if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) { + ctl->mixer_right->ds->panel_roi.x = + get_panel_xres(pinfo); + ctl->mixer_right->ds->panel_roi.y = 0; + ctl->mixer_right->ds->panel_roi.w = + get_panel_xres(pinfo); + ctl->mixer_right->ds->panel_roi.h = + get_panel_yres(pinfo); + } + } +} + /** * __adjust_pipe_rect() - Adjust pipe roi for dual partial update feature. * @pipe: pipe to check against. @@ -2145,6 +2178,9 @@ set_roi: } dual_roi->enabled = false; } + + if (pinfo->partial_update_enabled) + __restore_dest_scaler_roi(ctl); } pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d, dual_pu_roi:%d\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 6870193166f2..563cb8be1a04 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -2406,8 +2406,16 @@ bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_mixer *mixer, struct mdss_data_type *mdata) { /* do not apply for rotator or WB */ - return ((pipe->dst.y > mdata->prefill_data.ts_threshold) && - (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)); + if (!((pipe->dst.y > mdata->prefill_data.ts_threshold) && + (mixer->type == MDSS_MDP_MIXER_TYPE_INTF))) + return false; + + /* do not apply for sdm660 in command mode */ + if ((IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, + MDSS_MDP_HW_REV_320)) && !mixer->ctl->is_video_mode) + return false; + + return true; } static inline void __get_ordered_rects(struct mdss_mdp_pipe *pipe, diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 30dd3c856c7f..d83bedacec28 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.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 @@ -3980,8 +3980,7 @@ int mdss_mdp_igc_lut_config(struct msm_fb_data_type *mfd, disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; if (config->ops & MDP_PP_OPS_READ) { - if (config->len != IGC_LUT_ENTRIES && - !pp_ops[IGC].pp_get_config) { + if (config->len != IGC_LUT_ENTRIES) { pr_err("invalid len for IGC table for read %d\n", config->len); return -EINVAL; @@ -4827,6 +4826,11 @@ gamut_clk_off: goto gamut_set_dirty; } } + if (pp_gm_has_invalid_lut_size(config)) { + pr_debug("invalid lut size for gamut\n"); + ret = -EINVAL; + goto gamut_config_exit; + } local_cfg = *config; tbl_off = mdss_pp_res->gamut_tbl[disp_num]; for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { @@ -5279,7 +5283,7 @@ static int pp_hist_collect(struct mdp_histogram_data *hist, u32 block) { int ret = 0; - u32 sum; + int sum = 0; char __iomem *v_base = NULL; unsigned long flag; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 4698d441f365..3fc5b2226b3e 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.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 @@ -118,6 +118,11 @@ enum { }; enum { + MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0, + MDSS_PANEL_LOW_PERSIST_MODE_ON, +}; + +enum { MODE_GPIO_NOT_VALID = 0, MODE_SEL_DUAL_PORT, MODE_SEL_SINGLE_PORT, @@ -293,6 +298,7 @@ enum mdss_intf_events { MDSS_EVENT_DEEP_COLOR, MDSS_EVENT_DISABLE_PANEL, MDSS_EVENT_UPDATE_PANEL_PPM, + MDSS_EVENT_DSI_TIMING_DB_CTRL, MDSS_EVENT_MAX, }; @@ -372,9 +378,11 @@ struct lcd_panel_info { u32 h_back_porch; u32 h_front_porch; u32 h_pulse_width; + u32 h_active_low; u32 v_back_porch; u32 v_front_porch; u32 v_pulse_width; + u32 v_active_low; u32 border_clr; u32 underflow_clr; u32 hsync_skew; @@ -746,6 +754,8 @@ struct mdss_panel_hdr_properties { /* peak brightness supported by panel */ u32 peak_brightness; + /* average brightness supported by panel */ + u32 avg_brightness; /* Blackness level supported by panel */ u32 blackness_level; }; @@ -892,6 +902,9 @@ struct mdss_panel_info { /* debugfs structure for the panel */ struct mdss_panel_debugfs_info *debugfs_info; + /* persistence mode on/off */ + bool persist_mode; + /* stores initial adaptive variable refresh vtotal value */ u32 saved_avr_vtotal; @@ -936,6 +949,7 @@ struct mdss_panel_timing { struct mdss_panel_data { struct mdss_panel_info panel_info; void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level); + int (*apply_display_setting)(struct mdss_panel_data *pdata, u32 mode); unsigned char *mmss_cc_base; /** diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index 4fccf1178dac..30f8ca0487a7 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -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 @@ -42,6 +42,7 @@ struct msm_ext_disp { struct list_head display_list; struct mutex lock; struct completion hpd_comp; + u32 flags; }; static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp, @@ -365,7 +366,7 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp, { int ret = 0; - if (flags & MSM_EXT_DISP_HPD_NO_VIDEO) { + if (!(flags & MSM_EXT_DISP_HPD_VIDEO)) { pr_debug("skipping video setup for display (%s)\n", msm_ext_disp_name(type)); goto end; @@ -398,7 +399,7 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp, { int ret = 0; - if (flags & MSM_EXT_DISP_HPD_NO_AUDIO) { + if (!(flags & MSM_EXT_DISP_HPD_AUDIO)) { pr_debug("skipping audio setup for display (%s)\n", msm_ext_disp_name(type)); goto end; @@ -425,6 +426,47 @@ end: return ret; } +static bool msm_ext_disp_validate_connect(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_type type, u32 flags) +{ + /* allow new connections */ + if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX) + goto end; + + /* if already connected, block a new connection */ + if (ext_disp->current_disp != type) + return false; + + /* if same display connected, block same connection type */ + if (ext_disp->flags & flags) + return false; + +end: + ext_disp->flags |= flags; + ext_disp->current_disp = type; + return true; +} + +static bool msm_ext_disp_validate_disconnect(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_type type, u32 flags) +{ + /* check if nothing connected */ + if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX) + return false; + + /* check if a different display's request */ + if (ext_disp->current_disp != type) + return false; + + /* allow only an already connected type */ + if (ext_disp->flags & flags) { + ext_disp->flags &= ~flags; + return true; + } + + return false; +} + static int msm_ext_disp_hpd(struct platform_device *pdev, enum msm_ext_disp_type type, enum msm_ext_disp_cable_state state, @@ -446,8 +488,8 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, mutex_lock(&ext_disp->lock); - pr_debug("HPD for display (%s), NEW STATE = %d\n", - msm_ext_disp_name(type), state); + pr_debug("HPD for display (%s), NEW STATE = %d, flags = %d\n", + msm_ext_disp_name(type), state, flags); if (state < EXT_DISPLAY_CABLE_DISCONNECT || state >= EXT_DISPLAY_CABLE_STATE_MAX) { @@ -456,24 +498,13 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, goto end; } - if ((state == EXT_DISPLAY_CABLE_CONNECT) && - (ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX)) { - pr_err("Display interface (%s) already connected\n", - msm_ext_disp_name(ext_disp->current_disp)); - ret = -EINVAL; - goto end; - } - - if ((state == EXT_DISPLAY_CABLE_DISCONNECT) && - (ext_disp->current_disp != type)) { - pr_err("Display interface (%s) is not connected\n", - msm_ext_disp_name(type)); - ret = -EINVAL; - goto end; - } - if (state == EXT_DISPLAY_CABLE_CONNECT) { - ext_disp->current_disp = type; + if (!msm_ext_disp_validate_connect(ext_disp, type, flags)) { + pr_err("Display interface (%s) already connected\n", + msm_ext_disp_name(ext_disp->current_disp)); + ret = -EINVAL; + goto end; + } ret = msm_ext_disp_process_display(ext_disp, type, state, flags); @@ -490,11 +521,19 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, if (ret) goto end; } else { + if (!msm_ext_disp_validate_disconnect(ext_disp, type, flags)) { + pr_err("Display interface (%s) not connected\n", + msm_ext_disp_name(type)); + ret = -EINVAL; + goto end; + } + msm_ext_disp_process_audio(ext_disp, type, state, flags); msm_ext_disp_update_audio_ops(ext_disp, type, state, flags); msm_ext_disp_process_display(ext_disp, type, state, flags); - ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; + if (!ext_disp->flags) + ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; } pr_debug("Hpd (%d) for display (%s)\n", state, @@ -653,7 +692,7 @@ static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp, int ret = 0; struct msm_ext_disp_audio_codec_ops *ops = ext_disp->ops; - if (flags & MSM_EXT_DISP_HPD_NO_AUDIO) { + if (!(flags & MSM_EXT_DISP_HPD_AUDIO)) { pr_debug("skipping audio ops setup for display (%s)\n", msm_ext_disp_name(type)); goto end; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 5071d1039c26..025f11b9cffa 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -928,6 +928,8 @@ static int fuse_readpages_fill(void *_data, struct page *page) lock_page(newpage); put_page(newpage); + lru_cache_add_file(newpage); + /* finally release the old page and swap pointers */ unlock_page(oldpage); page_cache_release(oldpage); diff --git a/include/dt-bindings/clock/mdss-pll-clk.h b/include/dt-bindings/clock/mdss-pll-clk.h index 8cd0b2a9bc98..9015b4c0e1c9 100644 --- a/include/dt-bindings/clock/mdss-pll-clk.h +++ b/include/dt-bindings/clock/mdss-pll-clk.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,4 +39,11 @@ #define SHADOW_POST_N1_DIV_1_CLK 22 #define SHADOW_VCO_CLK_1_CLK 23 +/* DP PLL clocks */ +#define DP_VCO_CLK 0 +#define DP_LINK_2X_CLK_DIVSEL_FIVE 1 +#define DP_VCO_DIVSEL_FOUR_CLK_SRC 2 +#define DP_VCO_DIVSEL_TWO_CLK_SRC 3 +#define DP_VCO_DIVIDED_CLK_SRC_MUX 4 + #endif diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index da8ca5a7da58..6d73a04d0150 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -39,6 +39,15 @@ struct bvec_iter { current bvec */ }; +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +/* Double declaration from ktime.h so as to not break the include dependency + * chain. Should be kept up to date. + */ +union blk_ktime { + s64 tv64; +}; +#endif + /* * main unit of I/O for the block layer and lower layers (ie drivers and * stacking drivers) @@ -54,6 +63,10 @@ struct bio { struct bvec_iter bi_iter; +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK + union blk_ktime submit_time; + unsigned int blk_sector_count; +#endif /* Number of segments in this BIO after * physical address coalescing is performed. */ diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 0eab4811ee92..d81d6a2db342 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -113,7 +113,7 @@ extern const struct cpumask *const cpu_isolated_mask; #define cpu_possible(cpu) ((cpu) == 0) #define cpu_present(cpu) ((cpu) == 0) #define cpu_active(cpu) ((cpu) == 0) -#define cpu_isolated(cpu) ((cpu) == 0) +#define cpu_isolated(cpu) ((cpu) != 0) #endif /* verify cpu argument to cpumask_* operators */ diff --git a/include/linux/ipa.h b/include/linux/ipa.h index d545604cc22d..c11a5c4afece 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -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 @@ -901,6 +901,7 @@ struct IpaHwRingStats_t { * injected due to vdev_id change * @num_ic_inj_fw_desc_change : Number of times the Imm Cmd is * injected due to fw_desc change + * @num_qmb_int_handled : Number of QMB interrupts handled */ struct IpaHwStatsWDIRxInfoData_t { u32 max_outstanding_pkts; @@ -914,6 +915,7 @@ struct IpaHwStatsWDIRxInfoData_t { u32 num_pkts_in_dis_uninit_state; u32 num_ic_inj_vdev_change; u32 num_ic_inj_fw_desc_change; + u32 num_qmb_int_handled; u32 reserved1; u32 reserved2; } __packed; diff --git a/include/linux/irq.h b/include/linux/irq.h index 3c1c96786248..b0bcc1561d3d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -73,6 +73,7 @@ enum irqchip_irq_state; * it from the spurious interrupt detection * mechanism and from core side polling. * IRQ_DISABLE_UNLAZY - Disable lazy irq disable + * IRQ_AFFINITY_MANAGED - Affinity is auto-managed by the kernel */ enum { IRQ_TYPE_NONE = 0x00000000, @@ -99,13 +100,14 @@ enum { IRQ_PER_CPU_DEVID = (1 << 17), IRQ_IS_POLLED = (1 << 18), IRQ_DISABLE_UNLAZY = (1 << 19), + IRQ_AFFINITY_MANAGED = (1 << 21), }; #define IRQF_MODIFY_MASK \ (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \ IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \ IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \ - IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY) + IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY | IRQ_AFFINITY_MANAGED) #define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) @@ -191,6 +193,7 @@ struct irq_data { * IRQD_IRQ_INPROGRESS - In progress state of the interrupt * IRQD_WAKEUP_ARMED - Wakeup mode armed * IRQD_FORWARDED_TO_VCPU - The interrupt is forwarded to a VCPU + * IRQD_AFFINITY_MANAGED - Affinity is auto-managed by the kernel */ enum { IRQD_TRIGGER_MASK = 0xf, @@ -206,6 +209,7 @@ enum { IRQD_IRQ_INPROGRESS = (1 << 18), IRQD_WAKEUP_ARMED = (1 << 19), IRQD_FORWARDED_TO_VCPU = (1 << 20), + IRQD_AFFINITY_MANAGED = (1 << 21), }; #define __irqd_to_state(d) ((d)->common->state_use_accessors) @@ -299,6 +303,11 @@ static inline void irqd_clr_forwarded_to_vcpu(struct irq_data *d) __irqd_to_state(d) &= ~IRQD_FORWARDED_TO_VCPU; } +static inline bool irqd_affinity_is_managed(struct irq_data *d) +{ + return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED; +} + static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { return d->hwirq; diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index 11e8d89c337b..6eb8c1893a53 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -1,4 +1,4 @@ -/* 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 @@ -334,6 +334,7 @@ struct wcd9xxx { struct slim_device *slim_slave; struct mutex io_lock; struct mutex xfer_lock; + struct mutex reset_lock; u8 version; int reset_gpio; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 276dbf19805b..804d89a825fc 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -22,6 +22,7 @@ #include <linux/mmc/core.h> #include <linux/mmc/card.h> #include <linux/mmc/pm.h> +#include <linux/mmc/ring_buffer.h> #define MMC_AUTOSUSPEND_DELAY_MS 3000 @@ -571,6 +572,7 @@ struct mmc_host { } perf; bool perf_enable; #endif + struct mmc_trace_buffer trace_buf; enum dev_state dev_status; bool wakeup_on_idle; struct mmc_cmdq_context_info cmdq_ctx; diff --git a/include/linux/mmc/ring_buffer.h b/include/linux/mmc/ring_buffer.h new file mode 100644 index 000000000000..e6bf163ffcfe --- /dev/null +++ b/include/linux/mmc/ring_buffer.h @@ -0,0 +1,55 @@ +/* + * 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. + * + */ + +#ifndef __MMC_RING_BUFFER__ +#define __MMC_RING_BUFFER__ + +#include <linux/mmc/card.h> +#include <linux/smp.h> + +#include "core.h" + +#define MMC_TRACE_RBUF_SZ_ORDER 2 /* 2^2 pages */ +#define MMC_TRACE_RBUF_SZ (PAGE_SIZE * (1 << MMC_TRACE_RBUF_SZ_ORDER)) +#define MMC_TRACE_EVENT_SZ 256 +#define MMC_TRACE_RBUF_NUM_EVENTS (MMC_TRACE_RBUF_SZ / MMC_TRACE_EVENT_SZ) + +struct mmc_host; +struct mmc_trace_buffer { + int wr_idx; + bool stop_tracing; + spinlock_t trace_lock; + char *data; +}; + +#ifdef CONFIG_MMC_RING_BUFFER +void mmc_stop_tracing(struct mmc_host *mmc); +void mmc_trace_write(struct mmc_host *mmc, const char *fmt, ...); +void mmc_trace_init(struct mmc_host *mmc); +void mmc_trace_free(struct mmc_host *mmc); +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s); +#else +static inline void mmc_stop_tracing(struct mmc_host *mmc) {} +static inline void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) {} +static inline void mmc_trace_init(struct mmc_host *mmc) {} +static inline void mmc_trace_free(struct mmc_host *mmc) {} +static inline void mmc_dump_trace_buffer(struct mmc_host *mmc, + struct seq_file *s) {} +#endif + +#define MMC_TRACE(mmc, fmt, ...) \ + mmc_trace_write(mmc, fmt, ##__VA_ARGS__) + +#endif /* __MMC_RING_BUFFER__ */ diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h index b3a7e4ad722a..44a04b5c2fcd 100644 --- a/include/linux/msm_ext_display.h +++ b/include/linux/msm_ext_display.h @@ -1,6 +1,6 @@ /* include/linux/msm_ext_display.h * - * 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,11 +24,11 @@ /** * Flags to be used with the HPD operation of the external display * interface: - * MSM_EXT_DISP_HPD_NO_AUDIO: audio will not be routed to external display - * MSM_EXT_DISP_HPD_NO_VIDEO: video will not be routed to external display + * MSM_EXT_DISP_HPD_AUDIO: audio will be routed to external display + * MSM_EXT_DISP_HPD_VIDEO: video will be routed to external display */ -#define MSM_EXT_DISP_HPD_NO_AUDIO BIT(0) -#define MSM_EXT_DISP_HPD_NO_VIDEO BIT(1) +#define MSM_EXT_DISP_HPD_AUDIO BIT(0) +#define MSM_EXT_DISP_HPD_VIDEO BIT(1) /** * struct ext_disp_cable_notify - cable notify handler structure diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index bc5637ab01df..4cde40dac778 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -55,7 +55,7 @@ #define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */ /* big enough to hold our biggest descriptor */ -#define USB_COMP_EP0_BUFSIZ 1024 +#define USB_COMP_EP0_BUFSIZ 4096 #define USB_MS_TO_HS_INTERVAL(x) (ilog2((x * 1000 / 125)) + 1) struct usb_configuration; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 94ace231b3bd..e5930177c96a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -69,6 +69,8 @@ struct wiphy; #define CFG80211_ABORT_SCAN 1 #define CFG80211_UPDATE_CONNECT_PARAMS 1 #define CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT 1 +#define CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME 1 +#define CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN 1 /* * wireless hardware capability structures @@ -1568,6 +1570,17 @@ struct cfg80211_sched_scan_plan { }; /** + * struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment. + * + * @band: band of BSS which should match for RSSI level adjustment. + * @delta: value of RSSI level adjustment. + */ +struct cfg80211_bss_select_adjust { + enum nl80211_band band; + s8 delta; +}; + +/** * struct cfg80211_sched_scan_request - scheduled scan request description * * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans) @@ -1602,6 +1615,16 @@ struct cfg80211_sched_scan_plan { * cycle. The driver may ignore this parameter and start * immediately (or at any other time), if this feature is not * supported. + * @relative_rssi_set: Indicates whether @relative_rssi is set or not. + * @relative_rssi: Relative RSSI threshold in dB to restrict scan result + * reporting in connected state to cases where a matching BSS is determined + * to have better or slightly worse RSSI than the current connected BSS. + * The relative RSSI threshold values are ignored in disconnected state. + * @rssi_adjust: delta dB of RSSI preference to be given to the BSSs that belong + * to the specified band while deciding whether a better BSS is reported + * using @relative_rssi. If delta is a negative number, the BSSs that + * belong to the specified band will be penalized by delta dB in relative + * comparisions. */ struct cfg80211_sched_scan_request { struct cfg80211_ssid *ssids; @@ -1621,6 +1644,10 @@ struct cfg80211_sched_scan_request { u8 mac_addr[ETH_ALEN] __aligned(2); u8 mac_addr_mask[ETH_ALEN] __aligned(2); + bool relative_rssi_set; + s8 relative_rssi; + struct cfg80211_bss_select_adjust rssi_adjust; + /* internal */ struct wiphy *wiphy; struct net_device *dev; @@ -1906,6 +1933,22 @@ struct cfg80211_ibss_params { }; /** + * struct cfg80211_bss_selection - connection parameters for BSS selection. + * + * @behaviour: requested BSS selection behaviour. + * @param: parameters for requestion behaviour. + * @band_pref: preferred band for %NL80211_BSS_SELECT_ATTR_BAND_PREF. + * @adjust: parameters for %NL80211_BSS_SELECT_ATTR_RSSI_ADJUST. + */ +struct cfg80211_bss_selection { + enum nl80211_bss_select_attr behaviour; + union { + enum ieee80211_band band_pref; + struct cfg80211_bss_select_adjust adjust; + } param; +}; + +/** * struct cfg80211_connect_params - Connection parameters * * This structure provides information needed to complete IEEE 802.11 @@ -1942,6 +1985,7 @@ struct cfg80211_ibss_params { * @vht_capa_mask: The bits of vht_capa which are to be used. * @pbss: if set, connect to a PCP instead of AP. Valid for DMG * networks. + * @bss_select: criteria to be used for BSS selection. * @prev_bssid: previous BSSID, if not %NULL use reassociate frame */ struct cfg80211_connect_params { @@ -1966,6 +2010,7 @@ struct cfg80211_connect_params { struct ieee80211_vht_cap vht_capa; struct ieee80211_vht_cap vht_capa_mask; bool pbss; + struct cfg80211_bss_selection bss_select; const u8 *prev_bssid; }; @@ -3283,6 +3328,9 @@ struct wiphy_iftype_ext_capab { * low rssi when a frame is heard on different channel, then it should set * this variable to the maximal offset for which it can compensate. * This value should be set in MHz. + * @bss_select_support: bitmask indicating the BSS selection criteria supported + * by the driver in the .connect() callback. The bit position maps to the + * attribute indices defined in &enum nl80211_bss_select_attr. */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -3410,6 +3458,8 @@ struct wiphy { u8 max_num_csa_counters; u8 max_adj_channel_rssi_comp; + u32 bss_select_support; + char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ee5270f984ba..e4a54cd23211 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2685,6 +2685,33 @@ enum ieee80211_ampdu_mlme_action { }; /** + * struct ieee80211_ampdu_params - AMPDU action parameters + * + * @action: the ampdu action, value from %ieee80211_ampdu_mlme_action. + * @sta: peer of this AMPDU session + * @tid: tid of the BA session + * @ssn: start sequence number of the session. TX/RX_STOP can pass 0. When + * action is set to %IEEE80211_AMPDU_RX_START the driver passes back the + * actual ssn value used to start the session and writes the value here. + * @buf_size: reorder buffer size (number of subframes). Valid only when the + * action is set to %IEEE80211_AMPDU_RX_START or + * %IEEE80211_AMPDU_TX_OPERATIONAL + * @amsdu: indicates the peer's ability to receive A-MSDU within A-MPDU. + * valid when the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL + * @timeout: BA session timeout. Valid only when the action is set to + * %IEEE80211_AMPDU_RX_START + */ +struct ieee80211_ampdu_params { + enum ieee80211_ampdu_mlme_action action; + struct ieee80211_sta *sta; + u16 tid; + u16 ssn; + u8 buf_size; + bool amsdu; + u16 timeout; +}; + +/** * enum ieee80211_frame_release_type - frame release reason * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll * @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to @@ -3028,13 +3055,9 @@ enum ieee80211_reconfig_type { * @ampdu_action: Perform a certain A-MPDU action * The RA/TID combination determines the destination and TID we want * the ampdu action to be performed for. The action is defined through - * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) - * is the first frame we expect to perform the action on. Notice - * that TX/RX_STOP can pass NULL for this parameter. - * The @buf_size parameter is only valid when the action is set to - * %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder - * buffer size (number of subframes) for this session -- the driver - * may neither send aggregates containing more subframes than this + * ieee80211_ampdu_mlme_action. + * When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver + * may neither send aggregates containing more subframes than @buf_size * nor send aggregates in a way that lost frames would exceed the * buffer size. If just limiting the aggregate size, this would be * possible with a buf_size of 8: @@ -3045,9 +3068,6 @@ enum ieee80211_reconfig_type { * buffer size of 8. Correct ways to retransmit #1 would be: * - TX: 1 or 18 or 81 * Even "189" would be wrong since 1 could be lost again. - * The @amsdu parameter is valid when the action is set to - * %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability - * to receive A-MSDU within A-MPDU. * * Returns a negative error code on failure. * The callback can sleep. @@ -3389,9 +3409,7 @@ struct ieee80211_ops { int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); int (*get_survey)(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void (*rfkill_poll)(struct ieee80211_hw *hw); diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 38d49a2af8be..a047a33334d2 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -1349,6 +1349,8 @@ struct afe_mod_enable_param { * #AFE_MODULE_SIDETONE_IIR_FILTER module. */ #define AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG 0x00010204 +#define MAX_SIDETONE_IIR_DATA_SIZE 224 +#define MAX_NO_IIR_FILTER_STAGE 10 struct afe_sidetone_iir_filter_config_params { u16 num_biquad_stages; @@ -1360,6 +1362,7 @@ struct afe_sidetone_iir_filter_config_params { /* Pregain for the compensating filter response. * Supported values: Any number in Q13 format */ + uint8_t iir_config[MAX_SIDETONE_IIR_DATA_SIZE]; } __packed; #define AFE_MODULE_LOOPBACK 0x00010205 @@ -1511,6 +1514,55 @@ struct afe_loopback_cfg_v1 { } __packed; +struct afe_loopback_sidetone_gain { + u16 rx_port_id; + u16 gain; +} __packed; + +struct loopback_cfg_data { + u32 loopback_cfg_minor_version; +/* Minor version used for tracking the version of the RMC module + * configuration interface. + * Supported values: #AFE_API_VERSION_LOOPBACK_CONFIG + */ + u16 dst_port_id; + /* Destination Port Id. */ + u16 routing_mode; +/* Specifies data path type from src to dest port. + * Supported values: + * #LB_MODE_DEFAULT + * #LB_MODE_SIDETONE + * #LB_MODE_EC_REF_VOICE_AUDIO + * #LB_MODE_EC_REF_VOICE_A + * #LB_MODE_EC_REF_VOICE + */ + + u16 enable; +/* Specifies whether to enable (1) or + * disable (0) an AFE loopback. + */ + u16 reserved; +/* Reserved for 32-bit alignment. This field must be set to 0. + */ +} __packed; + +struct afe_st_loopback_cfg_v1 { + struct apr_hdr hdr; + struct afe_port_cmd_set_param_v2 param; + struct afe_port_param_data_v2 gain_pdata; + struct afe_loopback_sidetone_gain gain_data; + struct afe_port_param_data_v2 cfg_pdata; + struct loopback_cfg_data cfg_data; +} __packed; + +struct afe_loopback_iir_cfg_v2 { + struct apr_hdr hdr; + struct afe_port_cmd_set_param_v2 param; + struct afe_port_param_data_v2 st_iir_enable_pdata; + struct afe_mod_enable_param st_iir_mode_enable_data; + struct afe_port_param_data_v2 st_iir_filter_config_pdata; + struct afe_sidetone_iir_filter_config_params st_iir_filter_config_data; +} __packed; #define AFE_MODULE_SPEAKER_PROTECTION 0x00010209 #define AFE_PARAM_ID_SPKR_PROT_CONFIG 0x0001020a #define AFE_API_VERSION_SPKR_PROT_CONFIG 0x1 @@ -4924,8 +4976,8 @@ struct asm_amrwbplus_fmt_blk_v2 { } __packed; -#define ASM_MEDIA_FMT_AC3 0x00010DEE -#define ASM_MEDIA_FMT_EAC3 0x00010DEF +#define ASM_MEDIA_FMT_AC3 0x00010DEE +#define ASM_MEDIA_FMT_EAC3 0x00010DEF #define ASM_MEDIA_FMT_DTS 0x00010D88 #define ASM_MEDIA_FMT_MP2 0x00010DE9 #define ASM_MEDIA_FMT_FLAC 0x00010C16 @@ -4934,7 +4986,6 @@ struct asm_amrwbplus_fmt_blk_v2 { #define ASM_MEDIA_FMT_APE 0x00012F32 #define ASM_MEDIA_FMT_DSD 0x00012F3E - /* Media format ID for adaptive transform acoustic coding. This * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command * only. @@ -8941,6 +8992,31 @@ struct asm_dts_eagle_param_get { struct asm_stream_cmd_get_pp_params_v2 param; } __packed; +/* Opcode to set BT address and license for aptx decoder */ +#define APTX_DECODER_BT_ADDRESS 0x00013201 +#define APTX_CLASSIC_DEC_LICENSE_ID 0x00013202 + +struct aptx_dec_bt_addr_cfg { + uint32_t lap; + uint32_t uap; + uint32_t nap; +} __packed; + +struct aptx_dec_bt_dev_addr { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct aptx_dec_bt_addr_cfg bt_addr_cfg; +} __packed; + +struct asm_aptx_dec_fmt_blk_v2 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmtblk; + u32 sample_rate; +/* Number of samples per second. + * Supported values: 44100 and 48000 Hz + */ +} __packed; + /* LSM Specific */ #define VW_FEAT_DIM (39) diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index e0da428fa52f..a47d2805b9c5 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -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 @@ -265,7 +265,7 @@ struct aanc_data { int afe_open(u16 port_id, union afe_port_config *afe_config, int rate); int afe_close(int port_id); int afe_loopback(u16 enable, u16 rx_port, u16 tx_port); -int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain); +int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable); int afe_loopback_gain(u16 port_id, u16 volume); int afe_validate_port(u16 port_id); int afe_get_port_index(u16 port_id); diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index efa5af8e661c..9a3db9aaa25e 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -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 @@ -53,6 +53,7 @@ #define FORMAT_G711_MLAW_FS 0x001b #define FORMAT_DTS 0x001c #define FORMAT_DSD 0x001d +#define FORMAT_APTX 0x001e #define ENCDEC_SBCBITRATE 0x0001 #define ENCDEC_IMMEDIATE_DECODE 0x0002 @@ -270,7 +271,7 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample); int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample); + uint16_t bits_per_sample, bool ts_mode); int q6asm_open_write(struct audio_client *ac, uint32_t format /*, uint16_t bits_per_sample*/); @@ -552,6 +553,9 @@ int q6asm_media_format_block_ape(struct audio_client *ac, int q6asm_media_format_block_dsd(struct audio_client *ac, struct asm_dsd_cfg *cfg, int stream_id); +int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac, + uint32_t sr, int stream_id); + int q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id, int param_value); @@ -574,6 +578,10 @@ int q6asm_dts_eagle_set(struct audio_client *ac, int param_id, uint32_t size, int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size, void *data, struct param_outband *po, int m_id); +/* Send aptx decoder BT address */ +int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac, + struct aptx_dec_bt_addr_cfg *cfg); + /* Set SoftPause Params */ int q6asm_set_softpause(struct audio_client *ac, struct asm_softpause_params *param); diff --git a/include/uapi/linux/msm_audio_calibration.h b/include/uapi/linux/msm_audio_calibration.h index 3c6ab13ca470..f05f9aaddb70 100644 --- a/include/uapi/linux/msm_audio_calibration.h +++ b/include/uapi/linux/msm_audio_calibration.h @@ -98,12 +98,15 @@ enum { ULP_LSM_TOPOLOGY_ID_CAL_TYPE, AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE, AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE, + AFE_SIDETONE_IIR_CAL_TYPE, MAX_CAL_TYPES, }; #define AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE #define AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE +#define AFE_SIDETONE_IIR_CAL_TYPE AFE_SIDETONE_IIR_CAL_TYPE + enum { VERSION_0_0, }; @@ -346,6 +349,19 @@ struct audio_cal_info_sidetone { int32_t pid; }; +#define MAX_SIDETONE_IIR_DATA_SIZE 224 +#define MAX_NO_IIR_FILTER_STAGE 10 + +struct audio_cal_info_sidetone_iir { + uint16_t iir_enable; + uint16_t num_biquad_stages; + uint16_t pregain; + int32_t tx_acdb_id; + int32_t rx_acdb_id; + int32_t mid; + int32_t pid; + uint8_t iir_config[MAX_SIDETONE_IIR_DATA_SIZE]; +}; struct audio_cal_info_lsm_top { int32_t topology; int32_t acdb_id; @@ -580,6 +596,17 @@ struct audio_cal_sidetone { struct audio_cal_type_sidetone cal_type; }; +struct audio_cal_type_sidetone_iir { + struct audio_cal_type_header cal_hdr; + struct audio_cal_data cal_data; + struct audio_cal_info_sidetone_iir cal_info; +}; + +struct audio_cal_sidetone_iir { + struct audio_cal_header hdr; + struct audio_cal_type_sidetone_iir cal_type; +}; + struct audio_cal_type_lsm_top { struct audio_cal_type_header cal_hdr; struct audio_cal_data cal_data; diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 24f1e7c7b742..3bd8bea8ae0d 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -125,6 +125,12 @@ DESTINATION SCALER FLAG CONFIGURATION */ #define MDP_DESTSCALER_ENHANCER_UPDATE 0x4 +/* + * Indicating a partial update to panel ROI. ROI can be + * applied anytime when Destination scaler is enabled. + */ +#define MDP_DESTSCALER_ROI_ENABLE 0x8 + /********************************************************************** VALIDATE/COMMIT FLAG CONFIGURATION **********************************************************************/ @@ -405,6 +411,12 @@ struct mdp_destination_scaler_data { * A userspace pointer points to struct mdp_scale_data_v2. */ uint64_t __user scale; + + /* + * Panel ROI is used when partial update is required in + * current commit call. + */ + struct mdp_rect panel_roi; }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index cc8ece36e0e3..0505b1f9872b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1934,6 +1934,20 @@ enum nl80211_commands { * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also * used in various commands/events for specifying the BSSID. * + * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which + * other BSSs has to be better or slightly worse than the current + * connected BSS so that they get reported to user space. + * This will give an opportunity to userspace to consider connecting to + * other matching BSSs which have better or slightly worse RSSI than + * the current connected BSS by using an offloaded operation to avoid + * unnecessary wakeups. + * + * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in + * the specified band is to be adjusted before doing + * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out + * better BSSs. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2340,6 +2354,9 @@ enum nl80211_attrs { NL80211_ATTR_BSSID, + NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, + NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3008,6 +3025,13 @@ enum nl80211_reg_rule_attr { * how this API was implemented in the past. Also, due to the same problem, * the only way to create a matchset with only an RSSI filter (with this * attribute) is if there's only a single matchset with the RSSI attribute. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether + * %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or + * relative to current bss's RSSI. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for + * BSS-es in the specified band is to be adjusted before doing + * RSSI-based BSS selection. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use @@ -3017,6 +3041,8 @@ enum nl80211_sched_scan_match_attr { NL80211_SCHED_SCAN_MATCH_ATTR_SSID, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, + NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST, /* keep last */ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, @@ -4603,6 +4629,15 @@ enum nl80211_feature_flags { * configuration (AP/mesh) with HT rates. * @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate * configuration (AP/mesh) with VHT rates. + * @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup + * with user space SME (NL80211_CMD_AUTHENTICATE) in station mode. + * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA + * in @NL80211_CMD_FRAME while not associated. + * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports + * randomized TA in @NL80211_CMD_FRAME while associated. + * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan + * for reporting BSSs with better RSSI than the current connected BSS + * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI). * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -4617,6 +4652,10 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, NL80211_EXT_FEATURE_BEACON_RATE_HT, NL80211_EXT_FEATURE_BEACON_RATE_VHT, + NL80211_EXT_FEATURE_FILS_STA, + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA, + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED, + NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -4866,4 +4905,48 @@ enum nl80211_sched_scan_plan { __NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1 }; +/** + * struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters. + * + * @band: band of BSS that must match for RSSI value adjustment. + * @delta: value used to adjust the RSSI value of matching BSS. + */ +struct nl80211_bss_select_rssi_adjust { + __u8 band; + __s8 delta; +} __attribute__((packed)); + +/** + * enum nl80211_bss_select_attr - attributes for bss selection. + * + * @__NL80211_BSS_SELECT_ATTR_INVALID: reserved. + * @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection + * is requested. + * @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS + * selection should be done such that the specified band is preferred. + * When there are multiple BSS-es in the preferred band, the driver + * shall use RSSI-based BSS selection as a second step. The value of + * this attribute is according to &enum nl80211_band (u32). + * @NL80211_BSS_SELECT_ATTR_RSSI_ADJUST: When present the RSSI level for + * BSS-es in the specified band is to be adjusted before doing + * RSSI-based BSS selection. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * @NL80211_BSS_SELECT_ATTR_MAX: highest bss select attribute number. + * @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use. + * + * One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT + * for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour + * which the driver shall use. + */ +enum nl80211_bss_select_attr { + __NL80211_BSS_SELECT_ATTR_INVALID, + NL80211_BSS_SELECT_ATTR_RSSI, + NL80211_BSS_SELECT_ATTR_BAND_PREF, + NL80211_BSS_SELECT_ATTR_RSSI_ADJUST, + + /* keep last */ + __NL80211_BSS_SELECT_ATTR_AFTER_LAST, + NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index ef96966b2bbe..6a297ad6d380 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -103,7 +103,8 @@ #define SND_AUDIOCODEC_ALAC ((__u32) 0x00000019) #define SND_AUDIOCODEC_APE ((__u32) 0x00000020) #define SND_AUDIOCODEC_DSD ((__u32) 0x00000021) -#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_DSD +#define SND_AUDIOCODEC_APTX ((__u32) 0x00000022) +#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APTX /* * Profile and modes are listed with bit masks. This allows for a * more compact representation of fields that will not evolve @@ -396,6 +397,12 @@ struct snd_dec_ape { __u32 seek_table_present; }; +struct snd_dec_aptx { + __u32 lap; + __u32 uap; + __u32 nap; +}; + union snd_codec_options { struct snd_enc_wma wma; struct snd_enc_vorbis vorbis; @@ -407,6 +414,7 @@ union snd_codec_options { struct snd_dec_vorbis vorbis_dec; struct snd_dec_alac alac; struct snd_dec_ape ape; + struct snd_dec_aptx aptx_dec; }; /** struct snd_codec_desc - description of codec capabilities diff --git a/include/uapi/video/msm_hdmi_modes.h b/include/uapi/video/msm_hdmi_modes.h index 2200485daa6c..43ca6bab4c62 100644 --- a/include/uapi/video/msm_hdmi_modes.h +++ b/include/uapi/video/msm_hdmi_modes.h @@ -234,7 +234,11 @@ struct msm_hdmi_mode_timing_info { #define HDMI_VFRMT_1920x1200p60_16_10 ETIII_OFF(8) #define ETIII_VFRMT_END HDMI_VFRMT_1920x1200p60_16_10 -#define RESERVE_OFF(x) (ETIII_VFRMT_END + x) +#define MISC_VFRMT_OFF(x) (ETIII_VFRMT_END + x) +#define HDMI_VFRMT_640x480p59_4_3 MISC_VFRMT_OFF(1) +#define MISC_VFRMT_END HDMI_VFRMT_640x480p59_4_3 + +#define RESERVE_OFF(x) (MISC_VFRMT_END + x) #define HDMI_VFRMT_RESERVE1 RESERVE_OFF(1) #define HDMI_VFRMT_RESERVE2 RESERVE_OFF(2) @@ -425,6 +429,11 @@ struct msm_hdmi_mode_timing_info { {HDMI_VFRMT_3840x2160p60_64_27, 3840, 176, 88, 296, false, \ 2160, 8, 10, 72, false, 594000, 60000, false, true, \ HDMI_RES_AR_64_27, 0} +#define HDMI_VFRMT_640x480p59_4_3_TIMING \ + {HDMI_VFRMT_640x480p59_4_3, 640, 16, 96, 48, true, \ + 480, 10, 2, 33, true, 25170, 59928, false, true, \ + HDMI_RES_AR_4_3, 1} + #define MSM_HDMI_MODES_SET_TIMING(LUT, MODE) do { \ struct msm_hdmi_mode_timing_info mode = MODE##_TIMING; \ @@ -508,6 +517,8 @@ do { \ HDMI_VFRMT_3840x2160p50_64_27); \ MSM_HDMI_MODES_SET_TIMING(__lut, \ HDMI_VFRMT_3840x2160p60_64_27); \ + MSM_HDMI_MODES_SET_TIMING(__lut, \ + HDMI_VFRMT_640x480p59_4_3); \ } \ if (__type & MSM_HDMI_MODES_XTND) { \ MSM_HDMI_MODES_SET_TIMING(__lut, \ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 15206453b12a..9812d9c0d483 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -836,7 +836,8 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) irq_settings_clr_and_set(desc, clr, set); irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | - IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT); + IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT | + IRQD_AFFINITY_MANAGED); if (irq_settings_has_no_balance_set(desc)) irqd_set(&desc->irq_data, IRQD_NO_BALANCING); if (irq_settings_is_per_cpu(desc)) @@ -845,6 +846,8 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); if (irq_settings_is_level(desc)) irqd_set(&desc->irq_data, IRQD_LEVEL); + if (irq_settings_has_affinity_managed_set(desc)) + irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED); irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index fcab63c66905..56afc0be6289 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -105,6 +105,8 @@ static inline void unregister_handler_proc(unsigned int irq, struct irqaction *action) { } #endif +extern bool irq_can_set_affinity_usr(unsigned int irq); + extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask); extern void irq_set_thread_affinity(struct irq_desc *desc); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 5cb153a8474a..e5c70dcb7f8e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -115,12 +115,12 @@ EXPORT_SYMBOL(synchronize_irq); #ifdef CONFIG_SMP cpumask_var_t irq_default_affinity; -static int __irq_can_set_affinity(struct irq_desc *desc) +static bool __irq_can_set_affinity(struct irq_desc *desc) { if (!desc || !irqd_can_balance(&desc->irq_data) || !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) - return 0; - return 1; + return false; + return true; } /** @@ -134,6 +134,21 @@ int irq_can_set_affinity(unsigned int irq) } /** + * irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space + * @irq: Interrupt to check + * + * Like irq_can_set_affinity() above, but additionally checks for the + * AFFINITY_MANAGED flag. + */ +bool irq_can_set_affinity_usr(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + return __irq_can_set_affinity(desc) && + !irqd_affinity_is_managed(&desc->irq_data); +} + +/** * irq_set_thread_affinity - Notify irq threads to adjust affinity * @desc: irq descriptor which has affitnity changed * diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index a2c02fd5d6d0..a24c5b909047 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -96,7 +96,7 @@ static ssize_t write_irq_affinity(int type, struct file *file, cpumask_var_t new_value; int err; - if (!irq_can_set_affinity(irq) || no_irq_affinity) + if (!irq_can_set_affinity_usr(irq) || no_irq_affinity) return -EIO; if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index 320579d89091..f0964f058521 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -17,6 +17,7 @@ enum { _IRQ_IS_POLLED = IRQ_IS_POLLED, _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, + _IRQ_AFFINITY_MANAGED = IRQ_AFFINITY_MANAGED, }; #define IRQ_PER_CPU GOT_YOU_MORON @@ -32,6 +33,7 @@ enum { #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON +#define IRQ_AFFINITY_MANAGED GOT_YOU_MORON static inline void irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set) @@ -65,6 +67,16 @@ static inline bool irq_settings_has_no_balance_set(struct irq_desc *desc) return desc->status_use_accessors & _IRQ_NO_BALANCING; } +static inline void irq_settings_set_affinity_managed(struct irq_desc *desc) +{ + desc->status_use_accessors |= _IRQ_AFFINITY_MANAGED; +} + +static inline bool irq_settings_has_affinity_managed_set(struct irq_desc *desc) +{ + return desc->status_use_accessors & _IRQ_AFFINITY_MANAGED; +} + static inline u32 irq_settings_get_trigger_mask(struct irq_desc *desc) { return desc->status_use_accessors & IRQ_TYPE_SENSE_MASK; diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 40df4f8f1de0..95125c5518e2 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -590,6 +590,7 @@ void update_cluster_topology(void) * cluster_head visible. */ move_list(&cluster_head, &new_head, false); + update_all_clusters_stats(); } void init_clusters(void) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d3873333c766..a2a87c3ad44e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -178,7 +178,7 @@ extern int no_unaligned_warning; #define SYSCTL_WRITES_WARN 0 #define SYSCTL_WRITES_STRICT 1 -static int sysctl_writes_strict = SYSCTL_WRITES_WARN; +static int sysctl_writes_strict = SYSCTL_WRITES_STRICT; static int proc_do_cad_pid(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d41925306d75..c42587d02190 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1754,13 +1754,25 @@ static void unreserve_highatomic_pageblock(const struct alloc_context *ac) struct page, lru); /* - * It should never happen but changes to locking could - * inadvertently allow a per-cpu drain to add pages - * to MIGRATE_HIGHATOMIC while unreserving so be safe - * and watch for underflows. + * In page freeing path, migratetype change is racy so + * we can counter several free pages in a pageblock + * in this loop althoug we changed the pageblock type + * from highatomic to ac->migratetype. So we should + * adjust the count once. */ - zone->nr_reserved_highatomic -= min(pageblock_nr_pages, - zone->nr_reserved_highatomic); + if (get_pageblock_migratetype(page) == + MIGRATE_HIGHATOMIC) { + /* + * It should never happen but changes to + * locking could inadvertently allow a per-cpu + * drain to add pages to MIGRATE_HIGHATOMIC + * while unreserving so be safe and watch for + * underflows. + */ + zone->nr_reserved_highatomic -= min( + pageblock_nr_pages, + zone->nr_reserved_highatomic); + } /* * Convert to ac->migratetype and avoid the normal @@ -1802,7 +1814,8 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype) page = list_entry(area->free_list[fallback_mt].next, struct page, lru); - if (can_steal) + if (can_steal && + get_pageblock_migratetype(page) != MIGRATE_HIGHATOMIC) steal_suitable_fallback(zone, page, start_migratetype); /* Remove the page from the freelists */ @@ -2240,7 +2253,8 @@ int __isolate_free_page(struct page *page, unsigned int order) struct page *endpage = page + (1 << order) - 1; for (; page < endpage; page += pageblock_nr_pages) { int mt = get_pageblock_migratetype(page); - if (!is_migrate_isolate(mt) && !is_migrate_cma(mt)) + if (!is_migrate_isolate(mt) && !is_migrate_cma(mt) + && mt != MIGRATE_HIGHATOMIC) set_pageblock_migratetype(page, MIGRATE_MOVABLE); } diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 367784be5df2..f598ff80b30e 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -7,6 +7,7 @@ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007-2010, Intel Corporation + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -61,6 +62,14 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, { struct ieee80211_local *local = sta->local; struct tid_ampdu_rx *tid_rx; + struct ieee80211_ampdu_params params = { + .sta = &sta->sta, + .action = IEEE80211_AMPDU_RX_STOP, + .tid = tid, + .amsdu = false, + .timeout = 0, + .ssn = 0, + }; lockdep_assert_held(&sta->ampdu_mlme.mtx); @@ -78,8 +87,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", (int)reason); - if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, - &sta->sta, tid, NULL, 0, false)) + if (drv_ampdu_action(local, sta->sdata, ¶ms)) sdata_info(sta->sdata, "HW problem - can not stop rx aggregation for %pM tid %d\n", sta->sta.addr, tid); @@ -237,6 +245,15 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, { struct ieee80211_local *local = sta->sdata->local; struct tid_ampdu_rx *tid_agg_rx; + struct ieee80211_ampdu_params params = { + .sta = &sta->sta, + .action = IEEE80211_AMPDU_RX_START, + .tid = tid, + .amsdu = false, + .timeout = timeout, + .ssn = start_seq_num, + }; + int i, ret = -EOPNOTSUPP; u16 status = WLAN_STATUS_REQUEST_DECLINED; @@ -275,6 +292,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, /* make sure the size doesn't exceed the maximum supported by the hw */ if (buf_size > local->hw.max_rx_aggregation_subframes) buf_size = local->hw.max_rx_aggregation_subframes; + params.buf_size = buf_size; /* examine state machine */ mutex_lock(&sta->ampdu_mlme.mtx); @@ -322,8 +340,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, for (i = 0; i < buf_size; i++) __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); - ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, - &sta->sta, tid, &start_seq_num, 0, false); + ret = drv_ampdu_action(local, sta->sdata, ¶ms); ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", sta->sta.addr, tid, ret); if (ret) { diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ff757181b0a8..4932e9f243a2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -7,6 +7,7 @@ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007-2010, Intel Corporation + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -295,7 +296,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, { struct ieee80211_local *local = sta->local; struct tid_ampdu_tx *tid_tx; - enum ieee80211_ampdu_mlme_action action; + struct ieee80211_ampdu_params params = { + .sta = &sta->sta, + .tid = tid, + .buf_size = 0, + .amsdu = false, + .timeout = 0, + .ssn = 0, + }; int ret; lockdep_assert_held(&sta->ampdu_mlme.mtx); @@ -304,10 +312,10 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, case AGG_STOP_DECLINED: case AGG_STOP_LOCAL_REQUEST: case AGG_STOP_PEER_REQUEST: - action = IEEE80211_AMPDU_TX_STOP_CONT; + params.action = IEEE80211_AMPDU_TX_STOP_CONT; break; case AGG_STOP_DESTROY_STA: - action = IEEE80211_AMPDU_TX_STOP_FLUSH; + params.action = IEEE80211_AMPDU_TX_STOP_FLUSH; break; default: WARN_ON_ONCE(1); @@ -330,9 +338,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, spin_unlock_bh(&sta->lock); if (reason != AGG_STOP_DESTROY_STA) return -EALREADY; - ret = drv_ampdu_action(local, sta->sdata, - IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, - &sta->sta, tid, NULL, 0, false); + params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT; + ret = drv_ampdu_action(local, sta->sdata, ¶ms); WARN_ON_ONCE(ret); return 0; } @@ -381,8 +388,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, WLAN_BACK_INITIATOR; tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST; - ret = drv_ampdu_action(local, sta->sdata, action, - &sta->sta, tid, NULL, 0, false); + ret = drv_ampdu_action(local, sta->sdata, ¶ms); /* HW shall not deny going back to legacy */ if (WARN_ON(ret)) { @@ -445,7 +451,14 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) struct tid_ampdu_tx *tid_tx; struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; - u16 start_seq_num; + struct ieee80211_ampdu_params params = { + .sta = &sta->sta, + .action = IEEE80211_AMPDU_TX_START, + .tid = tid, + .buf_size = 0, + .amsdu = false, + .timeout = 0, + }; int ret; tid_tx = rcu_dereference_protected_tid_tx(sta, tid); @@ -467,10 +480,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) */ synchronize_net(); - start_seq_num = sta->tid_seq[tid] >> 4; - - ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, - &sta->sta, tid, &start_seq_num, 0, false); + params.ssn = sta->tid_seq[tid] >> 4; + ret = drv_ampdu_action(local, sdata, ¶ms); if (ret) { ht_dbg(sdata, "BA request denied - HW unavailable for %pM tid %d\n", @@ -499,7 +510,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) /* send AddBA request */ ieee80211_send_addba_request(sdata, sta->sta.addr, tid, - tid_tx->dialog_token, start_seq_num, + tid_tx->dialog_token, params.ssn, IEEE80211_MAX_AMPDU_BUF, tid_tx->timeout); } @@ -684,18 +695,24 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, struct sta_info *sta, u16 tid) { struct tid_ampdu_tx *tid_tx; + struct ieee80211_ampdu_params params = { + .sta = &sta->sta, + .action = IEEE80211_AMPDU_TX_OPERATIONAL, + .tid = tid, + .timeout = 0, + .ssn = 0, + }; lockdep_assert_held(&sta->ampdu_mlme.mtx); tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + params.buf_size = tid_tx->buf_size; + params.amsdu = tid_tx->amsdu; ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n", sta->sta.addr, tid); - drv_ampdu_action(local, sta->sdata, - IEEE80211_AMPDU_TX_OPERATIONAL, - &sta->sta, tid, NULL, tid_tx->buf_size, - tid_tx->amsdu); + drv_ampdu_action(local, sta->sdata, ¶ms); /* * synchronize with TX path, while splicing the TX path diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index ca1fe5576103..c258f1041d33 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c @@ -284,9 +284,7 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local, int drv_ampdu_action(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, - u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { int ret = -EOPNOTSUPP; @@ -296,12 +294,10 @@ int drv_ampdu_action(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_ampdu_action(local, sdata, action, sta, tid, - ssn, buf_size, amsdu); + trace_drv_ampdu_action(local, sdata, params); if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, - sta, tid, ssn, buf_size, amsdu); + ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); trace_drv_return_int(local, ret); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 154ce4b13406..18b0d65baff0 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -585,9 +585,7 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) int drv_ampdu_action(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, - u16 *ssn, u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); static inline int drv_get_survey(struct ieee80211_local *local, int idx, struct survey_info *survey) diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 56c6d6cfa5a1..913e959b03cf 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -80,7 +80,23 @@ #define KEY_PR_FMT " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d" #define KEY_PR_ARG __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx - +#define AMPDU_ACTION_ENTRY __field(enum ieee80211_ampdu_mlme_action, \ + ieee80211_ampdu_mlme_action) \ + STA_ENTRY \ + __field(u16, tid) \ + __field(u16, ssn) \ + __field(u8, buf_size) \ + __field(bool, amsdu) \ + __field(u16, timeout) +#define AMPDU_ACTION_ASSIGN STA_NAMED_ASSIGN(params->sta); \ + __entry->tid = params->tid; \ + __entry->ssn = params->ssn; \ + __entry->buf_size = params->buf_size; \ + __entry->amsdu = params->amsdu; \ + __entry->timeout = params->timeout; +#define AMPDU_ACTION_PR_FMT STA_PR_FMT " tid %d, ssn %d, buf_size %u, amsdu %d, timeout %d" +#define AMPDU_ACTION_PR_ARG STA_PR_ARG, __entry->tid, __entry->ssn, \ + __entry->buf_size, __entry->amsdu, __entry->timeout /* * Tracing for driver callbacks. @@ -970,38 +986,25 @@ DEFINE_EVENT(local_only_evt, drv_tx_last_beacon, TRACE_EVENT(drv_ampdu_action, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, - u16 *ssn, u8 buf_size, bool amsdu), + struct ieee80211_ampdu_params *params), - TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu), + TP_ARGS(local, sdata, params), TP_STRUCT__entry( LOCAL_ENTRY - STA_ENTRY - __field(u32, action) - __field(u16, tid) - __field(u16, ssn) - __field(u8, buf_size) - __field(bool, amsdu) VIF_ENTRY + AMPDU_ACTION_ENTRY ), TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - STA_ASSIGN; - __entry->action = action; - __entry->tid = tid; - __entry->ssn = ssn ? *ssn : 0; - __entry->buf_size = buf_size; - __entry->amsdu = amsdu; + AMPDU_ACTION_ASSIGN; ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d", - LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, - __entry->tid, __entry->buf_size, __entry->amsdu + LOCAL_PR_FMT VIF_PR_FMT AMPDU_ACTION_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG, AMPDU_ACTION_PR_ARG ) ); diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c index 2999e2c15fdb..2819da9ae3f2 100644 --- a/net/rmnet_data/rmnet_data_vnd.c +++ b/net/rmnet_data/rmnet_data_vnd.c @@ -504,6 +504,18 @@ static void rmnet_vnd_setup(struct net_device *dev) INIT_LIST_HEAD(&dev_conf->flow_head); } +/** + * rmnet_vnd_setup() - net_device initialization helper function + * @dev: Virtual network device + * + * Called during device initialization. Disables GRO. + */ +static void rmnet_vnd_disable_offload(struct net_device *dev) +{ + dev->wanted_features &= ~NETIF_F_GRO; + __netdev_update_features(dev); +} + /* ***************** Exposed API ******************************************** */ /** @@ -616,6 +628,8 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, *new_device = dev; } + rmnet_vnd_disable_offload(dev); + LOGM("Registered device %s", dev->name); return rc; } diff --git a/net/wireless/core.c b/net/wireless/core.c index 16043faba52c..14868e42f3ca 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -619,6 +619,13 @@ int wiphy_register(struct wiphy *wiphy) !rdev->ops->set_mac_acl))) return -EINVAL; + /* assure only valid behaviours are flagged by driver + * hence subtract 2 as bit 0 is invalid. + */ + if (WARN_ON(wiphy->bss_select_support && + (wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2)))) + return -EINVAL; + if (wiphy->addresses) memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index fb44fa3bf4ef..594eeea9533b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -644,8 +644,25 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return err; } - if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) - return -EINVAL; + if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) { + /* Allow random TA to be used with Public Action frames if the + * driver has indicated support for this. Otherwise, only allow + * the local address to be used. + */ + if (!ieee80211_is_action(mgmt->frame_control) || + mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) + return -EINVAL; + if (!wdev->current_bss && + !wiphy_ext_feature_isset( + &rdev->wiphy, + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA)) + return -EINVAL; + if (wdev->current_bss && + !wiphy_ext_feature_isset( + &rdev->wiphy, + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED)) + return -EINVAL; + } /* Transmit the Action frame as requested by user space */ return rdev_mgmt_tx(rdev, wdev, params, cookie); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2d71cafde513..5ec8e5cf8a8e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -402,7 +402,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, [NL80211_ATTR_PBSS] = { .type = NLA_FLAG }, + [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED }, [NL80211_ATTR_BSSID] = { .len = ETH_ALEN }, + [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 }, + [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = { + .len = sizeof(struct nl80211_bss_select_rssi_adjust) + }, }; /* policy for the key attributes */ @@ -487,6 +492,15 @@ nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = { [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 }, }; +static const struct nla_policy +nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = { + [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG }, + [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 }, + [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = { + .len = sizeof(struct nl80211_bss_select_rssi_adjust) + }, +}; + static int nl80211_prepare_wdev_dump(struct sk_buff *skb, struct netlink_callback *cb, struct cfg80211_registered_device **rdev, @@ -1778,6 +1792,25 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, } } + if (rdev->wiphy.bss_select_support) { + struct nlattr *nested; + u32 bss_select_support = rdev->wiphy.bss_select_support; + + nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT); + if (!nested) + goto nla_put_failure; + + i = 0; + while (bss_select_support) { + if ((bss_select_support & 1) && + nla_put_flag(msg, i)) + goto nla_put_failure; + i++; + bss_select_support >>= 1; + } + nla_nest_end(msg, nested); + } + /* done */ state->split_start = 0; break; @@ -6087,6 +6120,73 @@ static int validate_scan_freqs(struct nlattr *freqs) return n_channels; } +static bool is_band_valid(struct wiphy *wiphy, enum ieee80211_band b) +{ + return b < IEEE80211_NUM_BANDS && wiphy->bands[b]; +} + +static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy, + struct cfg80211_bss_selection *bss_select) +{ + struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1]; + struct nlattr *nest; + int err; + bool found = false; + int i; + + /* only process one nested attribute */ + nest = nla_data(nla); + if (!nla_ok(nest, nla_len(nest))) + return -EINVAL; + + err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest), + nla_len(nest), nl80211_bss_select_policy); + if (err) + return err; + + /* only one attribute may be given */ + for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) { + if (attr[i]) { + if (found) + return -EINVAL; + found = true; + } + } + + bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID; + + if (attr[NL80211_BSS_SELECT_ATTR_RSSI]) + bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI; + + if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) { + bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF; + bss_select->param.band_pref = + nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]); + if (!is_band_valid(wiphy, bss_select->param.band_pref)) + return -EINVAL; + } + + if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) { + struct nl80211_bss_select_rssi_adjust *adj_param; + + adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]); + bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST; + bss_select->param.adjust.band = adj_param->band; + bss_select->param.adjust.delta = adj_param->delta; + if (!is_band_valid(wiphy, bss_select->param.adjust.band)) + return -EINVAL; + } + + /* user-space did not provide behaviour attribute */ + if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID) + return -EINVAL; + + if (!(wiphy->bss_select_support & BIT(bss_select->behaviour))) + return -EINVAL; + + return 0; +} + static int nl80211_parse_random_mac(struct nlattr **attrs, u8 *mac_addr, u8 *mac_addr_mask) { @@ -6557,6 +6657,12 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, if (!n_plans || n_plans > wiphy->max_sched_scan_plans) return ERR_PTR(-EINVAL); + if (!wiphy_ext_feature_isset( + wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) && + (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] || + attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST])) + return ERR_PTR(-EINVAL); + request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->match_sets) * n_match_sets @@ -6762,6 +6868,26 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, request->delay = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]); + if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) { + request->relative_rssi = nla_get_s8( + attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]); + request->relative_rssi_set = true; + } + + if (request->relative_rssi_set && + attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) { + struct nl80211_bss_select_rssi_adjust *rssi_adjust; + + rssi_adjust = nla_data( + attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]); + request->rssi_adjust.band = rssi_adjust->band; + request->rssi_adjust.delta = rssi_adjust->delta; + if (!is_band_valid(wiphy, request->rssi_adjust.band)) { + err = -EINVAL; + goto out_free; + } + } + err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs); if (err) goto out_free; @@ -8349,6 +8475,21 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; } + if (info->attrs[NL80211_ATTR_BSS_SELECT]) { + /* bss selection makes no sense if bssid is set */ + if (connect.bssid) { + kzfree(connkeys); + return -EINVAL; + } + + err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT], + wiphy, &connect.bss_select); + if (err) { + kzfree(connkeys); + return err; + } + } + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); @@ -9245,6 +9386,20 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay)) return -ENOBUFS; + if (req->relative_rssi_set) { + struct nl80211_bss_select_rssi_adjust rssi_adjust; + + if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, + req->relative_rssi)) + return -ENOBUFS; + + rssi_adjust.band = req->rssi_adjust.band; + rssi_adjust.delta = req->rssi_adjust.delta; + if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, + sizeof(rssi_adjust), &rssi_adjust)) + return -ENOBUFS; + } + freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); if (!freqs) return -ENOBUFS; diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 0869a862f521..cd3f08b3959d 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -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 @@ -100,6 +100,9 @@ struct kc_entry { struct task_struct *thread_pending; enum pfk_kc_entry_state state; + + /* ref count for the number of requests in the HW queue for this key */ + int loaded_ref_cnt; int scm_error; }; @@ -520,6 +523,10 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, if (entry_exists) { kc_update_timestamp(entry); entry->state = ACTIVE_ICE_LOADED; + + if (async) + entry->loaded_ref_cnt++; + break; } case (FREE): @@ -529,8 +536,17 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, entry->scm_error = ret; pr_err("%s: key load error (%d)\n", __func__, ret); } else { - entry->state = ACTIVE_ICE_LOADED; kc_update_timestamp(entry); + entry->state = ACTIVE_ICE_LOADED; + + /* + * only increase ref cnt for async calls, + * sync calls from within work thread do not pass + * requests further to HW + */ + if (async) + entry->loaded_ref_cnt++; + } break; case (ACTIVE_ICE_PRELOAD): @@ -539,6 +555,10 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, break; case (ACTIVE_ICE_LOADED): kc_update_timestamp(entry); + + if (async) + entry->loaded_ref_cnt++; + break; case(SCM_ERROR): ret = entry->scm_error; @@ -572,6 +592,8 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, const unsigned char *salt, size_t salt_size) { struct kc_entry *entry = NULL; + struct task_struct *tmp_pending = NULL; + int ref_cnt = 0; if (!kc_is_ready()) return; @@ -591,14 +613,28 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, if (!entry) { kc_spin_unlock(); pr_err("internal error, there should an entry to unlock\n"); + return; } - entry->state = INACTIVE; + ref_cnt = --entry->loaded_ref_cnt; + + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); - /* wake-up invalidation if it's waiting for the entry to be released */ - if (entry->thread_pending) { - wake_up_process(entry->thread_pending); - entry->thread_pending = NULL; + if (!ref_cnt) { + entry->state = INACTIVE; + /* + * wake-up invalidation if it's waiting + * for the entry to be released + */ + if (entry->thread_pending) { + tmp_pending = entry->thread_pending; + entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; + } } kc_spin_unlock(); diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index b94001d8a6eb..85cf0eb48ee0 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -94,6 +94,7 @@ static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[]; /* By default enable the internal speaker boost */ static bool spkr_boost_en = true; static bool initial_boot = true; +static bool is_ssr_en; static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = { "cdc-vdd-mic-bias", @@ -4052,15 +4053,17 @@ int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root, return -ENOMEM; } sdm660_cdc_priv->version_entry = version_entry; - sdm660_cdc_priv->audio_ssr_nb.notifier_call = - sdm660_cdc_notifier_service_cb; - ret = audio_notifier_register("pmic_analog_cdc", - AUDIO_NOTIFIER_ADSP_DOMAIN, - &sdm660_cdc_priv->audio_ssr_nb); - if (ret < 0) { - pr_err("%s: Audio notifier register failed ret = %d\n", - __func__, ret); - return ret; + if (is_ssr_en) { + sdm660_cdc_priv->audio_ssr_nb.notifier_call = + sdm660_cdc_notifier_service_cb; + ret = audio_notifier_register("pmic_analog_cdc", + AUDIO_NOTIFIER_ADSP_DOMAIN, + &sdm660_cdc_priv->audio_ssr_nb); + if (ret < 0) { + pr_err("%s: Audio notifier register failed ret = %d\n", + __func__, ret); + return ret; + } } 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 c39b6d57f908..5c210dc2176e 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -333,21 +333,6 @@ static int msm_dig_cdc_codec_enable_interpolator(struct snd_soc_dapm_widget *w, return 0; } -static int msm_dig_cdc_codec_enable_rx_chain(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - - switch (event) { - case SND_SOC_DAPM_POST_PMD: - snd_soc_update_bits(codec, w->reg, - 1 << w->shift, 0x00); - break; - } - return 0; -} - static int msm_dig_cdc_get_iir_enable_audio_mixer( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -809,13 +794,18 @@ static int msm_dig_cdc_codec_enable_dmic(struct snd_soc_dapm_widget *w, (*dmic_clk_cnt)++; if (*dmic_clk_cnt == 1) { snd_soc_update_bits(codec, dmic_clk_reg, - 0x0E, 0x02); + 0x0E, 0x04); snd_soc_update_bits(codec, dmic_clk_reg, dmic_clk_en, dmic_clk_en); } snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_TX1_DMIC_CTL + (dmic - 1) * 0x20, - 0x07, 0x02); + MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x07, 0x02); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x07, 0x02); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_TX3_DMIC_CTL, 0x07, 0x02); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_TX4_DMIC_CTL, 0x07, 0x02); break; case SND_SOC_DAPM_POST_PMD: (*dmic_clk_cnt)--; @@ -1556,18 +1546,9 @@ static const struct snd_soc_dapm_widget msm_dig_dapm_widgets[] = { SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER_E("RX1 CHAIN", SND_SOC_NOPM, - 0, 0, NULL, 0, - msm_dig_cdc_codec_enable_rx_chain, - SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("RX2 CHAIN", SND_SOC_NOPM, - 0, 0, NULL, 0, - msm_dig_cdc_codec_enable_rx_chain, - SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("RX3 CHAIN", SND_SOC_NOPM, - 0, 0, NULL, 0, - msm_dig_cdc_codec_enable_rx_chain, - SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX3 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_mix1_inp1_mux), diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 3228be362bab..cb201899b4b8 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1554,6 +1554,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) if (mbhc->mbhc_cb->enable_mb_source) mbhc->mbhc_cb->enable_mb_source(mbhc, true); mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; wcd_mbhc_detect_plug_type(mbhc); } else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE) && !detection_type) { @@ -1571,6 +1572,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false); mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false); @@ -1759,6 +1761,7 @@ determine_plug: mic_trigerred = 0; mbhc->is_extn_cable = true; mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; wcd_mbhc_detect_plug_type(mbhc); WCD_MBHC_RSC_UNLOCK(mbhc); pr_debug("%s: leave\n", __func__); @@ -1935,15 +1938,13 @@ static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data) pr_debug("%s: enter\n", __func__); complete(&mbhc->btn_press_compl); WCD_MBHC_RSC_LOCK(mbhc); - /* send event to sw intr handler*/ - mbhc->is_btn_press = true; wcd_cancel_btn_work(mbhc); if (wcd_swch_level_remove(mbhc)) { pr_debug("%s: Switch level is low ", __func__); goto done; } - mbhc->btn_press_intr = true; + mbhc->is_btn_press = true; msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport); pr_debug("%s: msec_val = %ld\n", __func__, msec_val); if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) { @@ -1957,12 +1958,15 @@ static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data) __func__); goto done; } + mask = wcd_mbhc_get_button_mask(mbhc); + if (mask == SND_JACK_BTN_0) + mbhc->btn_press_intr = true; + if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) { pr_debug("%s: Plug isn't headset, ignore button press\n", __func__); goto done; } - mask = wcd_mbhc_get_button_mask(mbhc); mbhc->buttons_pressed |= mask; mbhc->mbhc_cb->lock_sleep(mbhc, true); if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, @@ -1988,8 +1992,8 @@ static irqreturn_t wcd_mbhc_release_handler(int irq, void *data) goto exit; } - if (mbhc->btn_press_intr) { - mbhc->btn_press_intr = false; + if (mbhc->is_btn_press) { + mbhc->is_btn_press = false; } else { pr_debug("%s: This release is for fake btn press\n", __func__); goto exit; diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 86ad8752b6ff..0030b1fcf773 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -8821,13 +8821,8 @@ static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx) WCD9XXX_DIG_CORE_REGION_1); mutex_lock(&tavil->codec_mutex); - /* - * Codec hardware by default comes up in SVS mode. - * Initialize the svs_ref_cnt to 1 to reflect the hardware - * state in the driver. - */ - tavil->svs_ref_cnt = 1; + tavil_vote_svs(tavil, true); tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la = control->slim_slave->laddr; tavil_slimbus_slave_port_cfg.slave_dev_pgd_la = @@ -8835,17 +8830,9 @@ static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx) tavil_init_slim_slave_cfg(codec); snd_soc_card_change_online_state(codec->component.card, 1); - /* Class-H Init */ - wcd_clsh_init(&tavil->clsh_d); - /* Default HPH Mode to Class-H LOHiFi */ - tavil->hph_mode = CLS_H_LOHIFI; - for (i = 0; i < TAVIL_MAX_MICBIAS; i++) tavil->micb_ref[i] = 0; - for (i = 0; i < COMPANDER_MAX; i++) - tavil->comp_enabled[i] = 0; - dev_dbg(codec->dev, "%s: MCLK Rate = %x\n", __func__, control->mclk_rate); diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h index ee7e587b3f24..53c9a84b51ad 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.h +++ b/sound/soc/codecs/wcd9xxx-common-v2.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 @@ -34,7 +34,12 @@ #define WCD_CLSH_STATE_HPHL (0x01 << 1) #define WCD_CLSH_STATE_HPHR (0x01 << 2) #define WCD_CLSH_STATE_LO (0x01 << 3) -#define WCD_CLSH_STATE_MAX 4 + +/* + * Though number of CLSH states are 4, max state shoulbe be 5 + * because state array index starts from 1. + */ +#define WCD_CLSH_STATE_MAX 5 #define NUM_CLSH_STATES_V2 (0x01 << WCD_CLSH_STATE_MAX) diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index bab4da4758ac..6c1897340e74 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -610,6 +610,49 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { }, { .playback = { + .stream_name = "USBAUDIO_HOSTLESS Playback", + .aif_name = "USBAUDIO_DL_HL", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 | + SNDRV_PCM_RATE_384000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 384000, + }, + .capture = { + .stream_name = "USBAUDIO_HOSTLESS Capture", + .aif_name = "USBAUDIO_UL_HL", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 | + SNDRV_PCM_RATE_384000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 384000, + }, + .ops = &msm_fe_dai_ops, + .name = "USBAUDIO_HOSTLESS", + .probe = fe_dai_probe, + }, + { + .playback = { .stream_name = "AFE Playback", .aif_name = "PCM_RX", .rates = (SNDRV_PCM_RATE_8000 | diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 4af737680118..557c7946506a 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -3329,10 +3329,11 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) * TX14, TX15, TX16 */ unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148, - 149, 150, 151}; + 149, 150, 151}; unsigned int tx_ch_tavil[WCD934X_TX_MAX] = {128, 129, 130, 131, 132, - 134, 135, 136, 137, 138, 139, - 133, 140, 141, 142, 143}; + 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, + 143}; pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev)); @@ -4983,6 +4984,22 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .ignore_pmdown_time = 1, .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6, }, + { + .name = "USB Audio Hostless", + .stream_name = "USB Audio Hostless", + .cpu_dai_name = "USBAUDIO_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c index 9b76b4892eb1..75af648baef3 100644 --- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c +++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.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 @@ -119,6 +119,9 @@ size_t get_cal_info_size(int32_t cal_type) case AFE_SIDETONE_CAL_TYPE: size = sizeof(struct audio_cal_info_sidetone); break; + case AFE_SIDETONE_IIR_CAL_TYPE: + size = sizeof(struct audio_cal_info_sidetone_iir); + break; case LSM_CUST_TOPOLOGY_CAL_TYPE: size = 0; break; @@ -265,6 +268,9 @@ size_t get_user_cal_type_size(int32_t cal_type) case AFE_SIDETONE_CAL_TYPE: size = sizeof(struct audio_cal_type_sidetone); break; + case AFE_SIDETONE_IIR_CAL_TYPE: + size = sizeof(struct audio_cal_type_sidetone_iir); + break; case LSM_CUST_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_basic); break; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 9421d03f6a8d..2ba41ac1877f 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -754,7 +754,7 @@ static void populate_codec_list(struct msm_compr_audio *prtd) COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; prtd->compr_cap.max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; - prtd->compr_cap.num_codecs = 14; + prtd->compr_cap.num_codecs = 15; prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3; prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC; prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3; @@ -769,6 +769,7 @@ static void populate_codec_list(struct msm_compr_audio *prtd) prtd->compr_cap.codecs[11] = SND_AUDIOCODEC_APE; prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS; prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD; + prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX; } static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, @@ -788,6 +789,7 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, struct asm_alac_cfg alac_cfg; struct asm_ape_cfg ape_cfg; struct asm_dsd_cfg dsd_cfg; + struct aptx_dec_bt_addr_cfg aptx_cfg; union snd_codec_options *codec_options; int ret = 0; @@ -1022,6 +1024,24 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, pr_err("%s: CMD DSD Format block failed ret %d\n", __func__, ret); break; + case FORMAT_APTX: + pr_debug("SND_AUDIOCODEC_APTX\n"); + memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg)); + ret = q6asm_stream_media_format_block_aptx_dec( + prtd->audio_client, + prtd->sample_rate, + stream_id); + if (ret >= 0) { + aptx_cfg.nap = codec_options->aptx_dec.nap; + aptx_cfg.uap = codec_options->aptx_dec.uap; + aptx_cfg.lap = codec_options->aptx_dec.lap; + q6asm_set_aptx_dec_bt_addr(prtd->audio_client, + &aptx_cfg); + } else { + pr_err("%s: CMD Format block failed ret %d\n", + __func__, ret); + } + break; default: pr_debug("%s, unsupported format, skip", __func__); break; @@ -1245,8 +1265,13 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) pr_debug("%s: stream_id %d bits_per_sample %d\n", __func__, ac->stream_id, bits_per_sample); - ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, - bits_per_sample); + if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) { + ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, + bits_per_sample, true); + } else { + ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, + bits_per_sample, false); + } if (ret < 0) { pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret); return ret; @@ -1789,6 +1814,12 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream, break; } + case SND_AUDIOCODEC_APTX: { + pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__); + prtd->codec = FORMAT_APTX; + break; + } + default: pr_err("codec not supported, id =%d\n", params->codec.id); return -EINVAL; @@ -2659,6 +2690,7 @@ static int msm_compr_get_codec_caps(struct snd_compr_stream *cstream, case SND_AUDIOCODEC_DTS: break; case SND_AUDIOCODEC_DSD: + case SND_AUDIOCODEC_APTX: break; default: pr_err("%s: Unsupported audio codec %d\n", @@ -3071,6 +3103,7 @@ static int msm_compr_send_dec_params(struct snd_compr_stream *cstream, switch (prtd->codec) { case FORMAT_MP3: case FORMAT_MPEG4_AAC: + case FORMAT_APTX: pr_debug("%s: no runtime parameters for codec: %d\n", __func__, prtd->codec); break; @@ -3137,6 +3170,7 @@ static int msm_compr_dec_params_put(struct snd_kcontrol *kcontrol, case FORMAT_APE: case FORMAT_DTS: case FORMAT_DSD: + case FORMAT_APTX: pr_debug("%s: no runtime parameters for codec: %d\n", __func__, prtd->codec); break; diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c index df32ede49ed0..8da75d74776b 100644 --- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c @@ -681,7 +681,7 @@ int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int rc = 0, port_id, copp_idx; - uint32_t idx, j; + uint32_t idx, j, current_offset; uint32_t device = ucontrol->value.integer.value[0]; uint32_t param_id = ucontrol->value.integer.value[1]; uint32_t offset = ucontrol->value.integer.value[2]; @@ -758,6 +758,19 @@ int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol, default: { /* cache the parameters */ dolby_dap_params_modified[idx] += 1; + current_offset = dolby_dap_params_offset[idx] + offset; + if (current_offset >= TOTAL_LENGTH_DOLBY_PARAM) { + pr_err("%s: invalid offset %d at idx %d\n", + __func__, offset, idx); + return -EINVAL; + } + if ((length == 0) || (current_offset + length - 1 + < current_offset) || (current_offset + length + > TOTAL_LENGTH_DOLBY_PARAM)) { + pr_err("%s: invalid length %d at idx %d\n", + __func__, length, idx); + return -EINVAL; + } dolby_dap_params_length[idx] = length; pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n", __func__, device, param_id, offset, length); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 920e7324f14a..9b672d803d31 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.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 @@ -423,7 +423,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) prtd->audio_client->perf_mode); ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, - bits_per_sample); + bits_per_sample, false); if (ret < 0) { pr_err("%s: q6asm_open_read failed\n", __func__); q6asm_audio_client_free(prtd->audio_client); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 485ffa06f5bd..a62420a23789 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -69,6 +69,7 @@ static int sec_mi2s_switch_enable; static int tert_mi2s_switch_enable; static int quat_mi2s_switch_enable; static int fm_pcmrx_switch_enable; +static int usb_switch_enable; static int lsm_mux_slim_port; static int slim0_rx_aanc_fb_port; static int msm_route_ec_ref_rx; @@ -721,8 +722,7 @@ static struct cal_block_data *msm_routing_find_topology_by_path(int path) static struct cal_block_data *msm_routing_find_topology(int path, int app_type, - int acdb_id, - int sample_rate) + int acdb_id) { struct list_head *ptr, *next; struct cal_block_data *cal_block = NULL; @@ -739,13 +739,12 @@ static struct cal_block_data *msm_routing_find_topology(int path, cal_block->cal_info; if ((cal_info->path == path) && (cal_info->app_type == app_type) && - (cal_info->acdb_id == acdb_id) && - (cal_info->sample_rate == sample_rate)) { + (cal_info->acdb_id == acdb_id)) { return cal_block; } } - pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d sample_rate %d defaulting to search by path\n", - __func__, path, app_type, acdb_id, sample_rate); + pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d defaulting to search by path\n", + __func__, path, app_type, acdb_id); return msm_routing_find_topology_by_path(path); } @@ -754,7 +753,7 @@ static int msm_routing_get_adm_topology(int path, int fedai_id, { int topology = NULL_COPP_TOPOLOGY; struct cal_block_data *cal_block = NULL; - int app_type = 0, acdb_dev_id = 0, sample_rate = 0; + int app_type = 0, acdb_dev_id = 0; pr_debug("%s\n", __func__); path = get_cal_path(path); @@ -765,10 +764,8 @@ static int msm_routing_get_adm_topology(int path, int fedai_id, app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type; acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id; - sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate; - cal_block = msm_routing_find_topology(path, app_type, - acdb_dev_id, sample_rate); + cal_block = msm_routing_find_topology(path, app_type, acdb_dev_id); if (cal_block == NULL) goto unlock; @@ -1695,6 +1692,35 @@ static int msm_routing_put_hfp_switch_mixer(struct snd_kcontrol *kcontrol, return 1; } +static int msm_routing_get_usb_switch_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = usb_switch_enable; + pr_debug("%s: HFP Switch enable %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_routing_put_usb_switch_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_dapm_update *update = NULL; + + pr_debug("%s: USB Switch enable %ld\n", __func__, + ucontrol->value.integer.value[0]); + if (ucontrol->value.integer.value[0]) + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, + 1, update); + else + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, + 0, update); + usb_switch_enable = ucontrol->value.integer.value[0]; + return 1; +} + static int msm_routing_get_pri_mi2s_switch_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -4871,6 +4897,12 @@ static const struct snd_kcontrol_new mmul2_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), @@ -7024,6 +7056,12 @@ static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = { msm_routing_put_port_mixer), }; +static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = { + SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_RX, + MSM_BACKEND_DAI_USB_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), +}; + static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, @@ -7693,6 +7731,11 @@ static const struct snd_kcontrol_new hfp_slim7_switch_mixer_controls = 0, 1, 0, msm_routing_get_hfp_switch_mixer, msm_routing_put_hfp_switch_mixer); +static const struct snd_kcontrol_new usb_switch_mixer_controls = + SOC_SINGLE_EXT("Switch", SND_SOC_NOPM, + 0, 1, 0, msm_routing_get_usb_switch_mixer, + msm_routing_put_usb_switch_mixer); + static const struct soc_enum lsm_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text); @@ -7806,7 +7849,8 @@ static int msm_routing_put_stereo_to_custom_stereo_control( continue; if ((port_id != SLIMBUS_0_RX) && (port_id != RT_PROXY_PORT_001_RX) && - (port_id != AFE_PORT_ID_PRIMARY_MI2S_RX)) + (port_id != AFE_PORT_ID_PRIMARY_MI2S_RX) && + (port_id != AFE_PORT_ID_INT4_MI2S_RX)) continue; for_each_set_bit(i, &msm_bedais[be_index].fe_sessions, @@ -8628,6 +8672,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("USBAUDIO_DL_HL", "USBAUDIO_HOSTLESS Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("USBAUDIO_UL_HL", "USBAUDIO_HOSTLESS Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback", @@ -9173,6 +9221,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &hfp_int_switch_mixer_controls), SND_SOC_DAPM_SWITCH("HFP_SLIM7_UL_HL", SND_SOC_NOPM, 0, 0, &hfp_slim7_switch_mixer_controls), + SND_SOC_DAPM_SWITCH("USB_DL_HL", SND_SOC_NOPM, 0, 0, + &usb_switch_mixer_controls), /* Mux Definitions */ SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux), @@ -9538,6 +9588,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("USB_AUDIO_RX_Voice Mixer", SND_SOC_NOPM, 0, 0, usb_audio_rx_voice_mixer_controls, ARRAY_SIZE(usb_audio_rx_voice_mixer_controls)), + SND_SOC_DAPM_MIXER("USB_AUDIO_RX Port Mixer", + SND_SOC_NOPM, 0, 0, usb_rx_port_mixer_controls, + ARRAY_SIZE(usb_rx_port_mixer_controls)), /* Virtual Pins to force backends ON atm */ SND_SOC_DAPM_OUTPUT("BE_OUT"), SND_SOC_DAPM_INPUT("BE_IN"), @@ -10246,6 +10299,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"}, + {"MultiMedia2 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"}, {"MultiMedia2 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -11327,6 +11382,12 @@ static const struct snd_soc_dapm_route intercon[] = { {"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"AFE_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"}, {"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"}, + {"USB_AUDIO_RX Port Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, + {"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Port Mixer"}, + {"USB_DL_HL", "Switch", "USBAUDIO_DL_HL"}, + {"USB_AUDIO_RX", NULL, "USB_DL_HL"}, + {"USBAUDIO_UL_HL", NULL, "USB_AUDIO_TX"}, + {"AUX_PCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, @@ -12050,6 +12111,33 @@ static const struct snd_kcontrol_new device_pp_params_mixer_controls[] = { msm_routing_put_device_pp_params_mixer), }; +static int msm_aptx_dec_license_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = + core_get_license_status(ASM_MEDIA_FMT_APTX); + pr_debug("%s: status %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_aptx_dec_license_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int32_t status = 0; + + status = core_set_license(ucontrol->value.integer.value[0], + APTX_CLASSIC_DEC_LICENSE_ID); + pr_debug("%s: status %d\n", __func__, status); + return status; +} + +static const struct snd_kcontrol_new aptx_dec_license_controls[] = { + SOC_SINGLE_EXT("APTX Dec License", SND_SOC_NOPM, 0, + 0xFFFF, 0, msm_aptx_dec_license_control_get, + msm_aptx_dec_license_control_put), +}; + static struct snd_pcm_ops msm_routing_pcm_ops = { .hw_params = msm_pcm_routing_hw_params, .close = msm_pcm_routing_close, @@ -12102,6 +12190,9 @@ static int msm_routing_probe(struct snd_soc_platform *platform) ARRAY_SIZE(msm_source_tracking_controls)); snd_soc_add_platform_controls(platform, adm_channel_config_controls, ARRAY_SIZE(adm_channel_config_controls)); + + snd_soc_add_platform_controls(platform, aptx_dec_license_controls, + ARRAY_SIZE(aptx_dec_license_controls)); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c index 286fff1eb4a8..f3ec45b8f9b1 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 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 @@ -390,6 +390,33 @@ static int msm_pcm_ioctl(struct snd_pcm_substream *substream, return ret; } +static int msm_voice_sidetone_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + bool sidetone_enable = ucontrol->value.integer.value[0]; + uint32_t session_id = ALL_SESSION_VSID; + + if (sidetone_enable < 0) { + pr_err("%s: Invalid arguments sidetone enable %d\n", + __func__, sidetone_enable); + ret = -EINVAL; + return ret; + } + ret = voc_set_afe_sidetone(session_id, sidetone_enable); + pr_debug("%s: AFE Sidetone enable=%d session_id=0x%x ret=%d\n", + __func__, sidetone_enable, session_id, ret); + return ret; +} + +static int msm_voice_sidetone_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + ucontrol->value.integer.value[0] = voc_get_afe_sidetone(); + return 0; +} + static int msm_voice_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -632,6 +659,9 @@ static struct snd_kcontrol_new msm_voice_controls[] = { .info = msm_voice_cvd_version_info, .get = msm_voice_cvd_version_get, }, + SOC_SINGLE_MULTI_EXT("Voice Sidetone Enable", SND_SOC_NOPM, 0, 1, 0, 1, + msm_voice_sidetone_get, msm_voice_sidetone_put), + }; static struct snd_pcm_ops msm_pcm_ops = { diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index 4ceaa452f14b..f1607b8e5d66 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -36,6 +36,7 @@ enum { AFE_FB_SPKR_PROT_CAL, AFE_HW_DELAY_CAL, AFE_SIDETONE_CAL, + AFE_SIDETONE_IIR_CAL, AFE_TOPOLOGY_CAL, AFE_CUST_TOPOLOGY_CAL, AFE_FB_SPKR_PROT_TH_VI_CAL, @@ -4849,58 +4850,249 @@ fail_cmd: return ret; } -int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain) +static int afe_sidetone_iir(u16 tx_port_id) { - struct afe_loopback_cfg_v1 cmd_sidetone; - int ret = 0; + struct afe_loopback_iir_cfg_v2 iir_sidetone; + int ret; int index = 0; + uint16_t size = 0; + int cal_index = AFE_SIDETONE_IIR_CAL; + int iir_pregain = 0; + int iir_num_biquad_stages = 0; + int iir_enable; + struct cal_block_data *cal_block; + int mid; + + memset(&iir_sidetone, 0, sizeof(iir_sidetone)); + index = q6audio_get_port_index(tx_port_id); + iir_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + iir_sidetone.hdr.pkt_size = sizeof(iir_sidetone); + iir_sidetone.hdr.src_port = 0; + iir_sidetone.hdr.dest_port = 0; + iir_sidetone.hdr.token = index; + iir_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + iir_sidetone.param.port_id = tx_port_id; + iir_sidetone.param.payload_address_lsw = 0x00; + iir_sidetone.param.payload_address_msw = 0x00; + iir_sidetone.param.mem_map_handle = 0x00; - pr_info("%s: tx_port_id: 0x%x rx_port_id: 0x%x enable:%d gain:%d\n", - __func__, tx_port_id, rx_port_id, enable, gain); - index = q6audio_get_port_index(rx_port_id); - if (index < 0 || index > AFE_MAX_PORTS) { - pr_err("%s: AFE port index[%d] invalid!\n", - __func__, index); - return -EINVAL; + if (this_afe.cal_data[cal_index] == NULL) { + pr_err("%s: cal data is NULL\n", __func__); + ret = -EINVAL; + goto done; } - ret = q6audio_validate_port(rx_port_id); - if (ret < 0) { - pr_err("%s: Invalid port 0x%x %d", __func__, rx_port_id, ret); - return -EINVAL; + mutex_lock(&this_afe.cal_data[cal_index]->lock); + cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]); + if (cal_block == NULL) { + pr_err("%s: cal_block not found\n ", __func__); + mutex_unlock(&this_afe.cal_data[cal_index]->lock); + ret = -EINVAL; + goto done; } + iir_pregain = ((struct audio_cal_info_sidetone_iir *) + cal_block->cal_info)->pregain; + iir_enable = ((struct audio_cal_info_sidetone_iir *) + cal_block->cal_info)->iir_enable; + iir_num_biquad_stages = ((struct audio_cal_info_sidetone_iir *) + cal_block->cal_info)->num_biquad_stages; + mid = ((struct audio_cal_info_sidetone_iir *) + cal_block->cal_info)->mid; + + /* + * calculate the actual size of payload based on no of stages + * enabled in calibration + */ + size = (MAX_SIDETONE_IIR_DATA_SIZE / MAX_NO_IIR_FILTER_STAGE) * + iir_num_biquad_stages; + /* + * For an odd number of stages, 2 bytes of padding are + * required at the end of the payload. + */ + if (iir_num_biquad_stages % 2) { + pr_debug("%s: adding 2 to size:%d\n", __func__, size); + size = size + 2; + } + memcpy(&iir_sidetone.st_iir_filter_config_data.iir_config, + &((struct audio_cal_info_sidetone_iir *) + cal_block->cal_info)->iir_config, + sizeof(iir_sidetone.st_iir_filter_config_data.iir_config)); + mutex_unlock(&this_afe.cal_data[cal_index]->lock); + + /* + * Calculate the payload size for setparams command + */ + iir_sidetone.param.payload_size = (sizeof(iir_sidetone) - + sizeof(struct apr_hdr) - + sizeof(struct afe_port_cmd_set_param_v2) - + (MAX_SIDETONE_IIR_DATA_SIZE - size)); + + pr_debug("%s: payload size :%d\n", __func__, + iir_sidetone.param.payload_size); + + /* + * Set IIR enable params + */ + iir_sidetone.st_iir_enable_pdata.module_id = mid; + iir_sidetone.st_iir_enable_pdata.param_id = + AFE_PARAM_ID_ENABLE; + iir_sidetone.st_iir_enable_pdata.param_size = + sizeof(iir_sidetone.st_iir_mode_enable_data); + iir_sidetone.st_iir_mode_enable_data.enable = iir_enable; + + /* + * Set IIR filter config params + */ + iir_sidetone.st_iir_filter_config_pdata.module_id = mid; + iir_sidetone.st_iir_filter_config_pdata.param_id = + AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG; + iir_sidetone.st_iir_filter_config_pdata.param_size = + sizeof(iir_sidetone.st_iir_filter_config_data.num_biquad_stages) + + + sizeof(iir_sidetone.st_iir_filter_config_data.pregain) + size; + iir_sidetone.st_iir_filter_config_pdata.reserved = 0; + iir_sidetone.st_iir_filter_config_data.num_biquad_stages = + iir_num_biquad_stages; + iir_sidetone.st_iir_filter_config_data.pregain = iir_pregain; + pr_debug("%s: tx(0x%x)mid(0x%x)iir_en(%d)stg(%d)gain(0x%x)size(%d)\n", + __func__, tx_port_id, mid, + iir_sidetone.st_iir_mode_enable_data.enable, + iir_sidetone.st_iir_filter_config_data.num_biquad_stages, + iir_sidetone.st_iir_filter_config_data.pregain, + iir_sidetone.st_iir_filter_config_pdata.param_size); + ret = afe_apr_send_pkt(&iir_sidetone, &this_afe.wait[index]); + if (ret) + pr_err("%s: AFE sidetone failed for tx_port(0x%x)\n", + __func__, tx_port_id); + +done: + return ret; + +} + +static int afe_sidetone(u16 tx_port_id, u16 rx_port_id, bool enable) +{ + struct afe_st_loopback_cfg_v1 cmd_sidetone; + int ret; + int index; + int cal_index = AFE_SIDETONE_CAL; + int sidetone_gain; + int sidetone_enable; + struct cal_block_data *cal_block; + int mid = 0; + + memset(&cmd_sidetone, 0, sizeof(cmd_sidetone)); + if (this_afe.cal_data[cal_index] == NULL) { + pr_err("%s: cal data is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + mutex_lock(&this_afe.cal_data[cal_index]->lock); + cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]); + if (cal_block == NULL) { + pr_err("%s: cal_block not found\n", __func__); + mutex_unlock(&this_afe.cal_data[cal_index]->lock); + ret = -EINVAL; + goto done; + } + sidetone_gain = ((struct audio_cal_info_sidetone *) + cal_block->cal_info)->gain; + sidetone_enable = ((struct audio_cal_info_sidetone *) + cal_block->cal_info)->enable; + mid = ((struct audio_cal_info_sidetone *) + cal_block->cal_info)->mid; + mutex_unlock(&this_afe.cal_data[cal_index]->lock); + + index = q6audio_get_port_index(tx_port_id); cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone); cmd_sidetone.hdr.src_port = 0; cmd_sidetone.hdr.dest_port = 0; - cmd_sidetone.hdr.token = 0; + cmd_sidetone.hdr.token = index; cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; - /* should it be rx or tx port id ?? , bharath*/ cmd_sidetone.param.port_id = tx_port_id; - /* size of data param & payload */ cmd_sidetone.param.payload_size = (sizeof(cmd_sidetone) - sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2)); cmd_sidetone.param.payload_address_lsw = 0x00; cmd_sidetone.param.payload_address_msw = 0x00; cmd_sidetone.param.mem_map_handle = 0x00; - cmd_sidetone.pdata.module_id = AFE_MODULE_LOOPBACK; - cmd_sidetone.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG; - /* size of actual payload only */ - cmd_sidetone.pdata.param_size = cmd_sidetone.param.payload_size - - sizeof(struct afe_port_param_data_v2); + cmd_sidetone.gain_pdata.module_id = AFE_MODULE_LOOPBACK; + cmd_sidetone.gain_pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH; + /* + * size of actual payload only + */ + cmd_sidetone.gain_pdata.param_size = sizeof( + struct afe_loopback_sidetone_gain); + cmd_sidetone.gain_data.rx_port_id = rx_port_id; + cmd_sidetone.gain_data.gain = sidetone_gain; - cmd_sidetone.loopback_cfg_minor_version = + cmd_sidetone.cfg_pdata.module_id = AFE_MODULE_LOOPBACK; + cmd_sidetone.cfg_pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG; + /* + * size of actual payload only + */ + cmd_sidetone.cfg_pdata.param_size = sizeof(struct loopback_cfg_data); + cmd_sidetone.cfg_data.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG; - cmd_sidetone.dst_port_id = rx_port_id; - cmd_sidetone.routing_mode = LB_MODE_SIDETONE; - cmd_sidetone.enable = enable; + cmd_sidetone.cfg_data.dst_port_id = rx_port_id; + cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE; + cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0); + + pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n", + __func__, rx_port_id, tx_port_id, + enable, mid, sidetone_gain, sidetone_enable); ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]); if (ret) - pr_err("%s: sidetone failed tx_port:0x%x rx_port:0x%x ret%d\n", - __func__, tx_port_id, rx_port_id, ret); + pr_err("%s: AFE sidetone send failed for tx_port:%d rx_port:%d ret:%d\n", + __func__, tx_port_id, rx_port_id, ret); +done: + return ret; +} + +int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable) +{ + int ret; + int index; + + index = q6audio_get_port_index(rx_port_id); + if (index < 0 || index > AFE_MAX_PORTS) { + pr_err("%s: AFE port index[%d] invalid!\n", + __func__, index); + ret = -EINVAL; + goto done; + } + if (q6audio_validate_port(rx_port_id) < 0) { + pr_err("%s: Invalid port 0x%x\n", + __func__, rx_port_id); + ret = -EINVAL; + goto done; + } + index = q6audio_get_port_index(tx_port_id); + if (index < 0 || index > AFE_MAX_PORTS) { + pr_err("%s: AFE port index[%d] invalid!\n", + __func__, index); + ret = -EINVAL; + goto done; + } + if (q6audio_validate_port(tx_port_id) < 0) { + pr_err("%s: Invalid port 0x%x\n", + __func__, tx_port_id); + ret = -EINVAL; + goto done; + } + if (enable) { + ret = afe_sidetone_iir(tx_port_id); + if (ret) + goto done; + } + + ret = afe_sidetone(tx_port_id, rx_port_id, enable); + +done: return ret; } @@ -5033,6 +5225,20 @@ int afe_validate_port(u16 port_id) case AFE_PORT_ID_QUATERNARY_TDM_TX_6: case AFE_PORT_ID_QUATERNARY_TDM_RX_7: case AFE_PORT_ID_QUATERNARY_TDM_TX_7: + case AFE_PORT_ID_INT0_MI2S_RX: + case AFE_PORT_ID_INT1_MI2S_RX: + case AFE_PORT_ID_INT2_MI2S_RX: + case AFE_PORT_ID_INT3_MI2S_RX: + case AFE_PORT_ID_INT4_MI2S_RX: + case AFE_PORT_ID_INT5_MI2S_RX: + case AFE_PORT_ID_INT6_MI2S_RX: + case AFE_PORT_ID_INT0_MI2S_TX: + case AFE_PORT_ID_INT1_MI2S_TX: + case AFE_PORT_ID_INT2_MI2S_TX: + case AFE_PORT_ID_INT3_MI2S_TX: + case AFE_PORT_ID_INT4_MI2S_TX: + case AFE_PORT_ID_INT5_MI2S_TX: + case AFE_PORT_ID_INT6_MI2S_TX: { ret = 0; break; @@ -6007,6 +6213,9 @@ static int get_cal_type_index(int32_t cal_type) case AFE_SIDETONE_CAL_TYPE: ret = AFE_SIDETONE_CAL; break; + case AFE_SIDETONE_IIR_CAL_TYPE: + ret = AFE_SIDETONE_IIR_CAL; + break; case AFE_TOPOLOGY_CAL_TYPE: ret = AFE_TOPOLOGY_CAL; break; @@ -6532,6 +6741,11 @@ static int afe_init_cal_data(void) afe_set_cal, NULL, NULL} }, {NULL, NULL, cal_utils_match_buf_num} }, + {{AFE_SIDETONE_IIR_CAL_TYPE, + {NULL, NULL, NULL, + afe_set_cal, NULL, NULL} }, + {NULL, NULL, cal_utils_match_buf_num} }, + {{AFE_TOPOLOGY_CAL_TYPE, {NULL, NULL, NULL, afe_set_cal, NULL, NULL} }, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index cfaa562fdaba..9353b2132e15 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -2442,13 +2442,14 @@ EXPORT_SYMBOL(q6asm_open_read_v3); * @ac: Client session handle * @format: encoder format * @bits_per_sample: bit width of capture session + * @ts_mode: timestamp mode */ int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample) + uint16_t bits_per_sample, bool ts_mode) { return __q6asm_open_read(ac, format, bits_per_sample, PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/, - true/*ts_mode*/); + ts_mode); } EXPORT_SYMBOL(q6asm_open_read_v4); @@ -2661,6 +2662,9 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, case FORMAT_DSD: open.dec_fmt_id = ASM_MEDIA_FMT_DSD; break; + case FORMAT_APTX: + open.dec_fmt_id = ASM_MEDIA_FMT_APTX; + break; default: pr_err("%s: Invalid format 0x%x\n", __func__, format); rc = -EINVAL; @@ -5773,6 +5777,57 @@ done: } EXPORT_SYMBOL(q6asm_media_format_block_dsd); +int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac, + uint32_t srate, int stream_id) +{ + struct asm_aptx_dec_fmt_blk_v2 aptx_fmt; + int rc = 0; + + if (!ac->session) { + pr_err("%s: ac session invalid\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n", + __func__, ac->session, srate, stream_id); + + q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE, + stream_id); + atomic_set(&ac->cmd_state, -1); + + aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) - + sizeof(aptx_fmt.fmtblk); + + aptx_fmt.sample_rate = srate; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt); + if (rc < 0) { + pr_err("%s :Comamnd media format update failed %d\n", + __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + rc = 0; +fail_cmd: + return rc; +} + static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id, int param_value, int stream_id) { @@ -6802,6 +6857,69 @@ int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance) return __q6asm_set_volume(ac, volume, instance); } +int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac, + struct aptx_dec_bt_addr_cfg *cfg) +{ + struct aptx_dec_bt_dev_addr paylod; + int sz = 0; + int rc = 0; + + pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap, + cfg->uap, cfg->lap); + + if (ac == NULL) { + pr_err("%s: AC handle NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + if (ac->apr == NULL) { + pr_err("%s: AC APR handle NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + + sz = sizeof(struct aptx_dec_bt_dev_addr); + q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS; + paylod.encdec.param_size = sz - sizeof(paylod.hdr) + - sizeof(paylod.encdec); + paylod.bt_addr_cfg.lap = cfg->lap; + paylod.bt_addr_cfg.uap = cfg->uap; + paylod.bt_addr_cfg.nap = cfg->nap; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod); + if (rc < 0) { + pr_err("%s: set-params send failed paramid[0x%x] rc %d\n", + __func__, paylod.encdec.param_id, rc); + rc = -EINVAL; + goto fail_cmd; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__, + paylod.encdec.param_id); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state)), + paylod.encdec.param_id); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + pr_debug("%s: set BT addr is success\n", __func__); + rc = 0; +fail_cmd: + return rc; +} + int q6asm_set_softpause(struct audio_client *ac, struct asm_softpause_params *pause_param) { diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c index 5cff3dd1ed4f..e7619c0ca0dd 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.c +++ b/sound/soc/msm/qdsp6v2/q6voice.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 @@ -5847,6 +5847,48 @@ int voc_set_hd_enable(uint32_t session_id, uint32_t enable) return ret; } +int voc_set_afe_sidetone(uint32_t session_id, bool sidetone_enable) +{ + struct voice_data *v = NULL; + int ret = -EINVAL; + struct voice_session_itr itr; + u16 rx_port, tx_port; + + common.sidetone_enable = sidetone_enable; + voice_itr_init(&itr, session_id); + while (voice_itr_get_next_session(&itr, &v)) { + if (v == NULL) { + pr_err("%s: invalid session_id 0x%x\n", __func__, + session_id); + ret = -EINVAL; + break; + } + mutex_lock(&v->lock); + if (v->voc_state != VOC_RUN) { + mutex_unlock(&v->lock); + continue; + } + rx_port = v->dev_rx.port_id; + tx_port = v->dev_tx.port_id; + ret = afe_sidetone_enable(tx_port, rx_port, + sidetone_enable); + if (!ret) { + mutex_unlock(&v->lock); + break; + } + mutex_unlock(&v->lock); + } + return ret; +} + +bool voc_get_afe_sidetone(void) +{ + bool ret; + + ret = common.sidetone_enable; + return ret; +} + int voc_get_pp_enable(uint32_t session_id, uint32_t module_id) { struct voice_data *v = voice_get_session(session_id); @@ -8559,6 +8601,9 @@ static int __init voice_init(void) memset(&common.ec_media_fmt_info.channel_mapping, 0, VSS_CHANNEL_MAPPING_SIZE); + /* Initialize AFE Sidetone Enable */ + common.sidetone_enable = false; + /* Initialize MVS info. */ common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT; diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h index 9c3ec62a980d..f7ea650dfda9 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.h +++ b/sound/soc/msm/qdsp6v2/q6voice.h @@ -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 @@ -1766,6 +1766,7 @@ struct common_data { struct vss_isoundfocus_rsp_get_sectors_t soundFocusResponse; struct shared_mem_info source_tracking_sh_mem; struct vss_isourcetrack_activity_data_t sourceTrackingResponse; + bool sidetone_enable; }; struct voice_session_itr { @@ -1899,4 +1900,6 @@ uint32_t voice_get_topology(uint32_t topology_idx); int voc_set_sound_focus(struct sound_focus_param sound_focus_param); int voc_get_sound_focus(struct sound_focus_param *soundFocusData); int voc_get_source_tracking(struct source_tracking_param *sourceTrackingData); +int voc_set_afe_sidetone(uint32_t session_id, bool sidetone_enable); +bool voc_get_afe_sidetone(void); #endif diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c index 63d8598d0b92..58eb30c39764 100644 --- a/sound/soc/msm/sdm660-common.c +++ b/sound/soc/msm/sdm660-common.c @@ -2909,7 +2909,7 @@ err: } devm_kfree(&pdev->dev, pdata); if (pdata->snd_card_val != INT_SND_CARD) - msm_ext_cdc_deinit(); + msm_ext_cdc_deinit(pdata); return ret; } @@ -2921,7 +2921,7 @@ static int msm_asoc_machine_remove(struct platform_device *pdev) if (pdata->snd_card_val == INT_SND_CARD) mutex_destroy(&pdata->cdc_int_mclk0_mutex); else - msm_ext_cdc_deinit(); + msm_ext_cdc_deinit(pdata); msm_free_auxdev_mem(pdev); gpio_free(pdata->us_euro_gpio); diff --git a/sound/soc/msm/sdm660-common.h b/sound/soc/msm/sdm660-common.h index 36c2d9b7ca4e..5742c8545b86 100644 --- a/sound/soc/msm/sdm660-common.h +++ b/sound/soc/msm/sdm660-common.h @@ -78,6 +78,14 @@ enum { EXT_SND_CARD_TAVIL, }; +struct msm_snd_interrupt { + void __iomem *mpm_wakeup; + void __iomem *intr1_cfg_apps; + void __iomem *lpi_gpio_intr_cfg; + void __iomem *lpi_gpio_cfg; + void __iomem *lpi_gpio_inout; +}; + struct msm_asoc_mach_data { int us_euro_gpio; /* used by gpio driver API */ int hph_en1_gpio; @@ -105,6 +113,7 @@ struct msm_asoc_mach_data { struct mutex cdc_int_mclk0_mutex; struct delayed_work disable_int_mclk0_work; struct afe_clk_set digital_cdc_core_clk; + struct msm_snd_interrupt msm_snd_intr_lpi; }; int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c index c900ce1a0fe9..0460d7f9fc68 100644 --- a/sound/soc/msm/sdm660-external.c +++ b/sound/soc/msm/sdm660-external.c @@ -67,16 +67,6 @@ struct msm_asoc_wcd93xx_codec { static struct msm_asoc_wcd93xx_codec msm_codec_fn; static struct platform_device *spdev; -struct msm_snd_interrupt { - void __iomem *mpm_wakeup; - void __iomem *intr1_cfg_apps; - void __iomem *lpi_gpio_intr_cfg; - void __iomem *lpi_gpio_cfg; - void __iomem *lpi_gpio_inout; -}; - -static struct msm_snd_interrupt msm_snd_intr_lpi; - static bool is_initial_boot; static void *def_ext_mbhc_cal(void); @@ -1220,25 +1210,25 @@ static void msm_afe_clear_config(void) afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG); } -static void msm_snd_interrupt_config(void) +static void msm_snd_interrupt_config(struct msm_asoc_mach_data *pdata) { int val; - val = ioread32(msm_snd_intr_lpi.mpm_wakeup); + val = ioread32(pdata->msm_snd_intr_lpi.mpm_wakeup); val |= LPI_GPIO_22_WAKEUP_VAL; - iowrite32(val, msm_snd_intr_lpi.mpm_wakeup); + iowrite32(val, pdata->msm_snd_intr_lpi.mpm_wakeup); - val = ioread32(msm_snd_intr_lpi.intr1_cfg_apps); + val = ioread32(pdata->msm_snd_intr_lpi.intr1_cfg_apps); val &= ~(LPI_GPIO_22_INTR1_CFG_MASK); val |= LPI_GPIO_22_INTR1_CFG_VAL; - iowrite32(val, msm_snd_intr_lpi.intr1_cfg_apps); + iowrite32(val, pdata->msm_snd_intr_lpi.intr1_cfg_apps); iowrite32(LPI_GPIO_INTR_CFG1_VAL, - msm_snd_intr_lpi.lpi_gpio_intr_cfg); + pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg); iowrite32(LPI_GPIO22_CFG_VAL, - msm_snd_intr_lpi.lpi_gpio_cfg); + pdata->msm_snd_intr_lpi.lpi_gpio_cfg); iowrite32(LPI_GPIO22_INOUT_VAL, - msm_snd_intr_lpi.lpi_gpio_inout); + pdata->msm_snd_intr_lpi.lpi_gpio_inout); } static int msm_adsp_power_up_config(struct snd_soc_codec *codec) @@ -1246,7 +1236,10 @@ static int msm_adsp_power_up_config(struct snd_soc_codec *codec) int ret = 0; unsigned long timeout; int adsp_ready = 0; + struct snd_soc_card *card = codec->component.card; + struct msm_asoc_mach_data *pdata; + pdata = snd_soc_card_get_drvdata(card); timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); @@ -1269,7 +1262,7 @@ static int msm_adsp_power_up_config(struct snd_soc_codec *codec) ret = -ETIMEDOUT; goto err_fail; } - msm_snd_interrupt_config(); + msm_snd_interrupt_config(pdata); ret = msm_afe_set_config(codec); if (ret) @@ -1817,15 +1810,15 @@ int msm_ext_cdc_init(struct platform_device *pdev, ret); ret = 0; } - msm_snd_intr_lpi.mpm_wakeup = + pdata->msm_snd_intr_lpi.mpm_wakeup = ioremap(TLMM_CENTER_MPM_WAKEUP_INT_EN_0, 4); - msm_snd_intr_lpi.intr1_cfg_apps = + pdata->msm_snd_intr_lpi.intr1_cfg_apps = ioremap(TLMM_LPI_DIR_CONN_INTR1_CFG_APPS, 4); - msm_snd_intr_lpi.lpi_gpio_intr_cfg = + pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg = ioremap(TLMM_LPI_GPIO_INTR_CFG1, 4); - msm_snd_intr_lpi.lpi_gpio_cfg = + pdata->msm_snd_intr_lpi.lpi_gpio_cfg = ioremap(TLMM_LPI_GPIO22_CFG, 4); - msm_snd_intr_lpi.lpi_gpio_inout = + pdata->msm_snd_intr_lpi.lpi_gpio_inout = ioremap(TLMM_LPI_GPIO22_INOUT, 4); err: return ret; @@ -1835,17 +1828,18 @@ EXPORT_SYMBOL(msm_ext_cdc_init); /** * msm_ext_cdc_deinit - external codec machine specific deinit. */ -void msm_ext_cdc_deinit(void) +void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata) { - if (msm_snd_intr_lpi.mpm_wakeup) - iounmap(msm_snd_intr_lpi.mpm_wakeup); - if (msm_snd_intr_lpi.intr1_cfg_apps) - iounmap(msm_snd_intr_lpi.intr1_cfg_apps); - if (msm_snd_intr_lpi.lpi_gpio_intr_cfg) - iounmap(msm_snd_intr_lpi.lpi_gpio_intr_cfg); - if (msm_snd_intr_lpi.lpi_gpio_cfg) - iounmap(msm_snd_intr_lpi.lpi_gpio_cfg); - if (msm_snd_intr_lpi.lpi_gpio_inout) - iounmap(msm_snd_intr_lpi.lpi_gpio_inout); + if (pdata->msm_snd_intr_lpi.mpm_wakeup) + iounmap(pdata->msm_snd_intr_lpi.mpm_wakeup); + if (pdata->msm_snd_intr_lpi.intr1_cfg_apps) + iounmap(pdata->msm_snd_intr_lpi.intr1_cfg_apps); + if (pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg) + iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg); + if (pdata->msm_snd_intr_lpi.lpi_gpio_cfg) + iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_cfg); + if (pdata->msm_snd_intr_lpi.lpi_gpio_inout) + iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_inout); + } EXPORT_SYMBOL(msm_ext_cdc_deinit); diff --git a/sound/soc/msm/sdm660-external.h b/sound/soc/msm/sdm660-external.h index 7625a24e8fae..acf5735c2502 100644 --- a/sound/soc/msm/sdm660-external.h +++ b/sound/soc/msm/sdm660-external.h @@ -34,7 +34,7 @@ int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *, struct snd_soc_card **, struct wcd_mbhc_config *); void msm_ext_register_audio_notifier(struct platform_device *pdev); -void msm_ext_cdc_deinit(void); +void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata); #else inline int msm_ext_cdc_init(struct platform_device *pdev, struct msm_asoc_mach_data *pdata, diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index 4ca579694a05..c002399beb6b 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -730,6 +730,12 @@ static int msm_int_enable_dig_cdc_clk(struct snd_soc_codec *codec, mutex_lock(&pdata->cdc_int_mclk0_mutex); if (atomic_read(&pdata->int_mclk0_enabled) == false || int_mclk0_freq_chg) { + if (atomic_read(&pdata->int_mclk0_enabled)) { + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2( + AFE_PORT_ID_INT0_MI2S_RX, + &pdata->digital_cdc_core_clk); + } pdata->digital_cdc_core_clk.clk_freq_in_hz = clk_freq_in_hz; pdata->digital_cdc_core_clk.enable = 1; @@ -1089,8 +1095,7 @@ static void update_int_mi2s_clk_val(int idx, int stream) bit_per_sample = get_int_mi2s_bits_per_sample(int_mi2s_cfg[idx].bit_format); int_mi2s_clk[idx].clk_freq_in_hz = - (int_mi2s_cfg[idx].sample_rate * int_mi2s_cfg[idx].channels - * bit_per_sample); + (int_mi2s_cfg[idx].sample_rate * 2 * bit_per_sample); } static int int_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable) |
