diff options
252 files changed, 20303 insertions, 3089 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index adcaa6444ab8..a8334e1cfde7 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -289,6 +289,16 @@ Properties: values per performance mode with a total of 4 tuples corresponding to each supported performance mode. +- qcom,perfcl-apcs-mem-acc-threshold-voltage + Usage: optional + Value type: <u32> + Definition: Specifies the highest MEM ACC threshold voltage in + microvolts for the Performance cluster. This voltage is + used to determine which MEM ACC setting is used for the + highest frequencies. If specified, the voltage must match + the MEM ACC threshold voltage specified for the + corresponding CPRh device. + - qcom,red-fsm-en Usage: optional Value type: <empty> diff --git a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt index 8b0f7841af8d..6aaf89c47781 100644 --- a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt @@ -10,6 +10,7 @@ Required properties : "qcom,mmcc-msm8960" "qcom,mmcc-msm8974" "qcom,mmcc-msm8996" + "qcom,mmcc-msmfalcon" - reg : shall contain base register location and length - #clock-cells : shall contain 1 diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 56ad8c361219..0174306135c1 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -459,7 +459,11 @@ the fps window. fields in the supply entry, refer to the qcom,ctrl-supply-entries binding above. - qcom,config-select: Optional property to select default configuration. - +- qcom,panel-allow-phy-poweroff: A boolean property indicates that panel allows to turn off the phy power + supply during idle screen. A panel should able to handle the dsi lanes + in floating state(not LP00 or LP11) to turn on this property. Software + turns off PHY pmic power supply, phy ldo and DSI Lane ldo during + idle screen (footswitch control off) when this property is enabled. [[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel. Default configuration can be chosen by specifying phandle of the selected subnode in the qcom,config-select. @@ -647,6 +651,7 @@ Example: qcom,suspend-ulps-enabled; qcom,panel-roi-alignment = <4 4 2 2 20 20>; qcom,esd-check-enabled; + qcom,panel-allow-phy-poweroff; qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt index b1869803d345..50b9b1ac8704 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt @@ -183,6 +183,9 @@ Optional properties: - qcom,bus-rage-kbps : an array of two items (<min max>) that indicate the minimum and maximum acceptable votes for the bus. In the absence of this property <0 INT_MAX> is used. +- qcom,ubwc-10bit : UBWC 10 bit content has different bus requirements, + this tag will be used to pick the appropriate bus as per the session profile + as shown below in example. Example: @@ -270,4 +273,17 @@ Example: qcom,bus-governor = "msm-vidc-ddr"; qcom,bus-range-kbps = <1000 3388000>; }; + qcom,profile-dec-ubwc-10bit { + qcom,codec-mask = <0xffffffff>; + qcom,ubwc-10bit; + qcom,load-busfreq-tbl = + <979200 2446336>, /* UHD30D */ + <864000 2108416>, /* 720p240D */ + <489600 1207296>, /* 1080p60D */ + <432000 1058816>, /* 720p120D */ + <244800 616448>, /* 1080p30D */ + <216000 534528>, /* 720p60D */ + <108000 271360>, /* 720p30D */ + <0 0>; + }; }; diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt index 421379116989..808e18b495d5 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt @@ -63,6 +63,14 @@ First Level Node - FG Gen3 device Definition: The voltage threshold (in mV) which upon set will be used for configuring the low battery voltage threshold. +- qcom,fg-recharge-voltage + Usage: optional + Value type: <u32> + Definition: The voltage threshold (in mV) based on which the charging + will be resumed once the charging is complete. If this + property is not specified, then the default value will be + 4250mV. + - qcom,fg-chg-term-current Usage: optional Value type: <u32> diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt index 9d8670c7594b..382587ea5922 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt @@ -138,6 +138,14 @@ Charger specific properties: then charge inhibit will be disabled by default. Allowed values are: 50, 100, 200, 300. +- qcom,auto-recharge-soc + Usage: optional + Value type: <empty> + Definition: Specifies if automatic recharge needs to be based off battery + SOC. If this property is not specified, then auto recharge will + be based off battery voltage. For both SOC and battery voltage, + charger receives the signal from FG to resume charging. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt index 8b806f4828bd..5b0770785dbe 100644 --- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt @@ -73,6 +73,24 @@ KBSS specific properties: switching. If this property is not specified, then a value of 0 is assumed. +- qcom,mem-acc-threshold-voltage + Usage: optional + Value type: <u32> + Definition: Specifies the highest memory accelerator (MEM ACC) threshold + voltage in microvolts. The floor to ceiling voltage range + for every corner is adjusted to ensure that it does not + intersect this voltage. The value of this property must + match with the MEM ACC threshold voltage defined in the OSM + device to ensure that MEM ACC settings are switched + appropriately. + +- qcom,mem-acc-crossover-voltage + Usage: required if qcom,mem-acc-threshold-voltage is specified + Value type: <u32> + Definition: Specifies the MEM ACC crossover voltage in microvolts which + corresponds to the voltage the VDD supply must be set to + when switching the MEM ACC configuration. + - qcom,voltage-base Usage: required Value type: <u32> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index bceee5e1747d..a25961c6e7de 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -55,6 +55,10 @@ Optional properties: - lanes-per-direction: number of lanes available per direction - either 1 or 2. Note that it is assume same number of lanes is used both directions at once. If not specified, default is 2 lanes per direction. +- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + for these optional properties + + Note: If above properties are not defined it can be assumed that the supply regulators or clocks are always on. diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index fdab1da887fa..730b76846c9d 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -113,7 +113,9 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ msm8998-v2-cdp.dtb \ msm8998-v2-qrd.dtb \ msm8998-qrd-skuk.dtb \ + msm8998-v2-qrd-skuk.dtb \ msm8998-qrd-vr1.dtb \ + msm8998-v2-qrd-vr1.dtb \ apq8998-mtp.dtb \ apq8998-cdp.dtb \ apq8998-v2-mtp.dtb \ @@ -125,6 +127,7 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ apq8998-v2.1-mtp.dtb \ apq8998-v2.1-cdp.dtb \ apq8998-v2.1-qrd.dtb \ + apq8998-v2.1-mediabox.dtb \ msm8998-v2.1-interposer-msmfalcon-cdp.dtb \ msm8998-v2.1-interposer-msmfalcon-mtp.dtb \ msm8998-v2.1-interposer-msmfalcon-qrd.dtb diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts new file mode 100644 index 000000000000..bc60d9a08c0b --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8998-v2.1.dtsi" +#include "msm8998-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ 8998 V2.1 mediabox"; + compatible = "qcom,apq8998-cdp", "qcom,apq8998", "qcom,cdp"; + qcom,board-id = <8 1>; +}; + +&pil_modem { + status = "disabled"; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "hdmi"; +}; 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 69067f5f1cc7..364b83320015 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 @@ -11,53 +11,53 @@ */ qcom,ascent_3450mah { - /* #Ascent_860_82209_0000_3450mAh_averaged_MasterSlave_Jul20th2016*/ + /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Nov28th2016 */ qcom,max-voltage-uv = <4350000>; qcom,fg-cc-cv-threshold-mv = <4340>; qcom,nom-batt-capacity-mah = <3450>; qcom,batt-id-kohm = <60>; qcom,battery-beta = <3435>; - qcom,battery-type = "ascent_860_82209_0000_3450mah"; - qcom,checksum = <0xD1D9>; - qcom,gui-version = "PMI8998GUI - 0.0.0.82"; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_nov28th2016"; + qcom,checksum = <0x2232>; + qcom,gui-version = "PMI8998GUI - 2.0.0.52"; qcom,fg-profile-data = [ - 2C 1F 3F FC - E9 03 A1 FD - 58 1D FD F5 - 27 12 2C 14 - 3F 18 FF 22 - 9B 45 A3 52 + 9C 1F 85 05 + 82 0A 73 FC + 2B 1D 6A EA + F2 03 63 0C + C8 17 F3 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 + 24 06 09 20 + 27 00 14 00 + 83 1F EE 05 + 1F 0A 45 FD + 6B 1D 52 E5 + EC 0B 31 14 + 44 18 49 23 + 18 45 A6 53 55 00 00 00 0E 00 00 00 - 00 00 1C AC - F7 CD 71 B5 - 1A 00 0C 00 - 3C EB 54 E4 - EC 05 7F FA - 76 05 F5 02 - CA F3 82 3A - 2A 09 40 40 - 07 00 05 00 - 58 1F 42 06 - 85 03 35 F4 - 4D 1D 37 F2 - 23 0A 79 15 - B7 18 32 23 - 26 45 72 53 - 55 00 00 00 - 0D 00 00 00 - 00 00 13 CC - 03 00 98 BD - 16 00 00 00 - 3C EB 54 E4 - 9F FC A3 F3 - 0F FC DF FA - FF E5 A9 23 - CB 33 08 33 + 00 00 61 CC + B7 C3 0F BC + 0F 00 00 00 + 92 00 5D ED + E3 06 81 F3 + 75 FD 9C 03 + 43 DB B3 22 + CB 33 CC FF 07 10 00 00 - 81 0D 99 45 - 16 00 19 00 - 75 01 0A FA + 99 0D 99 45 + 0F 00 40 00 + AB 01 0A FA FF 00 00 00 00 00 00 00 00 00 00 00 diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi new file mode 100644 index 000000000000..b107918a8e98 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi @@ -0,0 +1,78 @@ +/* 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. + */ + +qcom,demo_6000mah { + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,nom-batt-capacity-mah = <6000>; + qcom,batt-id-kohm = <75>; + qcom,battery-beta = <3435>; + qcom,battery-type = "Demo_battery_6000mah"; + qcom,fg-profile-data = [ + 2C 1F 3F FC + E9 03 A1 FD + 58 1D FD F5 + 27 12 2C 14 + 3F 18 FF 22 + 9B 45 A3 52 + 55 00 00 00 + 0E 00 00 00 + 00 00 1C AC + F7 CD 71 B5 + 1A 00 0C 00 + 3C EB 54 E4 + EC 05 7F FA + 76 05 F5 02 + CA F3 82 3A + 2A 09 40 40 + 07 00 05 00 + 58 1F 42 06 + 85 03 35 F4 + 4D 1D 37 F2 + 23 0A 79 15 + B7 18 32 23 + 26 45 72 53 + 55 00 00 00 + 0D 00 00 00 + 00 00 13 CC + 03 00 98 BD + 16 00 00 00 + 3C EB 54 E4 + 9F FC A3 F3 + 0F FC DF FA + FF E5 A9 23 + CB 33 08 33 + 07 10 00 00 + 81 0D 99 45 + 16 00 19 00 + 75 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi new file mode 100644 index 000000000000..74c1779e6fca --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi @@ -0,0 +1,838 @@ +/* + * 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. + */ + +&soc { + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + compr: qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "regular"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + pcm_noirq: qcom,msm-pcm-dsp-noirq { + compatible = "qcom,msm-pcm-dsp-noirq"; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + cpe: qcom,msm-cpe-lsm { + compatible = "qcom,msm-cpe-lsm"; + }; + + cpe3: qcom,msm-cpe-lsm@3 { + compatible = "qcom,msm-cpe-lsm"; + qcom,msm-cpe-lsm-id = <3>; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + dai_mi2s0: qcom,msm-dai-q6-mi2s-prim { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s1: qcom,msm-dai-q6-mi2s-sec { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <1>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s3: qcom,msm-dai-q6-mi2s-quat { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <3>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s2: qcom,msm-dai-q6-mi2s-tert { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <2>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_mi2s5: qcom,msm-dai-q6-mi2s-quin { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <5>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s6: qcom,msm-dai-q6-mi2s-senary { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <6>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <7>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <8>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <9>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <10>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <11>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <12>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <13>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + sb_0_rx: qcom,msm-dai-q6-sb-0-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16384>; + }; + + sb_0_tx: qcom,msm-dai-q6-sb-0-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16385>; + }; + + sb_1_rx: qcom,msm-dai-q6-sb-1-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16386>; + }; + + sb_1_tx: qcom,msm-dai-q6-sb-1-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16387>; + }; + + sb_2_rx: qcom,msm-dai-q6-sb-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16388>; + }; + + sb_2_tx: qcom,msm-dai-q6-sb-2-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16389>; + }; + + + sb_3_rx: qcom,msm-dai-q6-sb-3-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16390>; + }; + + sb_3_tx: qcom,msm-dai-q6-sb-3-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16391>; + }; + + sb_4_rx: qcom,msm-dai-q6-sb-4-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16392>; + }; + + sb_4_tx: qcom,msm-dai-q6-sb-4-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16393>; + }; + + sb_5_tx: qcom,msm-dai-q6-sb-5-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16395>; + }; + + sb_5_rx: qcom,msm-dai-q6-sb-5-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16394>; + }; + + sb_6_rx: qcom,msm-dai-q6-sb-6-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16396>; + }; + + sb_7_tx: qcom,msm-dai-q6-sb-7-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16399>; + }; + + sb_7_rx: qcom,msm-dai-q6-sb-7-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16398>; + }; + + sb_8_tx: qcom,msm-dai-q6-sb-8-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16401>; + }; + + sb_8_rx: qcom,msm-dai-q6-sb-8-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16400>; + }; + + bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12288>; + }; + + bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12289>; + }; + + int_fm_rx: qcom,msm-dai-q6-int-fm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12292>; + }; + + int_fm_tx: qcom,msm-dai-q6-int-fm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12293>; + }; + + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + + usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28672>; + }; + + usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28673>; + }; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + + dai_pri_auxpcm: qcom,msm-pri-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + }; + + dai_sec_auxpcm: qcom,msm-sec-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "secondary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_tert_auxpcm: qcom,msm-tert-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "tertiary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_quat_auxpcm: qcom,msm-quat-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "quaternary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <2>; + qcom,smmu-enabled; + iommus = <&lpass_q6_smmu 1>; + }; + + qcom,msm-adsp-loader { + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; + + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37152>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36896>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36896>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37153>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36897 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36897 >; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quat-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37168>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36912>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36912>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quat-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37169>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36913 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36913 >; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,avtimer@150f700c { + compatible = "qcom,avtimer"; + reg = <0x150f700c 0x4>, + <0x150f7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <27>; + }; + + tasha_snd: sound-9335 { + compatible = "qcom,msmfalcon-asoc-snd-tasha"; + qcom,model = "msmfalcon-tasha-snd-card"; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + + reg = <0x1508a000 0x4>, + <0x1508b000 0x4>, + <0x1508c000 0x4>, + <0x1508d000 0x4>; + reg-names = "lpaif_pri_mode_muxsel", + "lpaif_sec_mode_muxsel", + "lpaif_tert_mode_muxsel", + "lpaif_quat_mode_muxsel"; + + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "AMIC6", "MIC BIAS4", + "MIC BIAS4", "Analog Mic6", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,us-euro-gpios = <&us_euro_gpio>; + qcom,tasha-mclk-clk-freq = <9600000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>, <&cpe3>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq", + "msm-cpe-lsm.3"; + asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672", + "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36913"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + tavil_snd: sound-tavil { + compatible = "qcom,msmfalcon-asoc-snd-tavil"; + qcom,model = "msmfalcon-tavil-snd-card"; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + + reg = <0x1508a000 0x4>, + <0x1508b000 0x4>, + <0x1508c000 0x4>, + <0x1508d000 0x4>; + reg-names = "lpaif_pri_mode_muxsel", + "lpaif_sec_mode_muxsel", + "lpaif_tert_mode_muxsel", + "lpaif_quat_mode_muxsel"; + + qcom,audio-routing = + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,us-euro-gpios = <&tavil_us_euro_sw>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,tavil-mclk-clk-freq = <9600000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672", + "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36913"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + + us_euro_gpio: msm_cdc_pinctrl@75 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_gnd_mic_swap_active>; + pinctrl-1 = <&wcd_gnd_mic_swap_idle>; + }; + + wcd9xxx_intc: wcd9xxx-irq { + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 54 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio: audio_ext_clk { + compatible = "qcom,audio-ref-clk"; + qcom,audio-ref-clk-gpio = <&pmfalcon_gpios 3 0>; + clock-names = "osr_clk"; + clocks = <&clock_gcc clk_div_clk1>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&spkr_i2s_clk_sleep>; + pinctrl-1 = <&spkr_i2s_clk_active>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_gcc clk_ln_bb_clk2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 64 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; + +}; + diff --git a/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi new file mode 100644 index 000000000000..dcf7030a78e4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi @@ -0,0 +1,16 @@ +/* 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. + */ + +/* Disable WLED */ +&pm2falcon_wled { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi index b8fac8a183a2..93cfab700aa9 100644 --- a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi @@ -273,6 +273,158 @@ }; }; + pmfalcon_charger: qcom,qpnp-smb2 { + compatible = "qcom,qpnp-smb2"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,pmic-revid = <&pmfalcon_revid>; + + io-channels = <&pmfalcon_rradc 8>, + <&pmfalcon_rradc 10>, + <&pmfalcon_rradc 3>, + <&pmfalcon_rradc 4>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v"; + + qcom,wipower-max-uw = <5000000>; + dpdm-supply = <&qusb_phy0>; + + qcom,thermal-mitigation + = <3000000 1500000 1000000 500000>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, + <0x2 0x10 0x1 IRQ_TYPE_NONE>, + <0x2 0x10 0x2 IRQ_TYPE_NONE>, + <0x2 0x10 0x3 IRQ_TYPE_NONE>, + <0x2 0x10 0x4 IRQ_TYPE_NONE>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>, + <0x2 0x11 0x1 IRQ_TYPE_NONE>, + <0x2 0x11 0x2 IRQ_TYPE_NONE>, + <0x2 0x11 0x3 IRQ_TYPE_NONE>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>, + <0x2 0x12 0x1 IRQ_TYPE_NONE>, + <0x2 0x12 0x2 IRQ_TYPE_NONE>, + <0x2 0x12 0x3 IRQ_TYPE_NONE>, + <0x2 0x12 0x4 IRQ_TYPE_NONE>, + <0x2 0x12 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>, + <0x2 0x13 0x1 IRQ_TYPE_NONE>, + <0x2 0x13 0x2 IRQ_TYPE_NONE>, + <0x2 0x13 0x3 IRQ_TYPE_NONE>, + <0x2 0x13 0x4 IRQ_TYPE_NONE>, + <0x2 0x13 0x5 IRQ_TYPE_NONE>, + <0x2 0x13 0x6 IRQ_TYPE_NONE>, + <0x2 0x13 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>, + <0x2 0x14 0x1 IRQ_TYPE_NONE>, + <0x2 0x14 0x2 IRQ_TYPE_NONE>, + <0x2 0x14 0x3 IRQ_TYPE_NONE>, + <0x2 0x14 0x4 IRQ_TYPE_NONE>, + <0x2 0x14 0x5 IRQ_TYPE_NONE>, + <0x2 0x14 0x6 IRQ_TYPE_NONE>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>, + <0x2 0x16 0x1 IRQ_TYPE_NONE>, + <0x2 0x16 0x2 IRQ_TYPE_NONE>, + <0x2 0x16 0x3 IRQ_TYPE_NONE>, + <0x2 0x16 0x4 IRQ_TYPE_NONE>, + <0x2 0x16 0x5 IRQ_TYPE_NONE>, + <0x2 0x16 0x6 IRQ_TYPE_NONE>, + <0x2 0x16 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; + }; + + pmfalcon_pdphy: qcom,usb-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + vdd-pdphy-supply = <&pm2falcon_l7>; + vbus-supply = <&smb2_vbus>; + vconn-supply = <&smb2_vconn>; + interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded"; + }; + pmfalcon_adc_tm: vadc@3400 { compatible = "qcom,qpnp-adc-tm-hc"; reg = <0x3400 0x100>; @@ -337,6 +489,67 @@ #size-cells = <0>; #io-channel-cells = <1>; }; + + pmfalcon_fg: qpnp,fg { + compatible = "qcom,fg-gen3"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pmfalcon_revid>; + io-channels = <&pmfalcon_rradc 0>; + io-channel-names = "rradc_batt_id"; + qcom,fg-esr-timer-awake = <96>; + qcom,fg-esr-timer-asleep = <256>; + qcom,cycle-counter-en; + status = "okay"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x5 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta", + "msoc-low", + "msoc-empty", + "msoc-high", + "msoc-full"; + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x6 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbatt-pred-delta", + "vbatt-low", + "esr-delta", + "batt-missing", + "batt-temp-delta"; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x44 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x44 0x2 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "ima-rdy", + "mem-xcp", + "dma-grant"; + }; + }; }; qcom,pmfalcon@1 { diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi index a56e9836784c..14567c3b5010 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi @@ -220,6 +220,7 @@ cell-index = <0>; compatible = "qcom,camera"; reg = <0x0>; + qcom,special-support-sensors = "imx362_gt24c64a"; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; qcom,mount-angle = <270>; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi index da568fd8979c..36441f9aa15a 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi @@ -184,6 +184,8 @@ qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator0>; qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi new file mode 100644 index 000000000000..3ef09569a430 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi @@ -0,0 +1,224 @@ +/* + * 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. + */ + +&soc { + qcom,csiphy@ca34000 { + qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 + 0 384000000 0>; + }; + + qcom,csiphy@ca35000 { + qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 + 0 384000000 0>; + }; + + qcom,csiphy@ca36000 { + qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 + 0 384000000 0>; + }; + + qcom,csid@ca30000 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; + + qcom,csid@ca30400 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; + + qcom,csid@ca30800 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; + + qcom,csid@ca30c00 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; +}; + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + gpios = <&tlmm 27 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + gpios = <&tlmm 27 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + qcom,cci-master = <0>; + gpios = <&tlmm 27 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + status = "disabled"; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pmfalcon_l11>; + cam_vana-supply = <&pm2falcon_bob>; + cam_vdig-supply = <&pmfalcon_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <0 3300000 1350000>; + qcom,cam-vreg-max-voltage = <0 3600000 1350000>; + qcom,cam-vreg-op-mode = <0 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active + &cam_actuator_vaf_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend + &cam_actuator_vaf_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>, + <&pmfalcon_gpios 4 0>, + <&tlmm 29 0>, + <&tlmm 27 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-vaf = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA", + "CAM_VAF"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_mmss_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <270>; + qcom,actuator-src = <&actuator0>; + qcom,ois-src = <&ois0>; + qcom,eeprom-src = <&eeprom0>; + cam_vio-supply = <&pmfalcon_l11>; + cam_vana-supply = <&pm2falcon_bob>; + cam_vdig-supply = <&pmfalcon_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <0 3300000 1350000>; + qcom,cam-vreg-max-voltage = <0 3600000 1350000>; + qcom,cam-vreg-op-mode = <0 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>, + <&pmfalcon_gpios 4 0>, + <&tlmm 29 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_mmss_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; + +&pmfalcon_gpios { + gpio@c300 { /* GPIO4 -CAMERA SENSOR 0 VDIG*/ + qcom,mode = <1>; /* Output */ + qcom,pull = <5>; /* No Pull */ + qcom,vin-sel = <0>; /* VIN1 GPIO_LV */ + qcom,src-sel = <0>; /* GPIO */ + qcom,invert = <0>; /* Invert */ + qcom,master-en = <1>; /* Enable GPIO */ + status = "ok"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi new file mode 100644 index 000000000000..3ef09569a430 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi @@ -0,0 +1,224 @@ +/* + * 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. + */ + +&soc { + qcom,csiphy@ca34000 { + qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 + 0 384000000 0>; + }; + + qcom,csiphy@ca35000 { + qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 + 0 384000000 0>; + }; + + qcom,csiphy@ca36000 { + qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 + 0 384000000 0>; + }; + + qcom,csid@ca30000 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; + + qcom,csid@ca30400 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; + + qcom,csid@ca30800 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; + + qcom,csid@ca30c00 { + qcom,csi-vdd-voltage = <1225000>; + qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm2falcon_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + 0 0 0 0 0>; + }; +}; + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + gpios = <&tlmm 27 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + gpios = <&tlmm 27 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + qcom,cci-master = <0>; + gpios = <&tlmm 27 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + status = "disabled"; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pmfalcon_l11>; + cam_vana-supply = <&pm2falcon_bob>; + cam_vdig-supply = <&pmfalcon_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <0 3300000 1350000>; + qcom,cam-vreg-max-voltage = <0 3600000 1350000>; + qcom,cam-vreg-op-mode = <0 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active + &cam_actuator_vaf_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend + &cam_actuator_vaf_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>, + <&pmfalcon_gpios 4 0>, + <&tlmm 29 0>, + <&tlmm 27 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-vaf = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA", + "CAM_VAF"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_mmss_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <270>; + qcom,actuator-src = <&actuator0>; + qcom,ois-src = <&ois0>; + qcom,eeprom-src = <&eeprom0>; + cam_vio-supply = <&pmfalcon_l11>; + cam_vana-supply = <&pm2falcon_bob>; + cam_vdig-supply = <&pmfalcon_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <0 3300000 1350000>; + qcom,cam-vreg-max-voltage = <0 3600000 1350000>; + qcom,cam-vreg-op-mode = <0 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>, + <&pmfalcon_gpios 4 0>, + <&tlmm 29 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_mmss_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; + +&pmfalcon_gpios { + gpio@c300 { /* GPIO4 -CAMERA SENSOR 0 VDIG*/ + qcom,mode = <1>; /* Output */ + qcom,pull = <5>; /* No Pull */ + qcom,vin-sel = <0>; /* VIN1 GPIO_LV */ + qcom,src-sel = <0>; /* GPIO */ + qcom,invert = <0>; /* Invert */ + qcom,master-en = <1>; /* Enable GPIO */ + status = "ok"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi new file mode 100644 index 000000000000..20c69e0a9a1a --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi @@ -0,0 +1,73 @@ +/* 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. + */ + +&clock_audio { + qcom,audio-ref-clk-gpio = <&pmfalcon_gpios 3 0>; +}; + +&slim_aud { + tasha_codec { + cdc-vdd-buck-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmfalcon_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmfalcon_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + }; + + tavil_codec { + cdc-vdd-buck-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmfalcon_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmfalcon_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + }; +}; + +&pmfalcon_gpios { + gpio@c200 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,src-sel = <2>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi index 32f9dcdecb0c..76326e7ae86f 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi @@ -69,12 +69,12 @@ }; &sdhc_2 { - vdd-supply = <&pm8998_l21>; - qcom,vdd-voltage-level = <2950000 2960000>; + vdd-supply = <&pm2falcon_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; qcom,vdd-current-level = <200 800000>; - vdd-io-supply = <&pm8998_l13>; - qcom,vdd-io-voltage-level = <1808000 2960000>; + vdd-io-supply = <&pm2falcon_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <200 22000>; pinctrl-names = "active", "sleep"; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi index e73ffc884210..5c55732e0de7 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi @@ -70,12 +70,12 @@ }; &sdhc_2 { - vdd-supply = <&pm8998_l21>; - qcom,vdd-voltage-level = <2950000 2960000>; + vdd-supply = <&pm2falcon_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; qcom,vdd-current-level = <200 800000>; - vdd-io-supply = <&pm8998_l13>; - qcom,vdd-io-voltage-level = <1808000 2960000>; + vdd-io-supply = <&pm2falcon_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <200 22000>; pinctrl-names = "active", "sleep"; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi index 861be92a7bc2..1ca5ce6eabbb 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi @@ -1853,7 +1853,7 @@ <61 512 240000 800000>; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; - extcon = <&pmi8998_pdphy>; + extcon = <&pmfalcon_pdphy>; clocks = <&clock_gcc clk_gcc_usb30_master_clk>, <&clock_gcc clk_gcc_cfg_noc_usb3_axi_clk>, @@ -1921,9 +1921,9 @@ <0x01fcb24c 0x4>; reg-names = "qusb_phy_base", "tcsr_clamp_dig_n_1p8"; - vdd-supply = <&pm8998_l1>; - vdda18-supply = <&pm8998_l12>; - vdda33-supply = <&pm8998_l24>; + vdd-supply = <&pm2falcon_l1>; + vdda18-supply = <&pm2falcon_l10>; + vdda33-supply = <&pm2falcon_l7>; qcom,vdd-voltage-level = <0 880000 880000>; qcom,qusb-phy-init-seq = /* <value reg_offset> */ @@ -1951,8 +1951,8 @@ reg-names = "qmp_phy_base", "vls_clamp_reg", "tcsr_usb3_dp_phymode"; - vdd-supply = <&pm8998_l1>; - core-supply = <&pm8998_l2>; + vdd-supply = <&pm2falcon_l1>; + core-supply = <&pmfalcon_l1>; qcom,vdd-voltage-level = <0 880000 880000>; qcom,vbus-valid-override; qcom,qmp-phy-init-seq = @@ -3083,12 +3083,11 @@ #include "msm8998-bus.dtsi" #include "msm8998-gpu.dtsi" #include "msm8998-pinctrl.dtsi" -#include "msm-audio-lpass.dtsi" #include "msm8998-mdss.dtsi" #include "msm8998-mdss-pll.dtsi" #include "msm8998-blsp.dtsi" -#include "msm8998-audio.dtsi" - +#include "msm-audio.dtsi" +#include "msmfalcon-audio.dtsi" /* GPU overrides */ &msm_gpu { diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi index f5d5c7f400f9..54a2a4a00dc0 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi @@ -45,12 +45,6 @@ /delete-property/qcom,switch-source; }; -&eeprom0 { - /delete-property/cam_vio-supply; - /delete-property/cam_vana-supply; - /delete-property/cam_vdig-supply; - /delete-property/gpios; -}; &eeprom1 { /delete-property/cam_vio-supply; @@ -66,7 +60,6 @@ }; &cci { - /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; /delete-node/qcom,camera@2; @@ -199,9 +192,7 @@ }; &gfx_cpr { - reg = <0x05061000 0x4000>, - <0x00784000 0x1000>; - reg-names = "cpr_ctrl", "fuse_base"; + status = "disabled"; /* disable aging and closed-loop */ /delete-property/vdd-supply; @@ -212,6 +203,8 @@ }; &gfx_vreg { + status = "disabled"; + /delete-property/qcom,cpr-aging-max-voltage-adjustment; /delete-property/qcom,cpr-aging-ref-corner; /delete-property/qcom,cpr-aging-ro-scaling-factor; @@ -220,10 +213,6 @@ }; &soc { - /delete-node/qcom,csid@ca30000; - /delete-node/qcom,csid@ca30400; - /delete-node/qcom,csid@ca30800; - /delete-node/qcom,csid@ca30c00; /delete-node/gpio_keys; /delete-node/qcom,lpass@17300000; /delete-node/qcom,mss@4080000; @@ -263,6 +252,8 @@ #include "msm-pmfalcon.dtsi" #include "msm-pm2falcon.dtsi" +#include "msm-pmfalcon-rpm-regulator.dtsi" +#include "msm-pm2falcon-rpm-regulator.dtsi" #include "msmfalcon-regulator.dtsi" /* dummy LCDB regulator nodes */ diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi index 76124833dc36..45d6398daf25 100644 --- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi @@ -623,5 +623,6 @@ qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-itech-3000mah.dtsi" #include "fg-gen3-batterydata-ascent-3450mah.dtsi" + #include "fg-gen3-batterydata-demo-6000mah.dtsi" }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index 1f5facd5cde5..5685e9041fe4 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -1624,6 +1624,52 @@ }; }; + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + sdc2_clk_on: sdc2_clk_on { config { pins = "sdc2_clk"; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi index cead74b02528..c09900597d87 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi @@ -15,6 +15,33 @@ #include "msm8998-audio.dtsi" #include "msm8998-camera-sensor-skuk.dtsi" +/ { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pm8998_s3>; + qca,bt-vdd-xtal-supply = <&pm8998_s5>; + qca,bt-vdd-core-supply = <&pm8998_l7>; + qca,bt-vdd-pa-supply = <&pm8998_l17>; + qca,bt-vdd-ldo-supply = <&pm8998_l25>; + qca,bt-chip-pwd-supply = <&pmi8998_bob_pin1>; + clocks = <&clock_gcc clk_rf_clk2_pin>; + clock-names = "rf_clk2"; + + qca,bt-vdd-io-voltage-level = <1352000 1352000>; + qca,bt-vdd-xtal-voltage-level = <2040000 2040000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + qca,bt-chip-pwd-voltage-level = <3600000 3600000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */ + }; +}; + &blsp1_uart3_hs { status = "ok"; }; @@ -210,3 +237,105 @@ &pmi8998_haptics { status = "okay"; }; + +&pm8998_vadc { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@85 { + label = "vcoin"; + reg = <0x85>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8998_adc_tm { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,btm-channel-number = <0x60>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi index ccdfe7ee03f6..bd9d8147dd82 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi @@ -14,6 +14,33 @@ #include "msm8998-pinctrl.dtsi" #include "msm8998-camera-sensor-qrd-vr1.dtsi" +/ { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pm8998_s3>; + qca,bt-vdd-xtal-supply = <&pm8998_s5>; + qca,bt-vdd-core-supply = <&pm8998_l7>; + qca,bt-vdd-pa-supply = <&pm8998_l17>; + qca,bt-vdd-ldo-supply = <&pm8998_l25>; + qca,bt-chip-pwd-supply = <&pmi8998_bob_pin1>; + clocks = <&clock_gcc clk_rf_clk2_pin>; + clock-names = "rf_clk2"; + + qca,bt-vdd-io-voltage-level = <1352000 1352000>; + qca,bt-vdd-xtal-voltage-level = <2040000 2040000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + qca,bt-chip-pwd-voltage-level = <3600000 3600000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */ + }; +}; + &blsp1_uart3_hs { status = "ok"; }; @@ -144,3 +171,105 @@ &pmi8998_haptics { status = "okay"; }; + +&pm8998_vadc { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@85 { + label = "vcoin"; + reg = <0x85>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8998_adc_tm { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,btm-channel-number = <0x60>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi index 41f9c3c69fe9..0a011b3656be 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi @@ -11,7 +11,6 @@ */ #include <dt-bindings/interrupt-controller/irq.h> -#include "msm8998-mtp.dtsi" #include "msm8998-pinctrl.dtsi" #include "msm8998-camera-sensor-qrd.dtsi" / { diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi index d207628f06a1..dc548f8f499b 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi @@ -26,6 +26,25 @@ &clock_cpu { compatible = "qcom,cpu-clock-osm-msm8998-v2"; + reg = <0x179c0000 0x4000>, + <0x17916000 0x1000>, + <0x17816000 0x1000>, + <0x179d1000 0x1000>, + <0x17914800 0x800>, + <0x17814800 0x800>, + <0x00784130 0x8>, + <0x1791101c 0x8>; + reg-names = "osm", "pwrcl_pll", "perfcl_pll", + "apcs_common", "pwrcl_acd", "perfcl_acd", + "perfcl_efuse", "debug"; + + qcom,acdtd-val = <0x00009611 0x00009611>; + qcom,acdcr-val = <0x002b5ffd 0x002b5ffd>; + qcom,acdsscr-val = <0x00000501 0x00000501>; + qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>; + qcom,acdextint1-val = <0x2cf9afc 0x2cf9afc>; + qcom,acdautoxfer-val = <0x00000015 0x00000015>; + /delete-property/ qcom,llm-sw-overr; qcom,pwrcl-speedbin0-v0 = < 300000000 0x0004000f 0x01200020 0x1 1 >, diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts index 3c00de27f285..bb7046ab58cb 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts @@ -16,9 +16,73 @@ #include "msm8998-v2.1-interposer-msmfalcon.dtsi" #include "msm8998-interposer-msmfalcon-cdp.dtsi" #include "msm8998-interposer-pmfalcon.dtsi" +#include "msm8998-interposer-msmfalcon-audio.dtsi" +#include "msm8998-interposer-camera-sensor-cdp.dtsi" / { model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MSM FALCON Interposer CDP"; compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp"; qcom,board-id = <1 1>; }; + +&pmfalcon_charger { + qcom,batteryless-platform; +}; + +&clock_gcc { + vdd_dig-supply = <&pm2falcon_s3_level>; + vdd_dig_ao-supply = <&pm2falcon_s3_level_ao>; +}; + +&clock_mmss { + vdd_dig-supply = <&pm2falcon_s3_level>; + vdd_mmsscc_mx-supply = <&pm2falcon_s5_level>; +}; + +&clock_gpu { + vdd_dig-supply = <&pm2falcon_s3_level>; +}; + +&clock_gfx { + /* GFX Rail = CX */ + vdd_gpucc-supply = <&pm2falcon_s3_level>; + vdd_mx-supply = <&pm2falcon_s5_level>; + vdd_gpu_mx-supply = <&pm2falcon_s5_level>; + qcom,gfxfreq-speedbin0 = + < 0 0 0 >, + < 180000000 RPM_SMD_REGULATOR_LEVEL_MIN_SVS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 257000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS_PLUS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM + RPM_SMD_REGULATOR_LEVEL_NOM >, + < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM_PLUS + RPM_SMD_REGULATOR_LEVEL_NOM >, + < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO + RPM_SMD_REGULATOR_LEVEL_TURBO >, + < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO + RPM_SMD_REGULATOR_LEVEL_TURBO >; + qcom,gfxfreq-mx-speedbin0 = + < 0 0 >, + < 180000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 257000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM >, + < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM >, + < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, + < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; +}; + +&gdsc_gpu_gx { + clock-names = "core_root_clk"; + clocks = <&clock_gfx clk_gfx3d_clk_src>; + qcom,force-enable-root-clk; + /* GFX Rail = CX */ + parent-supply = <&pm2falcon_s3_level>; + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts index 7d0fe5a33875..166e09577d46 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts @@ -16,9 +16,73 @@ #include "msm8998-v2.1-interposer-msmfalcon.dtsi" #include "msm8998-interposer-msmfalcon-mtp.dtsi" #include "msm8998-interposer-pmfalcon.dtsi" +#include "msm8998-interposer-msmfalcon-audio.dtsi" +#include "msm8998-interposer-camera-sensor-mtp.dtsi" / { model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MSM FALCON Interposer MTP"; compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp"; qcom,board-id = <8 2>; }; + +&pmfalcon_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&clock_gcc { + vdd_dig-supply = <&pm2falcon_s3_level>; + vdd_dig_ao-supply = <&pm2falcon_s3_level_ao>; +}; + +&clock_mmss { + vdd_dig-supply = <&pm2falcon_s3_level>; + vdd_mmsscc_mx-supply = <&pm2falcon_s5_level>; +}; + +&clock_gpu { + vdd_dig-supply = <&pm2falcon_s3_level>; +}; + +&clock_gfx { + /* GFX Rail = CX */ + vdd_gpucc-supply = <&pm2falcon_s3_level>; + vdd_mx-supply = <&pm2falcon_s5_level>; + vdd_gpu_mx-supply = <&pm2falcon_s5_level>; + qcom,gfxfreq-speedbin0 = + < 0 0 0 >, + < 180000000 RPM_SMD_REGULATOR_LEVEL_MIN_SVS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 257000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS_PLUS + RPM_SMD_REGULATOR_LEVEL_SVS >, + < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM + RPM_SMD_REGULATOR_LEVEL_NOM >, + < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM_PLUS + RPM_SMD_REGULATOR_LEVEL_NOM >, + < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO + RPM_SMD_REGULATOR_LEVEL_TURBO >, + < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO + RPM_SMD_REGULATOR_LEVEL_TURBO >; + qcom,gfxfreq-mx-speedbin0 = + < 0 0 >, + < 180000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 257000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM >, + < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM >, + < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, + < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; +}; + +&gdsc_gpu_gx { + clock-names = "core_root_clk"; + clocks = <&clock_gfx clk_gfx3d_clk_src>; + qcom,force-enable-root-clk; + /* GFX Rail = CX */ + parent-supply = <&pm2falcon_s3_level>; + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi index 0f03ebd28b0f..cd0e20a295d9 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi @@ -20,6 +20,9 @@ }; &ufsphy1 { + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l10>; + vddp-ref-clk-supply = <&pmfalcon_l8>; vdda-phy-max-microamp = <51400>; vdda-pll-max-microamp = <14600>; vddp-ref-clk-max-microamp = <100>; @@ -30,6 +33,9 @@ &ufs1 { vdd-hba-supply = <&gdsc_ufs>; vdd-hba-fixed-regulator; + vcc-supply = <&pm2falcon_l4>; + vccq-supply = <&pmfalcon_l8>; + vccq2-supply = <&pmfalcon_l8>; vcc-max-microamp = <750000>; vccq-max-microamp = <560000>; vccq2-max-microamp = <750000>; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi index dc1922851a77..cc4e48ede2ad 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi @@ -26,6 +26,27 @@ &clock_cpu { compatible = "qcom,cpu-clock-osm-msm8998-v2"; + reg = <0x179c0000 0x4000>, + <0x17916000 0x1000>, + <0x17816000 0x1000>, + <0x179d1000 0x1000>, + <0x17914800 0x800>, + <0x17814800 0x800>, + <0x00784130 0x8>, + <0x1791101c 0x8>; + reg-names = "osm", "pwrcl_pll", "perfcl_pll", + "apcs_common", "pwrcl_acd", "perfcl_acd", + "perfcl_efuse", "debug"; + + qcom,acdtd-val = <0x00009611 0x00009611>; + qcom,acdcr-val = <0x002b5ffd 0x002b5ffd>; + qcom,acdsscr-val = <0x00000501 0x00000501>; + qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>; + qcom,acdextint1-val = <0x2cf9afe 0x2cf9afe>; + qcom,acdautoxfer-val = <0x00000015 0x00000015>; + qcom,perfcl-apcs-mem-acc-threshold-voltage = <852000>; + qcom,apm-threshold-voltage = <800000>; + /delete-property/ qcom,llm-sw-overr; qcom,pwrcl-speedbin0-v0 = < 300000000 0x0004000f 0x01200020 0x1 1 >, @@ -77,11 +98,20 @@ < 1958400000 0x04040066 0x09520052 0x2 23 >, < 2035200000 0x0404006a 0x09550055 0x3 24 >, < 2112000000 0x0404006e 0x0a580058 0x3 25 >, - < 2188800000 0x04040072 0x0a5b005b 0x3 26 >, + < 2208000000 0x04040073 0x0a5c005c 0x3 26 >, + < 2265600000 0x04010076 0x0a5e005e 0x3 26 >, < 2265600000 0x04040076 0x0a5e005e 0x3 27 >, + < 2342400000 0x0401007a 0x0a620062 0x3 27 >, < 2342400000 0x0404007a 0x0a620062 0x3 28 >, + < 2419200000 0x0401007e 0x0a650065 0x3 28 >, < 2419200000 0x0404007e 0x0a650065 0x3 29 >, - < 2496000000 0x04040082 0x0a680068 0x3 30 >; + < 2496000000 0x04010082 0x0a680068 0x3 29 >, + < 2457600000 0x04040080 0x0a660066 0x3 30 >, + < 2553600000 0x04010085 0x0a6a006a 0x3 30 >, + < 2476800000 0x04040081 0x0a670067 0x3 31 >, + < 2572800000 0x04010086 0x0a6b006b 0x3 31 >, + < 2496000000 0x04040082 0x0a680068 0x3 32 >, + < 2592000000 0x04010087 0x0a6c006c 0x3 32 >; qcom,perfcl-speedbin1-v0 = < 300000000 0x0004000f 0x01200020 0x1 1 >, @@ -110,7 +140,81 @@ < 2035200000 0x0404006a 0x09550055 0x3 24 >, < 2112000000 0x0404006e 0x0a580058 0x3 25 >, < 2208000000 0x04040073 0x0a5c005c 0x3 26 >, - < 2304000000 0x04010078 0x0a5c005c 0x3 26 >; + < 2304000000 0x04010078 0x0a600060 0x3 26 >; + + qcom,perfcl-speedbin2-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 345600000 0x05040012 0x01200020 0x1 2 >, + < 422400000 0x05040016 0x02200020 0x1 3 >, + < 499200000 0x0504001a 0x02200020 0x1 4 >, + < 576000000 0x0504001e 0x02200020 0x1 5 >, + < 652800000 0x05040022 0x03200020 0x1 6 >, + < 729600000 0x05040026 0x03200020 0x1 7 >, + < 806400000 0x0504002a 0x03220022 0x1 8 >, + < 902400000 0x0404002f 0x04260026 0x1 9 >, + < 979200000 0x04040033 0x04290029 0x1 10 >, + < 1056000000 0x04040037 0x052c002c 0x1 11 >, + < 1132800000 0x0404003b 0x052f002f 0x1 12 >, + < 1190400000 0x0404003e 0x05320032 0x2 13 >, + < 1267200000 0x04040042 0x06350035 0x2 14 >, + < 1344000000 0x04040046 0x06380038 0x2 15 >, + < 1420800000 0x0404004a 0x063b003b 0x2 16 >, + < 1497600000 0x0404004e 0x073e003e 0x2 17 >, + < 1574400000 0x04040052 0x07420042 0x2 18 >, + < 1651200000 0x04040056 0x07450045 0x2 19 >, + < 1728000000 0x0404005a 0x08480048 0x2 20 >, + < 1804800000 0x0404005e 0x084b004b 0x2 21 >, + < 1881600000 0x04040062 0x094e004e 0x2 22 >, + < 1958400000 0x04040066 0x09520052 0x2 23 >, + < 2035200000 0x0404006a 0x09550055 0x3 24 >, + < 2112000000 0x0404006e 0x0a580058 0x3 25 >, + < 2208000000 0x04040073 0x0a5c005c 0x3 26 >, + < 2265600000 0x04010076 0x0a5e005e 0x3 26 >, + < 2265600000 0x04040076 0x0a5e005e 0x3 27 >, + < 2342400000 0x0401007a 0x0a620062 0x3 27 >, + < 2323200000 0x04040079 0x0a610061 0x3 28 >, + < 2419200000 0x0401007e 0x0a650065 0x3 28 >, + < 2342400000 0x0404007a 0x0a620062 0x3 29 >, + < 2438400000 0x0401007f 0x0a660066 0x3 29 >, + < 2361600000 0x0404007b 0x0a620062 0x3 30 >, + < 2457600000 0x04010080 0x0a660066 0x3 30 >; + + qcom,perfcl-speedbin3-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 345600000 0x05040012 0x01200020 0x1 2 >, + < 422400000 0x05040016 0x02200020 0x1 3 >, + < 499200000 0x0504001a 0x02200020 0x1 4 >, + < 576000000 0x0504001e 0x02200020 0x1 5 >, + < 652800000 0x05040022 0x03200020 0x1 6 >, + < 729600000 0x05040026 0x03200020 0x1 7 >, + < 806400000 0x0504002a 0x03220022 0x1 8 >, + < 902400000 0x0404002f 0x04260026 0x1 9 >, + < 979200000 0x04040033 0x04290029 0x1 10 >, + < 1056000000 0x04040037 0x052c002c 0x1 11 >, + < 1132800000 0x0404003b 0x052f002f 0x1 12 >, + < 1190400000 0x0404003e 0x05320032 0x2 13 >, + < 1267200000 0x04040042 0x06350035 0x2 14 >, + < 1344000000 0x04040046 0x06380038 0x2 15 >, + < 1420800000 0x0404004a 0x063b003b 0x2 16 >, + < 1497600000 0x0404004e 0x073e003e 0x2 17 >, + < 1574400000 0x04040052 0x07420042 0x2 18 >, + < 1651200000 0x04040056 0x07450045 0x2 19 >, + < 1728000000 0x0404005a 0x08480048 0x2 20 >, + < 1804800000 0x0404005e 0x084b004b 0x2 21 >, + < 1881600000 0x04040062 0x094e004e 0x2 22 >, + < 1958400000 0x04040066 0x09520052 0x2 23 >, + < 2035200000 0x0404006a 0x09550055 0x3 24 >, + < 2112000000 0x0404006e 0x0a580058 0x3 25 >, + < 2208000000 0x04040073 0x0a5c005c 0x3 26 >, + < 2265600000 0x04010076 0x0a5e005e 0x3 26 >, + < 2265600000 0x04040076 0x0a5e005e 0x3 27 >, + < 2342400000 0x0401007a 0x0a620062 0x3 27 >, + < 2323200000 0x04040079 0x0a610061 0x3 28 >, + < 2419200000 0x0401007e 0x0a650065 0x3 28 >, + < 2342400000 0x0404007a 0x0a620062 0x3 29 >, + < 2438400000 0x0401007f 0x0a660066 0x3 29 >, + < 2361600000 0x0404007b 0x0a620062 0x3 30 >, + < 2457600000 0x04010080 0x0a660066 0x3 30 >; }; &msm_cpufreq { @@ -164,11 +268,17 @@ < 1958400 >, < 2035200 >, < 2112000 >, - < 2188800 >, + < 2208000 >, < 2265600 >, + < 2304000 >, + < 2323200 >, < 2342400 >, + < 2361600 >, < 2419200 >, - < 2496000 >; + < 2457600 >, + < 2476800 >, + < 2496000 >, + < 2592000 >; }; &bwmon { @@ -339,34 +449,21 @@ compatible = "qcom,cprh-msm8998-v2-kbss-regulator"; qcom,cpr-corner-switch-delay-time = <1042>; qcom,cpr-aging-ref-voltage = <1056000>; + qcom,apm-threshold-voltage = <800000>; + qcom,apm-hysteresis-voltage = <0>; }; &apc0_pwrcl_vreg { regulator-max-microvolt = <23>; - qcom,cpr-fuse-combos = <16>; - qcom,cpr-speed-bins = <2>; - qcom,cpr-speed-bin-corners = <22 22>; - qcom,cpr-corners = - /* Speed bin 0 */ - <22 22 22 22 22 22 22 22>, - /* Speed bin 1 */ - <22 22 22 22 22 22 22 22>; + qcom,cpr-fuse-combos = <32>; + qcom,cpr-speed-bins = <4>; + qcom,cpr-speed-bin-corners = <22 22 22 22>; + qcom,cpr-corners = <22>; - qcom,cpr-corner-fmax-map = - /* Speed bin 0 */ - <8 11 18 22>, - /* Speed bin 1 */ - <8 11 18 22>; + qcom,cpr-corner-fmax-map = <8 11 18 22>; qcom,cpr-voltage-ceiling = - /* Speed bin 0 */ - <828000 828000 828000 828000 828000 - 828000 828000 828000 828000 828000 - 828000 900000 900000 900000 900000 - 900000 900000 900000 952000 952000 - 1056000 1056000>, - /* Speed bin 1 */ <828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 900000 900000 900000 900000 @@ -374,13 +471,6 @@ 1056000 1056000>; qcom,cpr-voltage-floor = - /* Speed bin 0 */ - <568000 568000 568000 568000 568000 - 568000 568000 568000 568000 568000 - 568000 632000 632000 632000 632000 - 632000 632000 632000 712000 712000 - 772000 772000>, - /* Speed bin 1 */ <568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 632000 632000 632000 632000 @@ -388,32 +478,14 @@ 772000 772000>; qcom,cpr-floor-to-ceiling-max-range = - /* Speed bin 0 */ - <55000 55000 55000 55000 - 55000 55000 55000 55000 - 55000 55000 55000 65000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000>, - /* Speed bin 1 */ - <55000 55000 55000 55000 - 55000 55000 55000 55000 - 55000 55000 55000 65000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000>; + <32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 40000 40000 + 40000 40000>; qcom,corner-frequencies = - /* Speed bin 0 */ - <300000000 364800000 441600000 - 518400000 595200000 672000000 - 748800000 825600000 883200000 - 960000000 1036800000 1094400000 - 1171200000 1248000000 1324800000 - 1401600000 1478400000 1555200000 - 1670400000 1747200000 1824000000 - 1900800000>, - /* Speed bin 1 */ <300000000 364800000 441600000 518400000 595200000 672000000 748800000 825600000 883200000 @@ -439,78 +511,128 @@ qcom,cpr-open-loop-voltage-fuse-adjustment = /* Speed bin 0 */ - <40000 24000 0 30000>, - <40000 24000 0 30000>, - <40000 24000 0 30000>, - <40000 24000 0 30000>, - <25000 9000 (-15000) 15000>, - <25000 9000 (-15000) 15000>, - <25000 9000 (-15000) 15000>, - <25000 9000 (-15000) 15000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, /* Speed bin 1 */ - <40000 24000 0 30000>, - <40000 24000 0 30000>, - <40000 24000 0 30000>, - <40000 24000 0 30000>, - <25000 9000 (-15000) 15000>, - <25000 9000 (-15000) 15000>, - <25000 9000 (-15000) 15000>, - <25000 9000 (-15000) 15000>; + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + /* Speed bin 2 */ + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + /* Speed bin 3 */ + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <40000 24000 12000 30000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>, + <25000 9000 (-3000) 15000>; qcom,cpr-closed-loop-voltage-fuse-adjustment = /* Speed bin 0 */ - <20000 26000 0 30000>, - <20000 26000 0 30000>, - <20000 26000 0 30000>, - <20000 26000 0 30000>, - < 5000 11000 (-15000) 15000>, - < 5000 11000 (-15000) 15000>, - < 5000 11000 (-15000) 15000>, - < 5000 11000 (-15000) 15000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, /* Speed bin 1 */ - <20000 26000 0 30000>, - <20000 26000 0 30000>, - <20000 26000 0 30000>, - <20000 26000 0 30000>, - < 5000 11000 (-15000) 15000>, - < 5000 11000 (-15000) 15000>, - < 5000 11000 (-15000) 15000>, - < 5000 11000 (-15000) 15000>; + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + /* Speed bin 2 */ + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + /* Speed bin 3 */ + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + <20000 26000 12000 30000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>, + < 5000 11000 (-3000) 15000>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; - qcom,cpr-aging-ref-corner = <22 22>; + qcom,cpr-aging-ref-corner = <22>; qcom,cpr-aging-ro-scaling-factor = <1620>; qcom,allow-aging-voltage-adjustment = <0 0 0 0 1 1 1 1>, + <0 0 0 0 1 1 1 1>, + <0 0 0 0 1 1 1 1>, <0 0 0 0 1 1 1 1>; }; &apc1_cpr { compatible = "qcom,cprh-msm8998-v2-kbss-regulator"; qcom,cpr-corner-switch-delay-time = <1042>; - qcom,cpr-aging-ref-voltage = <1056000>; + qcom,cpr-aging-ref-voltage = <1136000>; + qcom,apm-threshold-voltage = <800000>; + qcom,apm-hysteresis-voltage = <0>; + qcom,mem-acc-threshold-voltage = <852000>; + qcom,mem-acc-crossover-voltage = <852000>; }; &apc1_perfcl_vreg { - regulator-max-microvolt = <31>; + regulator-max-microvolt = <34>; - qcom,cpr-fuse-combos = <16>; - qcom,cpr-speed-bins = <2>; - qcom,cpr-speed-bin-corners = <30 26>; + qcom,cpr-fuse-combos = <32>; + qcom,cpr-speed-bins = <4>; + qcom,cpr-speed-bin-corners = <32 26 30 31>; qcom,cpr-corners = /* Speed bin 0 */ - <30 30 30 30 30 30 30 30>, + <32 32 32 32 32 32 32 32>, /* Speed bin 1 */ - <26 26 26 26 26 26 26 26>; + <26 26 26 26 26 26 26 26>, + /* Speed bin 2 */ + <30 30 30 30 30 30 30 30>, + /* Speed bin 3 */ + <31 31 31 31 31 31 31 31>; qcom,cpr-corner-fmax-map = /* Speed bin 0 */ - <8 12 20 30>, + <8 12 20 32>, /* Speed bin 1 */ - <8 12 20 26>; + <8 12 20 26>, + /* Speed bin 2 */ + <8 12 20 30>, + /* Speed bin 3 */ + <8 12 20 31>; qcom,cpr-voltage-ceiling = /* Speed bin 0 */ @@ -518,15 +640,31 @@ 828000 828000 828000 828000 828000 828000 828000 900000 900000 900000 900000 900000 900000 900000 900000 - 952000 952000 952000 1056000 1056000 - 1056000 1056000 1056000 1056000 1056000>, + 952000 952000 952000 1136000 1136000 + 1136000 1136000 1136000 1136000 1136000 + 1136000 1136000>, /* Speed bin 1 */ <828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 900000 900000 900000 900000 900000 900000 900000 900000 - 952000 952000 952000 1056000 1056000 - 1056000>; + 952000 952000 952000 1136000 1136000 + 1136000>, + /* Speed bin 2 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 900000 900000 900000 + 900000 900000 900000 900000 900000 + 952000 952000 952000 1136000 1136000 + 1136000 1136000 1136000 1136000 1136000>, + /* Speed bin 3 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 900000 900000 900000 + 900000 900000 900000 900000 900000 + 952000 952000 952000 1136000 1136000 + 1136000 1136000 1136000 1136000 1136000 + 1136000>; qcom,cpr-voltage-floor = /* Speed bin 0 */ @@ -535,33 +673,67 @@ 568000 568000 632000 632000 632000 632000 632000 632000 632000 632000 712000 712000 712000 772000 772000 - 772000 772000 772000 772000 772000>, + 772000 772000 772000 772000 772000 + 772000 772000>, /* Speed bin 1 */ <568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 632000 632000 632000 632000 632000 632000 632000 632000 712000 712000 712000 772000 772000 + 772000>, + /* Speed bin 2 */ + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 568000 632000 632000 632000 + 632000 632000 632000 632000 632000 + 712000 712000 712000 772000 772000 + 772000 772000 772000 772000 772000>, + /* Speed bin 3 */ + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 568000 632000 632000 632000 + 632000 632000 632000 632000 632000 + 712000 712000 712000 772000 772000 + 772000 772000 772000 772000 772000 772000>; qcom,cpr-floor-to-ceiling-max-range = /* Speed bin 0 */ - <55000 55000 55000 55000 - 55000 55000 55000 55000 - 55000 55000 55000 55000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000>, + <32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 40000 40000 40000 40000 + 40000 40000 40000 40000 + 40000 40000 40000 40000>, /* Speed bin 1 */ - <55000 55000 55000 55000 - 55000 55000 55000 55000 - 55000 55000 55000 55000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000 65000 65000 - 65000 65000>; + <32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 40000 40000 40000 40000 + 40000 40000>, + /* Speed bin 2 */ + <32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 40000 40000 40000 40000 + 40000 40000 40000 40000 + 40000 40000>, + /* Speed bin 3 */ + <32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 32000 32000 32000 32000 + 40000 40000 40000 40000 + 40000 40000 40000 40000 + 40000 40000 40000>; qcom,corner-frequencies = /* Speed bin 0 */ @@ -573,8 +745,9 @@ 1420800000 1497600000 1574400000 1651200000 1728000000 1804800000 1881600000 1958400000 2035200000 - 2112000000 2188800000 2265600000 - 2342400000 2419200000 2496000000>, + 2112000000 2208000000 2265600000 + 2342400000 2419200000 2457600000 + 2476800000 2496000000>, /* Speed bin 1 */ <300000000 345600000 422400000 499200000 576000000 652800000 @@ -584,7 +757,30 @@ 1420800000 1497600000 1574400000 1651200000 1728000000 1804800000 1881600000 1958400000 2035200000 - 2112000000 2208000000>; + 2112000000 2208000000>, + /* Speed bin 2 */ + <300000000 345600000 422400000 + 499200000 576000000 652800000 + 729600000 806400000 902400000 + 979200000 1056000000 1132800000 + 1190400000 1267200000 1344000000 + 1420800000 1497600000 1574400000 + 1651200000 1728000000 1804800000 + 1881600000 1958400000 2035200000 + 2112000000 2208000000 2265600000 + 2323200000 2342400000 2361600000>, + /* Speed bin 3 */ + <300000000 345600000 422400000 + 499200000 576000000 652800000 + 729600000 806400000 902400000 + 979200000 1056000000 1132800000 + 1190400000 1267200000 1344000000 + 1420800000 1497600000 1574400000 + 1651200000 1728000000 1804800000 + 1881600000 1958400000 2035200000 + 2112000000 2208000000 2265600000 + 2323200000 2342400000 2361600000 + 2457600000>; qcom,cpr-ro-scaling-factor = <2857 3057 2828 2952 2699 2798 2446 @@ -602,52 +798,90 @@ qcom,cpr-open-loop-voltage-fuse-adjustment = /* Speed bin 0 */ - < 8000 0 0 52000>, - < 8000 0 0 52000>, - < 8000 0 0 52000>, - < 8000 0 0 52000>, - <(-7000) (-15000) (-15000) 37000>, - <(-7000) (-15000) (-15000) 37000>, - <(-7000) (-15000) (-15000) 37000>, - <(-7000) (-15000) (-15000) 37000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, /* Speed bin 1 */ - < 8000 0 0 52000>, - < 8000 0 0 52000>, - < 8000 0 0 52000>, - < 8000 0 0 52000>, - <(-7000) (-15000) (-15000) 37000>, - <(-7000) (-15000) (-15000) 37000>, - <(-7000) (-15000) (-15000) 37000>, - <(-7000) (-15000) (-15000) 37000>; + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + /* Speed bin 2 */ + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + /* Speed bin 3 */ + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + < 8000 0 12000 52000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>, + <(-7000) (-15000) (-3000) 37000>; qcom,cpr-closed-loop-voltage-fuse-adjustment = /* Speed bin 0 */ - < 0 0 0 50000>, - < 0 0 0 50000>, - < 0 0 0 50000>, - < 0 0 0 50000>, - <(-15000) (-15000) (-15000) 35000>, - <(-15000) (-15000) (-15000) 35000>, - <(-15000) (-15000) (-15000) 35000>, - <(-15000) (-15000) (-15000) 35000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + /* Speed bin 1 */ + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + /* Speed bin 0 */ + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, /* Speed bin 1 */ - < 0 0 0 50000>, - < 0 0 0 50000>, - < 0 0 0 50000>, - < 0 0 0 50000>, - <(-15000) (-15000) (-15000) 35000>, - <(-15000) (-15000) (-15000) 35000>, - <(-15000) (-15000) (-15000) 35000>, - <(-15000) (-15000) (-15000) 35000>; + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + < 0 0 12000 50000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>, + <(-15000) (-15000) (-3000) 35000>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; - qcom,cpr-aging-ref-corner = <30 26>; + qcom,cpr-aging-ref-corner = <32 26 30 31>; qcom,cpr-aging-ro-scaling-factor = <1700>; qcom,allow-aging-voltage-adjustment = <0 0 0 0 1 1 1 1>, + <0 0 0 0 1 1 1 1>, + <0 0 0 0 1 1 1 1>, <0 0 0 0 1 1 1 1>; }; @@ -839,7 +1073,7 @@ &soc { /* Gold L2 SAW */ qcom,spm@178120000 { - qcom,saw2-avs-limit = <0x4200420>; + qcom,saw2-avs-limit = <0x4700470>; }; /* Silver L2 SAW */ diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 7f7f2f65deee..ef488bbe0010 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -1660,6 +1660,10 @@ qcom,pm-qos-cpu-group-latency-us = <70 70>; qcom,pm-qos-default-cpu = <0>; + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + resets = <&clock_gcc UFS_BCR>; reset-names = "core_reset"; @@ -2994,11 +2998,6 @@ vdd-3.3-ch0-supply = <&pm8998_l25_pin_ctrl>; qcom,vdd-0.8-cx-mx-config = <800000 800000>; qcom,vdd-3.3-ch0-config = <3104000 3312000>; - qcom,msm-bus,name = "msm-icnss"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = <81 10065 0 0>, - <81 10065 0 16000>; qcom,icnss-vadc = <&pm8998_vadc>; qcom,icnss-adc_tm = <&pm8998_adc_tm>; }; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi new file mode 100644 index 000000000000..b6b3c1f6245f --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi @@ -0,0 +1,136 @@ +/* + * 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 "msmfalcon-wsa881x.dtsi" + +&slim_aud { + msm_dai_slim { + compatible = "qcom,msm-dai-slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; + + tasha_codec { + compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 a0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk", "wcd_native_clk"; + clocks = <&clock_audio clk_audio_pmi_clk>, + <&clock_audio clk_audio_ap_clk2>; + + cdc-vdd-buck-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmfalcon_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmfalcon_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; + + wcd934x_cdc: tavil_codec { + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb clk_audio_pmi_lnbb_clk>; + + cdc-vdd-buck-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmfalcon_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmfalcon_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmfalcon_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <10>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi index 90aa771332a3..a029d8689111 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi @@ -595,6 +595,67 @@ }; }; + /* WSA speaker reset pins */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + /* HS UART CONFIGURATION */ blsp1_uart1_active: blsp1_uart1_active { mux { diff --git a/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi index cfe968a7310a..0ab76c273ac3 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi @@ -440,6 +440,16 @@ }; }; +&pmfalcon_charger { + smb2_vbus: qcom,smb2-vbus { + regulator-name = "smb2-vbus"; + }; + + smb2_vconn: qcom,smb2-vconn { + regulator-name = "smb2-vconn"; + }; +}; + /* Stub regulators */ / { /* GFX Supply */ diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts index 1840221359e3..2b8a78ee1fdc 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -94,3 +94,20 @@ compatible = "qcom,dummycc"; clock-output-names = "gcc_clocks"; }; + +&pmfalcon_charger { + status = "disabled"; +}; + +&pmfalcon_fg { + status = "disabled"; +}; + +&clock_gfx { + compatible = "qcom,dummycc"; + clock-output-names = "gfx_clocks"; +}; + +&pmfalcon_pdphy { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts index 47759c9ce3ff..d279e742c23a 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts @@ -73,3 +73,15 @@ status = "ok"; }; + +&pmfalcon_charger { + status = "disabled"; +}; + +&pmfalcon_fg { + status = "disabled"; +}; + +&pmfalcon_pdphy { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi new file mode 100644 index 000000000000..73d1cac48f9e --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi @@ -0,0 +1,268 @@ +/* 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 <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/msm/msm-bus-ids.h> +#include <dt-bindings/clock/qcom,gcc-msmfalcon.h> +#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h> + +&soc { + msm_vidc: qcom,vidc@cc00000 { + compatible = "qcom,msm-vidc"; + status = "ok"; + reg = <0xcc00000 0x100000>; + interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; + qcom,hfi = "venus"; + qcom,hfi-version = "3xx"; + qcom,firmware-name = "venus"; + qcom,sw-power-collapse; + qcom,debug-timeout; + qcom,reg-presets = + <0x80124 0x00000003>, + <0x80550 0x01111111>, + <0x80560 0x01111111>, + <0x80568 0x01111111>, + <0x80570 0x01111111>, + <0x80580 0x01111111>, + <0x80588 0x01111111>, + <0xe2010 0x00000000>; + + qcom,max-hw-load = <1036800>; /* Full 4k @ 30 */ + qcom,allowed-clock-rates = + /* TURBO NOM+ NOM + * SVS+ SVS SVS- + */ + <518400000 441600000 404000000 + 320000000 269330000 133330000>; + + qcom,dcvs-tbl = + /* Dec UHD@30 All decoder - NOM to SVS+ */ + <897600 734400 979200 0x3f00000c>, + + /* Dec DCI@24 HEVC - NOM to SVS+ */ + <816000 734400 829440 0x0c000000>, + + /* Enc UHD@30 H264/HEVC - TURBO to NOM+ */ + <897600 897600 979200 0x4000004>; + qcom,dcvs-limit = + <32400 30>, /* Encoder UHD */ + <32400 24>; /* Decoder UHD */ + + /* Regulators */ + smmu-vdd-supply = <&gdsc_bimc_smmu>; + venus-supply = <&gdsc_venus>; + venus-core0-supply = <&gdsc_venus_core0>; + + /* Clocks */ + clock-names = "gcc_mmss_sys_noc_axi_clk", + "mmssnoc_axi_clk", "mmss_mnoc_ahb_clk", + "mmss_bimc_smmu_ahb_clk", "mmss_bimc_smmu_axi_clk", + "mmss_video_core_clk", "mmss_video_ahb_clk", + "mmss_video_axi_clk", + "mmss_video_core0_clk"; + clocks = <&clock_gcc GCC_MMSS_SYS_NOC_AXI_CLK>, + <&clock_gcc MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_VIDEO_CORE_CLK>, + <&clock_mmss MMSS_VIDEO_AHB_CLK>, + <&clock_mmss MMSS_VIDEO_AXI_CLK>, + <&clock_mmss MMSS_VIDEO_SUBCORE0_CLK>; + qcom,clock-configs = <0x0 0x0 0x0 0x0 0x0 + 0x3 0x0 0x2 0x3>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>; + qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>; + qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>; + qcom,bus-governor = "venus-ddr-gov"; + qcom,bus-range-kbps = <1000 2365000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>; + qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + + qcom,clock-freq-tbl { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,cycles-per-mb = <863>; + qcom,low-power-mode-factor = <35616>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xf3ffffff>; + qcom,cycles-per-mb = <355>; + }; + qcom,profile-hevcdec { + qcom,codec-mask = <0x0c000000>; + qcom,cycles-per-mb = <400>; + }; + }; + + venus-ddr-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "venus-ddr-gov"; + status = "ok"; + qcom,bus-freq-table { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,load-busfreq-tbl = + <979200 1044000>, /* UHD30E */ + <864000 887000>, /* 720p240LPE */ + <489600 666000>, /* 1080p60E */ + <432000 578000>, /* 720p120E */ + <244800 346000>, /* 1080p30E */ + <216000 293000>, /* 720p60E */ + <108000 151000>, /* 720p30E */ + <0 0>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,load-busfreq-tbl = + <979200 2365000>, /* UHD30D */ + <864000 1978000>, /* 720p240D */ + <489600 1133000>, /* 1080p60D */ + <432000 994000>, /* 720p120D */ + <244800 580000>, /* 1080p30D */ + <216000 501000>, /* 720p60E */ + <108000 255000>, /* 720p30D */ + <0 0>; + }; + qcom,profile-dec-ubwc { + qcom,codec-mask = <0xffffffff>; + qcom,ubwc-mode; + qcom,load-busfreq-tbl = + <979200 1892000>, /* UHD30D */ + <864000 1554000>, /* 720p240D */ + <489600 895000>, /* 1080p60D */ + <432000 781000>, /* 720p120D */ + <244800 460000>, /* 1080p30D */ + <216000 301000>, /* 720p60E */ + <108000 202000>, /* 720p30D */ + <0 0>; + }; + qcom,profile-dec-ubwc-10bit { + qcom,codec-mask = <0xffffffff>; + qcom,ubwc-10bit; + qcom,load-busfreq-tbl = + <979200 2446336>, /* UHD30D */ + <864000 2108416>, /* 720p240D */ + <489600 1207296>, /* 1080p60D */ + <432000 1058816>, /* 720p120D */ + <244800 616448>, /* 1080p30D */ + <216000 534528>, /* 720p60D */ + <108000 271360>, /* 720p30D */ + <0 0>; + }; + }; + }; + + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&mmss_bimc_smmu 0x400>, + <&mmss_bimc_smmu 0x401>, + <&mmss_bimc_smmu 0x40a>, + <&mmss_bimc_smmu 0x407>, + <&mmss_bimc_smmu 0x40e>, + <&mmss_bimc_smmu 0x40f>, + <&mmss_bimc_smmu 0x408>, + <&mmss_bimc_smmu 0x409>, + <&mmss_bimc_smmu 0x40b>, + <&mmss_bimc_smmu 0x40c>, + <&mmss_bimc_smmu 0x40d>, + <&mmss_bimc_smmu 0x410>, + <&mmss_bimc_smmu 0x421>, + <&mmss_bimc_smmu 0x428>, + <&mmss_bimc_smmu 0x429>, + <&mmss_bimc_smmu 0x42b>, + <&mmss_bimc_smmu 0x42c>, + <&mmss_bimc_smmu 0x42d>, + <&mmss_bimc_smmu 0x411>, + <&mmss_bimc_smmu 0x431>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x8f800000>; + }; + + firmware_cb { + compatible = "qcom,msm-vidc,context-bank"; + qcom,fw-context-bank; + iommus = <&mmss_bimc_smmu 0x580>, + <&mmss_bimc_smmu 0x586>; + }; + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&mmss_bimc_smmu 0x500>, + <&mmss_bimc_smmu 0x502>, + <&mmss_bimc_smmu 0x509>, + <&mmss_bimc_smmu 0x50a>, + <&mmss_bimc_smmu 0x50b>, + <&mmss_bimc_smmu 0x50e>, + <&mmss_bimc_smmu 0x526>, + <&mmss_bimc_smmu 0x529>, + <&mmss_bimc_smmu 0x52b>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x25800000>; + qcom,secure-context-bank; + }; + + venus_secure_pixel_cb: secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&mmss_bimc_smmu 0x504>, + <&mmss_bimc_smmu 0x50c>, + <&mmss_bimc_smmu 0x510>, + <&mmss_bimc_smmu 0x52c>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + venus_secure_non_pixel_cb: secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&mmss_bimc_smmu 0x505>, + <&mmss_bimc_smmu 0x507>, + <&mmss_bimc_smmu 0x508>, + <&mmss_bimc_smmu 0x50d>, + <&mmss_bimc_smmu 0x50f>, + <&mmss_bimc_smmu 0x525>, + <&mmss_bimc_smmu 0x528>, + <&mmss_bimc_smmu 0x52d>, + <&mmss_bimc_smmu 0x540>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi new file mode 100644 index 000000000000..29f4ccaede9f --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi @@ -0,0 +1,183 @@ +/* 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. + */ + +&slim_aud { + tasha_codec { + wsa_spkr_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + }; + + tavil_codec { + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctrl"; + qcom,num-gpios = <5>; + gpio-controller; + #gpio-cells = <2>; + + us_euro_sw_wcd_active: us_euro_sw_wcd_active { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-high; + }; + }; + + us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-low; + }; + }; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + + spkr_2_wcd_en_active: spkr_2_sd_n_active { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + output-high; + }; + }; + + spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + input-enable; + }; + }; + + hph_en0_wcd_active: hph_en0_wcd_active { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-high; + }; + }; + + hph_en0_wcd_sleep: hph_en0_wcd_sleep { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-low; + }; + }; + + hph_en1_wcd_active: hph_en1_wcd_active { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-high; + }; + }; + + hph_en1_wcd_sleep: hph_en1_wcd_sleep { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-low; + }; + }; + }; + + wsa_spkr_wcd_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_wcd_en_active>; + pinctrl-1 = <&spkr_1_wcd_en_sleep>; + }; + + wsa_spkr_wcd_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_wcd_en_active>; + pinctrl-1 = <&spkr_2_wcd_en_sleep>; + }; + + tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&us_euro_sw_wcd_active>; + pinctrl-1 = <&us_euro_sw_wcd_sleep>; + }; + + tavil_hph_en0: msm_cdc_pinctrl_hph_en0 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en0_wcd_active>; + pinctrl-1 = <&hph_en0_wcd_sleep>; + }; + + tavil_hph_en1: msm_cdc_pinctrl_hph_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en1_wcd_active>; + pinctrl-1 = <&hph_en1_wcd_sleep>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi new file mode 100644 index 000000000000..123f922facdd --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi @@ -0,0 +1,79 @@ +/* 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 "msmfalcon-wcd.dtsi" + +&slim_aud { + tasha_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd1>; + }; + + wsa881x_212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd2>; + }; + + wsa881x_213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd1>; + }; + + wsa881x_214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd2>; + }; + }; + }; + + tavil_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 23d3043fcc3b..6ef443c4de11 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -47,6 +47,8 @@ compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; + qcom,ea = <&ea0>; }; CPU1: cpu@1 { @@ -54,6 +56,8 @@ compatible = "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; + qcom,ea = <&ea1>; }; CPU2: cpu@2 { @@ -61,6 +65,8 @@ compatible = "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; + qcom,ea = <&ea2>; }; CPU3: cpu@3 { @@ -68,6 +74,8 @@ compatible = "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; + qcom,ea = <&ea3>; }; CPU4: cpu@100 { @@ -75,6 +83,8 @@ compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile1>; + qcom,ea = <&ea4>; }; CPU5: cpu@101 { @@ -82,6 +92,8 @@ compatible = "arm,armv8"; reg = <0x0 0x101>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile2>; + qcom,ea = <&ea5>; }; CPU6: cpu@102 { @@ -89,6 +101,8 @@ compatible = "arm,armv8"; reg = <0x0 0x102>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile3>; + qcom,ea = <&ea6>; }; CPU7: cpu@103 { @@ -96,6 +110,8 @@ compatible = "arm,armv8"; reg = <0x0 0x103>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile4>; + qcom,ea = <&ea7>; }; cpu-map { @@ -265,6 +281,13 @@ qcom,summing-threshold = <0x10>; }; + restart@10ac000 { + compatible = "qcom,pshold"; + reg = <0x10ac000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + spmi_bus: qcom,spmi@800f000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x800f000 0x1000>, @@ -351,6 +374,219 @@ clock-names = "core", "iface"; }; + qcom,sensor-information { + compatible = "qcom,sensor-information"; + sensor_information0: qcom,sensor-information-0 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor0"; + qcom,scaling-factor = <10>; + }; + sensor_information1: qcom,sensor-information-1 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor1"; + qcom,scaling-factor = <10>; + }; + sensor_information2: qcom,sensor-information-2 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor2"; + qcom,scaling-factor = <10>; + }; + sensor_information3: qcom,sensor-information-3 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor3"; + qcom,scaling-factor = <10>; + }; + sensor_information4: qcom,sensor-information-4 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor4"; + qcom,scaling-factor = <10>; + }; + sensor_information5: qcom,sensor-information-5 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor5"; + qcom,scaling-factor = <10>; + }; + sensor_information6: qcom,sensor-information-6 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor6"; + qcom,scaling-factor = <10>; + }; + sensor_information7: qcom,sensor-information-7 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor7"; + qcom,scaling-factor = <10>; + }; + sensor_information8: qcom,sensor-information-8 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor8"; + qcom,scaling-factor = <10>; + qcom,alias-name = "gpu"; + }; + sensor_information9: qcom,sensor-information-9 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor9"; + qcom,scaling-factor = <10>; + }; + sensor_information10: qcom,sensor-information-10 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor10"; + qcom,scaling-factor = <10>; + }; + sensor_information11: qcom,sensor-information-11 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor11"; + qcom,scaling-factor = <10>; + }; + sensor_information12: qcom,sensor-information-12 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor12"; + qcom,scaling-factor = <10>; + }; + sensor_information13: qcom,sensor-information-13 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor13"; + qcom,scaling-factor = <10>; + }; + sensor_information14: qcom,sensor-information-14 { + qcom,sensor-type = "alarm"; + qcom,sensor-name = "pmfalcon_tz"; + qcom,scaling-factor = <1000>; + }; + sensor_information15: qcom,sensor-information-15 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "msm_therm"; + }; + sensor_information16: qcom,sensor-information-16 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "xo_therm"; + }; + sensor_information17: qcom,sensor-information-17 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "pa_therm0"; + }; + sensor_information18: qcom,sensor-information-18 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "pa_therm1"; + }; + sensor_information19: qcom,sensor-information-19 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "quiet_therm"; + }; + sensor_information20: qcom,sensor-information-20 { + qcom,sensor-type = "llm"; + qcom,sensor-name = "limits_sensor-00"; + }; + sensor_information21: qcom,sensor-information-21 { + qcom,sensor-type = "llm"; + qcom,sensor-name = "limits_sensor-01"; + }; + }; + + mitigation_profile0: qcom,limit_info-0 { + qcom,temperature-sensor = <&sensor_information1>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile1: qcom,limit_info-1 { + qcom,temperature-sensor = <&sensor_information3>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile2: qcom,limit_info-2 { + qcom,temperature-sensor = <&sensor_information4>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile3: qcom,limit_info-3 { + qcom,temperature-sensor = <&sensor_information5>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile4: qcom,limit_info-4 { + qcom,temperature-sensor = <&sensor_information6>; + qcom,hotplug-mitigation-enable; + }; + + qcom,msm-thermal { + compatible = "qcom,msm-thermal"; + qcom,sensor-id = <1>; + qcom,poll-ms = <100>; + qcom,therm-reset-temp = <115>; + qcom,core-limit-temp = <70>; + qcom,core-temp-hysteresis = <10>; + qcom,hotplug-temp = <105>; + qcom,hotplug-temp-hysteresis = <20>; + qcom,online-hotplug-core; + qcom,synchronous-cluster-id = <0 1>; + qcom,synchronous-cluster-map = <0 4 &CPU0 &CPU1 &CPU2 &CPU3>, + <1 4 &CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,vdd-restriction-temp = <5>; + qcom,vdd-restriction-temp-hysteresis = <10>; + + vdd-dig-supply = <&pm2falcon_s3_floor_level>; + vdd-gfx-supply = <&gfx_vreg_corner>; + + qcom,vdd-dig-rstr{ + qcom,vdd-rstr-reg = "vdd-dig"; + qcom,levels = <RPM_SMD_REGULATOR_LEVEL_NOM + RPM_SMD_REGULATOR_LEVEL_TURBO + RPM_SMD_REGULATOR_LEVEL_TURBO>; + qcom,min-level = <RPM_SMD_REGULATOR_LEVEL_NONE>; + }; + + qcom,vdd-gfx-rstr{ + qcom,vdd-rstr-reg = "vdd-gfx"; + qcom,levels = <5 6 6>; /* Nominal, Turbo, Turbo */ + qcom,min-level = <1>; /* No Request */ + }; + + msm_thermal_freq: qcom,vdd-apps-rstr{ + qcom,vdd-rstr-reg = "vdd-apps"; + qcom,levels = <1248000>; + qcom,freq-req; + }; + }; + + qcom,msm-core@780000 { + compatible = "qcom,apss-core-ea"; + reg = <0x780000 0x1000>; + qcom,low-hyst-temp = <10>; + qcom,high-hyst-temp = <5>; + + ea0: ea0 { + sensor = <&sensor_information1>; + }; + + ea1: ea1 { + sensor = <&sensor_information1>; + }; + + ea2: ea2 { + sensor = <&sensor_information1>; + }; + + ea3: ea3 { + sensor = <&sensor_information1>; + }; + + ea4: ea4 { + sensor = <&sensor_information3>; + }; + + ea5: ea5 { + sensor = <&sensor_information4>; + }; + + ea6: ea6 { + sensor = <&sensor_information5>; + }; + + ea7: ea7 { + sensor = <&sensor_information6>; + }; + }; + uartblsp2dm1: serial@0c1b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xc1b0000 0x1000>; @@ -467,8 +703,21 @@ }; clock_gfx: clock-controller@5065000 { - compatible = "qcom,dummycc"; - clock-output-names = "gfx_clocks"; + compatible = "qcom,gpucc-msmfalcon"; + reg = <0x5065000 0x10000>; + vdd_dig_gfx-supply = <&pm2falcon_s3_level>; + vdd_mx_gfx-supply = <&pm2falcon_s5_level>; + vdd_gfx-supply = <&gfx_vreg_corner>; + qcom,gfxfreq-corner = + < 0 0>, + < 160000000 1>, /* MinSVS */ + < 266000000 2>, /* LowSVS */ + < 370000000 3>, /* SVS */ + < 465000000 4>, /* SVS_L1 */ + < 588000000 5>, /* NOM */ + < 647000000 6>, /* NOM_L1 */ + < 700000000 7>, /* TURBO */ + < 750000000 7>; /* TURBO */ #clock-cells = <1>; #reset-cells = <1>; }; @@ -493,6 +742,72 @@ status = "disabled"; }; + ipa_hw: qcom,ipa@14780000 { + compatible = "qcom,ipa"; + reg = <0x14780000 0x4effc>, <0x14784000 0x26934>; + reg-names = "ipa-base", "bam-base"; + interrupts = <0 333 0>, + <0 432 0>; + interrupt-names = "ipa-irq", "bam-irq"; + qcom,ipa-hw-ver = <6>; /* IPA core version = IPAv2.6L */ + qcom,ipa-hw-mode = <0>; /* IPA hw type = Normal */ + qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/ + qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/ + clocks = <&clock_rpmcc RPM_IPA_CLK>, + <&clock_rpmcc RPM_AGGR2_NOC_CLK>; + clock-names = "core_clk", "smmu_clk"; + qcom,arm-smmu; + qcom,smmu-disable-htw; + qcom,smmu-s1-bypass; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <90 512 0 0>, + <1 676 0 0>, + /* SVS */ + <90 512 80000 640000>, + <1 676 80000 80000>, + /* NOMINAL */ + <90 512 206000 960000>, + <1 676 206000 160000>, + /* TURBO */ + <90 512 206000 960000>, + <1 676 206000 160000>; + qcom,bus-vector-names = "MIN", "SVS", "PERF", "TURBO"; + qcom,rx-polling-sleep-ms = <2>; /* Polling sleep interval */ + qcom,ipa-polling-iteration = <5>; /* Polling Iteration */ + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&anoc2_smmu 0x19C0>; + qcom,iova-mapping = <0x10000000 0x40000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + status = "disabled"; + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&anoc2_smmu 0x19C1>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&anoc2_smmu 0x19C2>; + qcom,iova-mapping = <0x40000000 0x20000000>; + }; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa"; + qcom,rmnet-ipa-ssr; + qcom,ipa-loaduC; + qcom,ipa-advertise-sg-support; + }; + qcom,ipc-spinlock@1f40000 { compatible = "qcom,ipc-spinlock-sfpb"; reg = <0x1f40000 0x8000>; @@ -877,6 +1192,17 @@ status = "ok"; }; + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,mpm2-sleep-counter@10a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x10a3000 0x1000>; + clock-frequency = <32768>; + }; + qcom,msm-imem@146bf000 { compatible = "qcom,msm-imem"; reg = <0x146bf000 0x1000>; @@ -884,6 +1210,21 @@ #address-cells = <1>; #size-cells = <1>; + dload_type@18 { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x18 4>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + pil@94c { compatible = "qcom,msm-imem-pil"; reg = <0x94c 200>; @@ -906,18 +1247,52 @@ clock-names = "atb_clk"; clocks = <&clock_rpmcc RPM_QDSS_CLK>; }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 6 4>; + }; + + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 0x2200000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 200000 400000>, + <55 512 300000 800000>, + <55 512 400000 1000000>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc QSEECOM_CE1_CLK>, + <&clock_gcc QSEECOM_CE1_CLK>, + <&clock_gcc QSEECOM_CE1_CLK>, + <&clock_gcc QSEECOM_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,qsee-reentrancy-support = <2>; + }; }; #include "msmfalcon-ion.dtsi" #include "msmfalcon-bus.dtsi" +#include "msm-pmfalcon.dtsi" +#include "msm-pm2falcon.dtsi" #include "msm-pmfalcon-rpm-regulator.dtsi" #include "msm-pm2falcon-rpm-regulator.dtsi" #include "msmfalcon-regulator.dtsi" #include "msm-gdsc-falcon.dtsi" &gdsc_usb30 { - clock-names = "core_clk"; - clocks = <&clock_gcc GCC_USB30_MASTER_CLK>; status = "ok"; }; @@ -974,19 +1349,14 @@ }; &gdsc_mdss { - clock-names = "bus_clk", "rot_clk"; - clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>, - <&clock_mmss MMSS_MDSS_ROT_CLK>; proxy-supply = <&gdsc_mdss>; qcom,proxy-consumer-enable; status = "ok"; }; &gdsc_gpu_gx { - clock-names = "bimc_core_clk", "core_clk", "core_root_clk"; - clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>, - <&clock_gfx GPUCC_GFX3D_CLK>, - <&clock_gfx GFX3D_CLK_SRC>; + clock-names = "core_root_clk"; + clocks = <&clock_gfx GFX3D_CLK_SRC>; qcom,force-enable-root-clk; parent-supply = <&gfx_vreg_corner>; status = "ok"; @@ -996,9 +1366,8 @@ status = "ok"; }; -#include "msm-pmfalcon.dtsi" -#include "msm-pm2falcon.dtsi" #include "msm-arm-smmu-falcon.dtsi" #include "msm-arm-smmu-impl-defs-falcon.dtsi" #include "msmfalcon-common.dtsi" #include "msmfalcon-blsp.dtsi" +#include "msmfalcon-vidc.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts index 08809fb38cae..491b55aab9a6 100644 --- a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts @@ -63,3 +63,8 @@ compatible = "qcom,dummycc"; clock-output-names = "gcc_clocks"; }; + +&clock_gfx { + compatible = "qcom,dummycc"; + clock-output-names = "gfx_clocks"; +}; diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi index cd751f3181ee..2a22772c8d1d 100644 --- a/arch/arm/boot/dts/qcom/msmtriton.dtsi +++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi @@ -241,6 +241,13 @@ clock-frequency = <19200000>; }; + restart@10ac000 { + compatible = "qcom,pshold"; + reg = <0x10ac000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + qcom,sps { compatible = "qcom,msm_sps_4k"; qcom,pipe-attr-ee; @@ -382,8 +389,21 @@ }; clock_gfx: clock-controller@5065000 { - compatible = "qcom,dummycc"; - clock-output-names = "gfx_clocks"; + compatible = "qcom,gpucc-msmfalcon"; + reg = <0x5065000 0x10000>; + vdd_dig_gfx-supply = <&pm2falcon_s3_level>; + vdd_mx_gfx-supply = <&pm2falcon_s5_level>; + vdd_gfx-supply = <&gfx_vreg_corner>; + qcom,gfxfreq-corner = + < 0 0>, + < 160000000 1>, /* MinSVS */ + < 266000000 2>, /* LowSVS */ + < 370000000 3>, /* SVS */ + < 465000000 4>, /* SVS_L1 */ + < 588000000 5>, /* NOM */ + < 647000000 6>, /* NOM_L1 */ + < 700000000 7>, /* TURBO */ + < 750000000 7>; /* TURBO */ #clock-cells = <1>; #reset-cells = <1>; }; @@ -698,6 +718,17 @@ status = "ok"; }; + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,mpm2-sleep-counter@10a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x10a3000 0x1000>; + clock-frequency = <32768>; + }; + qcom,msm-imem@146bf000 { compatible = "qcom,msm-imem"; reg = <0x146bf000 0x1000>; @@ -705,6 +736,21 @@ #address-cells = <1>; #size-cells = <1>; + dload_type@18 { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x18 4>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + pil@94c { compatible = "qcom,msm-imem-pil"; reg = <0x94c 200>; @@ -727,6 +773,12 @@ clock-names = "atb_clk"; clocks = <&clock_rpmcc RPM_QDSS_CLK>; }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 6 4>; + }; }; #include "msmtriton-ion.dtsi" @@ -735,8 +787,6 @@ #include "msmfalcon-common.dtsi" &gdsc_usb30 { - clock-names = "core_clk"; - clocks = <&clock_gcc GCC_USB30_MASTER_CLK>; status = "ok"; }; @@ -785,19 +835,14 @@ }; &gdsc_mdss { - clock-names = "bus_clk", "rot_clk"; - clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>, - <&clock_mmss MMSS_MDSS_ROT_CLK>; proxy-supply = <&gdsc_mdss>; qcom,proxy-consumer-enable; status = "ok"; }; &gdsc_gpu_gx { - clock-names = "bimc_core_clk", "core_clk", "core_root_clk"; - clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>, - <&clock_gfx GPUCC_GFX3D_CLK>, - <&clock_gfx GFX3D_CLK_SRC>; + clock-names = "core_root_clk"; + clocks = <&clock_gfx GFX3D_CLK_SRC>; qcom,force-enable-root-clk; parent-supply = <&gfx_vreg_corner>; status = "ok"; diff --git a/arch/arm/configs/msmfalcon-perf_defconfig b/arch/arm/configs/msmfalcon-perf_defconfig new file mode 100644 index 000000000000..1f8d22153a32 --- /dev/null +++ b/arch/arm/configs/msmfalcon-perf_defconfig @@ -0,0 +1,607 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_HMP_CSTATE_AWARE=y +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 +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSMFALCON=y +CONFIG_ARCH_MSMTRITON=y +CONFIG_ARM_KERNMEM_PERMS=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +# CONFIG_CPU_FREQ_STAT is not set +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BTFM_SLIM=y +CONFIG_BTFM_SLIM_WCN3990=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=40 +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_HDCP_QSEECOM=y +CONFIG_UID_CPUTIME=y +CONFIG_MSM_ULTRASOUND=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_RNDIS_IPA=y +CONFIG_PHYLIB=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_ATH_CARDS=y +CONFIG_CLD_LL_CORE=y +CONFIG_QPNP_POWER_ON=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_SECURE_TOUCH=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SLIMBUS=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_PINCTRL_MSMFALCON=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_APSS_CORE_EA=y +CONFIG_MSM_APM=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_BATTERY_BCL=y +CONFIG_QPNP_SMB2=y +CONFIG_SMB138X_CHARGER=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LIMITS_LITE_HW=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_QCOM_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MSM_CDC_PINCTRL=y +CONFIG_MSM_CDC_SUPPLY=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR3_HMSS=y +CONFIG_REGULATOR_CPR3_MMSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_CAMERA=y +CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_QCOM_KGSL=y +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_DP_PANEL=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_SWITCH=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_COINCELL=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_GPIO_USB_DETECT=y +CONFIG_SEEMP_CORE=y +CONFIG_USB_BAM=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_MSM_GCC_FALCON=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_COMMON_LOG=y +CONFIG_MSM_SMEM=y +CONFIG_QPNP_HAPTIC=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMD_XPRT=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_QCOM_DCC=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_IRQ_HELPER=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_ICNSS=y +CONFIG_MSM_GLADIATOR_ERP_V2=y +CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_MSM_QDSP6_APRV2_GLINK=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_TRACER_PKT=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_AVTIMER=y +CONFIG_QCOM_REMOTEQDSS=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_PM_DEVFREQ_EVENT=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 +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_SENSORS_SSC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_DEBUG=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +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 +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_FUNCTION_TRACER=y +CONFIG_TRACER_SNAPSHOT=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_LINKS_AND_SINKS=y +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_QPDI=y +CONFIG_CORESIGHT_SOURCE_DUMMY=y +CONFIG_PFK=y +CONFIG_SECURITY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_XZ_DEC=y diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig index 8039441cc972..06faf702156f 100644 --- a/arch/arm/configs/msmfalcon_defconfig +++ b/arch/arm/configs/msmfalcon_defconfig @@ -6,16 +6,22 @@ CONFIG_IRQ_TIME_ACCOUNTING=y 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 CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y +CONFIG_SCHED_HMP_CSTATE_AWARE=y +CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set +CONFIG_SCHED_TUNE=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set @@ -32,6 +38,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y @@ -39,6 +46,7 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSMFALCON=y CONFIG_ARCH_MSMTRITON=y +CONFIG_ARM_KERNMEM_PERMS=y CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 @@ -49,6 +57,7 @@ CONFIG_HIGHMEM=y # CONFIG_HIGHPTE is not set CONFIG_CLEANCACHE=y CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y @@ -239,6 +248,8 @@ CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_NETDEVICES=y @@ -250,9 +261,15 @@ CONFIG_PHYLIB=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y CONFIG_CLD_LL_CORE=y @@ -265,6 +282,7 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_SECURE_TOUCH=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_KEYCHORD=y @@ -277,6 +295,7 @@ CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y @@ -289,10 +308,13 @@ CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y -CONFIG_PINCTRL_MSM8998=y CONFIG_PINCTRL_MSMFALCON=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_SYSCON=y CONFIG_APSS_CORE_EA=y CONFIG_MSM_APM=y CONFIG_QPNP_SMBCHARGER=y @@ -300,10 +322,19 @@ CONFIG_SMB135X_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y CONFIG_MSM_BCL_CTL=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_BATTERY_BCL=y CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LIMITS_LITE_HW=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_QCOM_THERMAL_LIMITS_DCVS=y CONFIG_MFD_SPMI_PMIC=y CONFIG_MFD_I2C_PMIC=y CONFIG_MSM_CDC_PINCTRL=y @@ -329,7 +360,10 @@ CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_CAMERA=y CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSM_VIDC_V4L2=m +CONFIG_MSM_VIDC_GOVERNORS=m CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y @@ -345,10 +379,16 @@ CONFIG_LOGO=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -359,6 +399,8 @@ CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y CONFIG_USB_OTG_WAKELOCK=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -367,12 +409,14 @@ CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_MTP=y CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_F_ACC=y CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_GSI=y @@ -392,6 +436,7 @@ CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_SYSCON=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_CPU=y @@ -420,9 +465,10 @@ CONFIG_GSI=y CONFIG_IPA3=y CONFIG_RMNET_IPA3=y CONFIG_GPIO_USB_DETECT=y +CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_QCOM_CLK_SMD_RPM=y -CONFIG_MSM_GCC_FALCON=y +CONFIG_MSM_GPUCC_FALCON=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y @@ -438,6 +484,7 @@ CONFIG_MSM_GLINK_LOOPBACK_SERVER=y CONFIG_MSM_GLINK_SMD_XPRT=y CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPSS_UTILS=y CONFIG_MSM_SMEM_LOGGING=y CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y @@ -464,6 +511,7 @@ CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_MSM_QDSP6_APRV2_GLINK=y +CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y @@ -473,15 +521,25 @@ CONFIG_TRACER_PKT=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_AVTIMER=y CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=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 @@ -493,6 +551,9 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -509,6 +570,8 @@ CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_SLUB_DEBUG_PANIC_ON=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_FREE=y @@ -542,8 +605,10 @@ CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_IPC_LOGGING=y CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y CONFIG_FUNCTION_TRACER=y -CONFIG_TRACER_SNAPSHOT=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_MEMTEST=y @@ -551,13 +616,19 @@ CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_LINKS_AND_SINKS=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y +CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y @@ -571,4 +642,5 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_XZ_DEC=y diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index cbccbeb483c9..a4fba1af7744 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -2,7 +2,7 @@ if ARCH_QCOM menu "QCOM SoC Type" config ARCH_MSMFALCON - bool "Enable Support for Qualcomm MSMFALCON" + bool "Enable Support for MSMFALCON" select CLKDEV_LOOKUP select HAVE_CLK select HAVE_CLK_PREPARE @@ -40,7 +40,7 @@ config ARCH_MSMFALCON wish to build a kernel that runs on this chipset, say 'N' here. config ARCH_MSMTRITON - bool "Enable Support for Qualcomm MSMTRITON" + bool "Enable Support for MSMTRITON" select CLKDEV_LOOKUP select HAVE_CLK select HAVE_CLK_PREPARE diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig index 54925c6bcf4e..1074672d252f 100644 --- a/arch/arm64/configs/msmfalcon-perf_defconfig +++ b/arch/arm64/configs/msmfalcon-perf_defconfig @@ -489,7 +489,7 @@ CONFIG_GPIO_USB_DETECT=y CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_QCOM_CLK_SMD_RPM=y -CONFIG_MSM_GCC_FALCON=y +CONFIG_MSM_GPUCC_FALCON=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig index 820385a0217a..6d8d9eeab2d5 100644 --- a/arch/arm64/configs/msmfalcon_defconfig +++ b/arch/arm64/configs/msmfalcon_defconfig @@ -498,7 +498,7 @@ CONFIG_GPIO_USB_DETECT=y CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_QCOM_CLK_SMD_RPM=y -CONFIG_MSM_GCC_FALCON=y +CONFIG_MSM_GPUCC_FALCON=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 55b944a913cb..7326be306618 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -283,7 +283,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, if (esr & ESR_LNX_EXEC) { vm_flags = VM_EXEC; - } else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) { + } else if (((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) || + ((esr & ESR_ELx_CM) && !(mm_flags & FAULT_FLAG_USER))) { vm_flags = VM_WRITE; mm_flags |= FAULT_FLAG_WRITE; } diff --git a/block/genhd.c b/block/genhd.c index 817c67c9e45e..82bc52cad1c1 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -831,6 +831,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v) if (iter) { class_dev_iter_exit(iter); kfree(iter); + seqf->private = NULL; } } diff --git a/block/ioprio.c b/block/ioprio.c index cc7800e9eb44..01b8116298a1 100644 --- a/block/ioprio.c +++ b/block/ioprio.c @@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p) if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); + task_lock(p); if (p->io_context) ret = p->io_context->ioprio; + task_unlock(p); out: return ret; } diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 0111b02634c8..876b455624b2 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1275,6 +1275,7 @@ static uint8_t hdlc_reset; static void hdlc_reset_timer_start(struct diag_md_session_t *info) { + mutex_lock(&driver->md_session_lock); if (!hdlc_timer_in_progress) { hdlc_timer_in_progress = 1; if (info) @@ -1284,6 +1285,7 @@ static void hdlc_reset_timer_start(struct diag_md_session_t *info) mod_timer(&driver->hdlc_reset_timer, jiffies + msecs_to_jiffies(200)); } + mutex_unlock(&driver->md_session_lock); } static void hdlc_reset_timer_func(unsigned long data) diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index c78a5f4fbe74..9c9d000c94db 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -989,8 +989,6 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info) } if (fwd_info->buf_1 && !atomic_read(&fwd_info->buf_1->in_busy)) { - temp_buf = fwd_info->buf_1; - atomic_set(&temp_buf->in_busy, 1); if (driver->feature[fwd_info->peripheral].encode_hdlc && (fwd_info->type == TYPE_DATA || fwd_info->type == TYPE_CMD)) { @@ -1000,9 +998,11 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info) read_buf = fwd_info->buf_1->data; read_len = fwd_info->buf_1->len; } + if (read_buf) { + temp_buf = fwd_info->buf_1; + atomic_set(&temp_buf->in_busy, 1); + } } else if (fwd_info->buf_2 && !atomic_read(&fwd_info->buf_2->in_busy)) { - temp_buf = fwd_info->buf_2; - atomic_set(&temp_buf->in_busy, 1); if (driver->feature[fwd_info->peripheral].encode_hdlc && (fwd_info->type == TYPE_DATA || fwd_info->type == TYPE_CMD)) { @@ -1012,6 +1012,10 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info) read_buf = fwd_info->buf_2->data; read_len = fwd_info->buf_2->len; } + if (read_buf) { + temp_buf = fwd_info->buf_2; + atomic_set(&temp_buf->in_busy, 1); + } } else { pr_debug("diag: In %s, both buffers are empty for p: %d, t: %d\n", __func__, fwd_info->peripheral, fwd_info->type); diff --git a/drivers/char/diag/diagfwd_smd.c b/drivers/char/diag/diagfwd_smd.c index 12069df1224d..f0698f0814d6 100644 --- a/drivers/char/diag/diagfwd_smd.c +++ b/drivers/char/diag/diagfwd_smd.c @@ -765,14 +765,13 @@ static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len) } /* - * In this case don't reset the buffers as there is no need to further - * read over peripherals. Also release the wake source hold earlier. + * Reset the buffers. Also release the wake source hold earlier. */ if (atomic_read(&smd_info->diag_state) == 0) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s closing read thread. diag state is closed\n", smd_info->name); - diag_ws_release(); + diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0); return 0; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 25ab30063072..c1865f9ee8b3 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -825,6 +825,9 @@ static void clk_core_unprepare(struct clk_core *core) if (WARN_ON(core->prepare_count == 0)) return; + if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL)) + return; + if (--core->prepare_count > 0) return; @@ -940,6 +943,9 @@ static void clk_core_disable(struct clk_core *core) if (WARN_ON(core->enable_count == 0)) return; + if (WARN_ON(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL)) + return; + if (--core->enable_count > 0) return; @@ -3121,6 +3127,16 @@ static int __clk_init(struct device *dev, struct clk *clk_user) if (core->ops->init) core->ops->init(core->hw); + if (core->flags & CLK_IS_CRITICAL) { + unsigned long flags; + + clk_core_prepare(core); + + flags = clk_enable_lock(); + clk_core_enable(core); + clk_enable_unlock(flags); + } + kref_init(&core->ref); out: clk_prepare_unlock(); @@ -3853,6 +3869,41 @@ static int parent_ready(struct device_node *np) } /** + * of_clk_detect_critical() - set CLK_IS_CRITICAL flag from Device Tree + * @np: Device node pointer associated with clock provider + * @index: clock index + * @flags: pointer to clk_core->flags + * + * Detects if the clock-critical property exists and, if so, sets the + * corresponding CLK_IS_CRITICAL flag. + * + * Do not use this function. It exists only for legacy Device Tree + * bindings, such as the one-clock-per-node style that are outdated. + * Those bindings typically put all clock data into .dts and the Linux + * driver has no clock data, thus making it impossible to set this flag + * correctly from the driver. Only those drivers may call + * of_clk_detect_critical from their setup functions. + * + * Return: error code or zero on success + */ +int of_clk_detect_critical(struct device_node *np, + int index, unsigned long *flags) +{ + struct property *prop; + const __be32 *cur; + uint32_t idx; + + if (!np || !flags) + return -EINVAL; + + of_property_for_each_u32(np, "clock-critical", prop, cur, idx) + if (index == idx) + *flags |= CLK_IS_CRITICAL; + + return 0; +} + +/** * of_clk_init() - Scan and init clock providers from the DT * @matches: array of compatible values and init functions for providers. * diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index b9e977088126..9ce6a1430250 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -85,7 +85,9 @@ enum clk_osm_trace_packet_id { #define OSM_TABLE_SIZE 40 #define MAX_CLUSTER_CNT 2 -#define MAX_CONFIG 4 +#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16) +#define SINGLE_CORE 1 +#define MAX_CORE_COUNT 4 #define LLM_SW_OVERRIDE_CNT 3 #define ENABLE_REG 0x1004 @@ -357,6 +359,8 @@ struct clk_osm { u32 irq; u32 apm_crossover_vc; u32 apm_threshold_vc; + u32 mem_acc_crossover_vc; + u32 mem_acc_threshold_vc; u32 cycle_counter_reads; u32 cycle_counter_delay; u32 cycle_counter_factor; @@ -642,11 +646,25 @@ static long clk_osm_round_rate(struct clk *c, unsigned long rate) static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) { - int i; + int quad_core_index, single_core_index = 0; + int core_count; + + for (quad_core_index = 0; quad_core_index < entries; + quad_core_index++) { + core_count = + CORE_COUNT_VAL(table[quad_core_index].freq_data); + if (rate == table[quad_core_index].frequency && + core_count == SINGLE_CORE) { + single_core_index = quad_core_index; + continue; + } + if (rate == table[quad_core_index].frequency && + core_count == MAX_CORE_COUNT) + return quad_core_index; + } + if (single_core_index) + return single_core_index; - for (i = 0; i < entries; i++) - if (rate == table[i].frequency) - return i; return -EINVAL; } @@ -829,6 +847,8 @@ static void clk_osm_print_osm_table(struct clk_osm *c) } pr_debug("APM threshold corner=%d, crossover corner=%d\n", c->apm_threshold_vc, c->apm_crossover_vc); + pr_debug("MEM-ACC threshold corner=%d, crossover corner=%d\n", + c->mem_acc_threshold_vc, c->mem_acc_crossover_vc); } static int clk_osm_get_lut(struct platform_device *pdev, @@ -839,8 +859,10 @@ static int clk_osm_get_lut(struct platform_device *pdev, int prop_len, total_elems, num_rows, i, j, k; int rc = 0; u32 *array; + u32 *fmax_temp; u32 data; bool last_entry = false; + unsigned long abs_fmax = 0; if (!of_find_property(of, prop_name, &prop_len)) { dev_err(&pdev->dev, "missing %s\n", prop_name); @@ -855,9 +877,9 @@ static int clk_osm_get_lut(struct platform_device *pdev, num_rows = total_elems / NUM_FIELDS; - clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long), - GFP_KERNEL); - if (!clk->fmax) + fmax_temp = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long), + GFP_KERNEL); + if (!fmax_temp) return -ENOMEM; array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL); @@ -893,18 +915,33 @@ static int clk_osm_get_lut(struct platform_device *pdev, c->osm_table[j].spare_data); data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16; - if (!last_entry) { - clk->fmax[k] = array[i]; + if (!last_entry && data == MAX_CORE_COUNT) { + fmax_temp[k] = array[i]; k++; } if (i < total_elems - NUM_FIELDS) i += NUM_FIELDS; - else + else { + abs_fmax = array[i]; last_entry = true; + } + } + + fmax_temp[k++] = abs_fmax; + clk->fmax = devm_kzalloc(&pdev->dev, k * sizeof(unsigned long), + GFP_KERNEL); + if (!clk->fmax) { + rc = -ENOMEM; + goto exit; } + + for (i = 0; i < k; i++) + clk->fmax[i] = fmax_temp[i]; + clk->num_fmax = k; exit: + devm_kfree(&pdev->dev, fmax_temp); devm_kfree(&pdev->dev, array); return rc; } @@ -1490,20 +1527,27 @@ static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c) } static int clk_osm_resolve_crossover_corners(struct clk_osm *c, - struct platform_device *pdev) + struct platform_device *pdev, + const char *mem_acc_prop) { struct regulator *regulator = c->vdd_reg; - int count, vc, i, threshold, rc = 0; + int count, vc, i, apm_threshold; + int mem_acc_threshold = 0; + int rc = 0; u32 corner_volt; rc = of_property_read_u32(pdev->dev.of_node, "qcom,apm-threshold-voltage", - &threshold); + &apm_threshold); if (rc) { pr_info("qcom,apm-threshold-voltage property not specified\n"); return rc; } + if (mem_acc_prop) + of_property_read_u32(pdev->dev.of_node, mem_acc_prop, + &mem_acc_threshold); + /* Determine crossover virtual corner */ count = regulator_count_voltages(regulator); if (count < 0) { @@ -1511,19 +1555,49 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c, return count; } - c->apm_crossover_vc = count - 1; + /* + * CPRh corners (in hardware) are ordered: + * 0 - n-1 - for n functional corners + * APM crossover - required for OSM + * [MEM ACC crossover] - optional + * + * 'count' corresponds to the total number of corners including n + * functional corners, the APM crossover corner, and potentially the + * MEM ACC cross over corner. + */ + if (mem_acc_threshold) { + c->apm_crossover_vc = count - 2; + c->mem_acc_crossover_vc = count - 1; + } else { + c->apm_crossover_vc = count - 1; + } - /* Determine threshold virtual corner */ + /* Determine APM threshold virtual corner */ for (i = 0; i < OSM_TABLE_SIZE; i++) { vc = c->osm_table[i].virtual_corner + 1; corner_volt = regulator_list_corner_voltage(regulator, vc); - if (corner_volt >= threshold) { + if (corner_volt >= apm_threshold) { c->apm_threshold_vc = c->osm_table[i].virtual_corner; break; } } + /* Determine MEM ACC threshold virtual corner */ + if (mem_acc_threshold) { + for (i = 0; i < OSM_TABLE_SIZE; i++) { + vc = c->osm_table[i].virtual_corner + 1; + corner_volt + = regulator_list_corner_voltage(regulator, vc); + + if (corner_volt >= mem_acc_threshold) { + c->mem_acc_threshold_vc + = c->osm_table[i].virtual_corner; + break; + } + } + } + return 0; } @@ -1822,6 +1896,7 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c) { int i, curr_level, j = 0; int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0}; + int threshold_vc[4]; curr_level = c->osm_table[0].spare_data; for (i = 0; i < c->num_entries; i++) { @@ -1829,7 +1904,8 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c) break; if (c->osm_table[i].spare_data != curr_level) { - mem_acc_level_map[j++] = i - 1; + mem_acc_level_map[j++] + = c->osm_table[i].virtual_corner - 1; curr_level = c->osm_table[i].spare_data; } } @@ -1855,14 +1931,37 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c) clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i], MEM_ACC_SEQ_REG_CFG_START(i)); } else { + if (c->mem_acc_crossover_vc) + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(88), + c->mem_acc_crossover_vc); + + threshold_vc[0] = mem_acc_level_map[0]; + threshold_vc[1] = mem_acc_level_map[0] + 1; + threshold_vc[2] = mem_acc_level_map[1]; + threshold_vc[3] = mem_acc_level_map[1] + 1; + + /* + * Use dynamic MEM ACC threshold voltage based value for the + * highest MEM ACC threshold if it is specified instead of the + * fixed mapping in the LUT. + */ + if (c->mem_acc_threshold_vc) { + threshold_vc[2] = c->mem_acc_threshold_vc - 1; + threshold_vc[3] = c->mem_acc_threshold_vc; + if (threshold_vc[1] >= threshold_vc[2]) + threshold_vc[1] = threshold_vc[2] - 1; + if (threshold_vc[0] >= threshold_vc[1]) + threshold_vc[0] = threshold_vc[1] - 1; + } + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55), - mem_acc_level_map[0]); + threshold_vc[0]); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56), - mem_acc_level_map[0] + 1); + threshold_vc[1]); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57), - mem_acc_level_map[1]); + threshold_vc[2]); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58), - mem_acc_level_map[1] + 1); + threshold_vc[3]); /* SEQ_REG(49) = SEQ_REG(28) init by TZ */ } @@ -3076,13 +3175,14 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } - rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev); + rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev, NULL); if (rc) dev_info(&pdev->dev, "No APM crossover corner programmed\n"); - rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev); + rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev, + "qcom,perfcl-apcs-mem-acc-threshold-voltage"); if (rc) - dev_info(&pdev->dev, "No APM crossover corner programmed\n"); + dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n"); clk_osm_setup_cycle_counters(&pwrcl_clk); clk_osm_setup_cycle_counters(&perfcl_clk); diff --git a/drivers/clk/msm/clock.h b/drivers/clk/msm/clock.h index b7aa946f1931..6d286a5d2e5b 100644 --- a/drivers/clk/msm/clock.h +++ b/drivers/clk/msm/clock.h @@ -41,6 +41,8 @@ extern struct list_head orphan_clk_list; #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMMON_CLK_MSM) int clock_debug_register(struct clk *clk); void clock_debug_print_enabled(void); +#elif defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMMON_CLK_QCOM) +void clock_debug_print_enabled(void); #else static inline int clock_debug_register(struct clk *unused) { diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c index c74162ae8148..029f779979c7 100644 --- a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c +++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c @@ -21,6 +21,7 @@ #include <linux/clk/msm-clk.h> #include <linux/clk/msm-clock-generic.h> #include <dt-bindings/clock/msm-clocks-8998.h> +#include <linux/math64.h> #include "mdss-pll.h" #include "mdss-hdmi-pll.h" @@ -29,6 +30,7 @@ #define _R(x, y) MDSS_PLL_REG_R(x, y) /* PLL REGISTERS */ +#define FREQ_UPDATE (0x008) #define BIAS_EN_CLKBUFLR_EN (0x034) #define CLK_ENABLE1 (0x038) #define SYS_CLK_CTRL (0x03C) @@ -77,9 +79,12 @@ #define PHY_CMN_CTRL (0x68) #define PHY_STATUS (0xB4) +#define HDMI_VCO_MAX_FREQ 12000000000 +#define HDMI_VCO_MIN_FREQ 8000000000 #define HDMI_BIT_CLK_TO_PIX_CLK_RATIO 10 #define HDMI_MHZ_TO_HZ 1000000 #define HDMI_HZ_TO_MHZ 1000000 +#define HDMI_KHZ_TO_HZ 1000 #define HDMI_REF_CLOCK_MHZ 19.2 #define HDMI_REF_CLOCK_HZ (HDMI_REF_CLOCK_MHZ * 1000000) #define HDMI_VCO_MIN_RATE_HZ 25000000 @@ -109,7 +114,7 @@ struct hdmi_8998_reg_cfg { u32 core_clk_en; u32 coreclk_div_mode0; u32 phy_mode; - u32 vco_freq; + u64 vco_freq; u32 hsclk_divsel; u32 vco_ratio; u32 ssc_en_center; @@ -142,17 +147,19 @@ static void hdmi_8998_get_div(struct hdmi_8998_reg_cfg *cfg, unsigned long pclk) u32 const band_list[] = {0, 1, 2, 3}; u32 const sz_ratio = ARRAY_SIZE(ratio_list); u32 const sz_band = ARRAY_SIZE(band_list); - u32 const min_freq = 8000, max_freq = 12000; u32 const cmp_cnt = 1024; u32 const th_min = 500, th_max = 1000; - u64 bit_clk = ((u64)pclk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; u32 half_rate_mode = 0; - u32 freq_optimal, list_elements; + u32 list_elements; int optimal_index; u32 i, j, k; - u32 freq_list[sz_ratio * sz_band]; u32 found_hsclk_divsel = 0, found_vco_ratio; - u32 found_tx_band_sel, found_vco_freq; + u32 found_tx_band_sel; + u64 const min_freq = HDMI_VCO_MIN_FREQ, max_freq = HDMI_VCO_MAX_FREQ; + u64 const bit_clk = ((u64)pclk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + u64 freq_list[sz_ratio * sz_band]; + u64 found_vco_freq; + u64 freq_optimal; find_optimal_index: freq_optimal = max_freq; @@ -164,7 +171,6 @@ find_optimal_index: u64 freq = div_u64(bit_clk, (1 << half_rate_mode)); freq *= (ratio_list[i] * (1 << band_list[j])); - do_div(freq, (u64) HDMI_MHZ_TO_HZ); freq_list[list_elements++] = freq; } } @@ -172,23 +178,23 @@ find_optimal_index: for (k = 0; k < ARRAY_SIZE(freq_list); k++) { u32 const clks_pll_div = 2, core_clk_div = 5; u32 const rng1 = 16, rng2 = 8; - u32 core_clk, rvar1; u32 th1, th2; + u64 core_clk, rvar1, rem; core_clk = (((freq_list[k] / ratio_list[k / sz_band]) / clks_pll_div) / core_clk_div); - rvar1 = HDMI_REF_CLOCK_HZ / cmp_cnt; - rvar1 *= rng1; - rvar1 /= core_clk; - + rvar1 = HDMI_REF_CLOCK_HZ * rng1 * HDMI_MHZ_TO_HZ; + rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem); + if (rem > ((cmp_cnt * core_clk) >> 1)) + rvar1++; th1 = rvar1; - rvar1 = HDMI_REF_CLOCK_HZ / cmp_cnt; - rvar1 *= rng2; - rvar1 /= core_clk; - + rvar1 = HDMI_REF_CLOCK_HZ * rng2 * HDMI_MHZ_TO_HZ; + rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem); + if (rem > ((cmp_cnt * core_clk) >> 1)) + rvar1++; th2 = rvar1; if (freq_list[k] >= min_freq && @@ -257,7 +263,7 @@ find_optimal_index: break; }; - pr_debug("found_vco_freq=%d\n", found_vco_freq); + pr_debug("found_vco_freq=%llu\n", found_vco_freq); pr_debug("found_hsclk_divsel=%d\n", found_hsclk_divsel); pr_debug("found_vco_ratio=%d\n", found_vco_ratio); pr_debug("found_tx_band_sel=%d\n", found_tx_band_sel); @@ -278,9 +284,9 @@ static int hdmi_8998_config_phy(unsigned long rate, u64 const mid_freq_bit_clk_threshold = 750000000; int rc = 0; u64 fdata, tmds_clk; - u64 pll_div = 4 * HDMI_REF_CLOCK_HZ; + u32 pll_div = 4 * HDMI_REF_CLOCK_HZ; u64 bclk; - u64 vco_freq_mhz; + u64 vco_freq; u64 hsclk_sel, dec_start, div_frac_start; u64 rem; u64 cpctrl, rctrl, cctrl; @@ -302,15 +308,15 @@ static int hdmi_8998_config_phy(unsigned long rate, hdmi_8998_get_div(cfg, rate); - vco_freq_mhz = cfg->vco_freq * (u64) HDMI_HZ_TO_MHZ; + vco_freq = cfg->vco_freq; fdata = cfg->vco_freq; do_div(fdata, cfg->vco_ratio); hsclk_sel = cfg->hsclk_divsel; - dec_start = vco_freq_mhz; + dec_start = vco_freq; do_div(dec_start, pll_div); - div_frac_start = vco_freq_mhz * (1 << 20); + div_frac_start = vco_freq * (1 << 20); rem = do_div(div_frac_start, pll_div); div_frac_start -= (dec_start * (1 << 20)); if (rem > (pll_div >> 1)) @@ -330,19 +336,19 @@ static int hdmi_8998_config_phy(unsigned long rate, integloop_gain = ((div_frac_start != 0) || (gen_ssc == true)) ? 0x3F : 0xC4; - integloop_gain <<= digclk_divsel; + integloop_gain <<= (digclk_divsel == 2 ? 1 : 0); integloop_gain = (integloop_gain <= 2046 ? integloop_gain : 0x7FE); cmp_rng = gen_ssc ? 0x40 : 0x10; pll_cmp = cmp_cnt * fdata; - rem = do_div(pll_cmp, (u64)(HDMI_REF_CLOCK_MHZ * 10)); - if (rem > ((u64)(HDMI_REF_CLOCK_MHZ * 10) >> 1)) + rem = do_div(pll_cmp, (u32)(HDMI_REF_CLOCK_HZ * 10)); + if (rem > ((u64)(HDMI_REF_CLOCK_HZ * 10) >> 1)) pll_cmp++; pll_cmp = pll_cmp - 1; - pr_debug("VCO_FREQ = %u\n", cfg->vco_freq); + pr_debug("VCO_FREQ = %llu\n", cfg->vco_freq); pr_debug("FDATA = %llu\n", fdata); pr_debug("DEC_START = %llu\n", dec_start); pr_debug("DIV_FRAC_START = %llu\n", div_frac_start); @@ -609,49 +615,6 @@ static int hdmi_8998_phy_ready_status(struct mdss_pll_resources *io) return rc; } -static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate) -{ - int rc = 0; - struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); - struct mdss_pll_resources *io = vco->priv; - - rc = mdss_pll_resource_enable(io, true); - if (rc) { - pr_err("pll resource enable failed, rc=%d\n", rc); - return rc; - } - - if (io->pll_on) - goto error; - - rc = hdmi_8998_pll_set_clk_rate(c, rate); - if (rc) { - pr_err("failed to set clk rate, rc=%d\n", rc); - goto error; - } - - vco->rate = rate; - vco->rate_set = true; - -error: - (void)mdss_pll_resource_enable(io, false); - - return rc; -} - -static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate) -{ - unsigned long rrate = rate; - struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); - - if (rate < vco->min_rate) - rrate = vco->min_rate; - if (rate > vco->max_rate) - rrate = vco->max_rate; - - return rrate; -} - static int hdmi_8998_pll_enable(struct clk *c) { int rc = 0; @@ -700,6 +663,151 @@ static int hdmi_8998_pll_enable(struct clk *c) return rc; } +/* + * Get the clock range allowed in atomic update. If clock rate + * goes beyond this range, a full tear down is required to set + * the new pixel clock. + */ +static int hdmi_8998_vco_get_lock_range(struct clk *c, + unsigned long pixel_clk) +{ + const u32 rng = 64, cmp_cnt = 1024; + const u32 coreclk_div = 5, clks_pll_divsel = 2; + u32 vco_freq, vco_ratio, ppm_range; + struct hdmi_8998_reg_cfg cfg = {0}; + + pr_debug("rate=%ld\n", pixel_clk); + + hdmi_8998_get_div(&cfg, pixel_clk); + if (cfg.vco_ratio <= 0 || cfg.vco_freq <= 0) { + pr_err("couldn't get post div\n"); + return -EINVAL; + } + + do_div(cfg.vco_freq, HDMI_KHZ_TO_HZ * HDMI_KHZ_TO_HZ); + + vco_freq = (u32) cfg.vco_freq; + vco_ratio = (u32) cfg.vco_ratio; + + pr_debug("freq %d, ratio %d\n", vco_freq, vco_ratio); + + ppm_range = (rng * HDMI_REF_CLOCK_HZ) / cmp_cnt; + ppm_range /= vco_freq / vco_ratio; + ppm_range *= coreclk_div * clks_pll_divsel; + + pr_debug("ppm range: %d\n", ppm_range); + + return ppm_range; +} + +static int hdmi_8998_vco_rate_atomic_update(struct clk *c, + unsigned long rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + void __iomem *pll; + struct hdmi_8998_reg_cfg cfg = {0}; + int rc = 0; + + rc = hdmi_8998_config_phy(rate, &cfg); + if (rc) { + pr_err("rate calculation failed\n, rc=%d", rc); + goto end; + } + + pll = io->pll_base; + + _W(pll, DEC_START_MODE0, cfg.dec_start_mode0); + _W(pll, DIV_FRAC_START1_MODE0, cfg.div_frac_start1_mode0); + _W(pll, DIV_FRAC_START2_MODE0, cfg.div_frac_start2_mode0); + _W(pll, DIV_FRAC_START3_MODE0, cfg.div_frac_start3_mode0); + + _W(pll, FREQ_UPDATE, 0x01); + _W(pll, FREQ_UPDATE, 0x00); + + pr_debug("updated to rate %ld\n", rate); +end: + return rc; +} + +static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + unsigned int set_power_dwn = 0; + bool atomic_update = false; + int pll_lock_range = 0; + int rc = 0; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource enable failed, rc=%d\n", rc); + return rc; + } + + pr_debug("rate %ld, vco_rate %ld\n", rate, vco->rate); + + if (_R(io->pll_base, C_READY_STATUS) & BIT(0) && + _R(io->phy_base, PHY_STATUS) & BIT(0)) { + pll_lock_range = hdmi_8998_vco_get_lock_range(c, vco->rate); + + if (pll_lock_range > 0 && vco->rate) { + u32 range_limit; + + range_limit = pll_lock_range * + (vco->rate / HDMI_KHZ_TO_HZ); + range_limit /= HDMI_KHZ_TO_HZ; + + pr_debug("range limit %d\n", range_limit); + + if (abs(rate - vco->rate) < range_limit) + atomic_update = true; + } + } + + if (io->pll_on && !atomic_update) + set_power_dwn = 1; + + if (atomic_update) + rc = hdmi_8998_vco_rate_atomic_update(c, rate); + else + rc = hdmi_8998_pll_set_clk_rate(c, rate); + + if (rc) { + pr_err("failed to set clk rate\n"); + goto error; + } + + if (set_power_dwn) { + rc = hdmi_8998_pll_enable(c); + if (rc) { + pr_err("failed to enable pll, rc=%d\n", rc); + goto error; + } + } + + vco->rate = rate; + vco->rate_set = true; + +error: + (void)mdss_pll_resource_enable(io, false); + + return rc; +} + +static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + return rrate; +} + static int hdmi_8998_vco_prepare(struct clk *c) { struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index e39686ca4feb..36ab5cf68740 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -173,6 +173,16 @@ config MSM_GPUCC_FALCON Say Y if you want to support graphics controller devices which will be required to enable those device. +config MSM_MMCC_FALCON + tristate "MSMFALCON Multimedia Clock Controller" + select MSM_GCC_FALCON + depends on COMMON_CLK_QCOM + help + Support for the multimedia clock controller on Qualcomm Technologies, Inc + MSMfalcon devices. + Say Y if you want to support multimedia devices such as display, + video encode/decode, camera, etc. + config QCOM_HFPLL tristate "High-Frequency PLL (HFPLL) Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index adebefd63e71..595254f69db1 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o obj-$(CONFIG_MSM_GPUCC_FALCON) += gpucc-msmfalcon.o +obj-$(CONFIG_MSM_MMCC_FALCON) += mmcc-msmfalcon.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o obj-$(CONFIG_KRAITCC) += krait-cc.o diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 6a975052cc85..ec3d02e8dcb1 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -286,11 +286,20 @@ static void clk_gate2_list_registers(struct seq_file *f, struct clk_hw *hw) } } +static int clk_gate2_set_flags(struct clk_hw *hw, unsigned flags) +{ + struct clk_gate2 *gt = to_clk_gate2(hw); + + return clk_cbcr_set_flags(gt->clkr.regmap, gt->clkr.enable_reg, + flags); +} + const struct clk_ops clk_gate2_ops = { .enable = clk_gate2_enable, .disable = clk_gate2_disable, .is_enabled = clk_is_enabled_regmap, .list_registers = clk_gate2_list_registers, + .set_flags = clk_gate2_set_flags, }; EXPORT_SYMBOL_GPL(clk_gate2_ops); diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c new file mode 100644 index 000000000000..f97cd1b03c81 --- /dev/null +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -0,0 +1,3301 @@ +/* + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/debugfs.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> +#include <linux/cpu.h> +#include <linux/platform_device.h> +#include <linux/of_platform.h> +#include <linux/pm_opp.h> +#include <linux/pm_qos.h> +#include <linux/interrupt.h> +#include <linux/regulator/driver.h> +#include <linux/uaccess.h> +#include <linux/sched.h> + +#include <soc/qcom/scm.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-alpha-pll.h> + +#include <dt-bindings/clock/msm-clocks-hwio-cobalt.h> +#include <dt-bindings/clock/msm-clocks-cobalt.h> + +#include "clock.h" + +enum clk_osm_bases { + OSM_BASE, + PLL_BASE, + EFUSE_BASE, + ACD_BASE, + NUM_BASES, +}; + +enum clk_osm_lut_data { + FREQ, + FREQ_DATA, + PLL_OVERRIDES, + SPARE_DATA, + VIRTUAL_CORNER, + NUM_FIELDS, +}; + +enum clk_osm_trace_method { + XOR_PACKET, + PERIODIC_PACKET, +}; + +enum clk_osm_trace_packet_id { + TRACE_PACKET0, + TRACE_PACKET1, + TRACE_PACKET2, + TRACE_PACKET3, +}; + +#define SEQ_REG(n) (0x300 + (n) * 4) +#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n))) +#define MEM_ACC_SEQ_CONST(n) (n) +#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40)) +#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n))) +#define SEQ_REG1_MSMCOBALT_V2 0x1048 +#define VERSION_REG 0x0 +#define VERSION_1P1 0x00010100 + +#define OSM_TABLE_SIZE 40 +#define MAX_CLUSTER_CNT 2 +#define MAX_CONFIG 4 +#define LLM_SW_OVERRIDE_CNT 3 + +#define ENABLE_REG 0x1004 +#define INDEX_REG 0x1150 +#define FREQ_REG 0x1154 +#define VOLT_REG 0x1158 +#define OVERRIDE_REG 0x115C +#define SPARE_REG 0x1164 + +#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00 +#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04 +#define DCVS_PERF_STATE_DESIRED_REG 0x1F10 +#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14 +#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18 +#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C +#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20 +#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24 +#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28 +#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C +#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30 +#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34 +#define OSM_CORE_TABLE_SIZE 8192 +#define OSM_REG_SIZE 32 + +#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00 +#define WDOG_PROGRAM_COUNTER 0x1c74 + +#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8) +#define PLL_MODE 0x0 +#define PLL_L_VAL 0x4 +#define PLL_USER_CTRL 0xC +#define PLL_CONFIG_CTL_LO 0x10 +#define PLL_TEST_CTL_HI 0x1C +#define PLL_STATUS 0x2C +#define PLL_LOCK_DET_MASK BIT(16) +#define PLL_WAIT_LOCK_TIME_US 10 +#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000) +#define PLL_MIN_LVAL 43 + +#define CC_ZERO_BEHAV_CTRL 0x100C +#define SPM_CC_DCVS_DISABLE 0x1020 +#define SPM_CC_CTRL 0x1028 +#define SPM_CC_HYSTERESIS 0x101C +#define SPM_CORE_RET_MAPPING 0x1024 +#define CFG_DELAY_VAL_3 0x12C + +#define LLM_FREQ_VOTE_HYSTERESIS 0x102C +#define LLM_VOLT_VOTE_HYSTERESIS 0x1030 +#define LLM_INTF_DCVS_DISABLE 0x1034 + +#define ENABLE_OVERRIDE BIT(0) + +#define ITM_CL0_DISABLE_CL1_ENABLED 0x2 +#define ITM_CL0_ENABLED_CL1_DISABLE 0x1 + +#define APM_MX_MODE 0 +#define APM_APC_MODE BIT(1) +#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3)) +#define APM_MX_MODE_VAL 0 +#define APM_APC_MODE_VAL 0x3 + +#define GPLL_SEL 0x400 +#define PLL_EARLY_SEL 0x500 +#define PLL_MAIN_SEL 0x300 +#define RCG_UPDATE 0x3 +#define RCG_UPDATE_SUCCESS 0x2 +#define PLL_POST_DIV1 0x1F +#define PLL_POST_DIV2 0x11F + +#define LLM_SW_OVERRIDE_REG 0x1038 +#define VMIN_REDUC_ENABLE_REG 0x103C +#define VMIN_REDUC_TIMER_REG 0x1040 +#define PDN_FSM_CTRL_REG 0x1070 +#define CC_BOOST_TIMER_REG0 0x1074 +#define CC_BOOST_TIMER_REG1 0x1078 +#define CC_BOOST_TIMER_REG2 0x107C +#define CC_BOOST_EN_MASK BIT(0) +#define PS_BOOST_EN_MASK BIT(1) +#define DCVS_BOOST_EN_MASK BIT(2) +#define PC_RET_EXIT_DROOP_EN_MASK BIT(3) +#define WFX_DROOP_EN_MASK BIT(4) +#define DCVS_DROOP_EN_MASK BIT(5) +#define LMH_PS_EN_MASK BIT(6) +#define IGNORE_PLL_LOCK_MASK BIT(15) +#define SAFE_FREQ_WAIT_NS 5000 +#define DEXT_DECREMENT_WAIT_NS 1000 +#define DCVS_BOOST_TIMER_REG0 0x1084 +#define DCVS_BOOST_TIMER_REG1 0x1088 +#define DCVS_BOOST_TIMER_REG2 0x108C +#define PS_BOOST_TIMER_REG0 0x1094 +#define PS_BOOST_TIMER_REG1 0x1098 +#define PS_BOOST_TIMER_REG2 0x109C +#define BOOST_PROG_SYNC_DELAY_REG 0x10A0 +#define DROOP_CTRL_REG 0x10A4 +#define DROOP_RELEASE_TIMER_CTRL 0x10A8 +#define DROOP_PROG_SYNC_DELAY_REG 0x10BC +#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC +#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0 +#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4 +#define OSM_PLL_SW_OVERRIDE_EN 0x10C0 + +#define PLL_SW_OVERRIDE_DROOP_EN BIT(0) +#define DCVS_DROOP_TIMER_CTRL 0x10B8 +#define SEQ_MEM_ADDR 0x500 +#define SEQ_CFG_BR_ADDR 0x170 +#define MAX_INSTRUCTIONS 256 +#define MAX_BR_INSTRUCTIONS 49 + +#define MAX_MEM_ACC_LEVELS 3 +#define MAX_MEM_ACC_VAL_PER_LEVEL 3 +#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \ + MAX_MEM_ACC_VAL_PER_LEVEL) +#define MEM_ACC_APM_READ_MASK 0xff + +#define TRACE_CTRL 0x1F38 +#define TRACE_CTRL_EN_MASK BIT(0) +#define TRACE_CTRL_ENABLE 1 +#define TRACE_CTRL_DISABLE 0 +#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30) +#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3) +#define TRACE_CTRL_PACKET_TYPE_SHIFT 1 +#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3) +#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3) +#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C +#define PERIODIC_TRACE_MIN_NS 1000 +#define PERIODIC_TRACE_MAX_NS 21474836475 +#define PERIODIC_TRACE_DEFAULT_NS 1000000 + +#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408 +#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f +#define PLL_DD_D0_USER_CTL_LO 0x17916208 +#define PLL_DD_D1_USER_CTL_LO 0x17816208 + +#define PWRCL_EFUSE_SHIFT 0 +#define PWRCL_EFUSE_MASK 0 +#define PERFCL_EFUSE_SHIFT 29 +#define PERFCL_EFUSE_MASK 0x7 + +#define MSMCOBALTV1_PWRCL_BOOT_RATE 1478400000 +#define MSMCOBALTV1_PERFCL_BOOT_RATE 1536000000 +#define MSMCOBALTV2_PWRCL_BOOT_RATE 1555200000 +#define MSMCOBALTV2_PERFCL_BOOT_RATE 1728000000 + +/* ACD registers */ +#define ACD_HW_VERSION 0x0 +#define ACDCR 0x4 +#define ACDTD 0x8 +#define ACDSSCR 0x28 +#define ACD_EXTINT_CFG 0x30 +#define ACD_DCVS_SW 0x34 +#define ACD_GFMUX_CFG 0x3c +#define ACD_READOUT_CFG 0x48 +#define ACD_AUTOXFER_CFG 0x80 +#define ACD_AUTOXFER 0x84 +#define ACD_AUTOXFER_CTL 0x88 +#define ACD_AUTOXFER_STATUS 0x8c +#define ACD_WRITE_CTL 0x90 +#define ACD_WRITE_STATUS 0x94 +#define ACD_READOUT 0x98 + +#define ACD_MASTER_ONLY_REG_ADDR 0x80 +#define ACD_WRITE_CTL_UPDATE_EN BIT(0) +#define ACD_WRITE_CTL_SELECT_SHIFT 1 +#define ACD_GFMUX_CFG_SELECT BIT(0) +#define ACD_AUTOXFER_START_CLEAR 0 +#define ACD_AUTOXFER_START_SET BIT(0) +#define AUTO_XFER_DONE_MASK BIT(0) +#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0) +#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0 +#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500 + +static void __iomem *virt_base; +static void __iomem *debug_base; + +#define lmh_lite_clk_src_source_val 1 + +#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4) +#define ACD_REG_RELATIVE_ADDR_BITMASK(addr) \ + (1 << (ACD_REG_RELATIVE_ADDR(addr))) + +#define FIXDIV(div) (div ? (2 * (div) - 1) : (0)) + +#define F(f, s, div, m, n) \ + { \ + .freq_hz = (f), \ + .src_clk = &s.c, \ + .m_val = (m), \ + .n_val = ~((n)-(m)) * !!(n), \ + .d_val = ~(n),\ + .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \ + | BVAL(10, 8, s##_source_val), \ + } + +static u32 seq_instr[] = { + 0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491, + 0x700a500b, 0x5001aefc, 0xaefd7000, 0x390938c8, 0xcb44c833, + 0xce56cd54, 0x341336e0, 0xa4baadba, 0xb480a493, 0x10004000, + 0x70005001, 0x1000500c, 0xc792c5a1, 0x501625e1, 0x3da335a2, + 0x50170006, 0x50150006, 0x1000c633, 0x1000acb3, 0xc422acb4, + 0xaefc1000, 0x700a500b, 0x70005001, 0x5010aefd, 0x5012700b, + 0xad41700c, 0x84e5adb9, 0xb3808566, 0x239b0003, 0x856484e3, + 0xb9800007, 0x2bad0003, 0xac3aa20b, 0x0003181b, 0x0003bb40, + 0xa30d239b, 0x500c181b, 0x5011500f, 0x181b3413, 0x853984b9, + 0x0003bd80, 0xa0012ba4, 0x72050803, 0x500e1000, 0x500c1000, + 0x1c011c0a, 0x3b181c06, 0x1c073b43, 0x1c061000, 0x1c073983, + 0x1c02500c, 0x10001c0a, 0x70015002, 0x81031000, 0x70025003, + 0x70035004, 0x3b441000, 0x81553985, 0x70025003, 0x50054003, + 0xa1467009, 0x0003b1c0, 0x4005238b, 0x835a1000, 0x855c84db, + 0x1000a51f, 0x84de835d, 0xa52c855c, 0x50061000, 0x39cd3a4c, + 0x3ad03a8f, 0x10004006, 0x70065007, 0xa00f2c12, 0x08034007, + 0xaefc7205, 0xaefd700d, 0xa9641000, 0x40071c1a, 0x700daefc, + 0x1000aefd, 0x70065007, 0x50101c16, 0x40075012, 0x700daefc, + 0x2411aefd, 0xa8211000, 0x0803a00f, 0x500c7005, 0x1c1591e0, + 0x500f5014, 0x10005011, 0x500c2bd4, 0x0803a00f, 0x10007205, + 0xa00fa9d1, 0x0803a821, 0xa9d07005, 0x91e0500c, 0x500f1c15, + 0x10005011, 0x1c162bce, 0x50125010, 0xa022a82a, 0x70050803, + 0x1c1591df, 0x5011500f, 0x5014500c, 0x0803a00f, 0x10007205, + 0x501391a4, 0x22172217, 0x70075008, 0xa9634008, 0x1c1a0006, + 0x70085009, 0x10004009, 0x00008ed9, 0x3e05c8dd, 0x1c033604, + 0xabaf1000, 0x856284e1, 0x0003bb80, 0x1000239f, 0x0803a037, + 0x10007205, 0x8dc61000, 0x38a71c2a, 0x1c2a8dc4, 0x100038a6, + 0x1c2a8dc5, 0x8dc73867, 0x38681c2a, 0x8c491000, 0x8d4b8cca, + 0x10001c00, 0x8ccd8c4c, 0x1c008d4e, 0x8c4f1000, 0x8d518cd0, + 0x10001c00, 0xa759a79a, 0x1000a718, 0xbf80af9b, 0x00001000, +}; + +static u32 seq_br_instr[] = { + 0x248, 0x20e, 0x21c, 0xf6, 0x112, + 0x11c, 0xe4, 0xea, 0xc6, 0xd6, + 0x126, 0x108, 0x184, 0x1a8, 0x1b0, + 0x134, 0x158, 0x16e, 0x14a, 0xc2, + 0x190, 0x1d2, 0x1cc, 0x1d4, 0x1e8, + 0x0, 0x1f6, 0x32, 0x66, 0xb0, + 0xa6, 0x1fc, 0x3c, 0x44, 0x5c, + 0x60, 0x204, 0x30, 0x22a, 0x234, + 0x23e, 0x0, 0x250, 0x0, 0x0, 0x9a, + 0x20c, +}; + +DEFINE_EXT_CLK(xo_ao, NULL); +DEFINE_EXT_CLK(sys_apcsaux_clk_gcc, NULL); +DEFINE_EXT_CLK(lmh_lite_clk_src, NULL); + +struct osm_entry { + u16 virtual_corner; + u16 open_loop_volt; + u32 freq_data; + u32 override_data; + u32 spare_data; + long frequency; +}; + +static struct dentry *osm_debugfs_base; + +struct clk_osm { + struct clk c; + struct osm_entry osm_table[OSM_TABLE_SIZE]; + struct dentry *debugfs; + struct regulator *vdd_reg; + struct platform_device *vdd_dev; + void *vbases[NUM_BASES]; + unsigned long pbases[NUM_BASES]; + spinlock_t lock; + + u32 version; + u32 cpu_reg_mask; + u32 num_entries; + u32 cluster_num; + u32 irq; + u32 apm_crossover_vc; + u32 apm_threshold_vc; + u32 cycle_counter_reads; + u32 cycle_counter_delay; + u32 cycle_counter_factor; + u64 total_cycle_counter; + u32 prev_cycle_counter; + u32 l_val_base; + u32 apcs_itm_present; + u32 apcs_cfg_rcgr; + u32 apcs_cmd_rcgr; + u32 apcs_pll_user_ctl; + u32 apcs_mem_acc_cfg[MAX_MEM_ACC_VAL_PER_LEVEL]; + u32 apcs_mem_acc_val[MAX_MEM_ACC_VALUES]; + u32 llm_sw_overr[LLM_SW_OVERRIDE_CNT]; + u32 apm_mode_ctl; + u32 apm_ctrl_status; + u32 osm_clk_rate; + u32 xo_clk_rate; + u32 acd_td; + u32 acd_cr; + u32 acd_sscr; + u32 acd_extint0_cfg; + u32 acd_extint1_cfg; + u32 acd_autoxfer_ctl; + u32 acd_debugfs_addr; + bool acd_init; + bool secure_init; + bool red_fsm_en; + bool boost_fsm_en; + bool safe_fsm_en; + bool ps_fsm_en; + bool droop_fsm_en; + bool wfx_fsm_en; + bool pc_fsm_en; + + enum clk_osm_trace_method trace_method; + enum clk_osm_trace_packet_id trace_id; + struct notifier_block panic_notifier; + u32 trace_periodic_timer; + bool trace_en; + bool wdog_trace_en; +}; + +static bool msmcobalt_v1; +static bool msmcobalt_v2; + +static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val, + u32 offset, u32 mask) +{ + u32 val2, orig_val; + + val2 = orig_val = readl_relaxed((char *)c->vbases[OSM_BASE] + offset); + val2 &= ~mask; + val2 |= val & mask; + + if (val2 != orig_val) + writel_relaxed(val2, (char *)c->vbases[OSM_BASE] + offset); +} + +static inline void clk_osm_write_reg(struct clk_osm *c, u32 val, u32 offset) +{ + writel_relaxed(val, (char *)c->vbases[OSM_BASE] + offset); +} + +static inline int clk_osm_read_reg(struct clk_osm *c, u32 offset) +{ + return readl_relaxed((char *)c->vbases[OSM_BASE] + offset); +} + +static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset) +{ + return readl_relaxed_no_log((char *)c->vbases[OSM_BASE] + offset); +} + +static inline int clk_osm_mb(struct clk_osm *c, int base) +{ + return readl_relaxed_no_log((char *)c->vbases[base] + VERSION_REG); +} + +static inline int clk_osm_acd_mb(struct clk_osm *c) +{ + return readl_relaxed_no_log((char *)c->vbases[ACD_BASE] + + ACD_HW_VERSION); +} + +static inline void clk_osm_acd_master_write_reg(struct clk_osm *c, + u32 val, u32 offset) +{ + writel_relaxed(val, (char *)c->vbases[ACD_BASE] + offset); +} + +static int clk_osm_acd_local_read_reg(struct clk_osm *c, u32 offset) +{ + u32 reg = 0; + int timeout; + + if (offset >= ACD_MASTER_ONLY_REG_ADDR) { + pr_err("ACD register at offset=0x%x not locally readable\n", + offset); + return -EINVAL; + } + + /* Set select field in read control register */ + writel_relaxed(ACD_REG_RELATIVE_ADDR(offset), + (char *)c->vbases[ACD_BASE] + ACD_READOUT_CFG); + + /* Clear write control register */ + writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL); + + /* Set select and update_en fields in write control register */ + reg = (ACD_REG_RELATIVE_ADDR(ACD_READOUT_CFG) + << ACD_WRITE_CTL_SELECT_SHIFT) + | ACD_WRITE_CTL_UPDATE_EN; + writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL); + + /* Ensure writes complete before polling */ + clk_osm_acd_mb(c); + + /* Poll write status register */ + for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS; timeout > 0; + timeout -= 100) { + reg = readl_relaxed((char *)c->vbases[ACD_BASE] + + ACD_WRITE_STATUS); + if ((reg & (ACD_REG_RELATIVE_ADDR_BITMASK(ACD_READOUT_CFG)))) + break; + ndelay(100); + } + + if (!timeout) { + pr_err("local read timed out, offset=0x%x status=0x%x\n", + offset, reg); + return -ETIMEDOUT; + } + + reg = readl_relaxed((char *)c->vbases[ACD_BASE] + + ACD_READOUT); + return reg; +} + +static int clk_osm_acd_local_write_reg(struct clk_osm *c, u32 val, u32 offset) +{ + u32 reg = 0; + int timeout; + + if (offset >= ACD_MASTER_ONLY_REG_ADDR) { + pr_err("ACD register at offset=0x%x not transferrable\n", + offset); + return -EINVAL; + } + + /* Clear write control register */ + writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL); + + /* Set select and update_en fields in write control register */ + reg = (ACD_REG_RELATIVE_ADDR(offset) << ACD_WRITE_CTL_SELECT_SHIFT) + | ACD_WRITE_CTL_UPDATE_EN; + writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL); + + /* Ensure writes complete before polling */ + clk_osm_acd_mb(c); + + /* Poll write status register */ + for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS; timeout > 0; + timeout -= 100) { + reg = readl_relaxed((char *)c->vbases[ACD_BASE] + + ACD_WRITE_STATUS); + if ((reg & (ACD_REG_RELATIVE_ADDR_BITMASK(offset)))) + break; + ndelay(100); + } + + if (!timeout) { + pr_err("local write timed out, offset=0x%x val=0x%x status=0x%x\n", + offset, val, reg); + return -ETIMEDOUT; + } + + return 0; +} + +static int clk_osm_acd_master_write_through_reg(struct clk_osm *c, + u32 val, u32 offset) +{ + writel_relaxed(val, (char *)c->vbases[ACD_BASE] + offset); + + /* Ensure writes complete before transfer to local copy */ + clk_osm_acd_mb(c); + + return clk_osm_acd_local_write_reg(c, val, offset); +} + +static int clk_osm_acd_auto_local_write_reg(struct clk_osm *c, u32 mask) +{ + u32 numregs, bitmask = mask; + u32 reg = 0; + int timeout; + + /* count number of bits set in register mask */ + for (numregs = 0; bitmask; numregs++) + bitmask &= bitmask - 1; + + /* Program auto-transfter mask */ + writel_relaxed(mask, (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER_CFG); + + /* Clear start field in auto-transfer register */ + writel_relaxed(ACD_AUTOXFER_START_CLEAR, + (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER); + + /* Set start field in auto-transfer register */ + writel_relaxed(ACD_AUTOXFER_START_SET, + (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER); + + /* Ensure writes complete before polling */ + clk_osm_acd_mb(c); + + /* Poll auto-transfer status register */ + for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS * numregs; + timeout > 0; timeout -= 100) { + reg = readl_relaxed((char *)c->vbases[ACD_BASE] + + ACD_AUTOXFER_STATUS); + if (reg & AUTO_XFER_DONE_MASK) + break; + ndelay(100); + } + + if (!timeout) { + pr_err("local register auto-transfer timed out, mask=0x%x registers=%d status=0x%x\n", + mask, numregs, reg); + return -ETIMEDOUT; + } + + return 0; +} + +static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec) +{ + u64 temp; + + temp = (u64)c->osm_clk_rate * nsec; + do_div(temp, 1000000000); + + return temp; +} + +static inline struct clk_osm *to_clk_osm(struct clk *c) +{ + return container_of(c, struct clk_osm, c); +} + +static enum handoff clk_osm_handoff(struct clk *c) +{ + return HANDOFF_DISABLED_CLK; +} + +static long clk_osm_list_rate(struct clk *c, unsigned n) +{ + if (n >= c->num_fmax) + return -ENXIO; + return c->fmax[n]; +} + +static long clk_osm_round_rate(struct clk *c, unsigned long rate) +{ + int i; + unsigned long rrate = 0; + + /* + * If the rate passed in is 0, return the first frequency in + * the FMAX table. + */ + if (!rate) + return c->fmax[0]; + + for (i = 0; i < c->num_fmax; i++) { + if (is_better_rate(rate, rrate, c->fmax[i])) { + rrate = c->fmax[i]; + if (rrate == rate) + break; + } + } + + return rrate; +} + +static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) +{ + int i; + + for (i = 0; i < entries; i++) + if (rate == table[i].frequency) + return i; + return -EINVAL; +} + +static int clk_osm_set_rate(struct clk *c, unsigned long rate) +{ + struct clk_osm *cpuclk = to_clk_osm(c); + int index = 0; + unsigned long r_rate; + + r_rate = clk_osm_round_rate(c, rate); + + if (rate != r_rate) { + pr_err("invalid rate requested rate=%ld\n", rate); + return -EINVAL; + } + + /* Convert rate to table index */ + index = clk_osm_search_table(cpuclk->osm_table, + cpuclk->num_entries, r_rate); + if (index < 0) { + pr_err("cannot set cluster %u to %lu\n", + cpuclk->cluster_num, rate); + return -EINVAL; + } + pr_debug("rate: %lu --> index %d\n", rate, index); + + if (cpuclk->llm_sw_overr[0]) { + clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[0], + LLM_SW_OVERRIDE_REG); + clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[1], + LLM_SW_OVERRIDE_REG); + udelay(1); + } + + /* Choose index and send request to OSM hardware */ + clk_osm_write_reg(cpuclk, index, DCVS_PERF_STATE_DESIRED_REG); + + if (cpuclk->llm_sw_overr[0]) { + udelay(1); + clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[2], + LLM_SW_OVERRIDE_REG); + } + + /* Make sure the write goes through before proceeding */ + clk_osm_mb(cpuclk, OSM_BASE); + + return 0; +} + +static int clk_osm_enable(struct clk *c) +{ + struct clk_osm *cpuclk = to_clk_osm(c); + + clk_osm_write_reg(cpuclk, 1, ENABLE_REG); + + /* Make sure the write goes through before proceeding */ + clk_osm_mb(cpuclk, OSM_BASE); + + /* Wait for 5us for OSM hardware to enable */ + udelay(5); + + pr_debug("OSM clk enabled for cluster=%d\n", cpuclk->cluster_num); + + return 0; +} + +static struct clk_ops clk_ops_cpu_osm = { + .enable = clk_osm_enable, + .set_rate = clk_osm_set_rate, + .round_rate = clk_osm_round_rate, + .list_rate = clk_osm_list_rate, + .handoff = clk_osm_handoff, +}; + +static struct regulator *vdd_pwrcl; +static struct regulator *vdd_perfcl; + +static struct clk_freq_tbl ftbl_osm_clk_src[] = { + F( 200000000, lmh_lite_clk_src, 1.5, 0, 0), + F_END +}; + +static struct rcg_clk osm_clk_src = { + .cmd_rcgr_reg = APCS_COMMON_LMH_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_osm_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_base, + .c = { + .dbg_name = "osm_clk_src", + .ops = &clk_ops_rcg, + CLK_INIT(osm_clk_src.c), + }, +}; + +static struct clk_osm pwrcl_clk = { + .cluster_num = 0, + .cpu_reg_mask = 0x3, + .c = { + .dbg_name = "pwrcl_clk", + .ops = &clk_ops_cpu_osm, + .parent = &xo_ao.c, + CLK_INIT(pwrcl_clk.c), + }, +}; + +static struct clk_osm perfcl_clk = { + .cluster_num = 1, + .cpu_reg_mask = 0x103, + .c = { + .dbg_name = "perfcl_clk", + .ops = &clk_ops_cpu_osm, + .parent = &xo_ao.c, + CLK_INIT(perfcl_clk.c), + }, +}; + +static struct clk_ops clk_ops_cpu_dbg_mux; + +static struct mux_clk cpu_debug_mux = { + .offset = 0x0, + .mask = 0x3, + .shift = 8, + .ops = &mux_reg_ops, + MUX_SRC_LIST( + { &pwrcl_clk.c, 0x00 }, + { &perfcl_clk.c, 0x01 }, + ), + .base = &debug_base, + .c = { + .dbg_name = "cpu_debug_mux", + .ops = &clk_ops_cpu_dbg_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(cpu_debug_mux.c), + }, +}; + +static struct clk_lookup cpu_clocks_osm[] = { + CLK_LIST(pwrcl_clk), + CLK_LIST(perfcl_clk), + CLK_LIST(sys_apcsaux_clk_gcc), + CLK_LIST(xo_ao), + CLK_LIST(osm_clk_src), + CLK_LIST(cpu_debug_mux), +}; + +static unsigned long cpu_dbg_mux_get_rate(struct clk *clk) +{ + /* Account for the divider between the clock and the debug mux */ + if (!strcmp(clk->parent->dbg_name, "pwrcl_clk")) + return clk->rate/4; + else if (!strcmp(clk->parent->dbg_name, "perfcl_clk")) + return clk->rate/8; + return clk->rate; +} + +static void clk_osm_print_osm_table(struct clk_osm *c) +{ + int i; + struct osm_entry *table = c->osm_table; + u32 pll_src, pll_div, lval, core_count; + + pr_debug("Index, Frequency, VC, OLV (mv), Core Count, PLL Src, PLL Div, L-Val, ACC Level\n"); + for (i = 0; i < c->num_entries; i++) { + pll_src = (table[i].freq_data & GENMASK(27, 26)) >> 26; + pll_div = (table[i].freq_data & GENMASK(25, 24)) >> 24; + lval = table[i].freq_data & GENMASK(7, 0); + core_count = (table[i].freq_data & GENMASK(18, 16)) >> 16; + + pr_debug("%3d, %11lu, %2u, %5u, %2u, %6u, %8u, %7u, %5u\n", + i, + table[i].frequency, + table[i].virtual_corner, + table[i].open_loop_volt, + core_count, + pll_src, + pll_div, + lval, + table[i].spare_data); + } + pr_debug("APM threshold corner=%d, crossover corner=%d\n", + c->apm_threshold_vc, c->apm_crossover_vc); +} + +static int clk_osm_get_lut(struct platform_device *pdev, + struct clk_osm *c, char *prop_name) +{ + struct clk *clk = &c->c; + struct device_node *of = pdev->dev.of_node; + int prop_len, total_elems, num_rows, i, j, k; + int rc = 0; + u32 *array; + u32 data; + bool last_entry = false; + + if (!of_find_property(of, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + total_elems = prop_len / sizeof(u32); + if (total_elems % NUM_FIELDS) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + num_rows = total_elems / NUM_FIELDS; + + clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long), + GFP_KERNEL); + if (!clk->fmax) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL); + if (!array) + return -ENOMEM; + + rc = of_property_read_u32_array(of, prop_name, array, total_elems); + if (rc) { + dev_err(&pdev->dev, "Unable to parse OSM table, rc=%d\n", rc); + goto exit; + } + + pr_debug("%s: Entries in Table: %d\n", __func__, num_rows); + c->num_entries = num_rows; + if (c->num_entries > OSM_TABLE_SIZE) { + pr_err("LUT entries %d exceed maximum size %d\n", + c->num_entries, OSM_TABLE_SIZE); + return -EINVAL; + } + + for (i = 0, j = 0, k = 0; j < OSM_TABLE_SIZE; j++) { + c->osm_table[j].frequency = array[i + FREQ]; + c->osm_table[j].freq_data = array[i + FREQ_DATA]; + c->osm_table[j].override_data = array[i + PLL_OVERRIDES]; + c->osm_table[j].spare_data = array[i + SPARE_DATA]; + /* Voltage corners are 0 based in the OSM LUT */ + c->osm_table[j].virtual_corner = array[i + VIRTUAL_CORNER] - 1; + pr_debug("index=%d freq=%ld virtual_corner=%d freq_data=0x%x override_data=0x%x spare_data=0x%x\n", + j, c->osm_table[j].frequency, + c->osm_table[j].virtual_corner, + c->osm_table[j].freq_data, + c->osm_table[j].override_data, + c->osm_table[j].spare_data); + + data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16; + if (!last_entry) { + clk->fmax[k] = array[i]; + k++; + } + + if (i < total_elems - NUM_FIELDS) + i += NUM_FIELDS; + else + last_entry = true; + } + clk->num_fmax = k; +exit: + devm_kfree(&pdev->dev, array); + return rc; +} + +static int clk_osm_parse_dt_configs(struct platform_device *pdev) +{ + struct device_node *of = pdev->dev.of_node; + u32 *array; + int i, rc = 0; + + array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), + GFP_KERNEL); + if (!array) + return -ENOMEM; + + rc = of_property_read_u32_array(of, "qcom,l-val-base", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,l-val-base property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.l_val_base = array[pwrcl_clk.cluster_num]; + perfcl_clk.l_val_base = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,apcs-itm-present", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,apcs-itm-present property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.apcs_itm_present = array[pwrcl_clk.cluster_num]; + perfcl_clk.apcs_itm_present = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,apcs-cfg-rcgr", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,apcs-cfg-rcgr property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.apcs_cfg_rcgr = array[pwrcl_clk.cluster_num]; + perfcl_clk.apcs_cfg_rcgr = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,apcs-cmd-rcgr", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,apcs-cmd-rcgr property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.apcs_cmd_rcgr = array[pwrcl_clk.cluster_num]; + perfcl_clk.apcs_cmd_rcgr = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,apcs-pll-user-ctl", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,apcs-pll-user-ctl property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.apcs_pll_user_ctl = array[pwrcl_clk.cluster_num]; + perfcl_clk.apcs_pll_user_ctl = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,apm-mode-ctl", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,apm-mode-ctl property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.apm_mode_ctl = array[pwrcl_clk.cluster_num]; + perfcl_clk.apm_mode_ctl = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,apm-ctrl-status", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,apm-ctrl-status property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.apm_ctrl_status = array[pwrcl_clk.cluster_num]; + perfcl_clk.apm_ctrl_status = array[perfcl_clk.cluster_num]; + + for (i = 0; i < LLM_SW_OVERRIDE_CNT; i++) + of_property_read_u32_index(of, "qcom,llm-sw-overr", + pwrcl_clk.cluster_num * + LLM_SW_OVERRIDE_CNT + i, + &pwrcl_clk.llm_sw_overr[i]); + + for (i = 0; i < LLM_SW_OVERRIDE_CNT; i++) + of_property_read_u32_index(of, "qcom,llm-sw-overr", + perfcl_clk.cluster_num * + LLM_SW_OVERRIDE_CNT + i, + &perfcl_clk.llm_sw_overr[i]); + + if (pwrcl_clk.acd_init || perfcl_clk.acd_init) { + rc = of_property_read_u32_array(of, "qcom,acdtd-val", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,acdtd-val property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.acd_td = array[pwrcl_clk.cluster_num]; + perfcl_clk.acd_td = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,acdcr-val", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,acdcr-val property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.acd_cr = array[pwrcl_clk.cluster_num]; + perfcl_clk.acd_cr = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,acdsscr-val", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,acdsscr-val property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.acd_sscr = array[pwrcl_clk.cluster_num]; + perfcl_clk.acd_sscr = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,acdextint0-val", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,acdextint0-val property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.acd_extint0_cfg = array[pwrcl_clk.cluster_num]; + perfcl_clk.acd_extint0_cfg = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,acdextint1-val", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,acdextint1-val property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.acd_extint1_cfg = array[pwrcl_clk.cluster_num]; + perfcl_clk.acd_extint1_cfg = array[perfcl_clk.cluster_num]; + + rc = of_property_read_u32_array(of, "qcom,acdautoxfer-val", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,acdautoxfer-val property, rc=%d\n", + rc); + return -EINVAL; + } + + pwrcl_clk.acd_autoxfer_ctl = array[pwrcl_clk.cluster_num]; + perfcl_clk.acd_autoxfer_ctl = array[perfcl_clk.cluster_num]; + } + + rc = of_property_read_u32(of, "qcom,xo-clk-rate", + &pwrcl_clk.xo_clk_rate); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,xo-clk-rate property, rc=%d\n", + rc); + return -EINVAL; + } + + perfcl_clk.xo_clk_rate = pwrcl_clk.xo_clk_rate; + + rc = of_property_read_u32(of, "qcom,osm-clk-rate", + &pwrcl_clk.osm_clk_rate); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,osm-clk-rate property, rc=%d\n", + rc); + return -EINVAL; + } + perfcl_clk.osm_clk_rate = pwrcl_clk.osm_clk_rate; + + rc = of_property_read_u32(of, "qcom,cc-reads", + &pwrcl_clk.cycle_counter_reads); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,cc-reads property, rc=%d\n", + rc); + return -EINVAL; + } + perfcl_clk.cycle_counter_reads = pwrcl_clk.cycle_counter_reads; + + rc = of_property_read_u32(of, "qcom,cc-delay", + &pwrcl_clk.cycle_counter_delay); + if (rc) + dev_dbg(&pdev->dev, "no delays between cycle counter reads\n"); + else + perfcl_clk.cycle_counter_delay = pwrcl_clk.cycle_counter_delay; + + rc = of_property_read_u32(of, "qcom,cc-factor", + &pwrcl_clk.cycle_counter_factor); + if (rc) + dev_dbg(&pdev->dev, "no factor specified for cycle counter estimation\n"); + else + perfcl_clk.cycle_counter_factor = + pwrcl_clk.cycle_counter_factor; + + perfcl_clk.red_fsm_en = pwrcl_clk.red_fsm_en = + of_property_read_bool(of, "qcom,red-fsm-en"); + + perfcl_clk.boost_fsm_en = pwrcl_clk.boost_fsm_en = + of_property_read_bool(of, "qcom,boost-fsm-en"); + + perfcl_clk.safe_fsm_en = pwrcl_clk.safe_fsm_en = + of_property_read_bool(of, "qcom,safe-fsm-en"); + + perfcl_clk.ps_fsm_en = pwrcl_clk.ps_fsm_en = + of_property_read_bool(of, "qcom,ps-fsm-en"); + + perfcl_clk.droop_fsm_en = pwrcl_clk.droop_fsm_en = + of_property_read_bool(of, "qcom,droop-fsm-en"); + + perfcl_clk.wfx_fsm_en = pwrcl_clk.wfx_fsm_en = + of_property_read_bool(of, "qcom,wfx-fsm-en"); + + perfcl_clk.pc_fsm_en = pwrcl_clk.pc_fsm_en = + of_property_read_bool(of, "qcom,pc-fsm-en"); + + devm_kfree(&pdev->dev, array); + + perfcl_clk.secure_init = pwrcl_clk.secure_init = + of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz"); + + if (!pwrcl_clk.secure_init) + return rc; + + rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-cfg", + pwrcl_clk.apcs_mem_acc_cfg, + MAX_MEM_ACC_VAL_PER_LEVEL); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-cfg property, rc=%d\n", + rc); + return -EINVAL; + } + + of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-cfg", + perfcl_clk.apcs_mem_acc_cfg, + MAX_MEM_ACC_VAL_PER_LEVEL); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-cfg property, rc=%d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-val", + pwrcl_clk.apcs_mem_acc_val, + MAX_MEM_ACC_VALUES); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-val property, rc=%d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-val", + perfcl_clk.apcs_mem_acc_val, + MAX_MEM_ACC_VALUES); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-val property, rc=%d\n", + rc); + return -EINVAL; + } + + return rc; +} + +static int clk_osm_resources_init(struct platform_device *pdev) +{ + struct device_node *node; + struct resource *res; + struct clk *c; + unsigned long pbase; + int i, rc = 0; + void *vbase; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osm"); + if (!res) { + dev_err(&pdev->dev, + "Unable to get platform resource for osm"); + return -ENOMEM; + } + + pwrcl_clk.pbases[OSM_BASE] = (unsigned long)res->start; + pwrcl_clk.vbases[OSM_BASE] = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pwrcl_clk.vbases[OSM_BASE]) { + dev_err(&pdev->dev, "Unable to map in osm base\n"); + return -ENOMEM; + } + + perfcl_clk.pbases[OSM_BASE] = pwrcl_clk.pbases[OSM_BASE] + + perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE; + perfcl_clk.vbases[OSM_BASE] = pwrcl_clk.vbases[OSM_BASE] + + perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE; + + for (i = 0; i < MAX_CLUSTER_CNT; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + i == pwrcl_clk.cluster_num ? + "pwrcl_pll" : "perfcl_pll"); + if (!res) { + dev_err(&pdev->dev, + "Unable to get platform resource\n"); + return -ENOMEM; + } + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in base\n"); + return -ENOMEM; + } + + if (i == pwrcl_clk.cluster_num) { + pwrcl_clk.pbases[PLL_BASE] = pbase; + pwrcl_clk.vbases[PLL_BASE] = vbase; + } else { + perfcl_clk.pbases[PLL_BASE] = pbase; + perfcl_clk.vbases[PLL_BASE] = vbase; + } + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug"); + if (!res) { + dev_err(&pdev->dev, "Failed to get debug mux base\n"); + return -EINVAL; + } + + debug_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!debug_base) { + dev_err(&pdev->dev, "Unable to map in debug mux base\n"); + return -ENOMEM; + } + + clk_ops_cpu_dbg_mux = clk_ops_gen_mux; + clk_ops_cpu_dbg_mux.get_rate = cpu_dbg_mux_get_rate; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_common"); + if (!res) { + dev_err(&pdev->dev, "Failed to get apcs common base\n"); + return -EINVAL; + } + + virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!virt_base) { + dev_err(&pdev->dev, "Failed to map apcs common registers\n"); + return -ENOMEM; + } + + /* efuse speed bin fuses are optional */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pwrcl_efuse"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in pwrcl_efuse base\n"); + return -ENOMEM; + } + pwrcl_clk.pbases[EFUSE_BASE] = pbase; + pwrcl_clk.vbases[EFUSE_BASE] = vbase; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "perfcl_efuse"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in perfcl_efuse base\n"); + return -ENOMEM; + } + perfcl_clk.pbases[EFUSE_BASE] = pbase; + perfcl_clk.vbases[EFUSE_BASE] = vbase; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pwrcl_acd"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in pwrcl_acd base\n"); + return -ENOMEM; + } + pwrcl_clk.pbases[ACD_BASE] = pbase; + pwrcl_clk.vbases[ACD_BASE] = vbase; + pwrcl_clk.acd_init = true; + } else { + pwrcl_clk.acd_init = false; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "perfcl_acd"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in perfcl_acd base\n"); + return -ENOMEM; + } + perfcl_clk.pbases[ACD_BASE] = pbase; + perfcl_clk.vbases[ACD_BASE] = vbase; + perfcl_clk.acd_init = true; + } else { + perfcl_clk.acd_init = false; + } + + vdd_pwrcl = devm_regulator_get(&pdev->dev, "vdd-pwrcl"); + if (IS_ERR(vdd_pwrcl)) { + rc = PTR_ERR(vdd_pwrcl); + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get the pwrcl vreg, rc=%d\n", + rc); + return rc; + } + + vdd_perfcl = devm_regulator_get(&pdev->dev, "vdd-perfcl"); + if (IS_ERR(vdd_perfcl)) { + rc = PTR_ERR(vdd_perfcl); + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get the perfcl vreg, rc=%d\n", + rc); + return rc; + } + + pwrcl_clk.vdd_reg = vdd_pwrcl; + perfcl_clk.vdd_reg = vdd_perfcl; + + node = of_parse_phandle(pdev->dev.of_node, "vdd-pwrcl-supply", 0); + if (!node) { + pr_err("Unable to find vdd-pwrcl-supply\n"); + return -EINVAL; + } + + pwrcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent); + if (!pwrcl_clk.vdd_dev) { + pr_err("Unable to find device for vdd-pwrcl-supply node\n"); + return -EINVAL; + } + + node = of_parse_phandle(pdev->dev.of_node, + "vdd-perfcl-supply", 0); + if (!node) { + pr_err("Unable to find vdd-perfcl-supply\n"); + return -EINVAL; + } + + perfcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent); + if (!perfcl_clk.vdd_dev) { + pr_err("Unable to find device for vdd-perfcl-supply\n"); + return -EINVAL; + } + + c = devm_clk_get(&pdev->dev, "aux_clk"); + if (IS_ERR(c)) { + rc = PTR_ERR(c); + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get aux_clk, rc=%d\n", + rc); + return rc; + } + sys_apcsaux_clk_gcc.c.parent = c; + + c = devm_clk_get(&pdev->dev, "xo_ao"); + if (IS_ERR(c)) { + rc = PTR_ERR(c); + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get xo_ao clk, rc=%d\n", + rc); + return rc; + } + xo_ao.c.parent = c; + + return 0; +} + +static void clk_osm_setup_cluster_pll(struct clk_osm *c) +{ + writel_relaxed(0x0, c->vbases[PLL_BASE] + PLL_MODE); + writel_relaxed(0x20, c->vbases[PLL_BASE] + PLL_L_VAL); + writel_relaxed(0x01000008, c->vbases[PLL_BASE] + + PLL_USER_CTRL); + writel_relaxed(0x20004AA8, c->vbases[PLL_BASE] + + PLL_CONFIG_CTL_LO); + writel_relaxed(0x2, c->vbases[PLL_BASE] + + PLL_MODE); + + /* Ensure writes complete before delaying */ + clk_osm_mb(c, PLL_BASE); + + udelay(PLL_WAIT_LOCK_TIME_US); + + writel_relaxed(0x6, c->vbases[PLL_BASE] + PLL_MODE); + + /* Ensure write completes before delaying */ + clk_osm_mb(c, PLL_BASE); + + usleep_range(50, 75); + + writel_relaxed(0x7, c->vbases[PLL_BASE] + PLL_MODE); +} + +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 table_entry_offset, last_spare, last_virtual_corner = 0; + + for (i = 0; i < OSM_TABLE_SIZE; i++) { + if (i < c->num_entries) { + freq_val = entry[i].freq_data; + volt_val = BVAL(21, 16, entry[i].virtual_corner) + | BVAL(11, 0, entry[i].open_loop_volt); + override_val = entry[i].override_data; + spare_val = entry[i].spare_data; + + if (last_virtual_corner && last_virtual_corner == + entry[i].virtual_corner && last_spare != + entry[i].spare_data) { + pr_err("invalid LUT entry at row=%d virtual_corner=%d, spare_data=%d\n", + i, entry[i].virtual_corner, + entry[i].spare_data); + return -EINVAL; + } + last_virtual_corner = entry[i].virtual_corner; + last_spare = entry[i].spare_data; + } + + table_entry_offset = i * OSM_REG_SIZE; + clk_osm_write_reg(c, i, INDEX_REG + table_entry_offset); + clk_osm_write_reg(c, freq_val, FREQ_REG + table_entry_offset); + clk_osm_write_reg(c, volt_val, VOLT_REG + table_entry_offset); + clk_osm_write_reg(c, override_val, OVERRIDE_REG + + table_entry_offset); + clk_osm_write_reg(c, spare_val, SPARE_REG + + table_entry_offset); + } + + /* Make sure all writes go through */ + clk_osm_mb(c, OSM_BASE); + + return 0; +} + +static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c) +{ + struct regulator *regulator = c->vdd_reg; + u32 vc, mv; + int i; + + for (i = 0; i < OSM_TABLE_SIZE; i++) { + vc = c->osm_table[i].virtual_corner + 1; + /* Voltage is in uv. Convert to mv */ + mv = regulator_list_corner_voltage(regulator, vc) / 1000; + c->osm_table[i].open_loop_volt = mv; + } + + return 0; +} + +static int clk_osm_resolve_crossover_corners(struct clk_osm *c, + struct platform_device *pdev) +{ + struct regulator *regulator = c->vdd_reg; + int count, vc, i, threshold, rc = 0; + u32 corner_volt; + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,apm-threshold-voltage", + &threshold); + if (rc) { + pr_info("qcom,apm-threshold-voltage property not specified\n"); + return rc; + } + + /* Determine crossover virtual corner */ + count = regulator_count_voltages(regulator); + if (count < 0) { + pr_err("Failed to get the number of virtual corners supported\n"); + return count; + } + + c->apm_crossover_vc = count - 1; + + /* Determine threshold virtual corner */ + for (i = 0; i < OSM_TABLE_SIZE; i++) { + vc = c->osm_table[i].virtual_corner + 1; + corner_volt = regulator_list_corner_voltage(regulator, vc); + + if (corner_volt >= threshold) { + c->apm_threshold_vc = c->osm_table[i].virtual_corner; + break; + } + } + + return 0; +} + +static int clk_osm_set_cc_policy(struct platform_device *pdev) +{ + int rc = 0, val; + u32 *array; + struct device_node *of = pdev->dev.of_node; + + array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), + GFP_KERNEL); + if (!array) + return -ENOMEM; + + rc = of_property_read_u32_array(of, "qcom,up-timer", array, + MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "No up timer value, rc=%d\n", + rc); + } else { + val = clk_osm_read_reg(&pwrcl_clk, SPM_CC_HYSTERESIS) + | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk, + array[pwrcl_clk.cluster_num])); + clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_HYSTERESIS); + val = clk_osm_read_reg(&perfcl_clk, SPM_CC_HYSTERESIS) + | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk, + array[perfcl_clk.cluster_num])); + clk_osm_write_reg(&perfcl_clk, val, SPM_CC_HYSTERESIS); + } + + rc = of_property_read_u32_array(of, "qcom,down-timer", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "No down timer value, rc=%d\n", rc); + } else { + val = clk_osm_read_reg(&pwrcl_clk, SPM_CC_HYSTERESIS) + | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk, + array[pwrcl_clk.cluster_num])); + clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_HYSTERESIS); + val = clk_osm_read_reg(&perfcl_clk, SPM_CC_HYSTERESIS) + | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk, + array[perfcl_clk.cluster_num])); + clk_osm_write_reg(&perfcl_clk, val, SPM_CC_HYSTERESIS); + } + + /* OSM index override for cluster PC */ + rc = of_property_read_u32_array(of, "qcom,pc-override-index", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "No PC override index value, rc=%d\n", + rc); + clk_osm_write_reg(&pwrcl_clk, 0, CC_ZERO_BEHAV_CTRL); + clk_osm_write_reg(&perfcl_clk, 0, CC_ZERO_BEHAV_CTRL); + } else { + val = BVAL(6, 1, array[pwrcl_clk.cluster_num]) + | ENABLE_OVERRIDE; + clk_osm_write_reg(&pwrcl_clk, val, CC_ZERO_BEHAV_CTRL); + val = BVAL(6, 1, array[perfcl_clk.cluster_num]) + | ENABLE_OVERRIDE; + clk_osm_write_reg(&perfcl_clk, val, CC_ZERO_BEHAV_CTRL); + } + + /* Wait for the writes to complete */ + clk_osm_mb(&perfcl_clk, OSM_BASE); + + rc = of_property_read_bool(pdev->dev.of_node, "qcom,set-ret-inactive"); + if (rc) { + dev_dbg(&pdev->dev, "Treat cores in retention as active\n"); + val = 0; + } else { + dev_dbg(&pdev->dev, "Treat cores in retention as inactive\n"); + val = 1; + } + + clk_osm_write_reg(&pwrcl_clk, val, SPM_CORE_RET_MAPPING); + clk_osm_write_reg(&perfcl_clk, val, SPM_CORE_RET_MAPPING); + + rc = of_property_read_bool(pdev->dev.of_node, "qcom,disable-cc-dvcs"); + if (rc) { + dev_dbg(&pdev->dev, "Disabling CC based DCVS\n"); + val = 1; + } else + val = 0; + + clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_DCVS_DISABLE); + clk_osm_write_reg(&perfcl_clk, val, SPM_CC_DCVS_DISABLE); + + /* Wait for the writes to complete */ + clk_osm_mb(&perfcl_clk, OSM_BASE); + + devm_kfree(&pdev->dev, array); + return 0; +} + +static void clk_osm_setup_itm_to_osm_handoff(void) +{ + /* Program address of ITM_PRESENT of CPUSS */ + clk_osm_write_reg(&pwrcl_clk, pwrcl_clk.apcs_itm_present, + SEQ_REG(37)); + clk_osm_write_reg(&pwrcl_clk, 0, SEQ_REG(38)); + clk_osm_write_reg(&perfcl_clk, perfcl_clk.apcs_itm_present, + SEQ_REG(37)); + clk_osm_write_reg(&perfcl_clk, 0, SEQ_REG(38)); + + /* + * Program data to write to ITM_PRESENT assuming ITM for other domain + * is enabled and the ITM for this domain is to be disabled. + */ + clk_osm_write_reg(&pwrcl_clk, ITM_CL0_DISABLE_CL1_ENABLED, + SEQ_REG(39)); + clk_osm_write_reg(&perfcl_clk, ITM_CL0_ENABLED_CL1_DISABLE, + SEQ_REG(39)); +} + +static int clk_osm_set_llm_freq_policy(struct platform_device *pdev) +{ + struct device_node *of = pdev->dev.of_node; + u32 *array; + int rc = 0, val, regval; + + array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), + GFP_KERNEL); + if (!array) + return -ENOMEM; + + /* + * Setup Timer to control how long OSM should wait before performing + * DCVS when a LLM up frequency request is received. + * Time is specified in us. + */ + rc = of_property_read_u32_array(of, "qcom,llm-freq-up-timer", array, + MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "Unable to get CC up timer value: %d\n", + rc); + } else { + val = clk_osm_read_reg(&pwrcl_clk, LLM_FREQ_VOTE_HYSTERESIS) + | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk, + array[pwrcl_clk.cluster_num])); + clk_osm_write_reg(&pwrcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS); + val = clk_osm_read_reg(&perfcl_clk, LLM_FREQ_VOTE_HYSTERESIS) + | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk, + array[perfcl_clk.cluster_num])); + clk_osm_write_reg(&perfcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS); + } + + /* + * Setup Timer to control how long OSM should wait before performing + * DCVS when a LLM down frequency request is received. + * Time is specified in us. + */ + rc = of_property_read_u32_array(of, "qcom,llm-freq-down-timer", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "No LLM Frequency down timer value: %d\n", + rc); + } else { + val = clk_osm_read_reg(&pwrcl_clk, LLM_FREQ_VOTE_HYSTERESIS) + | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk, + array[pwrcl_clk.cluster_num])); + clk_osm_write_reg(&pwrcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS); + val = clk_osm_read_reg(&perfcl_clk, LLM_FREQ_VOTE_HYSTERESIS) + | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk, + array[perfcl_clk.cluster_num])); + clk_osm_write_reg(&perfcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS); + } + + /* Enable or disable honoring of LLM frequency requests */ + rc = of_property_read_bool(pdev->dev.of_node, + "qcom,enable-llm-freq-vote"); + if (rc) { + dev_dbg(&pdev->dev, "Honoring LLM Frequency requests\n"); + val = 0; + } else + val = 1; + + /* Enable or disable LLM FREQ DVCS */ + regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE); + clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE); + regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE); + clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE); + + /* Wait for the write to complete */ + clk_osm_mb(&perfcl_clk, OSM_BASE); + + devm_kfree(&pdev->dev, array); + return 0; +} + +static int clk_osm_set_llm_volt_policy(struct platform_device *pdev) +{ + struct device_node *of = pdev->dev.of_node; + u32 *array; + int rc = 0, val, regval; + + array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), + GFP_KERNEL); + if (!array) + return -ENOMEM; + + /* + * Setup Timer to control how long OSM should wait before performing + * DCVS when a LLM up voltage request is received. + * Time is specified in us. + */ + rc = of_property_read_u32_array(of, "qcom,llm-volt-up-timer", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "No LLM voltage up timer value, rc=%d\n", + rc); + } else { + val = clk_osm_read_reg(&pwrcl_clk, LLM_VOLT_VOTE_HYSTERESIS) + | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk, + array[pwrcl_clk.cluster_num])); + clk_osm_write_reg(&pwrcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS); + val = clk_osm_read_reg(&perfcl_clk, LLM_VOLT_VOTE_HYSTERESIS) + | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk, + array[perfcl_clk.cluster_num])); + clk_osm_write_reg(&perfcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS); + } + + /* + * Setup Timer to control how long OSM should wait before performing + * DCVS when a LLM down voltage request is received. + * Time is specified in us. + */ + rc = of_property_read_u32_array(of, "qcom,llm-volt-down-timer", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_dbg(&pdev->dev, "No LLM Voltage down timer value: %d\n", + rc); + } else { + val = clk_osm_read_reg(&pwrcl_clk, LLM_VOLT_VOTE_HYSTERESIS) + | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk, + array[pwrcl_clk.cluster_num])); + clk_osm_write_reg(&pwrcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS); + val = clk_osm_read_reg(&perfcl_clk, LLM_VOLT_VOTE_HYSTERESIS) + | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk, + array[perfcl_clk.cluster_num])); + clk_osm_write_reg(&perfcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS); + } + + /* Enable or disable honoring of LLM Voltage requests */ + rc = of_property_read_bool(pdev->dev.of_node, + "qcom,enable-llm-volt-vote"); + if (rc) { + dev_dbg(&pdev->dev, "Honoring LLM Voltage requests\n"); + val = 0; + } else + val = BIT(1); + + /* Enable or disable LLM VOLT DVCS */ + regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE); + clk_osm_write_reg(&pwrcl_clk, val, LLM_INTF_DCVS_DISABLE); + regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE); + clk_osm_write_reg(&perfcl_clk, val, LLM_INTF_DCVS_DISABLE); + + /* Wait for the writes to complete */ + clk_osm_mb(&perfcl_clk, OSM_BASE); + + devm_kfree(&pdev->dev, array); + return 0; +} + +static void clk_osm_program_apm_regs(struct clk_osm *c) +{ + /* + * Program address of the control register used to configure + * the Array Power Mux controller + */ + clk_osm_write_reg(c, c->apm_mode_ctl, SEQ_REG(2)); + + /* Program address of controller status register */ + clk_osm_write_reg(c, c->apm_ctrl_status, SEQ_REG(3)); + + /* Program mode value to switch APM from VDD_APCC to VDD_MX */ + clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(77)); + + /* Program value used to determine current APM power supply is VDD_MX */ + clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(78)); + + /* Program mask used to determine status of APM power supply switch */ + clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(79)); + + /* Program mode value to switch APM from VDD_MX to VDD_APCC */ + clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(80)); + + /* + * Program value used to determine current APM power supply + * is VDD_APCC + */ + clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(81)); +} + +static void clk_osm_program_mem_acc_regs(struct clk_osm *c) +{ + int i, curr_level, j = 0; + int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0}; + + curr_level = c->osm_table[0].spare_data; + for (i = 0; i < c->num_entries; i++) { + if (curr_level == MAX_MEM_ACC_LEVELS) + break; + + if (c->osm_table[i].spare_data != curr_level) { + mem_acc_level_map[j++] = i - 1; + curr_level = c->osm_table[i].spare_data; + } + } + + if (c->secure_init) { + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54)); + clk_osm_write_reg(c, MEM_ACC_APM_READ_MASK, SEQ_REG(59)); + clk_osm_write_reg(c, mem_acc_level_map[0], SEQ_REG(55)); + clk_osm_write_reg(c, mem_acc_level_map[0] + 1, SEQ_REG(56)); + clk_osm_write_reg(c, mem_acc_level_map[1], SEQ_REG(57)); + clk_osm_write_reg(c, mem_acc_level_map[1] + 1, SEQ_REG(58)); + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(28), + SEQ_REG(49)); + + for (i = 0; i < MAX_MEM_ACC_VALUES; i++) + clk_osm_write_reg(c, c->apcs_mem_acc_val[i], + MEM_ACC_SEQ_REG_VAL_START(i)); + + for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++) + clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i], + MEM_ACC_SEQ_REG_CFG_START(i)); + } else { + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55), + mem_acc_level_map[0]); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56), + mem_acc_level_map[0] + 1); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57), + mem_acc_level_map[1]); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58), + mem_acc_level_map[1] + 1); + /* SEQ_REG(49) = SEQ_REG(28) init by TZ */ + } +} + +void clk_osm_setup_sequencer(struct clk_osm *c) +{ + u32 i; + + pr_debug("Setting up sequencer for cluster=%d\n", c->cluster_num); + for (i = 0; i < ARRAY_SIZE(seq_instr); i++) { + clk_osm_write_reg(c, seq_instr[i], + (long)(SEQ_MEM_ADDR + i * 4)); + } + + pr_debug("Setting up sequencer branch instructions for cluster=%d\n", + c->cluster_num); + for (i = 0; i < ARRAY_SIZE(seq_br_instr); i++) { + clk_osm_write_reg(c, seq_br_instr[i], + (long)(SEQ_CFG_BR_ADDR + i * 4)); + } +} + +static void clk_osm_setup_cycle_counters(struct clk_osm *c) +{ + u32 ratio = c->osm_clk_rate; + u32 val = 0; + + /* Enable cycle counter */ + val |= BIT(0); + /* Setup OSM clock to XO ratio */ + do_div(ratio, c->xo_clk_rate); + val |= BVAL(5, 1, ratio - 1) | OSM_CYCLE_COUNTER_USE_XO_EDGE_EN; + clk_osm_write_reg(c, val, OSM_CYCLE_COUNTER_CTRL_REG); + c->total_cycle_counter = 0; + c->prev_cycle_counter = 0; + pr_debug("OSM to XO clock ratio: %d\n", ratio); +} + +static void clk_osm_setup_osm_was(struct clk_osm *c) +{ + u32 cc_hyst; + u32 val; + + if (msmcobalt_v2) + return; + + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + val |= IGNORE_PLL_LOCK_MASK; + cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS); + + if (c->secure_init) { + clk_osm_write_reg(c, val, SEQ_REG(47)); + val &= ~IGNORE_PLL_LOCK_MASK; + clk_osm_write_reg(c, val, SEQ_REG(48)); + + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(42), + SEQ_REG(40)); + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(43), + SEQ_REG(41)); + clk_osm_write_reg(c, 0x1, SEQ_REG(44)); + clk_osm_write_reg(c, 0x0, SEQ_REG(45)); + clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG, + SEQ_REG(46)); + + /* C2D/C3 + D2D workaround */ + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS, + SEQ_REG(6)); + clk_osm_write_reg(c, cc_hyst, SEQ_REG(7)); + + /* Droop detector PLL lock detect workaround */ + clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4)); + clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5)); + clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO + : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21)); + + /* PLL lock detect and HMSS AHB clock workaround */ + clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3); + + /* DxFSM workaround */ + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 : + 0x17811200, SEQ_REG(22)); + clk_osm_write_reg(c, 0x80800, SEQ_REG(23)); + clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24)); + clk_osm_write_reg(c, 0x11f, SEQ_REG(25)); + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 : + 0x17811290, SEQ_REG(26)); + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 : + 0x17811290, SEQ_REG(20)); + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 : + 0x17911290, SEQ_REG(32)); + clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35)); + clk_osm_write_reg(c, 0x11f, SEQ_REG(25)); + clk_osm_write_reg(c, 0xa, SEQ_REG(86)); + clk_osm_write_reg(c, 0xe, SEQ_REG(87)); + clk_osm_write_reg(c, 0x00400000, SEQ_REG(88)); + clk_osm_write_reg(c, 0x00700000, SEQ_REG(89)); + } else { + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val); + val &= ~IGNORE_PLL_LOCK_MASK; + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val); + + /* C2D/C3 + D2D workaround */ + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7), + cc_hyst); + + /* Droop detector PLL lock detect workaround */ + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4), + PLL_DD_USER_CTL_LO_ENABLE); + } + + if (c->cluster_num == 0) { + val = readl_relaxed(c->vbases[PLL_BASE] + PLL_TEST_CTL_HI) + | BIT(13); + writel_relaxed(val, c->vbases[PLL_BASE] + + PLL_TEST_CTL_HI); + } + + /* Ensure writes complete before returning */ + clk_osm_mb(c, OSM_BASE); +} + +static void clk_osm_setup_fsms(struct clk_osm *c) +{ + u32 val; + + /* Reduction FSM */ + if (c->red_fsm_en) { + val = clk_osm_read_reg(c, VMIN_REDUC_ENABLE_REG) | BIT(0); + clk_osm_write_reg(c, val, VMIN_REDUC_ENABLE_REG); + clk_osm_write_reg(c, BVAL(15, 0, clk_osm_count_ns(c, 10000)), + VMIN_REDUC_TIMER_REG); + } + + /* Boost FSM */ + if (c->boost_fsm_en) { + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + clk_osm_write_reg(c, val | CC_BOOST_EN_MASK, PDN_FSM_CTRL_REG); + + val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG0); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); + clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG0); + + val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG1); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG1); + + val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG2); + val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); + clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG2); + } + + /* Safe Freq FSM */ + if (c->safe_fsm_en) { + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + clk_osm_write_reg(c, val | DCVS_BOOST_EN_MASK, + PDN_FSM_CTRL_REG); + + val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG0); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); + clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG0); + + val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG1); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG1); + + val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG2); + val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); + clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG2); + + } + + /* PS FSM */ + if (c->ps_fsm_en) { + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + clk_osm_write_reg(c, val | PS_BOOST_EN_MASK, PDN_FSM_CTRL_REG); + + val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG0); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); + clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG0); + + val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG1); + val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); + clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG1); + + val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG2); + val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); + clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG2); + } + + /* PLL signal timing control */ + if (c->boost_fsm_en || c->safe_fsm_en || c->ps_fsm_en) + clk_osm_write_reg(c, 0x5, BOOST_PROG_SYNC_DELAY_REG); + + /* Droop FSM */ + if (c->wfx_fsm_en) { + /* WFx FSM */ + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + clk_osm_write_reg(c, val | WFX_DROOP_EN_MASK, PDN_FSM_CTRL_REG); + + val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG); + val |= BVAL(31, 16, clk_osm_count_ns(c, 500)); + clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG); + + val = clk_osm_read_reg(c, + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + val |= BVAL(31, 16, clk_osm_count_ns(c, 250)); + clk_osm_write_reg(c, val, + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + } + + /* PC/RET FSM */ + if (c->pc_fsm_en) { + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + clk_osm_write_reg(c, val | PC_RET_EXIT_DROOP_EN_MASK, + PDN_FSM_CTRL_REG); + + val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG); + val |= BVAL(15, 0, clk_osm_count_ns(c, 500)); + clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG); + + val = clk_osm_read_reg(c, + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + val |= BVAL(15, 0, clk_osm_count_ns(c, 250)); + clk_osm_write_reg(c, val, + DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG); + } + + /* DCVS droop FSM - only if RCGwRC is not used for di/dt control */ + if (c->droop_fsm_en) { + val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); + clk_osm_write_reg(c, val | DCVS_DROOP_EN_MASK, + PDN_FSM_CTRL_REG); + } + + if (c->wfx_fsm_en || c->ps_fsm_en || c->droop_fsm_en) { + clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG); + clk_osm_write_reg(c, clk_osm_count_ns(c, 5), + DROOP_RELEASE_TIMER_CTRL); + clk_osm_write_reg(c, clk_osm_count_ns(c, 500), + DCVS_DROOP_TIMER_CTRL); + val = clk_osm_read_reg(c, DROOP_CTRL_REG); + val |= BIT(31) | BVAL(22, 16, 0x2) | + BVAL(6, 0, 0x8); + clk_osm_write_reg(c, val, DROOP_CTRL_REG); + } + + /* Enable the PLL Droop Override */ + val = clk_osm_read_reg(c, OSM_PLL_SW_OVERRIDE_EN); + val |= PLL_SW_OVERRIDE_DROOP_EN; + clk_osm_write_reg(c, val, OSM_PLL_SW_OVERRIDE_EN); +} + +static void clk_osm_do_additional_setup(struct clk_osm *c, + struct platform_device *pdev) +{ + if (!c->secure_init) + return; + + dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n", + c->cluster_num); + + clk_osm_write_reg(c, BVAL(23, 16, 0xF), SPM_CC_CTRL); + + /* PLL LVAL programming */ + clk_osm_write_reg(c, c->l_val_base, SEQ_REG(0)); + clk_osm_write_reg(c, PLL_MIN_LVAL, SEQ_REG(21)); + + /* PLL post-div programming */ + clk_osm_write_reg(c, c->apcs_pll_user_ctl, SEQ_REG(18)); + clk_osm_write_reg(c, PLL_POST_DIV2, SEQ_REG(19)); + clk_osm_write_reg(c, PLL_POST_DIV1, SEQ_REG(29)); + + /* APM Programming */ + clk_osm_program_apm_regs(c); + + /* GFMUX Programming */ + clk_osm_write_reg(c, c->apcs_cfg_rcgr, SEQ_REG(16)); + clk_osm_write_reg(c, c->apcs_cmd_rcgr, SEQ_REG(33)); + clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(34)); + clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17)); + clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(82)); + clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(83)); + clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(84)); + clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(85)); + + /* ITM to OSM handoff */ + clk_osm_setup_itm_to_osm_handoff(); + + pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr), + ARRAY_SIZE(seq_br_instr)); + clk_osm_setup_sequencer(&pwrcl_clk); + clk_osm_setup_sequencer(&perfcl_clk); +} + +static void clk_osm_apm_vc_setup(struct clk_osm *c) +{ + /* + * APM crossover virtual corner corresponds to switching + * voltage during APM transition. APM threshold virtual + * corner is the first corner which requires switch + * sequence of APM from MX to APC. + */ + if (c->secure_init) { + clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1)); + clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72)); + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1), + SEQ_REG(8)); + clk_osm_write_reg(c, c->apm_threshold_vc, + SEQ_REG(15)); + clk_osm_write_reg(c, c->apm_threshold_vc != 0 ? + c->apm_threshold_vc - 1 : 0xff, + SEQ_REG(31)); + clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6, + SEQ_REG(73)); + clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6, + SEQ_REG(76)); + + /* Ensure writes complete before returning */ + clk_osm_mb(c, OSM_BASE); + } else { + if (msmcobalt_v1) { + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1), + c->apm_threshold_vc); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73), + 0x3b | c->apm_threshold_vc << 6); + } else if (msmcobalt_v2) { + clk_osm_write_reg(c, c->apm_threshold_vc, + SEQ_REG1_MSMCOBALT_V2); + } + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72), + c->apm_crossover_vc); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(15), + c->apm_threshold_vc); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31), + c->apm_threshold_vc != 0 ? + c->apm_threshold_vc - 1 : 0xff); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76), + 0x39 | c->apm_threshold_vc << 6); + } +} + +static irqreturn_t clk_osm_debug_irq_cb(int irq, void *data) +{ + struct clk_osm *c = data; + unsigned long first, second, total_delta = 0; + u32 val, factor; + int i; + + val = clk_osm_read_reg(c, DCVS_PERF_STATE_DEVIATION_INTR_STAT); + if (val & BIT(0)) { + pr_info("OS DCVS performance state deviated\n"); + clk_osm_write_reg(c, BIT(0), + DCVS_PERF_STATE_DEVIATION_INTR_CLEAR); + } + + val = clk_osm_read_reg(c, + DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT); + if (val & BIT(0)) { + pr_info("OS DCVS performance state corrected\n"); + clk_osm_write_reg(c, BIT(0), + DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR); + } + + val = clk_osm_read_reg(c, DCVS_PERF_STATE_MET_INTR_STAT); + if (val & BIT(0)) { + pr_info("OS DCVS performance state desired reached\n"); + clk_osm_write_reg(c, BIT(0), DCVS_PERF_STATE_MET_INTR_CLR); + } + + factor = c->cycle_counter_factor ? c->cycle_counter_factor : 1; + + for (i = 0; i < c->cycle_counter_reads; i++) { + first = clk_osm_read_reg(c, OSM_CYCLE_COUNTER_STATUS_REG); + + if (c->cycle_counter_delay) + udelay(c->cycle_counter_delay); + + second = clk_osm_read_reg(c, OSM_CYCLE_COUNTER_STATUS_REG); + total_delta = total_delta + ((second - first) / factor); + } + + pr_info("cluster=%d, L_VAL (estimated)=%lu\n", + c->cluster_num, total_delta / c->cycle_counter_factor); + + return IRQ_HANDLED; +} + +static int clk_osm_setup_irq(struct platform_device *pdev, struct clk_osm *c, + char *irq_name) +{ + int rc = 0; + + rc = c->irq = platform_get_irq_byname(pdev, irq_name); + if (rc < 0) { + dev_err(&pdev->dev, "%s irq not specified\n", irq_name); + return rc; + } + + rc = devm_request_irq(&pdev->dev, c->irq, + clk_osm_debug_irq_cb, + IRQF_TRIGGER_RISING | IRQF_SHARED, + "OSM IRQ", c); + if (rc) + dev_err(&pdev->dev, "Request IRQ failed for OSM IRQ\n"); + + return rc; +} + +static u32 find_voltage(struct clk_osm *c, unsigned long rate) +{ + struct osm_entry *table = c->osm_table; + int entries = c->num_entries, i; + + for (i = 0; i < entries; i++) { + if (rate == table[i].frequency) { + /* OPP table voltages have units of mV */ + return table[i].open_loop_volt * 1000; + } + } + + return -EINVAL; +} + +static int add_opp(struct clk_osm *c, struct device *dev) +{ + unsigned long rate = 0; + u32 uv; + long rc; + int j = 0; + unsigned long min_rate = c->c.fmax[0]; + unsigned long max_rate = c->c.fmax[c->c.num_fmax - 1]; + + while (1) { + rate = c->c.fmax[j++]; + uv = find_voltage(c, rate); + if (uv <= 0) { + pr_warn("No voltage for %lu.\n", rate); + return -EINVAL; + } + + rc = dev_pm_opp_add(dev, rate, uv); + if (rc) { + pr_warn("failed to add OPP for %lu\n", rate); + return rc; + } + + /* + * Print the OPP pair for the lowest and highest frequency for + * each device that we're populating. This is important since + * this information will be used by thermal mitigation and the + * scheduler. + */ + if (rate == min_rate) + pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", + rate, uv, dev_name(dev)); + + if (rate == max_rate && max_rate != min_rate) { + pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", + rate, uv, dev_name(dev)); + break; + } + + if (min_rate == max_rate) + break; + } + + return 0; +} + +static struct clk *logical_cpu_to_clk(int cpu) +{ + struct device_node *cpu_node; + const u32 *cell; + u64 hwid; + static struct clk *cpu_clk_map[NR_CPUS]; + + if (cpu_clk_map[cpu]) + return cpu_clk_map[cpu]; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (!cpu_node) + goto fail; + + cell = of_get_property(cpu_node, "reg", NULL); + if (!cell) { + pr_err("%s: missing reg property\n", cpu_node->full_name); + goto fail; + } + + hwid = of_read_number(cell, of_n_addr_cells(cpu_node)); + if ((hwid | pwrcl_clk.cpu_reg_mask) == pwrcl_clk.cpu_reg_mask) { + cpu_clk_map[cpu] = &pwrcl_clk.c; + return &pwrcl_clk.c; + } + if ((hwid | perfcl_clk.cpu_reg_mask) == perfcl_clk.cpu_reg_mask) { + cpu_clk_map[cpu] = &perfcl_clk.c; + return &perfcl_clk.c; + } + +fail: + return NULL; +} + +static u64 clk_osm_get_cpu_cycle_counter(int cpu) +{ + struct clk_osm *c; + u32 val; + unsigned long flags; + + if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) + c = &pwrcl_clk; + else if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) + c = &perfcl_clk; + else { + pr_err("no clock device for CPU=%d\n", cpu); + return 0; + } + + spin_lock_irqsave(&c->lock, flags); + val = clk_osm_read_reg_no_log(c, OSM_CYCLE_COUNTER_STATUS_REG); + + if (val < c->prev_cycle_counter) { + /* Handle counter overflow */ + c->total_cycle_counter += UINT_MAX - + c->prev_cycle_counter + val; + c->prev_cycle_counter = val; + } else { + c->total_cycle_counter += val - c->prev_cycle_counter; + c->prev_cycle_counter = val; + } + spin_unlock_irqrestore(&c->lock, flags); + + return c->total_cycle_counter; +} + +static void populate_opp_table(struct platform_device *pdev) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) { + WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)), + "Failed to add OPP levels for power cluster\n"); + } + if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) { + WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)), + "Failed to add OPP levels for perf cluster\n"); + } + } +} + +static int debugfs_get_trace_enable(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = c->trace_en; + return 0; +} + +static int debugfs_set_trace_enable(void *data, u64 val) +{ + struct clk_osm *c = data; + + clk_osm_masked_write_reg(c, val ? TRACE_CTRL_ENABLE : + TRACE_CTRL_DISABLE, + TRACE_CTRL, TRACE_CTRL_EN_MASK); + c->trace_en = val ? true : false; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_enable_fops, + debugfs_get_trace_enable, + debugfs_set_trace_enable, + "%llu\n"); + +static int debugfs_get_wdog_trace(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = c->wdog_trace_en; + return 0; +} + +static int debugfs_set_wdog_trace(void *data, u64 val) +{ + struct clk_osm *c = data; + int regval; + + if (c->version >= VERSION_1P1) { + regval = clk_osm_read_reg(c, TRACE_CTRL); + regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS : + regval & ~TRACE_CTRL_ENABLE_WDOG_STATUS; + clk_osm_write_reg(c, regval, TRACE_CTRL); + c->wdog_trace_en = val ? true : false; + } else { + pr_info("wdog status registers enabled by default\n"); + } + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_wdog_enable_fops, + debugfs_get_wdog_trace, + debugfs_set_wdog_trace, + "%llu\n"); + +#define MAX_DEBUG_BUF_LEN 15 + +static DEFINE_MUTEX(debug_buf_mutex); +static char debug_buf[MAX_DEBUG_BUF_LEN]; + +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; + u32 val; + + if (IS_ERR(file) || file == NULL) { + pr_err("input error %ld\n", PTR_ERR(file)); + return -EINVAL; + } + + if (!c) { + pr_err("invalid clk_osm handle\n"); + return -EINVAL; + } + + if (count < MAX_DEBUG_BUF_LEN) { + mutex_lock(&debug_buf_mutex); + + if (copy_from_user(debug_buf, (void __user *) buf, count)) { + mutex_unlock(&debug_buf_mutex); + return -EFAULT; + } + debug_buf[count] = '\0'; + mutex_unlock(&debug_buf_mutex); + + /* check that user entered a supported packet type */ + if (strcmp(debug_buf, "periodic\n") == 0) { + clk_osm_write_reg(c, clk_osm_count_ns(c, + PERIODIC_TRACE_DEFAULT_NS), + PERIODIC_TRACE_TIMER_CTRL); + clk_osm_masked_write_reg(c, + TRACE_CTRL_PERIODIC_TRACE_ENABLE, + TRACE_CTRL, TRACE_CTRL_PERIODIC_TRACE_EN_MASK); + c->trace_method = PERIODIC_PACKET; + c->trace_periodic_timer = PERIODIC_TRACE_DEFAULT_NS; + return count; + } else if (strcmp(debug_buf, "xor\n") == 0) { + val = clk_osm_read_reg(c, TRACE_CTRL); + val &= ~TRACE_CTRL_PERIODIC_TRACE_ENABLE; + clk_osm_write_reg(c, val, TRACE_CTRL); + c->trace_method = XOR_PACKET; + return count; + } + } + + pr_err("error, supported trace mode types: 'periodic' or 'xor'\n"); + return -EINVAL; +} + +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; + int len, rc; + + if (IS_ERR(file) || file == NULL) { + pr_err("input error %ld\n", PTR_ERR(file)); + return -EINVAL; + } + + if (!c) { + pr_err("invalid clk_osm handle\n"); + return -EINVAL; + } + + mutex_lock(&debug_buf_mutex); + + if (c->trace_method == PERIODIC_PACKET) + len = snprintf(debug_buf, sizeof(debug_buf), "periodic\n"); + else if (c->trace_method == XOR_PACKET) + len = snprintf(debug_buf, sizeof(debug_buf), "xor\n"); + + rc = simple_read_from_buffer((void __user *) buf, len, ppos, + (void *) debug_buf, len); + + mutex_unlock(&debug_buf_mutex); + + return rc; +} + +static int debugfs_trace_method_open(struct inode *inode, struct file *file) +{ + if (IS_ERR(file) || file == NULL) { + pr_err("input error %ld\n", PTR_ERR(file)); + return -EINVAL; + } + + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations debugfs_trace_method_fops = { + .write = debugfs_trace_method_set, + .open = debugfs_trace_method_open, + .read = debugfs_trace_method_get, +}; + +static int debugfs_get_trace_packet_id(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = c->trace_id; + return 0; +} + +static int debugfs_set_trace_packet_id(void *data, u64 val) +{ + struct clk_osm *c = data; + + if (val < TRACE_PACKET0 || val > TRACE_PACKET3) { + pr_err("supported trace IDs=%d-%d\n", + TRACE_PACKET0, TRACE_PACKET3); + return 0; + } + + clk_osm_masked_write_reg(c, val << TRACE_CTRL_PACKET_TYPE_SHIFT, + TRACE_CTRL, TRACE_CTRL_PACKET_TYPE_MASK); + c->trace_id = val; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_packet_id_fops, + debugfs_get_trace_packet_id, + debugfs_set_trace_packet_id, + "%llu\n"); + +static int debugfs_get_trace_periodic_timer(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = c->trace_periodic_timer; + return 0; +} + +static int debugfs_set_trace_periodic_timer(void *data, u64 val) +{ + struct clk_osm *c = data; + + if (val < PERIODIC_TRACE_MIN_NS || val > PERIODIC_TRACE_MAX_NS) { + pr_err("supported periodic trace periods=%d-%ld ns\n", + PERIODIC_TRACE_MIN_NS, PERIODIC_TRACE_MAX_NS); + return 0; + } + + clk_osm_write_reg(c, clk_osm_count_ns(c, val), + PERIODIC_TRACE_TIMER_CTRL); + c->trace_periodic_timer = val; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_periodic_timer_fops, + debugfs_get_trace_periodic_timer, + debugfs_set_trace_periodic_timer, + "%llu\n"); + +static int debugfs_get_perf_state_met_irq(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = clk_osm_read_reg(c, DCVS_PERF_STATE_MET_INTR_EN); + return 0; +} + +static int debugfs_set_perf_state_met_irq(void *data, u64 val) +{ + struct clk_osm *c = data; + + clk_osm_write_reg(c, val ? 1 : 0, + DCVS_PERF_STATE_MET_INTR_EN); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_met_irq_fops, + debugfs_get_perf_state_met_irq, + debugfs_set_perf_state_met_irq, + "%llu\n"); + +static int debugfs_get_perf_state_deviation_irq(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = clk_osm_read_reg(c, + DCVS_PERF_STATE_DEVIATION_INTR_EN); + return 0; +} + +static int debugfs_set_perf_state_deviation_irq(void *data, u64 val) +{ + struct clk_osm *c = data; + + clk_osm_write_reg(c, val ? 1 : 0, + DCVS_PERF_STATE_DEVIATION_INTR_EN); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_deviation_irq_fops, + debugfs_get_perf_state_deviation_irq, + debugfs_set_perf_state_deviation_irq, + "%llu\n"); + +static int debugfs_get_perf_state_deviation_corrected_irq(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = clk_osm_read_reg(c, + DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN); + return 0; +} + +static int debugfs_set_perf_state_deviation_corrected_irq(void *data, u64 val) +{ + struct clk_osm *c = data; + + clk_osm_write_reg(c, val ? 1 : 0, + DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_deviation_corrected_irq_fops, + debugfs_get_perf_state_deviation_corrected_irq, + debugfs_set_perf_state_deviation_corrected_irq, + "%llu\n"); + +static int debugfs_get_debug_reg(void *data, u64 *val) +{ + struct clk_osm *c = data; + + if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR) + *val = readl_relaxed((char *)c->vbases[ACD_BASE] + + c->acd_debugfs_addr); + else + *val = clk_osm_acd_local_read_reg(c, c->acd_debugfs_addr); + return 0; +} + +static int debugfs_set_debug_reg(void *data, u64 val) +{ + struct clk_osm *c = data; + + if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR) + clk_osm_acd_master_write_reg(c, val, c->acd_debugfs_addr); + else + clk_osm_acd_master_write_through_reg(c, val, + c->acd_debugfs_addr); + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_fops, + debugfs_get_debug_reg, + debugfs_set_debug_reg, + "0x%llx\n"); + +static int debugfs_get_debug_reg_addr(void *data, u64 *val) +{ + struct clk_osm *c = data; + + *val = c->acd_debugfs_addr; + return 0; +} + +static int debugfs_set_debug_reg_addr(void *data, u64 val) +{ + struct clk_osm *c = data; + + c->acd_debugfs_addr = val; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_addr_fops, + debugfs_get_debug_reg_addr, + debugfs_set_debug_reg_addr, + "%llu\n"); + +static void populate_debugfs_dir(struct clk_osm *c) +{ + struct dentry *temp; + + if (osm_debugfs_base == NULL) { + osm_debugfs_base = debugfs_create_dir("osm", NULL); + if (IS_ERR_OR_NULL(osm_debugfs_base)) { + pr_err("osm debugfs base directory creation failed\n"); + osm_debugfs_base = NULL; + return; + } + } + + c->debugfs = debugfs_create_dir(c->c.dbg_name, osm_debugfs_base); + if (IS_ERR_OR_NULL(c->debugfs)) { + pr_err("osm debugfs directory creation failed\n"); + return; + } + + temp = debugfs_create_file("perf_state_met_irq_enable", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_perf_state_met_irq_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("perf_state_met_irq_enable debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("perf_state_deviation_irq_enable", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_perf_state_deviation_irq_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("perf_state_deviation_irq_enable debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("perf_state_deviation_corrected_irq_enable", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_perf_state_deviation_corrected_irq_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_perf_state_deviation_corrected_irq_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("wdog_trace_enable", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_trace_wdog_enable_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_trace_wdog_enable_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("trace_enable", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_trace_enable_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_trace_enable_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("trace_method", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_trace_method_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_trace_method_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("trace_packet_id", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_trace_packet_id_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_trace_packet_id_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("trace_periodic_timer", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_trace_periodic_timer_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_trace_periodic_timer_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("acd_debug_reg", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_acd_debug_reg_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_acd_debug_reg_fops debugfs file creation failed\n"); + goto exit; + } + + temp = debugfs_create_file("acd_debug_reg_addr", + S_IRUGO | S_IWUSR, + c->debugfs, c, + &debugfs_acd_debug_reg_addr_fops); + if (IS_ERR_OR_NULL(temp)) { + pr_err("debugfs_acd_debug_reg_addr_fops debugfs file creation failed\n"); + goto exit; + } + +exit: + if (IS_ERR_OR_NULL(temp)) + debugfs_remove_recursive(c->debugfs); +} + +static int clk_osm_panic_callback(struct notifier_block *nfb, + unsigned long event, + void *data) +{ + void __iomem *virt_addr; + u32 value, reg; + struct clk_osm *c = container_of(nfb, + struct clk_osm, + panic_notifier); + + reg = c->pbases[OSM_BASE] + WDOG_DOMAIN_PSTATE_STATUS; + virt_addr = ioremap(reg, 0x4); + if (virt_addr != NULL) { + value = readl_relaxed(virt_addr); + pr_err("DOM%d_PSTATE_STATUS[0x%08x]=0x%08x\n", c->cluster_num, + reg, value); + iounmap(virt_addr); + } + + reg = c->pbases[OSM_BASE] + WDOG_PROGRAM_COUNTER; + virt_addr = ioremap(reg, 0x4); + if (virt_addr != NULL) { + value = readl_relaxed(virt_addr); + pr_err("DOM%d_PROGRAM_COUNTER[0x%08x]=0x%08x\n", c->cluster_num, + reg, value); + iounmap(virt_addr); + } + + virt_addr = ioremap(c->apm_ctrl_status, 0x4); + if (virt_addr != NULL) { + value = readl_relaxed(virt_addr); + pr_err("APM_CTLER_STATUS_%d[0x%08x]=0x%08x\n", c->cluster_num, + c->apm_ctrl_status, value); + iounmap(virt_addr); + } + + return NOTIFY_OK; +} + +static int clk_osm_acd_init(struct clk_osm *c) +{ + + int rc = 0; + u32 auto_xfer_mask = 0; + + if (!c->acd_init) + return 0; + + c->acd_debugfs_addr = ACD_HW_VERSION; + + /* Program ACD tunable-length delay register */ + clk_osm_acd_master_write_reg(c, c->acd_td, ACDTD); + auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDTD); + + /* Program ACD control register */ + clk_osm_acd_master_write_reg(c, c->acd_cr, ACDCR); + auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDCR); + + /* Program ACD soft start control register */ + clk_osm_acd_master_write_reg(c, c->acd_sscr, ACDSSCR); + auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDSSCR); + + /* Program initial ACD external interface configuration register */ + clk_osm_acd_master_write_reg(c, c->acd_extint0_cfg, ACD_EXTINT_CFG); + auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACD_EXTINT_CFG); + + /* Program ACD auto-register transfer control register */ + clk_osm_acd_master_write_reg(c, c->acd_autoxfer_ctl, ACD_AUTOXFER_CTL); + + /* Ensure writes complete before transfers to local copy */ + clk_osm_acd_mb(c); + + /* Transfer master copies */ + rc = clk_osm_acd_auto_local_write_reg(c, auto_xfer_mask); + if (rc) + return rc; + + /* Switch CPUSS clock source to ACD clock */ + rc = clk_osm_acd_master_write_through_reg(c, ACD_GFMUX_CFG_SELECT, + ACD_GFMUX_CFG); + if (rc) + return rc; + + /* Program ACD_DCVS_SW */ + rc = clk_osm_acd_master_write_through_reg(c, + ACD_DCVS_SW_DCVS_IN_PRGR_SET, + ACD_DCVS_SW); + if (rc) + return rc; + + rc = clk_osm_acd_master_write_through_reg(c, + ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR, + ACD_DCVS_SW); + if (rc) + return rc; + + udelay(1); + + /* Program final ACD external interface configuration register */ + rc = clk_osm_acd_master_write_through_reg(c, c->acd_extint1_cfg, + ACD_EXTINT_CFG); + if (rc) + return rc; + + /* + * ACDCR, ACDTD, ACDSSCR, ACD_EXTINT_CFG, ACD_GFMUX_CFG + * must be copied from master to local copy on PC exit. + */ + auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACD_GFMUX_CFG); + clk_osm_acd_master_write_reg(c, auto_xfer_mask, ACD_AUTOXFER_CFG); + + return 0; +} + +static unsigned long init_rate = 300000000; +static unsigned long osm_clk_init_rate = 200000000; + +static int cpu_clock_osm_driver_probe(struct platform_device *pdev) +{ + int rc, cpu; + int speedbin = 0, pvs_ver = 0; + u32 pte_efuse; + char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; + char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; + struct cpu_cycle_counter_cb cb = { + .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter, + }; + + if (of_find_compatible_node(NULL, NULL, + "qcom,cpu-clock-osm-msmcobalt-v1")) { + msmcobalt_v1 = true; + } else if (of_find_compatible_node(NULL, NULL, + "qcom,cpu-clock-osm-msmcobalt-v2")) { + msmcobalt_v2 = true; + } + + rc = clk_osm_resources_init(pdev); + if (rc) { + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "resources init failed, rc=%d\n", + rc); + return rc; + } + + rc = clk_osm_parse_dt_configs(pdev); + if (rc) { + dev_err(&pdev->dev, "Unable to parse device tree configurations\n"); + return rc; + } + + if ((pwrcl_clk.secure_init || perfcl_clk.secure_init) && + msmcobalt_v2) { + pr_err("unsupported configuration for msmcobalt v2\n"); + return -EINVAL; + } + + if (pwrcl_clk.vbases[EFUSE_BASE]) { + /* Multiple speed-bins are supported */ + pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]); + speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) & + PWRCL_EFUSE_MASK); + snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr), + "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver); + } + + dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n", + speedbin, pvs_ver); + + rc = clk_osm_get_lut(pdev, &pwrcl_clk, + pwrclspeedbinstr); + if (rc) { + dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n", + rc); + return rc; + } + + if (perfcl_clk.vbases[EFUSE_BASE]) { + /* Multiple speed-bins are supported */ + pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]); + speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) & + PERFCL_EFUSE_MASK); + snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr), + "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver); + } + + dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n", + speedbin, pvs_ver); + + rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr); + if (rc) { + dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n", + rc); + return rc; + } + + rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk); + if (rc) { + if (rc == -EPROBE_DEFER) + return rc; + dev_err(&pdev->dev, "Unable to determine open-loop voltages for power cluster, rc=%d\n", + rc); + return rc; + } + + rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk); + if (rc) { + if (rc == -EPROBE_DEFER) + return rc; + dev_err(&pdev->dev, "Unable to determine open-loop voltages for perf cluster, rc=%d\n", + rc); + return rc; + } + + rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev); + if (rc) + dev_info(&pdev->dev, "No APM crossover corner programmed\n"); + + rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev); + if (rc) + dev_info(&pdev->dev, "No APM crossover corner programmed\n"); + + clk_osm_setup_cycle_counters(&pwrcl_clk); + clk_osm_setup_cycle_counters(&perfcl_clk); + + clk_osm_print_osm_table(&pwrcl_clk); + clk_osm_print_osm_table(&perfcl_clk); + + rc = clk_osm_setup_hw_table(&pwrcl_clk); + if (rc) { + dev_err(&pdev->dev, "failed to setup power cluster hardware table\n"); + goto exit; + } + rc = clk_osm_setup_hw_table(&perfcl_clk); + if (rc) { + dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n"); + goto exit; + } + + /* Policy tuning */ + rc = clk_osm_set_cc_policy(pdev); + if (rc < 0) { + dev_err(&pdev->dev, "cc policy setup failed"); + goto exit; + } + + /* LLM Freq Policy Tuning */ + rc = clk_osm_set_llm_freq_policy(pdev); + if (rc < 0) { + dev_err(&pdev->dev, "LLM Frequency Policy setup failed"); + goto exit; + } + + /* LLM Voltage Policy Tuning */ + rc = clk_osm_set_llm_volt_policy(pdev); + if (rc < 0) { + dev_err(&pdev->dev, "Failed to set LLM voltage Policy"); + goto exit; + } + + clk_osm_setup_fsms(&pwrcl_clk); + clk_osm_setup_fsms(&perfcl_clk); + + /* + * Perform typical secure-world HW initialization + * as necessary. + */ + clk_osm_do_additional_setup(&pwrcl_clk, pdev); + clk_osm_do_additional_setup(&perfcl_clk, pdev); + + /* MEM-ACC Programming */ + clk_osm_program_mem_acc_regs(&pwrcl_clk); + clk_osm_program_mem_acc_regs(&perfcl_clk); + + /* Program APM crossover corners */ + clk_osm_apm_vc_setup(&pwrcl_clk); + clk_osm_apm_vc_setup(&perfcl_clk); + + rc = clk_osm_setup_irq(pdev, &pwrcl_clk, "pwrcl-irq"); + if (rc) + pr_err("Debug IRQ not set for pwrcl\n"); + + rc = clk_osm_setup_irq(pdev, &perfcl_clk, "perfcl-irq"); + if (rc) + pr_err("Debug IRQ not set for perfcl\n"); + + clk_osm_setup_osm_was(&pwrcl_clk); + clk_osm_setup_osm_was(&perfcl_clk); + + if (of_property_read_bool(pdev->dev.of_node, + "qcom,osm-pll-setup")) { + clk_osm_setup_cluster_pll(&pwrcl_clk); + clk_osm_setup_cluster_pll(&perfcl_clk); + } + + rc = clk_osm_acd_init(&pwrcl_clk); + if (rc) { + pr_err("failed to initialize ACD for pwrcl, rc=%d\n", rc); + return rc; + } + rc = clk_osm_acd_init(&perfcl_clk); + if (rc) { + pr_err("failed to initialize ACD for perfcl, rc=%d\n", rc); + return rc; + } + + spin_lock_init(&pwrcl_clk.lock); + spin_lock_init(&perfcl_clk.lock); + + pwrcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback; + atomic_notifier_chain_register(&panic_notifier_list, + &pwrcl_clk.panic_notifier); + perfcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback; + atomic_notifier_chain_register(&panic_notifier_list, + &perfcl_clk.panic_notifier); + + rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm, + ARRAY_SIZE(cpu_clocks_osm)); + if (rc) { + dev_err(&pdev->dev, "Unable to register CPU clocks, rc=%d\n", + rc); + return rc; + } + + /* + * The hmss_gpll0 clock runs at 300 MHz. Ensure it is at the correct + * frequency before enabling OSM. LUT index 0 is always sourced from + * this clock. + */ + rc = clk_set_rate(&sys_apcsaux_clk_gcc.c, init_rate); + if (rc) { + dev_err(&pdev->dev, "Unable to set init rate on hmss_gpll0, rc=%d\n", + rc); + return rc; + } + clk_prepare_enable(&sys_apcsaux_clk_gcc.c); + + rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate); + if (rc) { + dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n", + rc); + goto exit2; + } + + /* Make sure index zero is selected */ + rc = clk_set_rate(&pwrcl_clk.c, init_rate); + if (rc) { + dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n", + rc); + goto exit2; + } + + rc = clk_set_rate(&perfcl_clk.c, init_rate); + if (rc) { + dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n", + rc); + goto exit2; + } + + get_online_cpus(); + + /* Enable OSM */ + for_each_online_cpu(cpu) { + WARN(clk_prepare_enable(logical_cpu_to_clk(cpu)), + "Failed to enable clock for cpu %d\n", cpu); + } + + /* Set final boot rate */ + rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ? + MSMCOBALTV1_PWRCL_BOOT_RATE : + MSMCOBALTV2_PWRCL_BOOT_RATE); + if (rc) { + dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n", + rc); + goto exit2; + } + + rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ? + MSMCOBALTV1_PERFCL_BOOT_RATE : + MSMCOBALTV2_PERFCL_BOOT_RATE); + if (rc) { + dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n", + rc); + goto exit2; + } + + pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG); + perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG); + + populate_opp_table(pdev); + populate_debugfs_dir(&pwrcl_clk); + populate_debugfs_dir(&perfcl_clk); + + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + + register_cpu_cycle_counter_cb(&cb); + + pr_info("OSM driver inited\n"); + put_online_cpus(); + + return 0; + +exit2: + clk_disable_unprepare(&sys_apcsaux_clk_gcc.c); +exit: + dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", + rc); + panic("Unable to Setup OSM"); +} + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,cpu-clock-osm-msmcobalt-v1" }, + { .compatible = "qcom,cpu-clock-osm-msmcobalt-v2" }, + {} +}; + +static struct platform_driver cpu_clock_osm_driver = { + .probe = cpu_clock_osm_driver_probe, + .driver = { + .name = "cpu-clock-osm", + .of_match_table = match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init cpu_clock_osm_init(void) +{ + return platform_driver_register(&cpu_clock_osm_driver); +} +arch_initcall(cpu_clock_osm_init); + +static void __exit cpu_clock_osm_exit(void) +{ + platform_driver_unregister(&cpu_clock_osm_driver); +} +module_exit(cpu_clock_osm_exit); + +MODULE_DESCRIPTION("CPU clock driver for OSM"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index bc982c9bfa71..c6ea293a8df3 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -250,7 +250,8 @@ static int clk_smd_rpm_set_rate_sleep(struct clk_smd_rpm *r, static void to_active_sleep(struct clk_smd_rpm *r, unsigned long rate, unsigned long *active, unsigned long *sleep) { - *active = rate; + /* Convert the rate (hz) to khz */ + *active = DIV_ROUND_UP(rate, 1000); /* * Active-only clocks don't care what the rate is during sleep. So, @@ -533,9 +534,9 @@ DEFINE_CLK_SMD_RPM(msm8996, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0); DEFINE_CLK_SMD_RPM(msm8996, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0); DEFINE_CLK_SMD_RPM_BRANCH(msm8996, cxo, cxo_a, QCOM_SMD_RPM_MISC_CLK, 0, 19200000); DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk, - QCOM_SMD_RPM_AGGR_CLK, 0, 1000); -DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk, QCOM_SMD_RPM_AGGR_CLK, 1, 1000); +DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 2, 1000); DEFINE_CLK_SMD_RPM_QDSS(msm8996, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk1, bb_clk1_a, 1); DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk2, bb_clk2_a, 2); @@ -544,7 +545,7 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk2, rf_clk2_a, 5); DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, ln_bb_clk, ln_bb_a_clk, 8); DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk1, div_clk1_ao, 0xb); DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk2, div_clk2_ao, 0xc); -DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_ao, 0xc); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_ao, 0xd); DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk1_pin, bb_clk1_a_pin, 1); DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2); DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4); @@ -613,13 +614,13 @@ DEFINE_CLK_SMD_RPM(msmfalcon, aggre2_noc_clk, aggre2_noc_a_clk, QCOM_SMD_RPM_AGGR_CLK, 2); DEFINE_CLK_SMD_RPM_QDSS(msmfalcon, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); -DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, rf_clk2, rf_clk2_ao, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, rf_clk1, rf_clk1_ao, 4); DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, div_clk1, div_clk1_ao, 0xb); DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk1, ln_bb_clk1_ao, 0x1); DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk2, ln_bb_clk2_ao, 0x2); DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk3, ln_bb_clk3_ao, 0x3); -DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, rf_clk2_pin, rf_clk2_a_pin, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, rf_clk1_pin, rf_clk1_ao_pin, 4); DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk1_pin, ln_bb_clk1_pin_ao, 0x1); DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk2_pin, @@ -656,8 +657,10 @@ static struct clk_hw *msmfalcon_clks[] = { [RPM_BIMC_A_CLK] = &msmfalcon_bimc_a_clk.hw, [RPM_QDSS_CLK] = &msmfalcon_qdss_clk.hw, [RPM_QDSS_A_CLK] = &msmfalcon_qdss_a_clk.hw, - [RPM_RF_CLK2_PIN] = &msmfalcon_rf_clk2_pin.hw, - [RPM_RF_CLK2_A_PIN] = &msmfalcon_rf_clk2_a_pin.hw, + [RPM_RF_CLK1] = &msmfalcon_rf_clk1.hw, + [RPM_RF_CLK1_A] = &msmfalcon_rf_clk1_ao.hw, + [RPM_RF_CLK1_PIN] = &msmfalcon_rf_clk1_pin.hw, + [RPM_RF_CLK1_A_PIN] = &msmfalcon_rf_clk1_ao_pin.hw, [RPM_AGGR2_NOC_CLK] = &msmfalcon_aggre2_noc_clk.hw, [RPM_AGGR2_NOC_A_CLK] = &msmfalcon_aggre2_noc_a_clk.hw, [RPM_CNOC_CLK] = &msmfalcon_cnoc_clk.hw, diff --git a/drivers/clk/qcom/mmcc-msmfalcon.c b/drivers/clk/qcom/mmcc-msmfalcon.c new file mode 100644 index 000000000000..e4a84765430a --- /dev/null +++ b/drivers/clk/qcom/mmcc-msmfalcon.c @@ -0,0 +1,3036 @@ +/* + * 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/kernel.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk-provider.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> +#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h> + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "common.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "reset.h" +#include "vdd-level-falcon.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } +#define F_SLEW(f, s, h, m, n, src_freq) { (f), (s), (2 * (h) - 1), (m), (n), \ + (src_freq) } + +enum vdd_a_levels { + VDDA_NONE, + VDDA_LOWER, /* SVS2 */ + VDDA_NUM, +}; + +static int vdda_levels[] = { + 0, + 1800000, +}; + +#define VDDA_FMAX_MAP1(l1, f1) \ + .vdd_class = &vdda, \ + .rate_max = (unsigned long[VDDA_NUM]) { \ + [VDDA_##l1] = (f1), \ + }, \ + .num_rate_max = VDDA_NUM + +static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_mx, VDD_DIG_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdda, VDDA_NUM, 1, vdda_levels); + +enum { + P_CORE_BI_PLL_TEST_SE, + P_CORE_PI_SLEEP_CLK, + P_CXO, + P_DP_PHY_PLL_LINK_CLK, + P_DP_PHY_PLL_VCO_DIV, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_MMPLL0_PLL_OUT_MAIN, + P_MMPLL10_PLL_OUT_MAIN, + P_MMPLL3_PLL_OUT_MAIN, + P_MMPLL4_PLL_OUT_MAIN, + P_MMPLL5_PLL_OUT_MAIN, + P_MMPLL6_PLL_OUT_MAIN, + P_MMPLL7_PLL_OUT_MAIN, + P_MMPLL8_PLL_OUT_MAIN, +}; + +static const struct parent_map mmcc_parent_map_0[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL4_PLL_OUT_MAIN, 2 }, + { P_MMPLL7_PLL_OUT_MAIN, 3 }, + { P_MMPLL8_PLL_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_0[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll4_pll_out_main", + "mmpll7_pll_out_main", + "mmpll8_pll_out_main", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_1[] = { + { P_CXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_1[] = { + "xo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_2[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL4_PLL_OUT_MAIN, 2 }, + { P_MMPLL7_PLL_OUT_MAIN, 3 }, + { P_MMPLL10_PLL_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_2[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll4_pll_out_main", + "mmpll7_pll_out_main", + "mmpll10_pll_out_main", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_3[] = { + { P_CXO, 0 }, + { P_MMPLL4_PLL_OUT_MAIN, 1 }, + { P_MMPLL7_PLL_OUT_MAIN, 2 }, + { P_MMPLL10_PLL_OUT_MAIN, 3 }, + { P_CORE_PI_SLEEP_CLK, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_3[] = { + "xo", + "mmpll4_pll_out_main", + "mmpll7_pll_out_main", + "mmpll10_pll_out_main", + "core_pi_sleep_clk", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_4[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL7_PLL_OUT_MAIN, 2 }, + { P_MMPLL10_PLL_OUT_MAIN, 3 }, + { P_CORE_PI_SLEEP_CLK, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_4[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll7_pll_out_main", + "mmpll10_pll_out_main", + "core_pi_sleep_clk", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_5[] = { + { P_CXO, 0 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_5[] = { + "xo", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_6[] = { + { P_CXO, 0 }, + { P_DP_PHY_PLL_LINK_CLK, 1 }, + { P_DP_PHY_PLL_VCO_DIV, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_6[] = { + "xo", + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_7[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL5_PLL_OUT_MAIN, 2 }, + { P_MMPLL7_PLL_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_7[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll5_pll_out_main", + "mmpll7_pll_out_main", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_8[] = { + { P_CXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_8[] = { + "xo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_9[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL4_PLL_OUT_MAIN, 2 }, + { P_MMPLL7_PLL_OUT_MAIN, 3 }, + { P_MMPLL10_PLL_OUT_MAIN, 4 }, + { P_MMPLL6_PLL_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_9[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll4_pll_out_main", + "mmpll7_pll_out_main", + "mmpll10_pll_out_main", + "mmpll6_pll_out_main", + "gcc_mmss_gpll0_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_10[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_10[] = { + "xo", + "mmpll0_pll_out_main", + "gcc_mmss_gpll0_clk", + "gcc_mmss_gpll0_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_11[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL4_PLL_OUT_MAIN, 2 }, + { P_MMPLL7_PLL_OUT_MAIN, 3 }, + { P_MMPLL10_PLL_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_MMPLL6_PLL_OUT_MAIN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_11[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll4_pll_out_main", + "mmpll7_pll_out_main", + "mmpll10_pll_out_main", + "gcc_mmss_gpll0_clk", + "mmpll6_pll_out_main", + "core_bi_pll_test_se", +}; + +static const struct parent_map mmcc_parent_map_12[] = { + { P_CXO, 0 }, + { P_MMPLL0_PLL_OUT_MAIN, 1 }, + { P_MMPLL8_PLL_OUT_MAIN, 2 }, + { P_MMPLL3_PLL_OUT_MAIN, 3 }, + { P_MMPLL6_PLL_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_MMPLL7_PLL_OUT_MAIN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const mmcc_parent_names_12[] = { + "xo", + "mmpll0_pll_out_main", + "mmpll8_pll_out_main", + "mmpll3_pll_out_main", + "mmpll6_pll_out_main", + "gcc_mmss_gpll0_clk", + "mmpll7_pll_out_main", + "core_bi_pll_test_se", +}; + +/* Voteable PLL */ +static struct clk_alpha_pll mmpll0_pll_out_main = { + .offset = 0xc000, + .clkr = { + .enable_reg = 0x1f0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmpll0_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 404000000, + LOW, 808000000), + }, + }, +}; + +static struct clk_alpha_pll mmpll6_pll_out_main = { + .offset = 0xf0, + .clkr = { + .enable_reg = 0x1f0, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "mmpll6_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 540000000, + LOW_L1, 1080000000), + }, + }, +}; + +/* APSS controlled PLLs */ +static struct pll_vco vco[] = { + { 1000000000, 2000000000, 0 }, + { 750000000, 1500000000, 1 }, + { 500000000, 1000000000, 2 }, + { 250000000, 500000000, 3 }, +}; + +static const struct pll_config mmpll10_config = { + .l = 0x1e, + .config_ctl_val = 0x00004289, + .main_output_mask = 0x1, +}; + +static struct clk_alpha_pll mmpll10_pll_out_main = { + .offset = 0x190, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmpll10_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDDA_FMAX_MAP1(LOWER, 576000000), + }, + }, +}; + +static struct pll_vco mmpll3_vco[] = { + { 750000000, 1500000000, 1 }, +}; + +static const struct pll_config mmpll3_config = { + .l = 0x2e, + .config_ctl_val = 0x4001055b, + .vco_val = 0x1 << 20, + .vco_mask = 0x3 << 20, + .main_output_mask = 0x1, +}; + +static struct clk_alpha_pll mmpll3_pll_out_main = { + .offset = 0x0, + .vco_table = mmpll3_vco, + .num_vco = ARRAY_SIZE(mmpll3_vco), + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmpll3_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_slew_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 441600000, + NOMINAL, 1036800000), + }, + }, +}; + +static const struct pll_config mmpll4_config = { + .l = 0x28, + .config_ctl_val = 0x4001055b, + .vco_val = 0x2 << 20, + .vco_mask = 0x3 << 20, + .main_output_mask = 0x1, +}; + +static struct clk_alpha_pll mmpll4_pll_out_main = { + .offset = 0x50, + .vco_table = vco, + .num_vco = ARRAY_SIZE(vco), + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmpll4_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 384000000, + LOW, 768000000), + }, + }, +}; + +static const struct pll_config mmpll5_config = { + .l = 0x2a, + .config_ctl_val = 0x4001055b, + .alpha_u = 0xf8, + .alpha_en_mask = BIT(24), + .vco_val = 0x2 << 20, + .vco_mask = 0x3 << 20, + .main_output_mask = 0x1, +}; + +static struct clk_alpha_pll mmpll5_pll_out_main = { + .offset = 0xa0, + .vco_table = vco, + .num_vco = ARRAY_SIZE(vco), + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmpll5_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 421500000, + LOW, 825000000), + }, + }, +}; + +static const struct pll_config mmpll7_config = { + .l = 0x32, + .config_ctl_val = 0x4001055b, + .vco_val = 0x2 << 20, + .vco_mask = 0x3 << 20, + .main_output_mask = 0x1, +}; + +static struct clk_alpha_pll mmpll7_pll_out_main = { + .offset = 0x140, + .vco_table = vco, + .num_vco = ARRAY_SIZE(vco), + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmpll7_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 480000000, + LOW, 960000000), + }, + }, +}; + +static const struct pll_config mmpll8_config = { + .l = 0x30, + .alpha_u = 0x70, + .alpha_en_mask = BIT(24), + .config_ctl_val = 0x4001055b, + .vco_val = 0x2 << 20, + .vco_mask = 0x3 << 20, + .main_output_mask = 0x1, +}; + +static struct clk_alpha_pll mmpll8_pll_out_main = { + .offset = 0x1c0, + .vco_table = vco, + .num_vco = ARRAY_SIZE(vco), + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmpll8_pll_out_main", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 465000000, + LOW, 930000000), + }, + }, +}; + +static const struct freq_tbl ftbl_ahb_clk_src[] = { + F(19200000, P_CXO, 1, 0, 0), + F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0), + F(80800000, P_MMPLL0_PLL_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 ahb_clk_src = { + .cmd_rcgr = 0x5000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_10, + .freq_tbl = ftbl_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ahb_clk_src", + .parent_names = mmcc_parent_names_10, + .num_parents = 5, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 19200000, + LOW, 40000000, + NOMINAL, 80800000), + }, +}; + +static struct clk_rcg2 byte0_clk_src = { + .cmd_rcgr = 0x2120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "byte0_clk_src", + .parent_names = mmcc_parent_names_1, + .num_parents = 4, + .ops = &clk_byte2_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + VDD_DIG_FMAX_MAP3( + LOWER, 131250000, + LOW, 210000000, + NOMINAL, 262500000), + }, +}; + +static struct clk_rcg2 byte1_clk_src = { + .cmd_rcgr = 0x2140, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "byte1_clk_src", + .parent_names = mmcc_parent_names_1, + .num_parents = 4, + .ops = &clk_byte2_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + VDD_DIG_FMAX_MAP3( + LOWER, 131250000, + LOW, 210000000, + NOMINAL, 262500000), + }, +}; + +static const struct freq_tbl ftbl_camss_gp0_clk_src[] = { + F(10000, P_CXO, 16, 1, 120), + F(24000, P_CXO, 16, 1, 50), + F(6000000, P_GPLL0_OUT_MAIN_DIV, 10, 1, 5), + F(12000000, P_GPLL0_OUT_MAIN_DIV, 10, 2, 5), + F(13043478, P_GPLL0_OUT_MAIN_DIV, 1, 1, 23), + F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25), + F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 camss_gp0_clk_src = { + .cmd_rcgr = 0x3420, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_4, + .freq_tbl = ftbl_camss_gp0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camss_gp0_clk_src", + .parent_names = mmcc_parent_names_4, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), + }, +}; + +static struct clk_rcg2 camss_gp1_clk_src = { + .cmd_rcgr = 0x3450, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_4, + .freq_tbl = ftbl_camss_gp0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camss_gp1_clk_src", + .parent_names = mmcc_parent_names_4, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), + }, +}; + +static const struct freq_tbl ftbl_cci_clk_src[] = { + F(37500000, P_GPLL0_OUT_MAIN_DIV, 8, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 cci_clk_src = { + .cmd_rcgr = 0x3300, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_4, + .freq_tbl = ftbl_cci_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cci_clk_src", + .parent_names = mmcc_parent_names_4, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 37500000, + LOW, 50000000, + NOMINAL, 100000000), + }, +}; + +static const struct freq_tbl ftbl_cpp_clk_src[] = { + F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0), + F(256000000, P_MMPLL4_PLL_OUT_MAIN, 3, 0, 0), + F(384000000, P_MMPLL4_PLL_OUT_MAIN, 2, 0, 0), + F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0), + F(540000000, P_MMPLL6_PLL_OUT_MAIN, 2, 0, 0), + F(576000000, P_MMPLL10_PLL_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cpp_clk_src = { + .cmd_rcgr = 0x3640, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_11, + .freq_tbl = ftbl_cpp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cpp_clk_src", + .parent_names = mmcc_parent_names_11, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP6( + LOWER, 120000000, + LOW, 256000000, + LOW_L1, 384000000, + NOMINAL, 480000000, + NOMINAL_L1, 540000000, + HIGH, 576000000), + }, +}; + +static const struct freq_tbl ftbl_csi0_clk_src[] = { + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(310000000, P_MMPLL8_PLL_OUT_MAIN, 3, 0, 0), + F(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0), + F(465000000, P_MMPLL8_PLL_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 csi0_clk_src = { + .cmd_rcgr = 0x3090, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_0, + .freq_tbl = ftbl_csi0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi0_clk_src", + .parent_names = mmcc_parent_names_0, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP5( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 310000000, + NOMINAL, 404000000, + NOMINAL_L1, 465000000), + }, +}; + +static const struct freq_tbl ftbl_csi0phytimer_clk_src[] = { + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 csi0phytimer_clk_src = { + .cmd_rcgr = 0x3000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_2, + .freq_tbl = ftbl_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi0phytimer_clk_src", + .parent_names = mmcc_parent_names_2, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 269333333), + }, +}; + +static struct clk_rcg2 csi1_clk_src = { + .cmd_rcgr = 0x3100, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_0, + .freq_tbl = ftbl_csi0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi1_clk_src", + .parent_names = mmcc_parent_names_0, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP5( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 310000000, + NOMINAL, 404000000, + NOMINAL_L1, 465000000), + }, +}; + +static struct clk_rcg2 csi1phytimer_clk_src = { + .cmd_rcgr = 0x3030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_2, + .freq_tbl = ftbl_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi1phytimer_clk_src", + .parent_names = mmcc_parent_names_2, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 269333333), + }, +}; + +static struct clk_rcg2 csi2_clk_src = { + .cmd_rcgr = 0x3160, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_0, + .freq_tbl = ftbl_csi0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi2_clk_src", + .parent_names = mmcc_parent_names_0, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP5( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 310000000, + NOMINAL, 404000000, + NOMINAL_L1, 465000000), + }, +}; + +static struct clk_rcg2 csi2phytimer_clk_src = { + .cmd_rcgr = 0x3060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_2, + .freq_tbl = ftbl_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi2phytimer_clk_src", + .parent_names = mmcc_parent_names_2, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 269333333), + }, +}; + +static struct clk_rcg2 csi3_clk_src = { + .cmd_rcgr = 0x31c0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_0, + .freq_tbl = ftbl_csi0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi3_clk_src", + .parent_names = mmcc_parent_names_0, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP5( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 310000000, + NOMINAL, 404000000, + NOMINAL_L1, 465000000), + }, +}; + +static const struct freq_tbl ftbl_csiphy_clk_src[] = { + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0), + F(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 csiphy_clk_src = { + .cmd_rcgr = 0x3800, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_0, + .freq_tbl = ftbl_csiphy_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csiphy_clk_src", + .parent_names = mmcc_parent_names_0, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP4( + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 269333333, + NOMINAL, 320000000), + }, +}; + +static const struct freq_tbl ftbl_dp_aux_clk_src[] = { + F(19200000, P_CXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 dp_aux_clk_src = { + .cmd_rcgr = 0x2260, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_5, + .freq_tbl = ftbl_dp_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "dp_aux_clk_src", + .parent_names = mmcc_parent_names_5, + .num_parents = 4, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP1( + LOWER, 19200000), + }, +}; + +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), + { } +}; + +static struct clk_rcg2 dp_crypto_clk_src = { + .cmd_rcgr = 0x2220, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_6, + .freq_tbl = ftbl_dp_crypto_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "dp_crypto_clk_src", + .parent_names = mmcc_parent_names_6, + .num_parents = 4, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 101250000, + LOW, 168750000, + NOMINAL, 337500000), + }, +}; + +static const struct freq_tbl ftbl_dp_gtc_clk_src[] = { + F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN_DIV, 1, 0, 0), + { } +}; + +static struct clk_rcg2 dp_gtc_clk_src = { + .cmd_rcgr = 0x2280, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_5, + .freq_tbl = ftbl_dp_gtc_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "dp_gtc_clk_src", + .parent_names = mmcc_parent_names_5, + .num_parents = 4, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP2( + LOWER, 40000000, + LOW, 300000000), + }, +}; + +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), + { } +}; + +static struct clk_rcg2 dp_link_clk_src = { + .cmd_rcgr = 0x2200, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_6, + .freq_tbl = ftbl_dp_link_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "dp_link_clk_src", + .parent_names = mmcc_parent_names_6, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + VDD_DIG_FMAX_MAP3( + LOWER, 162000000, + LOW, 270000000, + NOMINAL, 540000000), + }, +}; + +static struct clk_rcg2 dp_pixel_clk_src = { + .cmd_rcgr = 0x2240, + .mnd_width = 16, + .hid_width = 5, + .parent_map = mmcc_parent_map_6, + .clkr.hw.init = &(struct clk_init_data){ + .name = "dp_pixel_clk_src", + .parent_names = mmcc_parent_names_6, + .num_parents = 4, + .ops = &clk_dp_ops, + VDD_DIG_FMAX_MAP3( + LOWER, 148380000, + LOW, 296740000, + NOMINAL, 593470000), + }, +}; + +static struct clk_rcg2 esc0_clk_src = { + .cmd_rcgr = 0x2160, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_1, + .freq_tbl = ftbl_dp_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "esc0_clk_src", + .parent_names = mmcc_parent_names_1, + .num_parents = 4, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP1( + LOWER, 19200000), + }, +}; + +static struct clk_rcg2 esc1_clk_src = { + .cmd_rcgr = 0x2180, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_1, + .freq_tbl = ftbl_dp_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "esc1_clk_src", + .parent_names = mmcc_parent_names_1, + .num_parents = 4, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP1( + LOWER, 19200000), + }, +}; + +static const struct freq_tbl ftbl_jpeg0_clk_src[] = { + F(66666667, P_GPLL0_OUT_MAIN_DIV, 4.5, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(219428571, P_MMPLL4_PLL_OUT_MAIN, 3.5, 0, 0), + F(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0), + F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 jpeg0_clk_src = { + .cmd_rcgr = 0x3500, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_2, + .freq_tbl = ftbl_jpeg0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "jpeg0_clk_src", + .parent_names = mmcc_parent_names_2, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP5( + LOWER, 66666667, + LOW, 133333333, + LOW_L1, 219428571, + NOMINAL, 320000000, + NOMINAL_L1, 480000000), + }, +}; + +static const struct freq_tbl ftbl_mclk0_clk_src[] = { + F(4800000, P_CXO, 4, 0, 0), + F(6000000, P_GPLL0_OUT_MAIN_DIV, 10, 1, 5), + F(8000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 75), + F(9600000, P_CXO, 2, 0, 0), + F(16666667, P_GPLL0_OUT_MAIN_DIV, 2, 1, 9), + F(19200000, P_CXO, 1, 0, 0), + F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25), + F(33333333, P_GPLL0_OUT_MAIN_DIV, 1, 1, 9), + F(48000000, P_GPLL0_OUT_MAIN, 1, 2, 25), + F(66666667, P_GPLL0_OUT_MAIN, 1, 1, 9), + { } +}; + +static struct clk_rcg2 mclk0_clk_src = { + .cmd_rcgr = 0x3360, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_3, + .freq_tbl = ftbl_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "mclk0_clk_src", + .parent_names = mmcc_parent_names_3, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP2( + LOWER, 33333333, + LOW, 66666667), + }, +}; + +static struct clk_rcg2 mclk1_clk_src = { + .cmd_rcgr = 0x3390, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_3, + .freq_tbl = ftbl_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "mclk1_clk_src", + .parent_names = mmcc_parent_names_3, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP2( + LOWER, 33333333, + LOW, 66666667), + }, +}; + +static struct clk_rcg2 mclk2_clk_src = { + .cmd_rcgr = 0x33c0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_3, + .freq_tbl = ftbl_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "mclk2_clk_src", + .parent_names = mmcc_parent_names_3, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP2( + LOWER, 33333333, + LOW, 66666667), + }, +}; + +static struct clk_rcg2 mclk3_clk_src = { + .cmd_rcgr = 0x33f0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_3, + .freq_tbl = ftbl_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "mclk3_clk_src", + .parent_names = mmcc_parent_names_3, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP2( + LOWER, 33333333, + LOW, 66666667), + }, +}; + +static const struct freq_tbl ftbl_mdp_clk_src[] = { + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN_DIV, 2, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0), + F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 mdp_clk_src = { + .cmd_rcgr = 0x2040, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_7, + .freq_tbl = ftbl_mdp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "mdp_clk_src", + .parent_names = mmcc_parent_names_7, + .num_parents = 7, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP4( + LOWER, 171428571, + LOW, 275000000, + NOMINAL, 330000000, + HIGH, 412500000), + }, +}; + +static struct clk_rcg2 pclk0_clk_src = { + .cmd_rcgr = 0x2000, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_8, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pclk0_clk_src", + .parent_names = mmcc_parent_names_8, + .num_parents = 4, + .ops = &clk_pixel_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + VDD_DIG_FMAX_MAP3( + LOWER, 175000000, + LOW, 280000000, + NOMINAL, 350000000), + }, +}; + +static struct clk_rcg2 pclk1_clk_src = { + .cmd_rcgr = 0x2020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = mmcc_parent_map_8, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pclk1_clk_src", + .parent_names = mmcc_parent_names_8, + .num_parents = 4, + .ops = &clk_pixel_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + VDD_DIG_FMAX_MAP3( + LOWER, 175000000, + LOW, 280000000, + NOMINAL, 350000000), + }, +}; + +static const struct freq_tbl ftbl_rot_clk_src[] = { + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0), + F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0), + F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 rot_clk_src = { + .cmd_rcgr = 0x21a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_7, + .freq_tbl = ftbl_rot_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "rot_clk_src", + .parent_names = mmcc_parent_names_7, + .num_parents = 7, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP4( + LOWER, 171428571, + LOW, 275000000, + NOMINAL, 330000000, + HIGH, 412500000), + }, +}; + +static const struct freq_tbl ftbl_vfe0_clk_src[] = { + F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(256000000, P_MMPLL4_PLL_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0), + F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0), + F(540000000, P_MMPLL6_PLL_OUT_MAIN, 2, 0, 0), + F(576000000, P_MMPLL10_PLL_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 vfe0_clk_src = { + .cmd_rcgr = 0x3600, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_9, + .freq_tbl = ftbl_vfe0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "vfe0_clk_src", + .parent_names = mmcc_parent_names_9, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP6( + LOWER, 120000000, + LOW, 256000000, + LOW_L1, 404000000, + NOMINAL, 480000000, + NOMINAL_L1, 540000000, + HIGH, 576000000), + }, +}; + +static struct clk_rcg2 vfe1_clk_src = { + .cmd_rcgr = 0x3620, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_9, + .freq_tbl = ftbl_vfe0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "vfe1_clk_src", + .parent_names = mmcc_parent_names_9, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP6( + LOWER, 120000000, + LOW, 256000000, + LOW_L1, 404000000, + NOMINAL, 480000000, + NOMINAL_L1, 540000000, + HIGH, 576000000), + }, +}; + +static const struct freq_tbl ftbl_video_core_clk_src[] = { + F_SLEW(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0, FIXED_FREQ_SRC), + F_SLEW(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC), + F_SLEW(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC), + F_SLEW(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0, FIXED_FREQ_SRC), + F_SLEW(441600000, P_MMPLL3_PLL_OUT_MAIN, 2, 0, 0, 883200000), + F_SLEW(518400000, P_MMPLL3_PLL_OUT_MAIN, 2, 0, 0, 1036800000), + { } +}; + +static struct clk_rcg2 video_core_clk_src = { + .cmd_rcgr = 0x1000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_12, + .freq_tbl = ftbl_video_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "video_core_clk_src", + .parent_names = mmcc_parent_names_12, + .num_parents = 8, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP6( + LOWER, 133333333, + LOW, 269333333, + LOW_L1, 320000000, + NOMINAL, 404000000, + NOMINAL_L1, 441600000, + HIGH, 518400000), + }, +}; + +static struct clk_rcg2 vsync_clk_src = { + .cmd_rcgr = 0x2080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = mmcc_parent_map_5, + .freq_tbl = ftbl_dp_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "vsync_clk_src", + .parent_names = mmcc_parent_names_5, + .num_parents = 4, + .ops = &clk_rcg2_ops, + VDD_DIG_FMAX_MAP1( + LOWER, 19200000), + }, +}; + +static struct clk_branch mmss_bimc_smmu_ahb_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0xe004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_bimc_smmu_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_bimc_smmu_axi_clk = { + .halt_reg = 0xe008, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0xe008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_bimc_smmu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_ahb_clk = { + .halt_reg = 0x348c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x348c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cci_ahb_clk = { + .halt_reg = 0x3348, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3348, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cci_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cci_clk = { + .halt_reg = 0x3344, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3344, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cci_clk", + .parent_names = (const char *[]){ + "cci_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cphy_csid0_clk = { + .halt_reg = 0x3730, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3730, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cphy_csid0_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cphy_csid1_clk = { + .halt_reg = 0x3734, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3734, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cphy_csid1_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cphy_csid2_clk = { + .halt_reg = 0x3738, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3738, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cphy_csid2_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cphy_csid3_clk = { + .halt_reg = 0x373c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x373c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cphy_csid3_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cpp_ahb_clk = { + .halt_reg = 0x36b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36b4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cpp_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cpp_axi_clk = { + .halt_reg = 0x36c4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36c4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cpp_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cpp_clk = { + .halt_reg = 0x36b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36b0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cpp_clk", + .parent_names = (const char *[]){ + "cpp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_cpp_vbif_ahb_clk = { + .halt_reg = 0x36c8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_cpp_vbif_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi0_ahb_clk = { + .halt_reg = 0x30bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x30bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi0_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi0_clk = { + .halt_reg = 0x30b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x30b4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi0_clk", + .parent_names = (const char *[]){ + "csi0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi0phytimer_clk = { + .halt_reg = 0x3024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi0phytimer_clk", + .parent_names = (const char *[]){ + "csi0phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi0pix_clk = { + .halt_reg = 0x30e4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x30e4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi0pix_clk", + .parent_names = (const char *[]){ + "csi0_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi0rdi_clk = { + .halt_reg = 0x30d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x30d4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi0rdi_clk", + .parent_names = (const char *[]){ + "csi0_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi1_ahb_clk = { + .halt_reg = 0x3128, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3128, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi1_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi1_clk = { + .halt_reg = 0x3124, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3124, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi1_clk", + .parent_names = (const char *[]){ + "csi1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi1phytimer_clk = { + .halt_reg = 0x3054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi1phytimer_clk", + .parent_names = (const char *[]){ + "csi1phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi1pix_clk = { + .halt_reg = 0x3154, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3154, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi1pix_clk", + .parent_names = (const char *[]){ + "csi1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi1rdi_clk = { + .halt_reg = 0x3144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3144, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi1rdi_clk", + .parent_names = (const char *[]){ + "csi1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi2_ahb_clk = { + .halt_reg = 0x3188, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3188, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi2_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi2_clk = { + .halt_reg = 0x3184, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3184, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi2_clk", + .parent_names = (const char *[]){ + "csi2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi2phytimer_clk = { + .halt_reg = 0x3084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi2phytimer_clk", + .parent_names = (const char *[]){ + "csi2phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi2pix_clk = { + .halt_reg = 0x31b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31b4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi2pix_clk", + .parent_names = (const char *[]){ + "csi2_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi2rdi_clk = { + .halt_reg = 0x31a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi2rdi_clk", + .parent_names = (const char *[]){ + "csi2_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi3_ahb_clk = { + .halt_reg = 0x31e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31e8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi3_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi3_clk = { + .halt_reg = 0x31e4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31e4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi3_clk", + .parent_names = (const char *[]){ + "csi3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi3pix_clk = { + .halt_reg = 0x3214, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3214, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi3pix_clk", + .parent_names = (const char *[]){ + "csi3_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi3rdi_clk = { + .halt_reg = 0x3204, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3204, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi3rdi_clk", + .parent_names = (const char *[]){ + "csi3_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi_vfe0_clk = { + .halt_reg = 0x3704, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3704, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi_vfe0_clk", + .parent_names = (const char *[]){ + "vfe0_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csi_vfe1_clk = { + .halt_reg = 0x3714, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3714, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csi_vfe1_clk", + .parent_names = (const char *[]){ + "vfe1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csiphy0_clk = { + .halt_reg = 0x3740, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3740, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csiphy0_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csiphy1_clk = { + .halt_reg = 0x3744, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3744, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csiphy1_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_csiphy2_clk = { + .halt_reg = 0x3748, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3748, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_csiphy2_clk", + .parent_names = (const char *[]){ + "csiphy_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_gp0_clk = { + .halt_reg = 0x3444, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3444, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_gp0_clk", + .parent_names = (const char *[]){ + "camss_gp0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_gp1_clk = { + .halt_reg = 0x3474, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3474, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_gp1_clk", + .parent_names = (const char *[]){ + "camss_gp1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_ispif_ahb_clk = { + .halt_reg = 0x3224, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3224, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_ispif_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_jpeg0_clk = { + .halt_reg = 0x35a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x35a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_jpeg0_clk", + .parent_names = (const char *[]){ + "jpeg0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_jpeg_ahb_clk = { + .halt_reg = 0x35b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x35b4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_jpeg_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_jpeg_axi_clk = { + .halt_reg = 0x35b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x35b8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_jpeg_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_mclk0_clk = { + .halt_reg = 0x3384, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3384, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_mclk0_clk", + .parent_names = (const char *[]){ + "mclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_mclk1_clk = { + .halt_reg = 0x33b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33b4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_mclk1_clk", + .parent_names = (const char *[]){ + "mclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_mclk2_clk = { + .halt_reg = 0x33e4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33e4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_mclk2_clk", + .parent_names = (const char *[]){ + "mclk2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_mclk3_clk = { + .halt_reg = 0x3414, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3414, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_mclk3_clk", + .parent_names = (const char *[]){ + "mclk3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_micro_ahb_clk = { + .halt_reg = 0x3494, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3494, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_micro_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_top_ahb_clk = { + .halt_reg = 0x3484, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3484, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_top_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe0_ahb_clk = { + .halt_reg = 0x3668, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3668, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe0_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe0_clk = { + .halt_reg = 0x36a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe0_clk", + .parent_names = (const char *[]){ + "vfe0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe0_stream_clk = { + .halt_reg = 0x3720, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3720, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe0_stream_clk", + .parent_names = (const char *[]){ + "vfe0_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe1_ahb_clk = { + .halt_reg = 0x3678, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3678, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe1_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe1_clk = { + .halt_reg = 0x36ac, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36ac, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe1_clk", + .parent_names = (const char *[]){ + "vfe1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe1_stream_clk = { + .halt_reg = 0x3724, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3724, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe1_stream_clk", + .parent_names = (const char *[]){ + "vfe1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe_vbif_ahb_clk = { + .halt_reg = 0x36b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36b8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe_vbif_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_camss_vfe_vbif_axi_clk = { + .halt_reg = 0x36bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_camss_vfe_vbif_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_csiphy_ahb2crif_clk = { + .halt_reg = 0x374c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x374c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_csiphy_ahb2crif_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_ahb_clk = { + .halt_reg = 0x2308, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2308, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_axi_clk = { + .halt_reg = 0x2310, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2310, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_byte0_clk = { + .halt_reg = 0x233c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x233c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_byte0_clk", + .parent_names = (const char *[]){ + "byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_byte0_intf_clk = { + .halt_reg = 0x2374, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2374, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_byte0_intf_clk", + .parent_names = (const char *[]){ + "mmss_mdss_byte0_intf_div_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_div mmss_mdss_byte0_intf_div_clk = { + .reg = 0x237c, + .shift = 0, + .width = 2, + /* + * NOTE: Op does not work for div-3. Current assumption is that div-3 + * is not a recommended setting for this divider. + */ + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_byte0_intf_div_clk", + .parent_names = (const char *[]){ + "byte0_clk_src", + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, + }, +}; + +static struct clk_branch mmss_mdss_byte1_clk = { + .halt_reg = 0x2340, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2340, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_byte1_clk", + .parent_names = (const char *[]){ + "byte1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_byte1_intf_clk = { + .halt_reg = 0x2378, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2378, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_byte1_intf_clk", + .parent_names = (const char *[]){ + "byte1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_dp_aux_clk = { + .halt_reg = 0x2364, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2364, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_dp_aux_clk", + .parent_names = (const char *[]){ + "dp_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_dp_crypto_clk = { + .halt_reg = 0x235c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x235c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_dp_crypto_clk", + .parent_names = (const char *[]){ + "dp_crypto_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_dp_gtc_clk = { + .halt_reg = 0x2368, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2368, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_dp_gtc_clk", + .parent_names = (const char *[]){ + "dp_gtc_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_dp_link_clk = { + .halt_reg = 0x2354, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2354, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_dp_link_clk", + .parent_names = (const char *[]){ + "dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Reset state of MMSS_MDSS_DP_LINK_INTF_DIV is 0x3 (div-4) */ +static struct clk_branch mmss_mdss_dp_link_intf_clk = { + .halt_reg = 0x2358, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2358, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_dp_link_intf_clk", + .parent_names = (const char *[]){ + "dp_link_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_dp_pixel_clk = { + .halt_reg = 0x2360, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2360, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_dp_pixel_clk", + .parent_names = (const char *[]){ + "dp_pixel_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_esc0_clk = { + .halt_reg = 0x2344, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2344, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_esc0_clk", + .parent_names = (const char *[]){ + "esc0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_esc1_clk = { + .halt_reg = 0x2348, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2348, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_esc1_clk", + .parent_names = (const char *[]){ + "esc1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_hdmi_dp_ahb_clk = { + .halt_reg = 0x230c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x230c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_hdmi_dp_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_mdp_clk = { + .halt_reg = 0x231c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x231c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_mdp_clk", + .parent_names = (const char *[]){ + "mdp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_pclk0_clk = { + .halt_reg = 0x2314, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2314, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_pclk0_clk", + .parent_names = (const char *[]){ + "pclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_pclk1_clk = { + .halt_reg = 0x2318, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2318, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_pclk1_clk", + .parent_names = (const char *[]){ + "pclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_rot_clk = { + .halt_reg = 0x2350, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2350, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_rot_clk", + .parent_names = (const char *[]){ + "rot_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mdss_vsync_clk = { + .halt_reg = 0x2328, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2328, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mdss_vsync_clk", + .parent_names = (const char *[]){ + "vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_misc_ahb_clk = { + .halt_reg = 0x328, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x328, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_misc_ahb_clk", + /* + * Dependency to be enabled before the branch is + * enabled. + */ + .parent_names = (const char *[]){ + "mmss_mnoc_ahb_clk", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_misc_cxo_clk = { + .halt_reg = 0x324, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x324, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_misc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_mnoc_ahb_clk = { + .halt_reg = 0x5024, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x5024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_mnoc_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_snoc_dvm_axi_clk = { + .halt_reg = 0xe040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_snoc_dvm_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_video_ahb_clk = { + .halt_reg = 0x1030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_video_ahb_clk", + .parent_names = (const char *[]){ + "ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_video_axi_clk = { + .halt_reg = 0x1034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_video_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_video_core_clk = { + .halt_reg = 0x1028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_video_core_clk", + .parent_names = (const char *[]){ + "video_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mmss_video_subcore0_clk = { + .halt_reg = 0x1048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mmss_video_subcore0_clk", + .parent_names = (const char *[]){ + "video_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *mmcc_falcon_clocks[] = { + [AHB_CLK_SRC] = &ahb_clk_src.clkr, + [BYTE0_CLK_SRC] = &byte0_clk_src.clkr, + [BYTE1_CLK_SRC] = &byte1_clk_src.clkr, + [CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr, + [CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr, + [CCI_CLK_SRC] = &cci_clk_src.clkr, + [CPP_CLK_SRC] = &cpp_clk_src.clkr, + [CSI0_CLK_SRC] = &csi0_clk_src.clkr, + [CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr, + [CSI1_CLK_SRC] = &csi1_clk_src.clkr, + [CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr, + [CSI2_CLK_SRC] = &csi2_clk_src.clkr, + [CSI2PHYTIMER_CLK_SRC] = &csi2phytimer_clk_src.clkr, + [CSI3_CLK_SRC] = &csi3_clk_src.clkr, + [CSIPHY_CLK_SRC] = &csiphy_clk_src.clkr, + [DP_AUX_CLK_SRC] = &dp_aux_clk_src.clkr, + [DP_CRYPTO_CLK_SRC] = &dp_crypto_clk_src.clkr, + [DP_GTC_CLK_SRC] = &dp_gtc_clk_src.clkr, + [DP_LINK_CLK_SRC] = &dp_link_clk_src.clkr, + [DP_PIXEL_CLK_SRC] = &dp_pixel_clk_src.clkr, + [ESC0_CLK_SRC] = &esc0_clk_src.clkr, + [ESC1_CLK_SRC] = &esc1_clk_src.clkr, + [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr, + [MCLK0_CLK_SRC] = &mclk0_clk_src.clkr, + [MCLK1_CLK_SRC] = &mclk1_clk_src.clkr, + [MCLK2_CLK_SRC] = &mclk2_clk_src.clkr, + [MCLK3_CLK_SRC] = &mclk3_clk_src.clkr, + [MDP_CLK_SRC] = &mdp_clk_src.clkr, + [MMPLL0_PLL] = &mmpll0_pll_out_main.clkr, + [MMPLL10_PLL] = &mmpll10_pll_out_main.clkr, + [MMPLL3_PLL] = &mmpll3_pll_out_main.clkr, + [MMPLL4_PLL] = &mmpll4_pll_out_main.clkr, + [MMPLL5_PLL] = &mmpll5_pll_out_main.clkr, + [MMPLL6_PLL] = &mmpll6_pll_out_main.clkr, + [MMPLL7_PLL] = &mmpll7_pll_out_main.clkr, + [MMPLL8_PLL] = &mmpll8_pll_out_main.clkr, + [MMSS_BIMC_SMMU_AHB_CLK] = &mmss_bimc_smmu_ahb_clk.clkr, + [MMSS_BIMC_SMMU_AXI_CLK] = &mmss_bimc_smmu_axi_clk.clkr, + [MMSS_CAMSS_AHB_CLK] = &mmss_camss_ahb_clk.clkr, + [MMSS_CAMSS_CCI_AHB_CLK] = &mmss_camss_cci_ahb_clk.clkr, + [MMSS_CAMSS_CCI_CLK] = &mmss_camss_cci_clk.clkr, + [MMSS_CAMSS_CPHY_CSID0_CLK] = &mmss_camss_cphy_csid0_clk.clkr, + [MMSS_CAMSS_CPHY_CSID1_CLK] = &mmss_camss_cphy_csid1_clk.clkr, + [MMSS_CAMSS_CPHY_CSID2_CLK] = &mmss_camss_cphy_csid2_clk.clkr, + [MMSS_CAMSS_CPHY_CSID3_CLK] = &mmss_camss_cphy_csid3_clk.clkr, + [MMSS_CAMSS_CPP_AHB_CLK] = &mmss_camss_cpp_ahb_clk.clkr, + [MMSS_CAMSS_CPP_AXI_CLK] = &mmss_camss_cpp_axi_clk.clkr, + [MMSS_CAMSS_CPP_CLK] = &mmss_camss_cpp_clk.clkr, + [MMSS_CAMSS_CPP_VBIF_AHB_CLK] = &mmss_camss_cpp_vbif_ahb_clk.clkr, + [MMSS_CAMSS_CSI0_AHB_CLK] = &mmss_camss_csi0_ahb_clk.clkr, + [MMSS_CAMSS_CSI0_CLK] = &mmss_camss_csi0_clk.clkr, + [MMSS_CAMSS_CSI0PHYTIMER_CLK] = &mmss_camss_csi0phytimer_clk.clkr, + [MMSS_CAMSS_CSI0PIX_CLK] = &mmss_camss_csi0pix_clk.clkr, + [MMSS_CAMSS_CSI0RDI_CLK] = &mmss_camss_csi0rdi_clk.clkr, + [MMSS_CAMSS_CSI1_AHB_CLK] = &mmss_camss_csi1_ahb_clk.clkr, + [MMSS_CAMSS_CSI1_CLK] = &mmss_camss_csi1_clk.clkr, + [MMSS_CAMSS_CSI1PHYTIMER_CLK] = &mmss_camss_csi1phytimer_clk.clkr, + [MMSS_CAMSS_CSI1PIX_CLK] = &mmss_camss_csi1pix_clk.clkr, + [MMSS_CAMSS_CSI1RDI_CLK] = &mmss_camss_csi1rdi_clk.clkr, + [MMSS_CAMSS_CSI2_AHB_CLK] = &mmss_camss_csi2_ahb_clk.clkr, + [MMSS_CAMSS_CSI2_CLK] = &mmss_camss_csi2_clk.clkr, + [MMSS_CAMSS_CSI2PHYTIMER_CLK] = &mmss_camss_csi2phytimer_clk.clkr, + [MMSS_CAMSS_CSI2PIX_CLK] = &mmss_camss_csi2pix_clk.clkr, + [MMSS_CAMSS_CSI2RDI_CLK] = &mmss_camss_csi2rdi_clk.clkr, + [MMSS_CAMSS_CSI3_AHB_CLK] = &mmss_camss_csi3_ahb_clk.clkr, + [MMSS_CAMSS_CSI3_CLK] = &mmss_camss_csi3_clk.clkr, + [MMSS_CAMSS_CSI3PIX_CLK] = &mmss_camss_csi3pix_clk.clkr, + [MMSS_CAMSS_CSI3RDI_CLK] = &mmss_camss_csi3rdi_clk.clkr, + [MMSS_CAMSS_CSI_VFE0_CLK] = &mmss_camss_csi_vfe0_clk.clkr, + [MMSS_CAMSS_CSI_VFE1_CLK] = &mmss_camss_csi_vfe1_clk.clkr, + [MMSS_CAMSS_CSIPHY0_CLK] = &mmss_camss_csiphy0_clk.clkr, + [MMSS_CAMSS_CSIPHY1_CLK] = &mmss_camss_csiphy1_clk.clkr, + [MMSS_CAMSS_CSIPHY2_CLK] = &mmss_camss_csiphy2_clk.clkr, + [MMSS_CAMSS_GP0_CLK] = &mmss_camss_gp0_clk.clkr, + [MMSS_CAMSS_GP1_CLK] = &mmss_camss_gp1_clk.clkr, + [MMSS_CAMSS_ISPIF_AHB_CLK] = &mmss_camss_ispif_ahb_clk.clkr, + [MMSS_CAMSS_JPEG0_CLK] = &mmss_camss_jpeg0_clk.clkr, + [MMSS_CAMSS_JPEG_AHB_CLK] = &mmss_camss_jpeg_ahb_clk.clkr, + [MMSS_CAMSS_JPEG_AXI_CLK] = &mmss_camss_jpeg_axi_clk.clkr, + [MMSS_CAMSS_MCLK0_CLK] = &mmss_camss_mclk0_clk.clkr, + [MMSS_CAMSS_MCLK1_CLK] = &mmss_camss_mclk1_clk.clkr, + [MMSS_CAMSS_MCLK2_CLK] = &mmss_camss_mclk2_clk.clkr, + [MMSS_CAMSS_MCLK3_CLK] = &mmss_camss_mclk3_clk.clkr, + [MMSS_CAMSS_MICRO_AHB_CLK] = &mmss_camss_micro_ahb_clk.clkr, + [MMSS_CAMSS_TOP_AHB_CLK] = &mmss_camss_top_ahb_clk.clkr, + [MMSS_CAMSS_VFE0_AHB_CLK] = &mmss_camss_vfe0_ahb_clk.clkr, + [MMSS_CAMSS_VFE0_CLK] = &mmss_camss_vfe0_clk.clkr, + [MMSS_CAMSS_VFE0_STREAM_CLK] = &mmss_camss_vfe0_stream_clk.clkr, + [MMSS_CAMSS_VFE1_AHB_CLK] = &mmss_camss_vfe1_ahb_clk.clkr, + [MMSS_CAMSS_VFE1_CLK] = &mmss_camss_vfe1_clk.clkr, + [MMSS_CAMSS_VFE1_STREAM_CLK] = &mmss_camss_vfe1_stream_clk.clkr, + [MMSS_CAMSS_VFE_VBIF_AHB_CLK] = &mmss_camss_vfe_vbif_ahb_clk.clkr, + [MMSS_CAMSS_VFE_VBIF_AXI_CLK] = &mmss_camss_vfe_vbif_axi_clk.clkr, + [MMSS_CSIPHY_AHB2CRIF_CLK] = &mmss_csiphy_ahb2crif_clk.clkr, + [MMSS_MDSS_AHB_CLK] = &mmss_mdss_ahb_clk.clkr, + [MMSS_MDSS_AXI_CLK] = &mmss_mdss_axi_clk.clkr, + [MMSS_MDSS_BYTE0_CLK] = &mmss_mdss_byte0_clk.clkr, + [MMSS_MDSS_BYTE0_INTF_CLK] = &mmss_mdss_byte0_intf_clk.clkr, + [MMSS_MDSS_BYTE0_INTF_DIV_CLK] = &mmss_mdss_byte0_intf_div_clk.clkr, + [MMSS_MDSS_BYTE1_CLK] = &mmss_mdss_byte1_clk.clkr, + [MMSS_MDSS_BYTE1_INTF_CLK] = &mmss_mdss_byte1_intf_clk.clkr, + [MMSS_MDSS_DP_AUX_CLK] = &mmss_mdss_dp_aux_clk.clkr, + [MMSS_MDSS_DP_CRYPTO_CLK] = &mmss_mdss_dp_crypto_clk.clkr, + [MMSS_MDSS_DP_GTC_CLK] = &mmss_mdss_dp_gtc_clk.clkr, + [MMSS_MDSS_DP_LINK_CLK] = &mmss_mdss_dp_link_clk.clkr, + [MMSS_MDSS_DP_LINK_INTF_CLK] = &mmss_mdss_dp_link_intf_clk.clkr, + [MMSS_MDSS_DP_PIXEL_CLK] = &mmss_mdss_dp_pixel_clk.clkr, + [MMSS_MDSS_ESC0_CLK] = &mmss_mdss_esc0_clk.clkr, + [MMSS_MDSS_ESC1_CLK] = &mmss_mdss_esc1_clk.clkr, + [MMSS_MDSS_HDMI_DP_AHB_CLK] = &mmss_mdss_hdmi_dp_ahb_clk.clkr, + [MMSS_MDSS_MDP_CLK] = &mmss_mdss_mdp_clk.clkr, + [MMSS_MDSS_PCLK0_CLK] = &mmss_mdss_pclk0_clk.clkr, + [MMSS_MDSS_PCLK1_CLK] = &mmss_mdss_pclk1_clk.clkr, + [MMSS_MDSS_ROT_CLK] = &mmss_mdss_rot_clk.clkr, + [MMSS_MDSS_VSYNC_CLK] = &mmss_mdss_vsync_clk.clkr, + [MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr, + [MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr, + [MMSS_MNOC_AHB_CLK] = &mmss_mnoc_ahb_clk.clkr, + [MMSS_SNOC_DVM_AXI_CLK] = &mmss_snoc_dvm_axi_clk.clkr, + [MMSS_VIDEO_AHB_CLK] = &mmss_video_ahb_clk.clkr, + [MMSS_VIDEO_AXI_CLK] = &mmss_video_axi_clk.clkr, + [MMSS_VIDEO_CORE_CLK] = &mmss_video_core_clk.clkr, + [MMSS_VIDEO_SUBCORE0_CLK] = &mmss_video_subcore0_clk.clkr, + [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr, + [PCLK1_CLK_SRC] = &pclk1_clk_src.clkr, + [ROT_CLK_SRC] = &rot_clk_src.clkr, + [VFE0_CLK_SRC] = &vfe0_clk_src.clkr, + [VFE1_CLK_SRC] = &vfe1_clk_src.clkr, + [VIDEO_CORE_CLK_SRC] = &video_core_clk_src.clkr, + [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, +}; + +static const struct qcom_reset_map mmcc_falcon_resets[] = { + [CAMSS_MICRO_BCR] = { 0x3490 }, +}; + +static const struct regmap_config mmcc_falcon_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10004, + .fast_io = true, +}; + +static const struct qcom_cc_desc mmcc_falcon_desc = { + .config = &mmcc_falcon_regmap_config, + .clks = mmcc_falcon_clocks, + .num_clks = ARRAY_SIZE(mmcc_falcon_clocks), + .resets = mmcc_falcon_resets, + .num_resets = ARRAY_SIZE(mmcc_falcon_resets), +}; + +static const struct of_device_id mmcc_falcon_match_table[] = { + { .compatible = "qcom,mmcc-msmfalcon" }, + { } +}; +MODULE_DEVICE_TABLE(of, mmcc_falcon_match_table); + +static int mmcc_falcon_probe(struct platform_device *pdev) +{ + int ret = 0; + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &mmcc_falcon_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* PLLs connected on Mx rails of MMSS_CC */ + vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx_mmss"); + if (IS_ERR(vdd_mx.regulator[0])) { + if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_mx_mmss regulator\n"); + return PTR_ERR(vdd_mx.regulator[0]); + } + + vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_mmss"); + if (IS_ERR(vdd_dig.regulator[0])) { + if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_dig regulator\n"); + return PTR_ERR(vdd_dig.regulator[0]); + } + + /* MMPLL10 connected to the Analog Rail */ + vdda.regulator[0] = devm_regulator_get(&pdev->dev, "vdda"); + if (IS_ERR(vdda.regulator[0])) { + if (!(PTR_ERR(vdda.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdda regulator\n"); + return PTR_ERR(vdda.regulator[0]); + } + + clk_alpha_pll_configure(&mmpll3_pll_out_main, regmap, &mmpll3_config); + clk_alpha_pll_configure(&mmpll4_pll_out_main, regmap, &mmpll4_config); + clk_alpha_pll_configure(&mmpll5_pll_out_main, regmap, &mmpll5_config); + clk_alpha_pll_configure(&mmpll7_pll_out_main, regmap, &mmpll7_config); + clk_alpha_pll_configure(&mmpll8_pll_out_main, regmap, &mmpll8_config); + clk_alpha_pll_configure(&mmpll10_pll_out_main, regmap, &mmpll10_config); + + ret = qcom_cc_really_probe(pdev, &mmcc_falcon_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register MMSS clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered MMSS clocks\n"); + + return ret; +} + +static struct platform_driver mmcc_falcon_driver = { + .probe = mmcc_falcon_probe, + .driver = { + .name = "mmcc-msmfalcon", + .of_match_table = mmcc_falcon_match_table, + }, +}; + +static int __init mmcc_falcon_init(void) +{ + return platform_driver_register(&mmcc_falcon_driver); +} +core_initcall_sync(mmcc_falcon_init); + +static void __exit mmcc_falcon_exit(void) +{ + platform_driver_unregister(&mmcc_falcon_driver); +} +module_exit(mmcc_falcon_exit); diff --git a/drivers/clk/qcom/vdd-level-falcon.h b/drivers/clk/qcom/vdd-level-falcon.h index d54e801ecc67..8f9eefe3a89c 100644 --- a/drivers/clk/qcom/vdd-level-falcon.h +++ b/drivers/clk/qcom/vdd-level-falcon.h @@ -116,6 +116,21 @@ }, \ .num_rate_max = VDD_DIG_NUM +#define VDD_MMSS_PLL_DIG_FMAX_MAP1(l1, f1) \ + .vdd_class = &vdd_mx, \ + .rate_max = (unsigned long[VDD_DIG_NUM]) { \ + [VDD_DIG_##l1] = (f1), \ + }, \ + .num_rate_max = VDD_DIG_NUM + +#define VDD_MMSS_PLL_DIG_FMAX_MAP2(l1, f1, l2, f2) \ + .vdd_class = &vdd_mx, \ + .rate_max = (unsigned long[VDD_DIG_NUM]) { \ + [VDD_DIG_##l1] = (f1), \ + [VDD_DIG_##l2] = (f2), \ + }, \ + .num_rate_max = VDD_DIG_NUM + enum vdd_dig_levels { VDD_DIG_NONE, VDD_DIG_MIN, /* MIN SVS */ diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 55c043b44cea..0bef7effe601 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -1347,7 +1347,8 @@ go_proc: CRYPTO_CONFIG_REG)); /* issue go to crypto */ if (use_hw_key == false) { - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); } else { QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), @@ -1528,7 +1529,8 @@ static int _ce_setup_aead_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* issue go to crypto */ - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) @@ -1847,7 +1849,8 @@ static int _ce_setup_cipher_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* issue go to crypto */ if (use_hw_key == false) { - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); } else { QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), @@ -1935,7 +1938,8 @@ static int _ce_f9_setup_direct(struct qce_device *pce_dev, QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase + CRYPTO_CONFIG_REG)); /* write go */ - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) @@ -2012,7 +2016,8 @@ static int _ce_f8_setup_direct(struct qce_device *pce_dev, QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase + CRYPTO_CONFIG_REG)); /* write go */ - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) @@ -3336,8 +3341,8 @@ static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, int cri_index, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3450,8 +3455,8 @@ static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev, int cri_index, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3494,8 +3499,8 @@ static int _setup_cipher_null_cmdlistptrs(struct qce_device *pdev, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3672,8 +3677,8 @@ static int _setup_auth_cmdlistptrs(struct qce_device *pdev, int cri_index, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3889,8 +3894,8 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -4022,8 +4027,8 @@ static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, int cri_index, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -4108,8 +4113,8 @@ static int _setup_f8_cmdlistptrs(struct qce_device *pdev, int cri_index, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -4190,8 +4195,8 @@ static int _setup_f9_cmdlistptrs(struct qce_device *pdev, int cri_index, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index e2099c4e7877..433e4783d1d1 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -603,7 +603,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, while (len > 0) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) return -EFAULT; @@ -639,7 +639,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, /* Copy data from user src(s) */ user_src = (void __user *)qcedev_areq->sha_op_req.data[0].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[0].len)) { kzfree(k_buf_src); @@ -648,7 +648,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, k_src += qcedev_areq->sha_op_req.data[0].len; for (i = 1; i < qcedev_areq->sha_op_req.entries; i++) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) { kzfree(k_buf_src); @@ -702,13 +702,6 @@ static int qcedev_sha_update(struct qcedev_async_req *qcedev_areq, return -EINVAL; } - /* verify address src(s) */ - for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.data[i].vaddr, - qcedev_areq->sha_op_req.data[i].len)) - return -EFAULT; - if (qcedev_areq->sha_op_req.data_len > QCE_MAX_OPER_DATA) { struct qcedev_sha_op_req *saved_req; @@ -868,19 +861,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq, total = qcedev_areq->sha_op_req.data_len; - /* verify address src(s) */ - for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.data[i].vaddr, - qcedev_areq->sha_op_req.data[i].len)) - return -EFAULT; - - /* Verify Source Address */ - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.authkey, - qcedev_areq->sha_op_req.authklen)) - return -EFAULT; - if (__copy_from_user(&handle->sha_ctxt.authkey[0], + if (copy_from_user(&handle->sha_ctxt.authkey[0], (void __user *)qcedev_areq->sha_op_req.authkey, qcedev_areq->sha_op_req.authklen)) return -EFAULT; @@ -900,7 +881,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq, for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, (void __user *)user_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) { kzfree(k_buf_src); return -EFAULT; @@ -928,12 +909,7 @@ static int qcedev_set_hmac_auth_key(struct qcedev_async_req *areq, if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) { qcedev_sha_init(areq, handle); - /* Verify Source Address */ - if (!access_ok(VERIFY_READ, - (void __user *)areq->sha_op_req.authkey, - areq->sha_op_req.authklen)) - return -EFAULT; - if (__copy_from_user(&handle->sha_ctxt.authkey[0], + if (copy_from_user(&handle->sha_ctxt.authkey[0], (void __user *)areq->sha_op_req.authkey, areq->sha_op_req.authklen)) return -EFAULT; @@ -1146,7 +1122,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, byteoffset = areq->cipher_op_req.byteoffset; user_src = (void __user *)areq->cipher_op_req.vbuf.src[0].vaddr; - if (user_src && __copy_from_user((k_align_src + byteoffset), + if (user_src && copy_from_user((k_align_src + byteoffset), (void __user *)user_src, areq->cipher_op_req.vbuf.src[0].len)) return -EFAULT; @@ -1156,7 +1132,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, for (i = 1; i < areq->cipher_op_req.entries; i++) { user_src = (void __user *)areq->cipher_op_req.vbuf.src[i].vaddr; - if (user_src && __copy_from_user(k_align_src, + if (user_src && copy_from_user(k_align_src, (void __user *)user_src, areq->cipher_op_req.vbuf.src[i].len)) { return -EFAULT; @@ -1188,7 +1164,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, while (creq->data_len > 0) { if (creq->vbuf.dst[dst_i].len <= creq->data_len) { - if (err == 0 && __copy_to_user( + if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), creq->vbuf.dst[dst_i].len)) @@ -1199,7 +1175,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, creq->data_len -= creq->vbuf.dst[dst_i].len; dst_i++; } else { - if (err == 0 && __copy_to_user( + if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), creq->data_len)) @@ -1531,36 +1507,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, __func__, total, req->data_len); goto error; } - /* Verify Source Address's */ - for (i = 0, total = 0; i < req->entries; i++) { - if (total < req->data_len) { - if (!access_ok(VERIFY_READ, - (void __user *)req->vbuf.src[i].vaddr, - req->vbuf.src[i].len)) { - pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n", - __func__, i, (uintptr_t) - req->vbuf.src[i].vaddr); - goto error; - } - total += req->vbuf.src[i].len; - } - } - - /* Verify Destination Address's */ - for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) { - if ((req->vbuf.dst[i].vaddr != 0) && - (total < req->data_len)) { - if (!access_ok(VERIFY_WRITE, - (void __user *)req->vbuf.dst[i].vaddr, - req->vbuf.dst[i].len)) { - pr_err("%s:DST WR_VERIFY err %d=0x%lx\n", - __func__, i, (uintptr_t) - req->vbuf.dst[i].vaddr); - goto error; - } - total += req->vbuf.dst[i].len; - } - } return 0; error: return -EINVAL; @@ -1656,11 +1602,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) switch (cmd) { case QCEDEV_IOCTL_ENC_REQ: case QCEDEV_IOCTL_DEC_REQ: - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_cipher_op_req))) - return -EFAULT; - - if (__copy_from_user(&qcedev_areq.cipher_op_req, + if (copy_from_user(&qcedev_areq.cipher_op_req, (void __user *)arg, sizeof(struct qcedev_cipher_op_req))) return -EFAULT; @@ -1673,20 +1615,17 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle); if (err) return err; - if (__copy_to_user((void __user *)arg, + if (copy_to_user((void __user *)arg, &qcedev_areq.cipher_op_req, sizeof(struct qcedev_cipher_op_req))) - return -EFAULT; + return -EFAULT; break; case QCEDEV_IOCTL_SHA_INIT_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1696,9 +1635,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_hash_init(&qcedev_areq, handle, &sg_src); if (err) return err; - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) - return -EFAULT; + return -EFAULT; } handle->sha_ctxt.init_done = true; break; @@ -1708,11 +1647,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case QCEDEV_IOCTL_SHA_UPDATE_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1734,10 +1670,15 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return err; } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + return -EINVAL; + } memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; } @@ -1749,11 +1690,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("%s Init was not called\n", __func__); return -EINVAL; } - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1767,7 +1704,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; handle->sha_ctxt.init_done = false; @@ -1776,11 +1713,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case QCEDEV_IOCTL_GET_SHA_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1798,7 +1732,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; } diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index eb5e3fc127e0..0276952debbb 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -92,14 +92,15 @@ static ssize_t gpu_load_show(struct device *dev, struct device_attribute *attr, char *buf) { - unsigned long sysfs_busy_perc; + unsigned long sysfs_busy_perc = 0; /* * Average out the samples taken since last read * This will keep the average value in sync with * with the client sampling duration. */ spin_lock(&sample_lock); - sysfs_busy_perc = (acc_relative_busy * 100) / acc_total; + if (acc_total) + sysfs_busy_perc = (acc_relative_busy * 100) / acc_total; /* Reset the parameters */ acc_total = 0; diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index a02ed40ba9d5..e6163384f9c1 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -269,7 +269,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .patchid = ANY_ID, .features = ADRENO_PREEMPTION | ADRENO_64BIT | ADRENO_CONTENT_PROTECTION | - ADRENO_GPMU | ADRENO_SPTP_PC | ADRENO_LM, + ADRENO_GPMU | ADRENO_SPTP_PC, .pm4fw_name = "a530_pm4.fw", .pfpfw_name = "a530_pfp.fw", .zap_name = "a540_zap", @@ -283,4 +283,18 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gpmu_tsens = 0x000C000D, .max_power = 5448, }, + { + .gpurev = ADRENO_REV_A512, + .core = 5, + .major = 1, + .minor = 2, + .patchid = ANY_ID, + .features = ADRENO_64BIT, + .pm4fw_name = "a530_pm4.fw", + .pfpfw_name = "a530_pfp.fw", + .gpudev = &adreno_a5xx_gpudev, + .gmem_size = (SZ_256K + SZ_16K), + .num_protected_regs = 0x20, + .busy_mask = 0xFFFFFFFE, + }, }; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index d81142db5b58..1c30b43fdfcf 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -170,6 +170,7 @@ enum adreno_gpurev { ADRENO_REV_A505 = 505, ADRENO_REV_A506 = 506, ADRENO_REV_A510 = 510, + ADRENO_REV_A512 = 512, ADRENO_REV_A530 = 530, ADRENO_REV_A540 = 540, }; @@ -998,6 +999,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev) ADRENO_TARGET(a505, ADRENO_REV_A505) ADRENO_TARGET(a506, ADRENO_REV_A506) ADRENO_TARGET(a510, ADRENO_REV_A510) +ADRENO_TARGET(a512, ADRENO_REV_A512) ADRENO_TARGET(a530, ADRENO_REV_A530) ADRENO_TARGET(a540, ADRENO_REV_A540) diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index dc35c0080d11..90b833888d9d 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -57,6 +57,7 @@ static const struct adreno_vbif_data a540_vbif[] = { static const struct adreno_vbif_platform a5xx_vbif_platforms[] = { { adreno_is_a540, a540_vbif }, { adreno_is_a530, a530_vbif }, + { adreno_is_a512, a540_vbif }, { adreno_is_a510, a530_vbif }, { adreno_is_a505, a530_vbif }, { adreno_is_a506, a530_vbif }, @@ -1884,7 +1885,7 @@ static void a5xx_start(struct adreno_device *adreno_dev) if (adreno_is_a505_or_a506(adreno_dev)) kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL, (0x100 << 11 | 0x100 << 22)); - else if (adreno_is_a510(adreno_dev)) + else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev)) kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL, (0x200 << 11 | 0x200 << 22)); else @@ -1976,8 +1977,8 @@ static void a5xx_start(struct adreno_device *adreno_dev) kgsl_regwrite(device, A5XX_TPL1_MODE_CNTL, bit << 7); kgsl_regwrite(device, A5XX_RB_MODE_CNTL, bit << 1); - - if (adreno_is_a540(adreno_dev)) + if (adreno_is_a540(adreno_dev) || + adreno_is_a512(adreno_dev)) kgsl_regwrite(device, A5XX_UCHE_DBG_ECO_CNTL_2, bit); } diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index 09c550c9f58c..0e56731b16e2 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -22,7 +22,7 @@ #define PREEMPT_SMMU_RECORD(_field) \ offsetof(struct a5xx_cp_smmu_info, _field) -static void _update_wptr(struct adreno_device *adreno_dev) +static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) { struct adreno_ringbuffer *rb = adreno_dev->cur_rb; unsigned int wptr; @@ -35,10 +35,16 @@ static void _update_wptr(struct adreno_device *adreno_dev) if (wptr != rb->wptr) { adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr); + /* + * In case something got submitted while preemption was on + * going, reset the timer. + */ + reset_timer = 1; + } + if (reset_timer) rb->dispatch_q.expires = jiffies + msecs_to_jiffies(adreno_drawobj_timeout); - } spin_unlock_irqrestore(&rb->preempt_lock, flags); } @@ -90,7 +96,7 @@ static void _a5xx_preemption_done(struct adreno_device *adreno_dev) adreno_dev->next_rb = NULL; /* Update the wptr for the new command queue */ - _update_wptr(adreno_dev); + _update_wptr(adreno_dev, true); /* Update the dispatcher timer for the new command queue */ mod_timer(&adreno_dev->dispatcher.timer, @@ -213,7 +219,7 @@ void a5xx_preemption_trigger(struct adreno_device *adreno_dev) */ if (next != NULL) { - _update_wptr(adreno_dev); + _update_wptr(adreno_dev, false); mod_timer(&adreno_dev->dispatcher.timer, adreno_dev->cur_rb->dispatch_q.expires); @@ -304,7 +310,7 @@ void a5xx_preempt_callback(struct adreno_device *adreno_dev, int bit) adreno_dev->next_rb = NULL; /* Update the wptr if it changed while preemption was ongoing */ - _update_wptr(adreno_dev); + _update_wptr(adreno_dev, true); /* Update the dispatcher timer for the new command queue */ mod_timer(&adreno_dev->dispatcher.timer, diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c index aa00dcb84185..4bb7f6286664 100644 --- a/drivers/gpu/msm/adreno_iommu.c +++ b/drivers/gpu/msm/adreno_iommu.c @@ -856,6 +856,17 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, int result = 0; int cpu_path = 0; + /* Just do the context switch incase of NOMMU */ + if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) { + if ((!(flags & ADRENO_CONTEXT_SWITCH_FORCE_GPU)) && + adreno_isidle(device)) + _set_ctxt_cpu(rb, drawctxt); + else + result = _set_ctxt_gpu(rb, drawctxt); + + return result; + } + if (rb->drawctxt_active) cur_pt = rb->drawctxt_active->base.proc_priv->pagetable; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 699d99651f2c..6ef542416959 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -353,8 +353,10 @@ static int kgsl_mem_entry_track_gpuaddr(struct kgsl_device *device, /* * If SVM is enabled for this object then the address needs to be * assigned elsewhere + * Also do not proceed further in case of NoMMU. */ - if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) + if (kgsl_memdesc_use_cpu_map(&entry->memdesc) || + (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) return 0; pagetable = kgsl_memdesc_is_secured(&entry->memdesc) ? diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 03f278ead20f..c1c2afa68756 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -284,7 +284,8 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, memdesc->flags = flags; memdesc->priv = priv; - if ((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) + if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) || + (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) ret = kgsl_sharedmem_alloc_contig(device, memdesc, (size_t) size); else { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9dc9f93f4e36..577183bea07c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1251,6 +1251,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, /* Ignore report if ErrorRollOver */ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && value[n] >= min && value[n] <= max && + value[n] - min < field->maxusage && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) goto exit; } @@ -1263,11 +1264,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, } if (field->value[n] >= min && field->value[n] <= max + && field->value[n] - min < field->maxusage && field->usage[field->value[n] - min].hid && search(value, field->value[n], count)) hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); if (value[n] >= min && value[n] <= max + && value[n] - min < field->maxusage && field->usage[value[n] - min].hid && search(field->value, value[n], count)) hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c index 2282fe005bc7..0ec16e606545 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c @@ -358,6 +358,7 @@ static struct device_attribute attrs[] = { static struct synaptics_rmi4_fwu_handle *fwu; DECLARE_COMPLETION(fwu_dsx_remove_complete); +DEFINE_MUTEX(dsx_fwu_sysfs_mutex); static unsigned int extract_uint_le(const unsigned char *ptr) { @@ -1589,39 +1590,72 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file, char *buf, loff_t pos, size_t count) { struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; if (count < fwu->config_size) { dev_err(rmi4_data->pdev->dev.parent, "%s: Not enough space (%zu bytes) in buffer\n", __func__, count); - return -EINVAL; + retval = -EINVAL; + goto show_image_exit; } memcpy(buf, fwu->read_config_buf, fwu->config_size); - - return fwu->config_size; + retval = fwu->config_size; +show_image_exit: + mutex_unlock(&dsx_fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_store_image(struct file *data_file, struct kobject *kobj, struct bin_attribute *attributes, char *buf, loff_t pos, size_t count) { + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + + if (count > (fwu->image_size - fwu->data_pos)) { + dev_err(fwu->rmi4_data->pdev->dev.parent, + "%s: Not enough space in buffer\n", + __func__); + retval = -EINVAL; + goto exit; + } + + if (!fwu->ext_data_source) { + dev_err(fwu->rmi4_data->pdev->dev.parent, + "%s: Need to set imagesize\n", + __func__); + retval = -EINVAL; + goto exit; + } + memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), (const void *)buf, count); fwu->data_pos += count; +exit: + mutex_unlock(&dsx_fwu_sysfs_mutex); return count; } static ssize_t fwu_sysfs_force_reflash_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int retval; + ssize_t retval; unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; goto exit; @@ -1650,6 +1684,9 @@ exit: fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = DO_LOCKDOWN; + fwu->data_pos = 0; + fwu->image_size = 0; + mutex_unlock(&dsx_fwu_sysfs_mutex); return retval; } @@ -1660,6 +1697,9 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; goto exit; @@ -1693,6 +1733,9 @@ exit: fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = DO_LOCKDOWN; + fwu->data_pos = 0; + fwu->image_size = 0; + mutex_unlock(&dsx_fwu_sysfs_mutex); return retval; } @@ -1703,6 +1746,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; goto exit; @@ -1726,6 +1772,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; + fwu->data_pos = 0; + fwu->image_size = 0; + mutex_unlock(&dsx_fwu_sysfs_mutex); return retval; } @@ -1742,7 +1791,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev, if (input != 1) return -EINVAL; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; retval = fwu_do_read_config(); + mutex_unlock(&dsx_fwu_sysfs_mutex); + if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to read config\n", @@ -1763,7 +1816,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev, if (retval) return retval; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; fwu->config_area = config_area; + mutex_unlock(&dsx_fwu_sysfs_mutex); return count; } @@ -1771,17 +1827,30 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev, static ssize_t fwu_sysfs_image_name_show(struct device *dev, struct device_attribute *attr, char *buf) { + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0) - return snprintf(buf, PAGE_SIZE, "%s\n", + retval = snprintf(buf, PAGE_SIZE, "%s\n", fwu->rmi4_data->fw_name); else - return snprintf(buf, PAGE_SIZE, "No firmware name given\n"); + retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n"); + mutex_unlock(&dsx_fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_image_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (sscanf(buf, "%s", fwu->image_name) != 1) + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + retval = sscanf(buf, "%49s", fwu->image_name); + mutex_unlock(&dsx_fwu_sysfs_mutex); + + if (retval != 1) return -EINVAL; return count; @@ -1794,9 +1863,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, unsigned long size; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + retval = sstrtoul(buf, 10, &size); if (retval) - return retval; + goto exit; fwu->image_size = size; fwu->data_pos = 0; @@ -1807,10 +1879,14 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to alloc mem for image data\n", __func__); - return -ENOMEM; + retval = -ENOMEM; + goto exit; } - return count; + retval = count; +exit: + mutex_unlock(&dsx_fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_block_size_show(struct device *dev, 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 feede3a14e07..d6b32036f31c 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 @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/dma-buf.h> #include <asm/dma-iommu.h> +#include <asm/cacheflush.h> #include <linux/dma-direction.h> #include <linux/dma-attrs.h> #include <linux/of_platform.h> @@ -23,6 +24,8 @@ #include <linux/dma-mapping.h> #include <linux/msm_dma_iommu_mapping.h> #include <linux/workqueue.h> +#include <soc/qcom/scm.h> +#include <soc/qcom/secure_buffer.h> #include "cam_smmu_api.h" #define SCRATCH_ALLOC_START SZ_128K @@ -35,10 +38,15 @@ #define COOKIE_MASK ((1<<COOKIE_SIZE)-1) #define HANDLE_INIT (-1) #define CAM_SMMU_CB_MAX 2 +#define CAM_SMMU_SID_MAX 4 + #define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK)) #define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK) +#define CAMERA_DEVICE_ID 0x16 +#define SECURE_SYSCALL_ID 0x18 + #ifdef CONFIG_CAM_SMMU_DBG #define CDBG(fmt, args...) pr_err(fmt, ##args) #else @@ -104,6 +112,8 @@ struct cam_context_bank_info { int, void*); void *token[CAM_SMMU_CB_MAX]; int cb_count; + int ref_cnt; + int sids[CAM_SMMU_SID_MAX]; }; struct cam_iommu_cb_set { @@ -136,6 +146,17 @@ struct cam_dma_buff_info { size_t phys_len; }; +struct cam_sec_buff_info { + struct ion_handle *i_hdl; + struct ion_client *i_client; + enum dma_data_direction dir; + int ref_count; + dma_addr_t paddr; + struct list_head list; + int ion_fd; + size_t len; +}; + static struct cam_iommu_cb_set iommu_cb_set; static enum dma_data_direction cam_smmu_translate_dir( @@ -151,6 +172,9 @@ static int cam_smmu_create_add_handle_in_table(char *name, static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, int ion_fd); +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd); + static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, dma_addr_t base, size_t size, int order); @@ -477,10 +501,14 @@ void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops) iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH; iommu_cb_set.cb_info[i].dev = NULL; iommu_cb_set.cb_info[i].cb_count = 0; + iommu_cb_set.cb_info[i].ref_cnt = 0; for (j = 0; j < CAM_SMMU_CB_MAX; j++) { iommu_cb_set.cb_info[i].token[j] = NULL; iommu_cb_set.cb_info[i].handler[j] = NULL; } + for (j = 0; j < CAM_SMMU_SID_MAX; j++) + iommu_cb_set.cb_info[i].sids[j] = -1; + if (ops == CAM_SMMU_TABLE_INIT) mutex_init(&iommu_cb_set.cb_info[i].lock); else @@ -549,6 +577,8 @@ static int cam_smmu_create_add_handle_in_table(char *name, pr_err("Error: %s already got handle 0x%x\n", name, iommu_cb_set.cb_info[i].handle); + *hdl = iommu_cb_set.cb_info[i].handle; + iommu_cb_set.cb_info[i].ref_cnt++; mutex_unlock(&iommu_cb_set.cb_info[i].lock); return -EINVAL; } @@ -561,6 +591,7 @@ static int cam_smmu_create_add_handle_in_table(char *name, /* put handle in the table */ iommu_cb_set.cb_info[i].handle = handle; iommu_cb_set.cb_info[i].cb_count = 0; + iommu_cb_set.cb_info[i].ref_cnt++; *hdl = handle; CDBG("%s creates handle 0x%x\n", name, handle); mutex_unlock(&iommu_cb_set.cb_info[i].lock); @@ -698,6 +729,23 @@ static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, return NULL; } +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd) +{ + 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) { + CDBG("[sec_cam] find ion_fd %d\n", ion_fd); + return mapping; + } + } + pr_err("Error: Cannot find fd %d by index %d\n", + ion_fd, idx); + return NULL; +} + static void cam_smmu_clean_buffer_list(int idx) { int ret; @@ -754,6 +802,148 @@ static int cam_smmu_attach(int idx) return ret; } +static int cam_smmu_send_syscall_cpp_intf(int vmid, int idx) +{ + int rc = 0; + struct scm_desc desc = {0}; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + uint32_t sid_info; + + + sid_info = cb->sids[0]; /* CPP SID */ + + desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL); + desc.args[0] = CAMERA_DEVICE_ID; + desc.args[1] = SCM_BUFFER_PHYS(&sid_info); + desc.args[2] = sizeof(uint32_t); + desc.args[3] = vmid; + /* + * Syscall to hypervisor to switch CPP SID's + * between secure and non-secure contexts + */ + dmac_flush_range(&sid_info, &sid_info + 1); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID), + &desc)){ + pr_err("call to hypervisor failed\n"); + return -EINVAL; + } + return rc; +} + +static int cam_smmu_send_syscall_pix_intf(int vmid, int idx) +{ + int rc = 0; + struct scm_desc desc = {0}; + uint32_t *sid_info = NULL; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + sid_info = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL); + if (!sid_info) + return -ENOMEM; + + sid_info[0] = cb->sids[0]; /* VFE 0 Image SID */ + sid_info[1] = cb->sids[2]; /* VFE 1 Image SID */ + + desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL); + desc.args[0] = CAMERA_DEVICE_ID; + desc.args[1] = SCM_BUFFER_PHYS(sid_info); + desc.args[2] = sizeof(uint32_t) * 2; + desc.args[3] = vmid; + /* + * Syscall to hypervisor to switch VFE SID's + * between secure and non-secure contexts + */ + dmac_flush_range(sid_info, sid_info + 2); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID), + &desc)){ + pr_err("call to hypervisor failed\n"); + kfree(sid_info); + return -EINVAL; + } + + kfree(sid_info); + return rc; +} + +static int cam_smmu_detach_device(int idx) +{ + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + /* detach the mapping to device */ + arm_iommu_detach_device(cb->dev); + iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; + return 0; +} + +static int cam_smmu_attach_sec_cpp(int idx) +{ + /* + * When switching to secure, detach CPP NS, do scm call + * with CPP SID and no need of attach again, because + * all cpp sids are shared in SCM call. so no need of + * attach again. + */ + + if (cam_smmu_send_syscall_cpp_intf(VMID_CP_CAMERA, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + return 0; +} + +static int cam_smmu_detach_sec_cpp(int idx) +{ + /* + * When exiting secure, do scm call to attach + * with CPP SID in NS mode. + */ + if (cam_smmu_send_syscall_cpp_intf(VMID_HLOS, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + return 0; +} + +static int cam_smmu_attach_sec_vfe_ns_stats(int idx) +{ + /* + *When switching to secure, for secure pixel and non-secure stats + *localizing scm/attach of non-secure SID's in attach secure + */ + if (cam_smmu_send_syscall_pix_intf(VMID_CP_CAMERA, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + if (cam_smmu_attach(idx)) { + pr_err("error: failed to attach\n"); + return -EINVAL; + } + } + return 0; +} + +static int cam_smmu_detach_sec_vfe_ns_stats(int idx) +{ + /* + *While exiting from secure mode for secure pixel and non-secure stats, + *localizing detach/scm of non-secure SID's to detach secure + */ + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_DETACH) { + if (cam_smmu_detach_device(idx) < 0) { + pr_err("Error: ARM IOMMU detach failed\n"); + return -ENODEV; + } + } + + if (cam_smmu_send_syscall_pix_intf(VMID_HLOS, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + return 0; +} + static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, size_t *len_ptr) @@ -805,7 +995,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, } else { rc = -EINVAL; pr_err("Error: table sgl is null\n"); - goto err_unmap_sg; + goto err_map_addr; } /* fill up mapping_info */ @@ -813,7 +1003,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, if (!mapping_info) { pr_err("Error: No enough space!\n"); rc = -ENOSPC; - goto err_unmap_sg; + goto err_map_addr; } mapping_info->ion_fd = ion_fd; mapping_info->buf = buf; @@ -831,7 +1021,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, if (!*paddr_ptr || !*len_ptr) { pr_err("Error: Space Allocation failed!\n"); rc = -ENOSPC; - goto err_unmap_sg; + goto err_mapping_info; } CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd, (void *)iommu_cb_set.cb_info[idx].dev, @@ -841,6 +1031,12 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); return 0; +err_mapping_info: + kzfree(mapping_info); +err_map_addr: + msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, + table->sgl, table->nents, + dma_dir, buf); err_unmap_sg: dma_buf_unmap_attachment(attach, table, dma_dir); err_detach: @@ -851,6 +1047,98 @@ err_out: return rc; } +static int cam_smmu_map_secure_buffer_and_add_to_list(int idx, + struct dma_buf *buf, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = -1; + struct cam_dma_buff_info *mapping_info; + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + + attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach); + pr_err("Error: dma buf attach failed\n"); + goto err_put; + } + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + pr_err("Error: dma buf map attachment failed\n"); + goto err_detach; + } + + rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, table->sgl, + table->nents, dma_dir, buf); + if (!rc) { + pr_err("Error: msm_dma_map_sg_lazy failed\n"); + goto err_unmap_sg; + } + + if (table->sgl) { + CDBG("DMA buf: %p, device: %p, attach: %p, table: %p\n", + (void *)buf, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)attach, (void *)table); + CDBG("table sgl: %p, rc: %d, dma_address: 0x%x\n", + (void *)table->sgl, rc, + (unsigned int)table->sgl->dma_address); + } else { + rc = -EINVAL; + pr_err("Error: table sgl is null\n"); + goto err_map_addr; + } + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); + if (!mapping_info) { + rc = -ENOSPC; + goto err_map_addr; + } + mapping_info->ion_fd = 0; + mapping_info->buf = buf; + mapping_info->attach = attach; + mapping_info->table = table; + mapping_info->paddr = sg_dma_address(table->sgl); + mapping_info->len = (size_t)sg_dma_len(table->sgl); + mapping_info->dir = dma_dir; + mapping_info->ref_count = 1; + + /* return paddr and len to client */ + *paddr_ptr = sg_dma_address(table->sgl); + *len_ptr = (size_t)sg_dma_len(table->sgl); + + if (!*paddr_ptr || !*len_ptr) { + pr_err("Error: Invalid dma address/length\n"); + rc = -ENOSPC; + goto err_mapping_info; + } + CDBG("dev = %p, paddr= %p, len = %u\n", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + /* add to the list */ + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return 0; + +err_mapping_info: + kzfree(mapping_info); +err_map_addr: + msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, + table->sgl, table->nents, + dma_dir, buf); +err_unmap_sg: + dma_buf_unmap_attachment(attach, table, dma_dir); +err_detach: + dma_buf_detach(buf, attach); +err_put: + return rc; +} + static int cam_smmu_unmap_buf_and_remove_from_list( struct cam_dma_buff_info *mapping_info, int idx) @@ -951,7 +1239,23 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops) break; } case CAM_SMMU_DETACH: { - ret = 0; + ret = cam_smmu_detach_device(idx); + break; + } + case CAM_SMMU_ATTACH_SEC_VFE_NS_STATS: { + ret = cam_smmu_attach_sec_vfe_ns_stats(idx); + break; + } + case CAM_SMMU_DETACH_SEC_VFE_NS_STATS: { + ret = cam_smmu_detach_sec_vfe_ns_stats(idx); + break; + } + case CAM_SMMU_ATTACH_SEC_CPP: { + ret = cam_smmu_attach_sec_cpp(idx); + break; + } + case CAM_SMMU_DETACH_SEC_CPP: { + ret = cam_smmu_detach_sec_cpp(idx); break; } case CAM_SMMU_VOTE: @@ -1126,7 +1430,7 @@ int cam_smmu_get_phy_addr_scratch(int handle, size_t virt_len, size_t phys_len) { - int idx, rc; + int idx, rc = 0; unsigned int iommu_dir; if (!paddr_ptr || !virt_len || !phys_len) { @@ -1250,12 +1554,384 @@ int cam_smmu_put_phy_addr_scratch(int handle, pr_err("Error: unmap or remove list fail\n"); goto handle_err; } +handle_err: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +int cam_smmu_get_phy_addr_secure_scratch(int handle, + enum cam_smmu_map_dir dir, + struct dma_buf *scratch_buf, + dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int idx, rc; + enum dma_data_direction dma_dir; + + if (!paddr_ptr || !len_ptr) { + pr_err("Error: Input pointer or lengths invalid\n"); + return -EINVAL; + } + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + pr_err("Error: translate direction failed. dir = %d\n", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto error; + } + + CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n", + __func__, handle, idx, dir); + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto error; + } + + rc = cam_smmu_map_secure_buffer_and_add_to_list(idx, + scratch_buf, + dma_dir, + paddr_ptr, + len_ptr); + if (rc < 0) { + pr_err("Error: mapping or add list fail\n"); + goto error; + } + + CDBG("Mapped scratch buffer physical address is %lx\n", + (unsigned long)*paddr_ptr); +error: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +int cam_smmu_put_phy_addr_secure_scratch(int handle, + dma_addr_t paddr) +{ + int idx; + int rc = -1; + struct cam_dma_buff_info *mapping_info; + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto handle_err; + } + + /* Based on virtual address and index, we can find mapping info + * of the scratch buffer + */ + mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr); + if (!mapping_info) { + pr_err("Error: Invalid params\n"); + rc = -EINVAL; + goto handle_err; + } + + /* unmapping one buffer from device */ + rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) { + pr_err("Error: unmap or remove list fail\n"); + goto handle_err; + } + CDBG("Unmap secure scratch buffer %lx success fully\n", + (unsigned long)paddr); handle_err: mutex_unlock(&iommu_cb_set.cb_info[idx].lock); return rc; } +int cam_smmu_alloc_get_stage2_scratch_mem(int handle, + enum cam_smmu_map_dir dir, struct ion_client *client, + struct ion_handle **sc_handle, ion_phys_addr_t *addr, + size_t *len_ptr) +{ + int idx, rc = 0; + enum dma_data_direction dma_dir; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + pr_err("Error: translate direction failed. dir = %d\n", dir); + return -EINVAL; + } + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + return -EINVAL; + } + *sc_handle = ion_alloc(client, SZ_2M, SZ_2M, + ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID), + ION_FLAG_SECURE | ION_FLAG_CP_CAMERA); + if (IS_ERR_OR_NULL((void *) (*sc_handle))) { + rc = -ENOMEM; + goto err_ion_handle; + } + + /* return addr and len to client */ + rc = ion_phys(client, *sc_handle, addr, len_ptr); + if (rc) { + pr_err("%s: ION Get Physical failed, rc = %d\n", + __func__, rc); + rc = -EINVAL; + goto err_ion_phys; + } + + CDBG("dev = %pK, paddr= %pK, len = %u\n", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*addr, (unsigned int)*len_ptr); + return rc; + +err_ion_phys: + ion_free(client, *sc_handle); + +err_ion_handle: + *sc_handle = NULL; + return rc; +} + +int cam_smmu_free_stage2_scratch_mem(int handle, + struct ion_client *client, struct ion_handle *sc_handle) +{ + int idx = 0; + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + ion_free(client, sc_handle); + return 0; +} + +static int cam_smmu_secure_unmap_buf_and_remove_from_list( + struct cam_sec_buff_info *mapping_info, + int idx) +{ + if (!mapping_info) { + pr_err("Error: List doesn't exist\n"); + return -EINVAL; + } + ion_free(mapping_info->i_client, mapping_info->i_hdl); + list_del_init(&mapping_info->list); + + /* free one buffer */ + kfree(mapping_info); + return 0; +} + +int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd) +{ + int idx, rc; + struct cam_sec_buff_info *mapping_info; + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto put_addr_end; + } + + /* based on ion fd and index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd); + if (!mapping_info) { + pr_err("Error: Invalid params! idx = %d, fd = %d\n", + idx, ion_fd); + rc = -EINVAL; + goto put_addr_end; + } + + mapping_info->ref_count--; + if (mapping_info->ref_count > 0) { + CDBG("There are still %u buffer(s) with same fd %d", + mapping_info->ref_count, mapping_info->ion_fd); + rc = 0; + goto put_addr_end; + } + + /* unmapping one buffer from device */ + rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) { + pr_err("Error: unmap or remove list fail\n"); + goto put_addr_end; + } + +put_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_put_stage2_phy_addr); + +static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, + enum dma_data_direction dma_dir, struct ion_client *client, + dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = 0; + struct ion_handle *i_handle = NULL; + struct cam_sec_buff_info *mapping_info; + + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + return -EINVAL; + } + + i_handle = ion_import_dma_buf(client, ion_fd); + if (IS_ERR_OR_NULL((void *)(i_handle))) { + pr_err("%s: ion import dma buffer failed\n", __func__); + return -EINVAL; + } + + /* return addr and len to client */ + rc = ion_phys(client, i_handle, paddr_ptr, len_ptr); + if (rc) { + pr_err("%s: ION Get Physical failed, rc = %d\n", + __func__, rc); + return -EINVAL; + } + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL); + if (!mapping_info) + return -ENOSPC; + + mapping_info->ion_fd = ion_fd; + mapping_info->paddr = *paddr_ptr; + mapping_info->len = *len_ptr; + mapping_info->dir = dma_dir; + mapping_info->ref_count = 1; + mapping_info->i_hdl = i_handle; + mapping_info->i_client = client; + + CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + /* add to the list */ + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return rc; +} + +int cam_smmu_get_stage2_phy_addr(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + struct ion_client *client, ion_phys_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int idx, rc; + enum dma_data_direction dma_dir; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + pr_err("Error: Input pointers are invalid\n"); + return -EINVAL; + } + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + pr_err("Error: translate direction failed. dir = %d\n", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_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); + rc = 0; + goto get_addr_end; + } + rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir, + client, paddr_ptr, len_ptr); + if (rc < 0) { + pr_err("Error: mapping or add list fail\n"); + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + + int cam_smmu_get_phy_addr(int handle, int ion_fd, enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, size_t *len_ptr) @@ -1383,6 +2059,11 @@ int cam_smmu_destroy_handle(int handle) } mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (--iommu_cb_set.cb_info[idx].ref_cnt != 0) { + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; + } + if (iommu_cb_set.cb_info[idx].handle != handle) { pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", iommu_cb_set.cb_info[idx].handle, handle); @@ -1469,6 +2150,28 @@ end: return rc; } +static int cam_smmu_populate_sids(struct device *dev, + struct cam_context_bank_info *cb) +{ + int i, j, rc = 0; + unsigned int cnt = 0; + const void *property; + + /* set the name of the context bank */ + property = of_get_property(dev->of_node, "iommus", &cnt); + cnt /= 4; + for (i = 0, j = 0; i < cnt; i = i + 2, j++) { + rc = of_property_read_u32_index(dev->of_node, + "iommus", i + 1, &cb->sids[j]); + if (rc < 0) + pr_err("misconfiguration, can't fetch SID\n"); + + pr_err("__debug cnt = %d, cb->name: :%s sid [%d] = %d\n,", + cnt, cb->name, j, cb->sids[j]); + } + return rc; +} + static int cam_alloc_smmu_context_banks(struct device *dev) { struct device_node *domains_child_node = NULL; @@ -1541,6 +2244,11 @@ static int cam_populate_smmu_context_banks(struct device *dev, goto cb_init_fail; } + /* populate SID's for each cb */ + rc = cam_smmu_populate_sids(dev, cb); + if (rc < 0) + pr_err("Error: failed to populate sids : %s\n", cb->name); + /* Check if context bank supports scratch buffers */ if (of_property_read_bool(dev->of_node, "qcom,scratch-buf-support")) cb->scratch_buf_support = 1; @@ -1549,9 +2257,9 @@ static int cam_populate_smmu_context_banks(struct device *dev, /* set the secure/non secure domain type */ if (of_property_read_bool(dev->of_node, "qcom,secure-context")) - cb->is_secure = CAM_SECURE; + cb->is_secure = true; else - cb->is_secure = CAM_NON_SECURE; + cb->is_secure = false; CDBG("cb->name :%s, cb->is_secure :%d, cb->scratch_support :%d\n", cb->name, cb->is_secure, cb->scratch_buf_support); diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h index 59d085989a9c..3b8481f8bf7e 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h @@ -23,6 +23,8 @@ #include <linux/random.h> #include <linux/spinlock_types.h> #include <linux/mutex.h> +#include <linux/msm_ion.h> + /* * Enum for possible CAM SMMU operations @@ -31,6 +33,10 @@ enum cam_smmu_ops_param { CAM_SMMU_ATTACH, CAM_SMMU_DETACH, + CAM_SMMU_ATTACH_SEC_VFE_NS_STATS, + CAM_SMMU_DETACH_SEC_VFE_NS_STATS, + CAM_SMMU_ATTACH_SEC_CPP, + CAM_SMMU_DETACH_SEC_CPP, CAM_SMMU_VOTE, CAM_SMMU_DEVOTE, CAM_SMMU_OPS_INVALID @@ -87,6 +93,59 @@ int cam_smmu_get_phy_addr(int handle, int cam_smmu_put_phy_addr(int handle, int ion_fd); /** + * @param handle: Client has to pass back the smmu handle provided. + * @param ion_fd: ION handle identifying the memory buffer. + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE + * @client : Client has to pass the ion_client pointer created by the client. + * @phys_addr : Pointer to physical address where mapped address will be + * returned. + * @len : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_stage2_phy_addr(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + struct ion_client *client, ion_phys_addr_t *addr, + size_t *len_ptr); + +/** + * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param ion_fd: ION handle identifying the memory buffer. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd); + +/** + * @param handle: Client has to pass back the smmu handle provided. + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE, client has to pass. + * @client : Client has to pass the ion_client pointer created by the client. + * @ion_handle : handle to the buffer returned by CAM SMMU driver. + * @phys_addr : Pointer to physical address where mapped address will be + * returned. + * @len : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_alloc_get_stage2_scratch_mem(int handle, + enum cam_smmu_map_dir dir, struct ion_client *client, + struct ion_handle **sc_handle, ion_phys_addr_t *addr, + size_t *len_ptr); + + +/** + * @param handle: Client has to pass back the smmu handle provided. + * @client : Client has to pass the ion_client pointer provided by SMMU + * driver. + * @ion_handle : Client has to pass the ion_handle provided by SMMU + * driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ + +int cam_smmu_free_stage2_scratch_mem(int handle, + struct ion_client *client, struct ion_handle *sc_handle); + +/** * @brief : Allocates a scratch buffer * * This function allocates a scratch virtual buffer of length virt_len in the diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 3b6a2eecb4b6..13a7a398759b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -243,6 +243,8 @@ struct msm_vfe_core_ops { bool (*is_module_cfg_lock_needed)(uint32_t reg_offset); int (*ahb_clk_cfg)(struct vfe_device *vfe_dev, struct msm_isp_ahb_clk_cfg *ahb_cfg); + int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev, + void *arg); }; struct msm_vfe_stats_ops { int (*get_stats_idx)(enum msm_isp_stats_type stats_type); @@ -774,7 +776,7 @@ struct vfe_device { struct msm_isp_statistics *stats; uint64_t msm_isp_last_overflow_ab; uint64_t msm_isp_last_overflow_ib; - uint64_t msm_isp_vfe_clk_rate; + uint32_t msm_isp_vfe_clk_rate; struct msm_isp_ub_info *ub_info; uint32_t isp_sof_debug; uint32_t isp_raw0_debug; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 96f9e61578f2..1375d3ce8c65 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -1054,11 +1054,72 @@ static int msm_vfe40_start_fetch_engine(struct vfe_device *vfe_dev, return 0; } +static int msm_vfe40_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev, + void *arg) +{ + int rc = 0; + uint32_t bufq_handle = 0; + struct msm_isp_buffer *buf = NULL; + struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg; + struct msm_isp_buffer_mapped_info mapped_info; + + if (vfe_dev->fetch_engine_info.is_busy == 1) { + pr_err("%s: fetch engine busy\n", __func__); + return -EINVAL; + } + memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info)); + /* There is other option of passing buffer address from user, + * in such case, driver needs to map the buffer and use it + */ + vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id; + vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id; + vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode; + vfe_dev->fetch_engine_info.fd = fe_cfg->fd; + + if (!fe_cfg->offline_mode) { + bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, fe_cfg->session_id, + fe_cfg->stream_id); + vfe_dev->fetch_engine_info.bufq_handle = bufq_handle; + + rc = vfe_dev->buf_mgr->ops->get_buf_by_index( + vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf); + if (rc < 0 || !buf) { + pr_err("%s: No fetch buffer rc= %d buf= %p\n", + __func__, rc, buf); + return -EINVAL; + } + mapped_info = buf->mapped_info[0]; + buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED; + } else { + rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr, + &mapped_info, fe_cfg->fd); + if (rc < 0) { + pr_err("%s: can not map buffer\n", __func__); + return -EINVAL; + } + } + vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx; + vfe_dev->fetch_engine_info.is_busy = 1; + + msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset, + vfe_dev->vfe_base + 0x228); + + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); + + msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C); + msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C); + + ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id); + return 0; +} + static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev, struct msm_vfe_pix_cfg *pix_cfg) { uint32_t x_size_word; uint32_t temp = 0; + uint32_t main_unpack_pattern = 0; struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL; if (pix_cfg->input_mux != EXTERNAL_READ) { @@ -1089,10 +1150,14 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev, /* need to update to use formulae to calculate X_SIZE_WORD*/ x_size_word = msm_isp_cal_word_per_line( vfe_dev->axi_data.src_info[VFE_PIX_0].input_format, - fe_cfg->fetch_width); + fe_cfg->buf_width); msm_camera_io_w((x_size_word - 1) << 16, vfe_dev->vfe_base + 0x23C); + x_size_word = msm_isp_cal_word_per_line( + vfe_dev->axi_data.src_info[VFE_PIX_0].input_format, + fe_cfg->fetch_width); + temp = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); temp |= 2 << 16 | pix_cfg->pixel_pattern; msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C); @@ -1118,7 +1183,19 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev, } /* need to use formulae to calculate MAIN_UNPACK_PATTERN*/ - msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x248); + switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) { + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + main_unpack_pattern = 0xB210; + break; + default: + main_unpack_pattern = 0xF6543210; + break; + } + msm_camera_io_w(main_unpack_pattern, + vfe_dev->vfe_base + 0x248); msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x264); return; @@ -2261,6 +2338,8 @@ struct msm_vfe_hardware_info vfe40_hw_info = { .is_module_cfg_lock_needed = msm_vfe40_is_module_cfg_lock_needed, .ahb_clk_cfg = NULL, + .start_fetch_eng_multi_pass = + msm_vfe40_start_fetch_engine_multi_pass, }, .stats_ops = { .get_stats_idx = msm_vfe40_get_stats_idx, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index c50c55a69fb5..98e73d48ad15 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1077,11 +1077,70 @@ int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev, return 0; } +int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev, + void *arg) +{ + int rc = 0; + uint32_t bufq_handle = 0; + struct msm_isp_buffer *buf = NULL; + struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg; + struct msm_isp_buffer_mapped_info mapped_info; + + if (vfe_dev->fetch_engine_info.is_busy == 1) { + pr_err("%s: fetch engine busy\n", __func__); + return -EINVAL; + } + + memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info)); + + vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id; + vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id; + vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode; + vfe_dev->fetch_engine_info.fd = fe_cfg->fd; + + if (!fe_cfg->offline_mode) { + bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, fe_cfg->session_id, + fe_cfg->stream_id); + vfe_dev->fetch_engine_info.bufq_handle = bufq_handle; + + rc = vfe_dev->buf_mgr->ops->get_buf_by_index( + vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf); + if (rc < 0 || !buf) { + pr_err("%s: No fetch buffer rc= %d buf= %pK\n", + __func__, rc, buf); + return -EINVAL; + } + mapped_info = buf->mapped_info[0]; + buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED; + } else { + rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr, + &mapped_info, fe_cfg->fd); + if (rc < 0) { + pr_err("%s: can not map buffer\n", __func__); + return -EINVAL; + } + } + + vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx; + vfe_dev->fetch_engine_info.is_busy = 1; + + msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset, + vfe_dev->vfe_base + 0x2F4); + msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80); + msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80); + + ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id); + + return 0; +} + void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, struct msm_vfe_pix_cfg *pix_cfg) { uint32_t x_size_word, temp; struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL; + uint32_t main_unpack_pattern = 0; if (pix_cfg->input_mux == EXTERNAL_READ) { fe_cfg = &pix_cfg->fetch_engine_cfg; @@ -1107,10 +1166,13 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, x_size_word = msm_isp_cal_word_per_line( vfe_dev->axi_data.src_info[VFE_PIX_0].input_format, - fe_cfg->fetch_width); + fe_cfg->buf_width); msm_camera_io_w((x_size_word - 1) << 16, vfe_dev->vfe_base + 0x30c); + x_size_word = msm_isp_cal_word_per_line( + vfe_dev->axi_data.src_info[VFE_PIX_0].input_format, + fe_cfg->fetch_width); msm_camera_io_w(x_size_word << 16 | (temp & 0x3FFF) << 2 | VFE47_FETCH_BURST_LEN, vfe_dev->vfe_base + 0x310); @@ -1120,7 +1182,19 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, msm_camera_io_w(temp, vfe_dev->vfe_base + 0x314); /* need to use formulae to calculate MAIN_UNPACK_PATTERN*/ - msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x318); + switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) { + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + main_unpack_pattern = 0xB210; + break; + default: + main_unpack_pattern = 0xF6543210; + break; + } + msm_camera_io_w(main_unpack_pattern, + vfe_dev->vfe_base + 0x318); msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x334); temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50); @@ -2721,6 +2795,8 @@ struct msm_vfe_hardware_info vfe47_hw_info = { .is_module_cfg_lock_needed = msm_vfe47_is_module_cfg_lock_needed, .ahb_clk_cfg = msm_isp47_ahb_clk_cfg, + .start_fetch_eng_multi_pass = + msm_vfe47_start_fetch_engine_multi_pass, }, .stats_ops = { .get_stats_idx = msm_vfe47_get_stats_idx, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h index 3955196d1deb..6524ac84edf3 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h @@ -65,6 +65,8 @@ int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev, enum msm_vfe_axi_stream_src stream_src, uint32_t io_format); int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev, void *arg); +int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev, + void *arg); void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, struct msm_vfe_pix_cfg *pix_cfg); void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c index 49520bb44ad8..568125e2d7c2 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c @@ -309,6 +309,8 @@ struct msm_vfe_hardware_info vfe48_hw_info = { .is_module_cfg_lock_needed = msm_vfe47_is_module_cfg_lock_needed, .ahb_clk_cfg = msm_isp47_ahb_clk_cfg, + .start_fetch_eng_multi_pass = + msm_vfe47_start_fetch_engine_multi_pass, }, .stats_ops = { .get_stats_idx = msm_vfe47_get_stats_idx, 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 e8289f05d28f..3b9c3c9d3926 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 @@ -1691,6 +1691,76 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( return buf; } +int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + uint32_t buf_idx) +{ + int i, rc = 0; + struct msm_isp_buffer *buf = NULL; + uint32_t pingpong_bit; + uint32_t buffer_size_byte = 0; + int32_t word_per_line = 0; + dma_addr_t paddr; + uint32_t bufq_handle = 0; + int vfe_idx; + + bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT]; + + if (!vfe_dev->is_split) { + rc = vfe_dev->buf_mgr->ops->get_buf_by_index( + vfe_dev->buf_mgr, bufq_handle, buf_idx, &buf); + if (rc < 0 || !buf) { + pr_err("%s: No fetch buffer rc= %d buf= %p\n", + __func__, rc, buf); + return -EINVAL; + } + + if (buf->num_planes != stream_info->num_planes) { + pr_err("%s: Invalid buffer\n", __func__); + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + bufq_handle, buf->buf_idx); + return -EINVAL; + } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + pingpong_bit = ((pingpong_status >> + stream_info->wm[vfe_idx][0]) & 0x1); + + for (i = 0; i < stream_info->num_planes; i++) { + word_per_line = msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[vfe_idx][i]. + output_stride); + if (word_per_line < 0) { + /* 0 means no prefetch*/ + word_per_line = 0; + buffer_size_byte = 0; + } else { + buffer_size_byte = (word_per_line * 8 * + stream_info->plane_cfg[vfe_idx][i]. + output_scan_lines) - + stream_info-> + plane_cfg[vfe_idx][i].plane_addr_offset; + } + paddr = buf->mapped_info[i].paddr; + + vfe_dev->hw_info->vfe_ops.axi_ops. + update_ping_pong_addr( + vfe_dev->vfe_base, stream_info->wm[vfe_idx][i], + pingpong_bit, paddr + + stream_info-> + plane_cfg[vfe_idx][i].plane_addr_offset, + buffer_size_byte); + stream_info->buf[!pingpong_bit] = buf; + buf->pingpong_bit = !pingpong_bit; + } + buf->state = MSM_ISP_BUFFER_STATE_DEQUEUED; + stream_info->buf[!pingpong_bit] = buf; + buf->pingpong_bit = !pingpong_bit; + } + return rc; + +} + static int msm_isp_cfg_ping_pong_address( struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) { @@ -1888,6 +1958,11 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, buf_event.u.buf_done.buf_idx = buf->buf_idx; buf_event.u.buf_done.output_format = stream_info->runtime_output_format; + if (vfe_dev->fetch_engine_info.is_busy && + SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) { + vfe_dev->fetch_engine_info.is_busy = 0; + } + if (stream_info->buf_divert && buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) { @@ -2065,7 +2140,8 @@ static void msm_isp_input_enable(struct vfe_device *vfe_dev, continue; /* activate the input since it is deactivated */ axi_data->src_info[i].frame_id = 0; - axi_data->src_info[i].active = 1; + if (axi_data->src_info[i].input_mux != EXTERNAL_READ) + axi_data->src_info[i].active = 1; if (i >= VFE_RAW_0 && sync_frame_id_src) { /* * Incase PIX and RDI streams are part @@ -3534,6 +3610,7 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) unsigned long flags; struct msm_isp_timestamp timestamp; uint32_t frame_id; + int vfe_idx; /*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/ if (update_cmd->num_streams > MAX_NUM_STREAM) @@ -3746,6 +3823,20 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) __func__); break; } + case UPDATE_STREAM_OFFLINE_AXI_CONFIG: { + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); + vfe_idx = msm_isp_get_vfe_idx_for_stream( + vfe_dev, stream_info); + msm_isp_stream_axi_cfg_update(vfe_dev, stream_info, + update_info); + } + break; + } default: pr_err("%s: Invalid update type %d\n", __func__, update_cmd->update_type); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index 9c642370b1a1..f9ae5fb74281 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -157,4 +157,7 @@ static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream( index); } +int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + uint32_t buf_idx); #endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index b0789ce4a71c..72eac5d81627 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -375,6 +375,47 @@ static int msm_isp_start_fetch_engine(struct vfe_device *vfe_dev, start_fetch_eng(vfe_dev, arg); } +static int msm_isp_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev, + void *arg) +{ + struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg; + struct msm_vfe_axi_stream *stream_info = NULL; + int i = 0, rc; + uint32_t wm_reload_mask = 0; + int vfe_idx; + /* + * For Offline VFE, HAL expects same frame id + * for offline output which it requested in do_reprocess. + */ + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = + fe_cfg->frame_id; + if (fe_cfg->offline_pass == OFFLINE_SECOND_PASS) { + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(fe_cfg->output_stream_id)); + if (stream_info == NULL) { + pr_err("%s: Error in Offline process\n", __func__); + return -EINVAL; + } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + msm_isp_reset_framedrop(vfe_dev, stream_info); + + rc = msm_isp_cfg_offline_ping_pong_address(vfe_dev, stream_info, + VFE_PING_FLAG, fe_cfg->output_buf_idx); + if (rc < 0) { + pr_err("%s: Fetch engine config failed\n", __func__); + return -EINVAL; + } + for (i = 0; i < stream_info->num_planes; i++) + wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, + VFE_SRC_MAX); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, + vfe_dev->vfe_base, wm_reload_mask); + } + return vfe_dev->hw_info->vfe_ops.core_ops. + start_fetch_eng_multi_pass(vfe_dev, arg); +} + void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, struct msm_vfe_fetch_engine_info *fetch_engine_info) { @@ -880,6 +921,13 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, rc = msm_isp_start_fetch_engine(vfe_dev, arg); mutex_unlock(&vfe_dev->core_mutex); break; + + case VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START: + case VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_start_fetch_engine_multi_pass(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; case VIDIOC_MSM_ISP_REG_UPDATE_CMD: if (arg) { enum msm_vfe_input_src frame_src = diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 094a7861831a..dc2061fc4537 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -1444,7 +1444,8 @@ static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, } if (fatal_err == true) { - pr_err("%s: fatal error, stop ispif immediately\n", __func__); + pr_err_ratelimited("%s: fatal error, stop ispif immediately\n", + __func__); for (i = 0; i < ispif->vfe_info.num_vfe; i++) { msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index 437af72a6a55..de27e585f63d 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -71,8 +71,8 @@ static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd, int rc; struct msm_jpeg_device *pgmn_dev = filp->private_data; - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__, - __LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev, + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__, + __LINE__, _IOC_NR(cmd), pgmn_dev, (unsigned long)arg); rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg); @@ -87,8 +87,8 @@ static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd, int rc; struct msm_jpeg_device *pgmn_dev = filp->private_data; - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__, - __LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev, + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__, + __LINE__, _IOC_NR(cmd), pgmn_dev, (unsigned long)arg); rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg); @@ -114,9 +114,9 @@ int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd) struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)jpeg_sd->host_priv; - JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%lx\n", + JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%pK\n", __func__, __LINE__, (unsigned long)jpeg_sd, - (unsigned long)pgmn_dev); + pgmn_dev); rc = __msm_jpeg_open(pgmn_dev); JPEG_DBG("%s:%d: rc=%d\n", __func__, __LINE__, rc); @@ -132,7 +132,7 @@ static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd, JPEG_DBG("%s: cmd=%d\n", __func__, cmd); - JPEG_DBG("%s: pgmn_dev 0x%lx", __func__, (unsigned long)pgmn_dev); + JPEG_DBG("%s: pgmn_dev 0x%pK", __func__, pgmn_dev); JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__); @@ -146,7 +146,7 @@ void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd) int rc; struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)jpeg_sd->host_priv; - JPEG_DBG("%s:pgmn_dev=0x%lx", __func__, (unsigned long)pgmn_dev); + JPEG_DBG("%s:pgmn_dev=0x%pK", __func__, pgmn_dev); rc = __msm_jpeg_release(pgmn_dev); JPEG_DBG("%s:rc=%d", __func__, rc); } diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index 071ce0a41ed9..e40869d41a5d 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -847,7 +847,7 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, uint32_t data; while (m_cmds--) { - if (hw_cmd_p->offset > max_size) { + if (hw_cmd_p->offset >= max_size) { JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, __LINE__, hw_cmd_p->offset, max_size); return -EFAULT; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index 63d7e715162b..3301fc446193 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -128,6 +128,21 @@ static inline void msm_jpegdma_schedule_next_config(struct jpegdma_ctx *ctx) } /* + * msm_jpegdma_cast_long_to_buff_ptr - Cast long to buffer pointer. + * @vaddr: vaddr as long + * @buff_ptr_head: buffer pointer head + */ +static inline void msm_jpegdma_cast_long_to_buff_ptr(unsigned long vaddr, + struct msm_jpeg_dma_buff **buff_ptr_head) +{ +#ifdef CONFIG_COMPAT + *buff_ptr_head = compat_ptr(vaddr); +#else + *buff_ptr_head = (struct msm_jpeg_dma_buff *) vaddr; +#endif +} + +/* * msm_jpegdma_get_format_idx - Get jpeg dma format lookup index. * @ctx: Pointer to dma ctx. * @f: v4l2 format. @@ -410,10 +425,12 @@ static void *msm_jpegdma_get_userptr(void *alloc_ctx, { struct msm_jpegdma_device *dma = alloc_ctx; struct msm_jpegdma_buf_handle *buf; - struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(vaddr); + struct msm_jpeg_dma_buff __user *up_buff; struct msm_jpeg_dma_buff kp_buff; int ret; + msm_jpegdma_cast_long_to_buff_ptr(vaddr, &up_buff); + if (!access_ok(VERIFY_READ, up_buff, sizeof(struct msm_jpeg_dma_buff)) || get_user(kp_buff.fd, &up_buff->fd)) { @@ -813,10 +830,12 @@ static int msm_jpegdma_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); - struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(buf->m.userptr); + struct msm_jpeg_dma_buff __user *up_buff; struct msm_jpeg_dma_buff kp_buff; int ret; + msm_jpegdma_cast_long_to_buff_ptr(buf->m.userptr, &up_buff); + if (!access_ok(VERIFY_READ, up_buff, sizeof(struct msm_jpeg_dma_buff)) || get_user(kp_buff.fd, &up_buff->fd) || diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index ab074ffbcdfb..7e452e9e4ee2 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -220,6 +220,7 @@ void msm_cpp_deinit_bandwidth_mgr(struct cpp_device *cpp_dev) static int msm_cpp_update_bandwidth_setting(struct cpp_device *cpp_dev, uint64_t ab, uint64_t ib) { int rc; + if (cpp_dev->bus_master_flag) rc = msm_cpp_update_bandwidth(cpp_dev, ab, ib); else @@ -242,6 +243,7 @@ static void msm_enqueue(struct msm_device_queue *queue, struct list_head *entry) { unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); queue->len++; if (queue->len > queue->max) { @@ -302,6 +304,7 @@ static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev) { uint32_t i; unsigned long flags; + CPP_DBG("Frame done qlen %d\n", cpp_dev->processing_q.len); if (cpp_dev->processing_q.len <= 1) { msm_cpp_clear_timer(cpp_dev); @@ -323,6 +326,7 @@ static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev) static uint32_t msm_cpp_read(void __iomem *cpp_base) { uint32_t tmp, retry = 0; + do { tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT); } while (((tmp & 0x2) == 0x0) && (retry++ < 10)); @@ -409,14 +413,22 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, pr_err("error allocating memory\n"); goto error; } - buff->map_info.buff_info = *buffer_info; + buff->map_info.buff_info = *buffer_info; buff->map_info.buf_fd = buffer_info->fd; - rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl, buffer_info->fd, - CAM_SMMU_MAP_RW, &buff->map_info.phy_addr, - (size_t *)&buff->map_info.len); + + if (buff_queue->security_mode == SECURE_MODE) + rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl, + buffer_info->fd, CAM_SMMU_MAP_RW, + cpp_dev->ion_client, &buff->map_info.phy_addr, + (size_t *)&buff->map_info.len); + else + rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl, + buffer_info->fd, CAM_SMMU_MAP_RW, + &buff->map_info.phy_addr, + (size_t *)&buff->map_info.len); if (rc < 0) { - pr_err("ION mmap failed\n"); + pr_err("ION mmap for CPP buffer failed\n"); kzfree(buff); goto error; } @@ -430,10 +442,17 @@ error: } static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue, struct msm_cpp_buffer_map_list_t *buff) { int ret = -1; - ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl, buff->map_info.buf_fd); + + if (buff_queue->security_mode == SECURE_MODE) + ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl, + buff->map_info.buf_fd); + else + ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl, + buff->map_info.buf_fd); if (ret < 0) pr_err("Error: cannot put the iommu handle back to ion fd\n"); @@ -466,6 +485,7 @@ static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev, buffer_info); *fd = buffer_info->fd; } + return phy_addr; } @@ -477,12 +497,12 @@ static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev, buff_head = &buff_queue_info->native_buff_head; list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); + msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff); } buff_head = &buff_queue_info->vb2_buff_head; list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); + msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff); } return 0; @@ -502,7 +522,8 @@ static int32_t msm_cpp_dequeue_buff(struct cpp_device *cpp_dev, list_for_each_entry_safe(buff, save, buff_head, entry) { if (buff->map_info.buff_info.index == buff_index) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); + msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, + buff); break; } } @@ -522,6 +543,8 @@ static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev, buff_queue_info->used = 1; buff_queue_info->session_id = session_id; buff_queue_info->stream_id = stream_id; + buff_queue_info->security_mode = + cpp_dev->security_mode; INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); INIT_LIST_HEAD(&buff_queue_info->native_buff_head); return 0; @@ -548,6 +571,7 @@ static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev, buff_queue_info->used = 0; buff_queue_info->session_id = 0; buff_queue_info->stream_id = 0; + buff_queue_info->security_mode = NON_SECURE_MODE; INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); INIT_LIST_HEAD(&buff_queue_info->native_buff_head); return 0; @@ -557,6 +581,7 @@ static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev, uint32_t num_buffq) { struct msm_cpp_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq, GFP_KERNEL); @@ -602,6 +627,7 @@ static int32_t msm_cpp_poll(void __iomem *cpp_base, u32 val) { uint32_t tmp, retry = 0; int32_t rc = 0; + do { tmp = msm_cpp_read(cpp_base); if (tmp != 0xDEADBEEF) @@ -796,6 +822,7 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; struct cpp_device *cpp_dev = data; struct msm_cpp_tasklet_queue_cmd *queue_cmd; + irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT); if (irq_status & 0x8) { @@ -1028,6 +1055,7 @@ reg_enable_failed: static void cpp_release_hardware(struct cpp_device *cpp_dev) { int32_t rc; + if (cpp_dev->state != CPP_STATE_BOOT) { msm_camera_unregister_irq(cpp_dev->pdev, cpp_dev->irq, cpp_dev); tasklet_kill(&cpp_dev->cpp_tasklet); @@ -1061,7 +1089,7 @@ static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) goto end; } pr_debug("%s:%d] FW file: %s\n", __func__, __LINE__, fw_name_bin); - if (NULL == cpp_dev->fw) { + if (cpp_dev->fw == NULL) { pr_err("%s:%d] fw NULL", __func__, __LINE__); rc = -EINVAL; goto end; @@ -1192,7 +1220,8 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) int rc; uint32_t i; struct cpp_device *cpp_dev = NULL; - CPP_DBG("E\n"); + + CPP_DBG("E"); if (!sd || !fh) { pr_err("Wrong input parameters sd %pK fh %pK!", @@ -1246,6 +1275,14 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return rc; } cpp_dev->state = CPP_STATE_IDLE; + + CPP_DBG("Invoking msm_ion_client_create()\n"); + cpp_dev->ion_client = msm_ion_client_create("cpp"); + if (cpp_dev->ion_client == NULL) { + pr_err("msm_ion_client_create() failed\n"); + mutex_unlock(&cpp_dev->mutex); + rc = -ENOMEM; + } } mutex_unlock(&cpp_dev->mutex); return 0; @@ -1338,6 +1375,12 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_cpp_empty_list(processing_q, list_frame); msm_cpp_empty_list(eventData_q, list_eventdata); cpp_dev->state = CPP_STATE_OFF; + + if (cpp_dev->ion_client) { + CPP_DBG("Invoking ion_client_destroy()\n"); + ion_client_destroy(cpp_dev->ion_client); + cpp_dev->ion_client = NULL; + } } mutex_unlock(&cpp_dev->mutex); @@ -1415,7 +1458,8 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev, SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame, iden, processed_frame->duplicate_identity); - memset(&buff_mgr_info, 0 , + + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF); @@ -1460,7 +1504,7 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev, SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame, iden, processed_frame->identity); - memset(&buff_mgr_info, 0 , + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF); @@ -1500,6 +1544,7 @@ static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) { int i, i1, i2; struct cpp_device *cpp_dev = cpp_timer.data.cpp_dev; + CPP_DBG("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n", frame_info->identity, frame_info->frame_id); @@ -1935,6 +1980,7 @@ static int msm_cpp_check_buf_type(struct msm_buf_mngr_info *buff_mgr_info, { int32_t num_output_bufs = 0; uint32_t i = 0; + if (buff_mgr_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { new_frame->batch_info.cont_idx = buff_mgr_info->index; @@ -2009,7 +2055,7 @@ static void msm_cpp_update_frame_msg_phy_address(struct cpp_device *cpp_dev, dup_we_mmu_pf_ptr_off = cpp_dev->payload_params.dup_we_mmu_pf_ptr_off; ref_we_mmu_pf_ptr_off = cpp_dev->payload_params.ref_we_mmu_pf_ptr_off; - pr_debug("%s: feature_mask 0x%x\n", __func__, new_frame->feature_mask); + pr_debug("feature_mask 0x%x\n", new_frame->feature_mask); /* Update individual module status from feature mask */ tnr_enabled = ((new_frame->feature_mask & TNR_MASK) >> 2); @@ -2460,6 +2506,7 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, /* get buffer for duplicate output */ if (new_frame->duplicate_output) { int32_t iden = new_frame->duplicate_identity; + CPP_DBG("duplication enabled, dup_id=0x%x", new_frame->duplicate_identity); @@ -2599,7 +2646,7 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, int32_t rc = 0; int32_t i = 0; int32_t num_buff = sizeof(k_frame_info.output_buffer_info)/ - sizeof(struct msm_cpp_buffer_info_t); + sizeof(struct msm_cpp_buffer_info_t); if (copy_from_user(&k_frame_info, (void __user *)ioctl_ptr->ioctl_ptr, sizeof(k_frame_info))) @@ -2660,6 +2707,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, struct msm_camera_v4l2_ioctl_t *ioctl_ptr) { int ret; + if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) { pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__, ioctl_ptr, ioctl_ptr->len); @@ -2683,6 +2731,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, struct msm_camera_v4l2_ioctl_t *ioctl_ptr) { int ret; + if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) { pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__, ioctl_ptr, ioctl_ptr->len); @@ -2758,14 +2807,15 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, break; default: { if (ioctl_ptr == NULL) { - pr_err("Wrong ioctl_ptr for cmd %u\n", cmd); + pr_err("Wrong ioctl_ptr %pK for cmd %u\n", + ioctl_ptr, cmd); return -EINVAL; } *ioctl_ptr = arg; if ((*ioctl_ptr == NULL) || - (*ioctl_ptr)->ioctl_ptr == NULL) { - pr_err("Error invalid ioctl argument cmd %u", cmd); + ((*ioctl_ptr)->ioctl_ptr == NULL)) { + pr_err("Wrong arg %pK for cmd %u\n", arg, cmd); return -EINVAL; } break; @@ -3007,7 +3057,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, mutex_unlock(&cpp_dev->mutex); return -EINVAL; } - if (VIDIOC_MSM_CPP_DELETE_STREAM_BUFF == cmd) { + if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF) { for (j = 0; j < k_stream_buff_info.num_buffs; j++) { msm_cpp_dequeue_buff(cpp_dev, buff_queue_info, k_stream_buff_info.buffer_info[j].index, @@ -3030,9 +3080,9 @@ STREAM_BUFF_END: case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { uint32_t identity; struct msm_cpp_buff_queue_info_t *buff_queue_info; + CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); - if ((ioctl_ptr->len == 0) || - (ioctl_ptr->len > sizeof(uint32_t))) { + if (ioctl_ptr->len != sizeof(uint32_t)) { mutex_unlock(&cpp_dev->mutex); return -EINVAL; } @@ -3079,6 +3129,7 @@ STREAM_BUFF_END: struct msm_device_queue *queue = &cpp_dev->eventData_q; struct msm_queue_cmd *event_qcmd; struct msm_cpp_frame_info_t *process_frame; + CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n"); event_qcmd = msm_dequeue(queue, list_eventdata, POP_FRONT); if (!event_qcmd) { @@ -3107,6 +3158,7 @@ STREAM_BUFF_END: uint32_t msm_cpp_core_clk_idx; struct msm_cpp_clock_settings_t clock_settings; unsigned long clock_rate = 0; + CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n"); if (ioctl_ptr->len == 0) { pr_err("ioctl_ptr->len is 0\n"); @@ -3185,6 +3237,7 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_QUEUE_BUF: { struct msm_pproc_queue_buf_info queue_buf_info; + CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n"); if (ioctl_ptr->len != sizeof(struct msm_pproc_queue_buf_info)) { @@ -3267,9 +3320,27 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_IOMMU_ATTACH: { if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { - rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_ATTACH); + struct msm_camera_smmu_attach_type cpp_attach_info; + + memset(&cpp_attach_info, 0, sizeof(cpp_attach_info)); + rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info, + ioctl_ptr); if (rc < 0) { - pr_err("%s:%dError iommu_attach_device failed\n", + ERR_COPY_FROM_USER(); + return -EINVAL; + } + + cpp_dev->security_mode = cpp_attach_info.attach; + + if (cpp_dev->security_mode == SECURE_MODE) { + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_ATTACH_SEC_CPP); + } else { + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_ATTACH); + } + if (rc < 0) { + pr_err("%s:%diommu_attach_device failed\n", __func__, __LINE__); rc = -EINVAL; break; @@ -3285,10 +3356,28 @@ STREAM_BUFF_END: case VIDIOC_MSM_CPP_IOMMU_DETACH: { if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) && (cpp_dev->stream_cnt == 0)) { - rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_DETACH); + + struct msm_camera_smmu_attach_type cpp_attach_info; + + memset(&cpp_attach_info, 0, sizeof(cpp_attach_info)); + rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info, + ioctl_ptr); if (rc < 0) { - pr_err("%s:%dError iommu atach failed\n", - __func__, __LINE__); + ERR_COPY_FROM_USER(); + return -EINVAL; + } + + cpp_dev->security_mode = cpp_attach_info.attach; + + if (cpp_dev->security_mode == SECURE_MODE) + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_DETACH_SEC_CPP); + else + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_DETACH); + if (rc < 0) { + pr_err("%s:%diommu detach failed\n", __func__, + __LINE__); rc = -EINVAL; break; } @@ -3368,6 +3457,7 @@ static long msm_cpp_subdev_do_ioctl( struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; struct msm_cpp_frame_info_t inst_info; + memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t)); for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) { @@ -3736,6 +3826,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, struct msm_cpp_frame_info32_t inst_info; struct v4l2_fh *vfh = NULL; uint32_t i; + vfh = file->private_data; memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info32_t)); for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { @@ -3979,6 +4070,7 @@ static int msm_cpp_update_gdscr_status(struct cpp_device *cpp_dev, { int rc = 0; int value = 0; + if (!cpp_dev) { pr_err("%s: cpp device invalid\n", __func__); rc = -EINVAL; @@ -4081,6 +4173,7 @@ static int cpp_probe(struct platform_device *pdev) struct cpp_device *cpp_dev; int rc = 0; int i = 0; + CPP_DBG("E"); cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL); @@ -4252,6 +4345,8 @@ static int cpp_probe(struct platform_device *pdev) cpp_timer_callback, (unsigned long)&cpp_timer); cpp_dev->fw_name_bin = NULL; cpp_dev->max_timeout_trial_cnt = MSM_CPP_MAX_TIMEOUT_TRIAL; + + if (rc == 0) CPP_DBG("SUCCESS."); else @@ -4294,6 +4389,7 @@ static int cpp_device_remove(struct platform_device *dev) { struct v4l2_subdev *sd = platform_get_drvdata(dev); struct cpp_device *cpp_dev; + if (!sd) { pr_err("%s: Subdevice is NULL\n", __func__); return 0; @@ -4304,6 +4400,7 @@ static int cpp_device_remove(struct platform_device *dev) pr_err("%s: cpp device is NULL\n", __func__); return 0; } + if (cpp_dev->fw) { release_firmware(cpp_dev->fw); cpp_dev->fw = NULL; @@ -4367,6 +4464,7 @@ DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL, static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev) { struct dentry *debugfs_base; + debugfs_base = debugfs_create_dir("msm_cpp", NULL); if (!debugfs_base) return -ENOMEM; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index d5abe0202717..f46cc10cef46 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -169,6 +169,7 @@ struct msm_cpp_buff_queue_info_t { uint32_t used; uint16_t session_id; uint16_t stream_id; + enum smmu_attach_mode security_mode; struct list_head vb2_buff_head; struct list_head native_buff_head; }; @@ -234,6 +235,8 @@ struct cpp_device { uint32_t min_clk_rate; int iommu_hdl; + struct ion_client *ion_client; + enum smmu_attach_mode security_mode; /* Reusing proven tasklet from msm isp */ atomic_t irq_cnt; uint8_t taskletq_idx; diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index b1c23823c122..f113bdc5de01 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -115,15 +115,16 @@ static int32_t msm_cci_set_clk_param(struct cci_device *cci_dev, enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; - clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; - if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { pr_err("%s:%d invalid i2c_freq_mode = %d", __func__, __LINE__, i2c_freq_mode); return -EINVAL; } + if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode) return 0; + + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; if (MASTER_0 == master) { msm_camera_io_w_mb(clk_params->hw_thigh << 16 | clk_params->hw_tlow, @@ -1196,6 +1197,13 @@ static uint32_t *msm_cci_get_clk_rates(struct cci_device *cci_dev, struct msm_cci_clk_params_t *clk_params = NULL; enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; struct device_node *of_node = cci_dev->pdev->dev.of_node; + + if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { + pr_err("%s:%d invalid i2c_freq_mode %d\n", + __func__, __LINE__, i2c_freq_mode); + return NULL; + } + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; cci_clk_src = clk_params->cci_clk_src; 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 0d8c6cb8f3f3..dc5a5a0dc851 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -237,7 +237,7 @@ static void sde_rotator_set_clk_rate(struct sde_rot_mgr *mgr, clk_rate = clk_round_rate(clk, rate); if (IS_ERR_VALUE(clk_rate)) { SDEROT_ERR("unable to round rate err=%ld\n", clk_rate); - } else if (clk_rate != clk_get_rate(clk)) { + } else { ret = clk_set_rate(clk, clk_rate); if (IS_ERR_VALUE(ret)) SDEROT_ERR("clk_set_rate failed, err:%d\n", 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 4e86a3ff820d..eaf35733b38a 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -2013,15 +2013,18 @@ static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr, } } - fmt = sde_get_format_params(item->output.format); - /* Tiled format downscale support not applied to AYUV tiled */ - if (sde_mdp_is_tilea5x_format(fmt) && (entry->dnsc_factor_h > 4)) { - SDEROT_DBG("max downscale for tiled format is 4\n"); + fmt = sde_get_format_params(item->input.format); + /* + * Rotator downscale support max 4 times for UBWC format and + * max 2 times for TP10/TP10_UBWC format + */ + if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 4)) { + SDEROT_DBG("max downscale for UBWC format is 4\n"); ret = -EINVAL; goto dnsc_err; } - if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 2)) { - SDEROT_DBG("downscale with ubwc cannot be more than 2\n"); + if (sde_mdp_is_tp10_format(fmt) && (entry->dnsc_factor_h > 2)) { + SDEROT_DBG("downscale with TP10 cannot be more than 2\n"); ret = -EINVAL; } goto dnsc_err; @@ -2076,6 +2079,7 @@ static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr, struct device_attribute *attr, char *buf, ssize_t len) { struct sde_hw_rotator *hw_data; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); int cnt = 0; if (!mgr || !buf) @@ -2087,6 +2091,10 @@ static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr, (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) /* insert capabilities here */ + if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map)) + SPRINT("min_downscale=1.5\n"); + else + SPRINT("min_downscale=2.0\n"); #undef SPRINT return cnt; diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c index dded8a25961a..98d9eb733371 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c @@ -24,6 +24,7 @@ enum bus_profile { VIDC_BUS_PROFILE_NORMAL = BIT(0), VIDC_BUS_PROFILE_LOW = BIT(1), VIDC_BUS_PROFILE_UBWC = BIT(2), + VIDC_BUS_PROFILE_UBWC_10_BIT = BIT(3), }; struct bus_profile_entry { @@ -53,7 +54,7 @@ static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov, load = NUM_MBS_PER_SEC(data->width, data->height, data->fps); sess_type = VIDC_VOTE_DATA_SESSION_VAL(data->codec, data->domain); - /* check if ubwc bus profile is present */ + /* check if appropriate bus profile is present */ for (i = 0; i < gov->count; i++) { entry = &gov->bus_prof_entries[i]; if (!entry->bus_table || !entry->bus_table_size) @@ -119,18 +120,23 @@ static int msm_vidc_table_get_target_freq(struct devfreq *dev, } profile = VIDC_BUS_PROFILE_NORMAL; - if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_TP10_UBWC || - data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC) + if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC) profile = VIDC_BUS_PROFILE_UBWC; + else if (data->color_formats[0] == + HAL_COLOR_FORMAT_NV12_TP10_UBWC) + profile = VIDC_BUS_PROFILE_UBWC_10_BIT; freq = __get_bus_freq(gov, data, profile); /* * chose frequency from normal profile * if specific profile frequency was not found. */ - if (!freq) + if (!freq) { + dprintk(VIDC_WARN, + "appropriate bus table not found, voting with Normal Profile\n"); freq = __get_bus_freq(gov, data, VIDC_BUS_PROFILE_NORMAL); + } *frequency += (unsigned long)freq; @@ -260,6 +266,8 @@ static int msm_vidc_load_bus_table(struct platform_device *pdev, entry->profile = VIDC_BUS_PROFILE_LOW; else if (of_find_property(child_node, "qcom,ubwc-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_UBWC; + else if (of_find_property(child_node, "qcom,ubwc-10bit", NULL)) + entry->profile = VIDC_BUS_PROFILE_UBWC_10_BIT; else entry->profile = VIDC_BUS_PROFILE_NORMAL; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index c4d06b658b30..7bc1fe1af26d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1320,11 +1320,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst) msm_comm_ctrl_deinit(inst); - mutex_destroy(&inst->sync_lock); - mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); - mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); - mutex_destroy(&inst->lock); - DEINIT_MSM_VIDC_LIST(&inst->pendingq); DEINIT_MSM_VIDC_LIST(&inst->scratchbufs); DEINIT_MSM_VIDC_LIST(&inst->persistbufs); @@ -1338,6 +1333,11 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst) for (i = 0; i < MAX_PORT_NUM; i++) vb2_queue_release(&inst->bufq[i].vb2_bufq); + mutex_destroy(&inst->sync_lock); + mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); + mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); + mutex_destroy(&inst->lock); + pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n", VIDC_MSG_PRIO2STRING(VIDC_INFO), inst); kfree(inst); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index fa2ad1754e77..73c52841fd34 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -298,6 +298,11 @@ static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst) rc = msm_comm_g_ctrl(inst, &ctrl); if (!rc && ctrl.value) { fps = (ctrl.value >> 16) ? ctrl.value >> 16 : 1; + /* + * Check if operating rate is less than fps. + * If Yes, then use fps to scale clocks + */ + fps = fps > inst->prop.fps ? fps : inst->prop.fps; return max(output_port_mbs, capture_port_mbs) * fps; } else return max(output_port_mbs, capture_port_mbs) * inst->prop.fps; @@ -1666,7 +1671,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) */ mutex_lock(&core->lock); - inst = list_first_entry(&core->instances, + inst = list_first_entry_or_null(&core->instances, struct msm_vidc_inst, list); mutex_unlock(&core->lock); @@ -5359,10 +5364,10 @@ static void msm_comm_print_debug_info(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "Venus core frequency = %lu", msm_comm_get_clock_rate(core)); + mutex_lock(&core->lock); dprintk(VIDC_ERR, "Printing instance info that caused Error\n"); msm_comm_print_inst_info(inst); dprintk(VIDC_ERR, "Printing remaining instances info\n"); - mutex_lock(&core->lock); list_for_each_entry(temp, &core->instances, list) { /* inst already printed above. Hence don't repeat.*/ if (temp == inst) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 787ee43ccbd2..0055e22b40b4 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -75,7 +75,7 @@ const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = { .imem_size = 0, }; -const int max_packets = 250; +const int max_packets = 1000; static void venus_hfi_pm_handler(struct work_struct *work); static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler); @@ -3576,6 +3576,7 @@ static void venus_hfi_core_work_handler(struct work_struct *work) struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); int num_responses = 0, i = 0; + u32 intr_status; mutex_lock(&device->lock); @@ -3601,10 +3602,9 @@ static void venus_hfi_core_work_handler(struct work_struct *work) num_responses = __response_handler(device); err_no_work: - /* We need re-enable the irq which was disabled in ISR handler */ - if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) - enable_irq(device->hal_data->irq); + /* Keep the interrupt status before releasing device lock */ + intr_status = device->intr_status; mutex_unlock(&device->lock); /* @@ -3619,6 +3619,10 @@ err_no_work: device->callback(r->response_type, &r->response); } + /* We need re-enable the irq which was disabled in ISR handler */ + if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) + enable_irq(device->hal_data->irq); + /* * XXX: Don't add any code beyond here. Reacquiring locks after release * it above doesn't guarantee the atomicity that we're aiming for. @@ -4548,7 +4552,7 @@ static struct venus_hfi_device *__add_device(u32 device_id, } hdevice->response_pkt = kmalloc_array(max_packets, - sizeof(*hdevice->response_pkt), GFP_TEMPORARY); + sizeof(*hdevice->response_pkt), GFP_KERNEL); if (!hdevice->response_pkt) { dprintk(VIDC_ERR, "failed to allocate response_pkt\n"); goto err_cleanup; diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 4e941f00b600..082ff5608455 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -1403,11 +1403,12 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) * in order to avoid troubles during device release. */ kfree(priv->ctrl.fname); + priv->ctrl.fname = NULL; memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); if (p->fname) { priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); if (priv->ctrl.fname == NULL) - rc = -ENOMEM; + return -ENOMEM; } /* diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 56ddf8467d16..011d5bd88d90 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -65,7 +65,8 @@ #define REPEATER_AUTH_SEND_ACK_MESSAGE_ID 15 #define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16 #define REPEATER_AUTH_STREAM_READY_MESSAGE_ID 17 -#define HDCP2P2_MAX_MESSAGES 18 +#define SKE_SEND_TYPE_ID 18 +#define HDCP2P2_MAX_MESSAGES 19 #define HDCP1_SET_KEY_MESSAGE_ID 202 #define HDCP1_SET_ENC_MESSAGE_ID 205 @@ -94,7 +95,7 @@ * minimum wait as per standard is 200 ms. keep it 300 ms * to be on safe side. */ -#define SLEEP_SET_HW_KEY_MS 300 +#define SLEEP_SET_HW_KEY_MS 220 #define QSEECOM_ALIGN_SIZE 0x40 #define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1) @@ -187,6 +188,9 @@ static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = { [SKE_SEND_EKS_MESSAGE_ID] = { 2, { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} }, 0 }, + [SKE_SEND_TYPE_ID] = { 1, + { {"type", 0x69494, 1} }, + 0 }, [REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4, { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3}, {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} }, @@ -499,8 +503,10 @@ struct hdcp_lib_handle { uint32_t tz_ctxhandle; uint32_t hdcp_timeout; uint32_t timeout_left; + uint32_t wait_timeout; bool no_stored_km_flag; bool feature_supported; + bool authenticated; void *client_ctx; struct hdcp_client_ops *client_ops; struct mutex msg_lock; @@ -521,7 +527,7 @@ struct hdcp_lib_handle { enum hdcp_device_type device_type; struct task_struct *thread; - struct completion topo_wait; + struct completion poll_wait; struct kthread_worker worker; struct kthread_work wk_init; @@ -529,7 +535,7 @@ struct hdcp_lib_handle { struct kthread_work wk_msg_recvd; struct kthread_work wk_timeout; struct kthread_work wk_clean; - struct kthread_work wk_topology; + struct kthread_work wk_wait; struct kthread_work wk_stream; int (*hdcp_app_init)(struct hdcp_lib_handle *handle); @@ -574,6 +580,7 @@ static const char *hdcp_lib_message_name(int msg_id) {15, "REPEATER_AUTH_SEND_ACK"}, {16, "REPEATER_AUTH_STREAM_MANAGE"}, {17, "REPEATER_AUTH_STREAM_READY"}, + {18, "SKE_SEND_TYPE_ID"}, }; int i; @@ -612,8 +619,14 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle, case LC_SEND_L_PRIME_MESSAGE_ID: return SKE_SEND_EKS_MESSAGE_ID; case SKE_SEND_EKS_MESSAGE_ID: + if (!handle->repeater_flag) + return SKE_SEND_TYPE_ID; + case SKE_SEND_TYPE_ID: case REPEATER_AUTH_STREAM_READY_MESSAGE_ID: case REPEATER_AUTH_SEND_ACK_MESSAGE_ID: + if (!handle->repeater_flag) + return INVALID_MESSAGE_ID; + if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE) return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID; else @@ -628,6 +641,33 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle, } } +static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle, + struct hdmi_hdcp_wakeup_data *data) +{ + switch (handle->last_msg) { + case AKE_SEND_H_PRIME_MESSAGE_ID: + if (handle->no_stored_km_flag) + handle->wait_timeout = HZ; + else + handle->wait_timeout = HZ / 4; + break; + case AKE_SEND_PAIRING_INFO_MESSAGE_ID: + handle->wait_timeout = HZ / 4; + break; + case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID: + if (!handle->authenticated) + handle->wait_timeout = HZ * 3; + else + handle->wait_timeout = 0; + break; + default: + handle->wait_timeout = 0; + } + + if (handle->wait_timeout) + queue_kthread_work(&handle->worker, &handle->wk_wait); +} + static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, struct hdmi_hdcp_wakeup_data *data) { @@ -639,43 +679,42 @@ static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE; - if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE || - data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE || - data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) { + if (data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE || + data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) handle->last_msg = hdcp_lib_get_next_message(handle, data); + if (handle->last_msg != INVALID_MESSAGE_ID && + data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS && + data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_FAILED) { + u32 msg_num, rx_status; + const struct hdcp_msg_part *msg; + pr_debug("lib->client: %s (%s)\n", hdmi_hdcp_cmd_to_str(data->cmd), hdcp_lib_message_name(handle->last_msg)); - if (handle->last_msg > INVALID_MESSAGE_ID && - handle->last_msg < HDCP2P2_MAX_MESSAGES) { - u32 msg_num, rx_status; - const struct hdcp_msg_part *msg; - - data->message_data = &hdcp_msg_lookup[handle->last_msg]; + data->message_data = &hdcp_msg_lookup[handle->last_msg]; - msg_num = data->message_data->num_messages; - msg = data->message_data->messages; - rx_status = data->message_data->rx_status; + msg_num = data->message_data->num_messages; + msg = data->message_data->messages; + rx_status = data->message_data->rx_status; - pr_debug("rxstatus 0x%x\n", rx_status); - pr_debug("%10s | %6s | %4s\n", "name", "offset", "len"); + pr_debug("%10s | %6s | %4s\n", "name", "offset", "len"); - for (i = 0; i < msg_num; i++) - pr_debug("%10s | %6x | %4d\n", - msg[i].name, msg[i].offset, - msg[i].length); - } + for (i = 0; i < msg_num; i++) + pr_debug("%10s | %6x | %4d\n", + msg[i].name, msg[i].offset, + msg[i].length); } else { - pr_debug("lib->client: %s\n", - hdmi_hdcp_cmd_to_str(data->cmd)); + pr_debug("lib->client: %s\n", hdmi_hdcp_cmd_to_str(data->cmd)); } rc = handle->client_ops->wakeup(data); if (rc) pr_err("error sending %s to client\n", hdmi_hdcp_cmd_to_str(data->cmd)); + + hdcp_lib_wait_for_response(handle, data); } static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle) @@ -1286,6 +1325,8 @@ static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle) hdcp_lib_message_name((int)rsp_buf->message[0]), jiffies_to_msecs(jiffies)); + handle->last_msg = (int)rsp_buf->message[0]; + /* send the response to HDMI driver */ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message, @@ -1404,6 +1445,8 @@ static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle) hdcp_lib_message_name((int)rsp_buf->message[0]), jiffies_to_msecs(jiffies)); + handle->last_msg = (int)rsp_buf->message[0]; + /* send the response to HDMI driver */ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message, @@ -1470,6 +1513,8 @@ static void hdcp_lib_stream(struct hdcp_lib_handle *handle) pr_debug("message received from TZ: %s\n", hdcp_lib_message_name((int)rsp_buf->msg[0])); + handle->last_msg = (int)rsp_buf->msg[0]; + memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg, rsp_buf->msglen); @@ -1550,11 +1595,11 @@ static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle) if (handle->worker.current_work == &handle->wk_clean) pr_debug("clean work executing\n"); - if (!list_empty(&handle->wk_topology.node)) - pr_debug("topology work queued\n"); + if (!list_empty(&handle->wk_wait.node)) + pr_debug("wait work queued\n"); - if (handle->worker.current_work == &handle->wk_topology) - pr_debug("topology work executing\n"); + if (handle->worker.current_work == &handle->wk_wait) + pr_debug("wait work executing\n"); if (!list_empty(&handle->wk_stream.node)) pr_debug("stream work queued\n"); @@ -1613,7 +1658,7 @@ static void hdcp_lib_update_exec_type(void *ctx, bool tethered) mutex_unlock(&handle->wakeup_mutex); } -static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) +static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data) { struct hdcp_lib_handle *handle; int rc = 0; @@ -1630,8 +1675,9 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) handle->wakeup_cmd = data->cmd; handle->timeout_left = data->timeout; - pr_debug("client->lib: %s\n", - hdcp_lib_cmd_to_str(handle->wakeup_cmd)); + pr_debug("client->lib: %s (%s)\n", + hdcp_lib_cmd_to_str(data->cmd), + hdcp_lib_message_name(handle->last_msg)); rc = hdcp_lib_check_valid_state(handle); if (rc) @@ -1655,8 +1701,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) } mutex_unlock(&handle->msg_lock); - if (!completion_done(&handle->topo_wait)) - complete_all(&handle->topo_wait); + if (!completion_done(&handle->poll_wait)) + complete_all(&handle->poll_wait); switch (handle->wakeup_cmd) { case HDCP_LIB_WKUP_CMD_START: @@ -1719,22 +1765,30 @@ static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle) cdata.context = handle->client_ctx; switch (handle->last_msg_sent) { - case SKE_SEND_EKS_MESSAGE_ID: - if (handle->repeater_flag) { - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, - &handle->wk_topology); - } - + case SKE_SEND_TYPE_ID: if (!hdcp_lib_enable_encryption(handle)) { + handle->authenticated = true; + cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS; hdcp_lib_wakeup_client(handle, &cdata); + } + /* poll for link check */ + cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL; + break; + case SKE_SEND_EKS_MESSAGE_ID: + if (handle->repeater_flag) { /* poll for link check */ cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL; } else { - if (!atomic_read(&handle->hdcp_off)) - HDCP_LIB_EXECUTE(clean); + memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); + handle->listener_buf[0] = SKE_SEND_TYPE_ID; + handle->msglen = 2; + cdata.cmd = HDMI_HDCP_WKUP_CMD_SEND_MESSAGE; + cdata.send_msg_buf = handle->listener_buf; + cdata.send_msg_len = handle->msglen; + handle->last_msg = hdcp_lib_get_next_message(handle, + &cdata); } break; case REPEATER_AUTH_SEND_ACK_MESSAGE_ID: @@ -1915,6 +1969,8 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle) return; } + handle->authenticated = false; + hdcp_lib_txmtr_deinit(handle); if (!handle->legacy_app) hdcp_lib_session_deinit(handle); @@ -2040,6 +2096,13 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) (rc == 0) && (rsp_buf->status == 0)) { pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n"); + if (!hdcp_lib_enable_encryption(handle)) { + handle->authenticated = true; + + cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS; + hdcp_lib_wakeup_client(handle, &cdata); + } + cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL; goto exit; } @@ -2057,6 +2120,8 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) hdcp_lib_message_name((int)rsp_buf->msg[0]), jiffies_to_msecs(jiffies)); + handle->last_msg = (int)rsp_buf->msg[0]; + /* set the flag if response is AKE_No_Stored_km */ if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) { pr_debug("Setting no_stored_km_flag\n"); @@ -2101,12 +2166,11 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) hdcp_lib_msg_recvd(handle); } -static void hdcp_lib_topology_work(struct kthread_work *work) +static void hdcp_lib_wait_work(struct kthread_work *work) { u32 timeout; struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, - wk_topology); + struct hdcp_lib_handle, wk_wait); if (!handle) { pr_err("invalid input\n"); @@ -2123,14 +2187,17 @@ static void hdcp_lib_topology_work(struct kthread_work *work) return; } - reinit_completion(&handle->topo_wait); - timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); + reinit_completion(&handle->poll_wait); + timeout = wait_for_completion_timeout(&handle->poll_wait, + handle->wait_timeout); if (!timeout) { - pr_err("topology receiver id list timeout\n"); + pr_err("wait timeout\n"); if (!atomic_read(&handle->hdcp_off)) HDCP_LIB_EXECUTE(clean); } + + handle->wait_timeout = 0; } bool hdcp1_check_if_supported_load_app(void) @@ -2266,7 +2333,7 @@ int hdcp_library_register(struct hdcp_register_data *data) /* populate ops to be called by client */ data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported; - data->txmtr_ops->wakeup = hdcp_lib_wakeup; + data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread; data->txmtr_ops->update_exec_type = hdcp_lib_update_exec_type; handle = kzalloc(sizeof(*handle), GFP_KERNEL); @@ -2296,10 +2363,10 @@ int hdcp_library_register(struct hdcp_register_data *data) init_kthread_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work); init_kthread_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work); init_kthread_work(&handle->wk_clean, hdcp_lib_cleanup_work); - init_kthread_work(&handle->wk_topology, hdcp_lib_topology_work); + init_kthread_work(&handle->wk_wait, hdcp_lib_wait_work); init_kthread_work(&handle->wk_stream, hdcp_lib_query_stream_work); - init_completion(&handle->topo_wait); + init_completion(&handle->poll_wait); handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL); if (!(handle->listener_buf)) { diff --git a/drivers/misc/qcom/qdsp6v2/Makefile b/drivers/misc/qcom/qdsp6v2/Makefile index 7006ff4a272f..90a123adbb7f 100644 --- a/drivers/misc/qcom/qdsp6v2/Makefile +++ b/drivers/misc/qcom/qdsp6v2/Makefile @@ -1,5 +1,6 @@ -obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o +obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o g711mlaw_in.o g711alaw_in.o audio_utils.o obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_alac.o audio_ape.o audio_utils_aio.o obj-$(CONFIG_MSM_QDSP6V2_CODECS) += q6audio_v2.o q6audio_v2_aio.o +obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_g711mlaw.o audio_g711alaw.o obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o audio_hwacc_effects.o obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/ diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c index 78bcdb74af0e..9e4f74bfacd9 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c +++ b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c @@ -14,6 +14,9 @@ * GNU General Public License for more details. * */ + +#include <linux/types.h> +#include <linux/compat.h> #include "audio_utils_aio.h" static struct miscdevice audio_amrnb_misc; @@ -68,6 +71,52 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return rc; } +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("AUDIO_START success enable[%d]\n", audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio); + rc = audio->codec_compat_ioctl(file, cmd, arg); + } + return rc; +} + + static int audio_open(struct inode *inode, struct file *file) { struct q6audio_aio *audio = NULL; @@ -155,6 +204,7 @@ static const struct file_operations audio_amrnb_fops = { .release = audio_aio_release, .unlocked_ioctl = audio_ioctl, .fsync = audio_aio_fsync, + .compat_ioctl = audio_compat_ioctl, }; static struct miscdevice audio_amrnb_misc = { diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c index 2283cf26bda9..2403dbbe426b 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c +++ b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c @@ -15,6 +15,8 @@ * */ +#include <linux/compat.h> +#include <linux/types.h> #include "audio_utils_aio.h" static struct miscdevice audio_amrwb_misc; @@ -71,6 +73,53 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return rc; } +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__, + audio->ac->session, + audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio); + rc = audio->codec_compat_ioctl(file, cmd, arg); + } + return rc; +} + static int audio_open(struct inode *inode, struct file *file) { struct q6audio_aio *audio = NULL; @@ -159,6 +208,7 @@ static const struct file_operations audio_amrwb_fops = { .release = audio_aio_release, .unlocked_ioctl = audio_ioctl, .fsync = audio_aio_fsync, + .compat_ioctl = audio_compat_ioctl, }; static struct miscdevice audio_amrwb_misc = { diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c new file mode 100644 index 000000000000..6f02654d3d4c --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c @@ -0,0 +1,396 @@ +/* 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/types.h> +#include <linux/msm_audio_g711_dec.h> +#include <linux/compat.h> +#include "audio_utils_aio.h" + +static struct miscdevice audio_g711alaw_misc; +static struct ws_mgr audio_g711_ws_mgr; + +static const struct file_operations audio_g711_debug_fops = { + .read = audio_aio_debug_read, + .open = audio_aio_debug_open, +}; + +static struct dentry *config_debugfs_create_file(const char *name, void *data) +{ + return debugfs_create_file(name, S_IFREG | S_IRUGO, + NULL, (void *)data, &audio_g711_debug_fops); +} + +static int g711_channel_map(u8 *channel_mapping, uint32_t channels); + +static long audio_ioctl_shared(struct file *file, unsigned int cmd, + void *arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + struct asm_g711_dec_cfg g711_dec_cfg; + struct msm_audio_g711_dec_config *g711_dec_config; + u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL]; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg)); + + if (g711_channel_map(channel_mapping, + audio->pcm_cfg.channel_count)) { + pr_err("%s: setting channel map failed %d\n", + __func__, audio->pcm_cfg.channel_count); + } + + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count, + 16, /*bits per sample*/ + false, false, channel_mapping); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_cfg.sample_rate = g711_dec_config->sample_rate; + /* Configure Media format block */ + rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg, + audio->ac->stream_id); + if (rc < 0) { + pr_err("%s: cmd media format block failed rc=%d\n", + __func__, rc); + break; + } + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("%s: AUDIO_START success enable[%d]\n", + __func__, audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd); + break; + } + return rc; +} + +static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG: { + if (copy_to_user((void *)arg, audio->codec_cfg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG: { + if (copy_from_user(audio->codec_cfg, (void *)arg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + default: { + rc = audio->codec_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_dec_config_32 { + u32 sample_rate; +}; + +enum { + AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32), + AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32) +}; + +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config_32.sample_rate = g711_dec_config->sample_rate; + + if (copy_to_user((void *)arg, &g711_dec_config_32, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + if (copy_from_user(&g711_dec_config_32, (void *)arg, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + break; + } + + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config->sample_rate = g711_dec_config_32.sample_rate; + + break; + } + default: { + rc = audio->codec_compat_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} +#else +#define audio_compat_ioctl NULL +#endif + +static int audio_open(struct inode *inode, struct file *file) +{ + struct q6audio_aio *audio = NULL; + int rc = 0; + /* 4 bytes represents decoder number, 1 byte for terminate string */ + char name[sizeof "msm_g711_" + 5]; + + audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL); + + if (!audio) + return -ENOMEM; + audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config), + GFP_KERNEL); + if (!audio->codec_cfg) { + kfree(audio); + return -ENOMEM; + } + + audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN; + audio->miscdevice = &audio_g711alaw_misc; + audio->wakelock_voted = false; + audio->audio_ws_mgr = &audio_g711_ws_mgr; + + init_waitqueue_head(&audio->event_wait); + + audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb, + (void *)audio); + + if (!audio->ac) { + pr_err("%s: Could not allocate memory for audio client\n", + __func__); + kfree(audio->codec_cfg); + kfree(audio); + return -ENOMEM; + } + rc = audio_aio_open(audio, file); + if (rc < 0) { + pr_err("%s: audio_aio_open rc=%d\n", + __func__, rc); + goto fail; + } + /* open in T/NT mode */ /*foramt:G711_ALAW*/ + if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { + rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM, + FORMAT_G711_ALAW_FS); + if (rc < 0) { + pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = NON_TUNNEL_MODE; + /* open G711 decoder, expected frames is always 1*/ + audio->buf_cfg.frames_per_buf = 0x01; + audio->buf_cfg.meta_info_enable = 0x01; + } else if ((file->f_mode & FMODE_WRITE) && + !(file->f_mode & FMODE_READ)) { + rc = q6asm_open_write(audio->ac, FORMAT_G711_ALAW_FS); + if (rc < 0) { + pr_err("%s: T mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = TUNNEL_MODE; + audio->buf_cfg.meta_info_enable = 0x00; + } else { + pr_err("%s: %d mode is not supported mode\n", + __func__, file->f_mode); + rc = -EACCES; + goto fail; + } + + snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session); + audio->dentry = config_debugfs_create_file(name, (void *)audio); + + if (IS_ERR_OR_NULL(audio->dentry)) + pr_debug("%s: debugfs_create_file failed\n", __func__); + pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__, + audio->feedback, + audio->ac->session); + return rc; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->codec_cfg); + kfree(audio); + return rc; +} + +static int g711_channel_map(u8 *channel_mapping, uint32_t channels) +{ + u8 *lchannel_mapping; + + lchannel_mapping = channel_mapping; + pr_debug("%s: channels passed: %d\n", __func__, channels); + if (channels == 1) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + } else if (channels == 2) { + lchannel_mapping[0] = PCM_CHANNEL_FL; + lchannel_mapping[1] = PCM_CHANNEL_FR; + } else if (channels == 3) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + } else if (channels == 4) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_CS; + } else if (channels == 5) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + } else if (channels == 6) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_LFE; + } else if (channels == 7) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_CS; + lchannel_mapping[6] = PCM_CHANNEL_LFE; + } else if (channels == 8) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FLC; + lchannel_mapping[2] = PCM_CHANNEL_FRC; + lchannel_mapping[3] = PCM_CHANNEL_FL; + lchannel_mapping[4] = PCM_CHANNEL_FR; + lchannel_mapping[5] = PCM_CHANNEL_LS; + lchannel_mapping[6] = PCM_CHANNEL_RS; + lchannel_mapping[7] = PCM_CHANNEL_LFE; + } else { + pr_err("%s: ERROR.unsupported num_ch = %u\n", + __func__, channels); + return -EINVAL; + } + return 0; +} + +static const struct file_operations audio_g711_fops = { + .owner = THIS_MODULE, + .open = audio_open, + .release = audio_aio_release, + .unlocked_ioctl = audio_ioctl, + .compat_ioctl = audio_compat_ioctl, + .fsync = audio_aio_fsync, +}; + +static struct miscdevice audio_g711alaw_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711alaw", + .fops = &audio_g711_fops, +}; + +static int __init audio_g711alaw_init(void) +{ + int ret = misc_register(&audio_g711alaw_misc); + + if (ret == 0) + device_init_wakeup(audio_g711alaw_misc.this_device, true); + audio_g711_ws_mgr.ref_cnt = 0; + mutex_init(&audio_g711_ws_mgr.ws_lock); + + return ret; +} +static void __exit audio_g711alaw_exit(void) +{ + misc_deregister(&audio_g711alaw_misc); + mutex_destroy(&audio_g711_ws_mgr.ws_lock); +} + +device_initcall(audio_g711alaw_init); +__exitcall(audio_g711alaw_exit); diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c new file mode 100644 index 000000000000..cae2490feb7a --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c @@ -0,0 +1,396 @@ +/* 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/types.h> +#include <linux/msm_audio_g711_dec.h> +#include <linux/compat.h> +#include "audio_utils_aio.h" + +static struct miscdevice audio_g711mlaw_misc; +static struct ws_mgr audio_g711_ws_mgr; + +static const struct file_operations audio_g711_debug_fops = { + .read = audio_aio_debug_read, + .open = audio_aio_debug_open, +}; + +static struct dentry *config_debugfs_create_file(const char *name, void *data) +{ + return debugfs_create_file(name, S_IFREG | S_IRUGO, + NULL, (void *)data, &audio_g711_debug_fops); +} + +static int g711_channel_map(u8 *channel_mapping, uint32_t channels); + +static long audio_ioctl_shared(struct file *file, unsigned int cmd, + void *arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + struct asm_g711_dec_cfg g711_dec_cfg; + struct msm_audio_g711_dec_config *g711_dec_config; + u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL]; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg)); + + if (g711_channel_map(channel_mapping, + audio->pcm_cfg.channel_count)) { + pr_err("%s: setting channel map failed %d\n", + __func__, audio->pcm_cfg.channel_count); + } + + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count, + 16, /*bits per sample*/ + false, false, channel_mapping); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_cfg.sample_rate = g711_dec_config->sample_rate; + /* Configure Media format block */ + rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg, + audio->ac->stream_id); + if (rc < 0) { + pr_err("%s: cmd media format block failed rc=%d\n", + __func__, rc); + break; + } + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("%s: AUDIO_START success enable[%d]\n", + __func__, audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd); + break; + } + return rc; +} + +static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG: { + if (copy_to_user((void *)arg, audio->codec_cfg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: AUDIO_GET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG: { + if (copy_from_user(audio->codec_cfg, (void *)arg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: AUDIO_SET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + default: { + rc = audio->codec_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_dec_config_32 { + u32 sample_rate; +}; + +enum { + AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32), + AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32) +}; + +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config_32.sample_rate = g711_dec_config->sample_rate; + + if (copy_to_user((void *)arg, &g711_dec_config_32, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + if (copy_from_user(&g711_dec_config_32, (void *)arg, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + break; + } + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config->sample_rate = g711_dec_config_32.sample_rate; + + break; + } + default: { + rc = audio->codec_compat_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} +#else +#define audio_compat_ioctl NULL +#endif + +static int audio_open(struct inode *inode, struct file *file) +{ + struct q6audio_aio *audio = NULL; + int rc = 0; + /* 4 bytes represents decoder number, 1 byte for terminate string */ + char name[sizeof "msm_g711_" + 5]; + + audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL); + + if (!audio) + return -ENOMEM; + audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config), + GFP_KERNEL); + if (!audio->codec_cfg) { + kfree(audio); + return -ENOMEM; + } + + audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN; + audio->miscdevice = &audio_g711mlaw_misc; + audio->wakelock_voted = false; + audio->audio_ws_mgr = &audio_g711_ws_mgr; + + init_waitqueue_head(&audio->event_wait); + + audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb, + (void *)audio); + + if (!audio->ac) { + pr_err("%s: Could not allocate memory for audio client\n", + __func__); + kfree(audio->codec_cfg); + kfree(audio); + return -ENOMEM; + } + rc = audio_aio_open(audio, file); + if (rc < 0) { + pr_err("%s: audio_aio_open rc=%d\n", + __func__, rc); + goto fail; + } + /* open in T/NT mode */ /*foramt:G711_ALAW*/ + if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { + rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM, + FORMAT_G711_MLAW_FS); + if (rc < 0) { + pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = NON_TUNNEL_MODE; + /* open G711 decoder, expected frames is always 1*/ + audio->buf_cfg.frames_per_buf = 0x01; + audio->buf_cfg.meta_info_enable = 0x01; + } else if ((file->f_mode & FMODE_WRITE) && + !(file->f_mode & FMODE_READ)) { + rc = q6asm_open_write(audio->ac, FORMAT_G711_MLAW_FS); + if (rc < 0) { + pr_err("%s: T mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = TUNNEL_MODE; + audio->buf_cfg.meta_info_enable = 0x00; + } else { + pr_err("%s: %d mode is not supported\n", __func__, + file->f_mode); + rc = -EACCES; + goto fail; + } + + snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session); + audio->dentry = config_debugfs_create_file(name, (void *)audio); + + if (IS_ERR_OR_NULL(audio->dentry)) + pr_debug("%s: debugfs_create_file failed\n", __func__); + pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__, + audio->feedback, + audio->ac->session); + return rc; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->codec_cfg); + kfree(audio); + return rc; +} + +static int g711_channel_map(u8 *channel_mapping, uint32_t channels) +{ + u8 *lchannel_mapping; + + lchannel_mapping = channel_mapping; + pr_debug("%s: channels passed: %d\n", __func__, channels); + if (channels == 1) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + } else if (channels == 2) { + lchannel_mapping[0] = PCM_CHANNEL_FL; + lchannel_mapping[1] = PCM_CHANNEL_FR; + } else if (channels == 3) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + } else if (channels == 4) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_CS; + } else if (channels == 5) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + } else if (channels == 6) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_LFE; + } else if (channels == 7) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_CS; + lchannel_mapping[6] = PCM_CHANNEL_LFE; + } else if (channels == 8) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FLC; + lchannel_mapping[2] = PCM_CHANNEL_FRC; + lchannel_mapping[3] = PCM_CHANNEL_FL; + lchannel_mapping[4] = PCM_CHANNEL_FR; + lchannel_mapping[5] = PCM_CHANNEL_LS; + lchannel_mapping[6] = PCM_CHANNEL_RS; + lchannel_mapping[7] = PCM_CHANNEL_LFE; + } else { + pr_err("%s: ERROR.unsupported num_ch = %u\n", + __func__, channels); + return -EINVAL; + } + return 0; +} + +static const struct file_operations audio_g711_fops = { + .owner = THIS_MODULE, + .open = audio_open, + .release = audio_aio_release, + .unlocked_ioctl = audio_ioctl, + .compat_ioctl = audio_compat_ioctl, + .fsync = audio_aio_fsync, +}; + +static struct miscdevice audio_g711mlaw_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711mlaw", + .fops = &audio_g711_fops, +}; + +static int __init audio_g711mlaw_init(void) +{ + int ret = misc_register(&audio_g711mlaw_misc); + + if (ret == 0) + device_init_wakeup(audio_g711mlaw_misc.this_device, true); + audio_g711_ws_mgr.ref_cnt = 0; + mutex_init(&audio_g711_ws_mgr.ws_lock); + + return ret; +} + +static void __exit audio_g711mlaw_exit(void) +{ + misc_deregister(&audio_g711mlaw_misc); + mutex_destroy(&audio_g711_ws_mgr.ws_lock); +} + +device_initcall(audio_g711mlaw_init); +__exitcall(audio_g711mlaw_exit); diff --git a/drivers/misc/qcom/qdsp6v2/g711alaw_in.c b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c new file mode 100644 index 000000000000..ac720b53ff5b --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c @@ -0,0 +1,382 @@ +/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/msm_audio_g711.h> +#include <linux/atomic.h> +#include <linux/compat.h> +#include <asm/ioctls.h> +#include "audio_utils.h" + +/* Buffer with meta*/ +#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in)) + +/* Maximum 10 frames in buffer with meta */ +#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10)) +static long g711_in_ioctl_shared(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + int cnt = 0; + + switch (cmd) { + case AUDIO_START: { + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__, + audio->ac->session, audio->buf_alloc); + if (audio->enabled == 1) { + rc = 0; + break; + } + rc = audio_in_buf_alloc(audio); + if (rc < 0) { + pr_err("%s:session id %d: buffer allocation failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate); + rc = q6asm_enc_cfg_blk_g711(audio->ac, + audio->buf_cfg.frames_per_buf, + enc_cfg->sample_rate); + + if (rc < 0) { + pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + if (audio->feedback == NON_TUNNEL_MODE) { + rc = q6asm_media_format_block_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + + if (rc < 0) { + pr_err("%s:session id %d: media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + } + pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__, + audio->ac->session, audio->enabled); + rc = audio_in_enable(audio); + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + while (cnt++ < audio->str_cfg.buffer_count) + q6asm_read(audio->ac); /* Push buffer to DSP */ + rc = 0; + pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n", + __func__, audio->ac->session, audio->enabled); + break; + } + case AUDIO_STOP: { + pr_debug("%s:session id %d: AUDIO_STOP\n", __func__, + audio->ac->session); + rc = audio_in_disable(audio); + if (rc < 0) { + pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n", + __func__, audio->ac->session, + rc); + break; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config *cfg; + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + + cfg = (struct msm_audio_g711_enc_config *)arg; + if (cfg == NULL) { + pr_err("%s: NULL config pointer\n", __func__); + rc = -EINVAL; + break; + } + if (cfg->sample_rate != 8000 && + cfg->sample_rate != 16000) { + pr_err("%s:session id %d: invalid sample rate\n", + __func__, audio->ac->session); + rc = -EINVAL; + break; + } + enc_cfg->sample_rate = cfg->sample_rate; + pr_debug("%s:session id %d: sample_rate= 0x%x", + __func__, + audio->ac->session, enc_cfg->sample_rate); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +static long g711_in_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG: { + if (copy_to_user((void *)arg, audio->enc_cfg, + sizeof(struct msm_audio_g711_enc_config))) { + pr_err( + "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config cfg; + + if (copy_from_user(&cfg, (void *) arg, + sizeof(cfg))) { + pr_err( + "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + break; + } + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_enc_config32 { + uint32_t sample_rate; +}; + +enum { + AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32), + AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32) +}; + +static long g711_in_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg; + cfg_32.sample_rate = enc_cfg->sample_rate; + if (copy_to_user((void *)arg, &cfg_32, + sizeof(cfg_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 cfg; + + if (copy_from_user(&cfg_32, (void *) arg, + sizeof(cfg_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + break; + } + cfg.sample_rate = cfg_32.sample_rate; + cmd = AUDIO_SET_G711_ENC_CONFIG; + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} +#else +#define g711_in_compat_ioctl NULL +#endif + +static int g711_in_open(struct inode *inode, struct file *file) +{ + struct q6audio_in *audio = NULL; + struct msm_audio_g711_enc_config *enc_cfg; + int rc = 0; + + audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL); + + if (audio == NULL) + return -ENOMEM; + /* Allocate memory for encoder config param */ + audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config), + GFP_KERNEL); + if (audio->enc_cfg == NULL) { + kfree(audio); + return -ENOMEM; + } + enc_cfg = audio->enc_cfg; + + mutex_init(&audio->lock); + mutex_init(&audio->read_lock); + mutex_init(&audio->write_lock); + spin_lock_init(&audio->dsp_lock); + init_waitqueue_head(&audio->read_wait); + init_waitqueue_head(&audio->write_wait); + + /* + * Settings will be re-config at AUDIO_SET_CONFIG, + * but at least we need to have initial config + */ + audio->str_cfg.buffer_size = FRAME_SIZE; + audio->str_cfg.buffer_count = FRAME_NUM; + audio->min_frame_size = 320; + audio->max_frames_per_buf = 10; + audio->pcm_cfg.buffer_size = PCM_BUF_SIZE; + audio->pcm_cfg.buffer_count = PCM_BUF_COUNT; + enc_cfg->sample_rate = 8000; + audio->pcm_cfg.channel_count = 1; + audio->pcm_cfg.sample_rate = 8000; + audio->buf_cfg.meta_info_enable = 0x01; + audio->buf_cfg.frames_per_buf = 0x01; + audio->event_abort = 0; + + audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb, + (void *)audio); + + if (!audio->ac) { + kfree(audio->enc_cfg); + kfree(audio); + return -ENOMEM; + } + + /* open g711 encoder in T/NT mode */ + if ((file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = NON_TUNNEL_MODE; + rc = q6asm_open_read_write(audio->ac, FORMAT_G711_ALAW_FS, + FORMAT_LINEAR_PCM); + if (rc < 0) { + pr_err("%s:session id %d: NT mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else if (!(file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = TUNNEL_MODE; + rc = q6asm_open_read(audio->ac, FORMAT_G711_ALAW_FS); + if (rc < 0) { + pr_err("%s:session id %d: T mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + /* register for tx overflow (valid for tunnel mode only) */ + rc = q6asm_reg_tx_overflow(audio->ac, 0x01); + if (rc < 0) { + pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else { + pr_err("%s:session id %d: Unexpected mode\n", __func__, + audio->ac->session); + rc = -EACCES; + goto fail; + } + + audio->opened = 1; + audio->reset_event = false; + atomic_set(&audio->in_count, PCM_BUF_COUNT); + atomic_set(&audio->out_count, 0x00); + audio->enc_compat_ioctl = g711_in_compat_ioctl; + audio->enc_ioctl = g711_in_ioctl; + file->private_data = audio; + + pr_info("%s:session id %d: success\n", __func__, audio->ac->session); + return 0; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->enc_cfg); + kfree(audio); + return rc; +} + +static const struct file_operations audio_in_fops = { + .owner = THIS_MODULE, + .open = g711_in_open, + .release = audio_in_release, + .read = audio_in_read, + .write = audio_in_write, + .unlocked_ioctl = audio_in_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = audio_in_compat_ioctl, +#endif +}; + +struct miscdevice audio_g711alaw_in_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711alaw_in", + .fops = &audio_in_fops, +}; + +static int __init g711alaw_in_init(void) +{ + return misc_register(&audio_g711alaw_in_misc); +} + +device_initcall(g711alaw_in_init); diff --git a/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c new file mode 100644 index 000000000000..6660f83683f8 --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c @@ -0,0 +1,385 @@ +/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/msm_audio_g711.h> +#include <linux/atomic.h> +#include <linux/compat.h> +#include <asm/ioctls.h> +#include "audio_utils.h" + +#ifdef CONFIG_COMPAT +#undef PROC_ADD +#endif +/* Buffer with meta*/ +#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in)) + +/* Maximum 10 frames in buffer with meta */ +#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10)) +static long g711_in_ioctl_shared(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + int cnt = 0; + + switch (cmd) { + case AUDIO_START: { + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__, + audio->ac->session, audio->buf_alloc); + if (audio->enabled == 1) { + rc = 0; + break; + } + rc = audio_in_buf_alloc(audio); + if (rc < 0) { + pr_err("%s:session id %d: buffer allocation failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate); + rc = q6asm_enc_cfg_blk_g711(audio->ac, + audio->buf_cfg.frames_per_buf, + enc_cfg->sample_rate); + + if (rc < 0) { + pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + if (audio->feedback == NON_TUNNEL_MODE) { + rc = q6asm_media_format_block_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + + if (rc < 0) { + pr_err("%s:session id %d: media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + } + pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__, + audio->ac->session, audio->enabled); + rc = audio_in_enable(audio); + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + while (cnt++ < audio->str_cfg.buffer_count) + q6asm_read(audio->ac); /* Push buffer to DSP */ + rc = 0; + pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n", + __func__, audio->ac->session, audio->enabled); + break; + } + case AUDIO_STOP: { + pr_debug("%s:session id %d: AUDIO_STOP\n", __func__, + audio->ac->session); + rc = audio_in_disable(audio); + if (rc < 0) { + pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n", + __func__, audio->ac->session, + rc); + break; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config *cfg; + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + + cfg = (struct msm_audio_g711_enc_config *)arg; + if (cfg == NULL) { + pr_err("%s: NULL config pointer\n", __func__); + rc = -EINVAL; + break; + } + if (cfg->sample_rate != 8000 && + cfg->sample_rate != 16000) { + pr_err("%s:session id %d: invalid sample rate\n", + __func__, audio->ac->session); + rc = -EINVAL; + break; + } + enc_cfg->sample_rate = cfg->sample_rate; + pr_debug("%s:session id %d: sample_rate= 0x%x", + __func__, + audio->ac->session, enc_cfg->sample_rate); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +static long g711_in_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG: { + if (copy_to_user((void *)arg, audio->enc_cfg, + sizeof(struct msm_audio_g711_enc_config))) { + pr_err( + "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config cfg; + + if (copy_from_user(&cfg, (void *) arg, + sizeof(cfg))) { + pr_err( + "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + break; + } + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_enc_config32 { + uint32_t sample_rate; +}; + +enum { + AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32), + AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32) +}; + +static long g711_in_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg; + cfg_32.sample_rate = enc_cfg->sample_rate; + if (copy_to_user((void *)arg, &cfg_32, + sizeof(cfg_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 cfg; + + if (copy_from_user(&cfg_32, (void *) arg, + sizeof(cfg_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + break; + } + cfg.sample_rate = cfg_32.sample_rate; + cmd = AUDIO_SET_G711_ENC_CONFIG; + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} +#else +#define g711_in_compat_ioctl NULL +#endif + +static int g711_in_open(struct inode *inode, struct file *file) +{ + struct q6audio_in *audio = NULL; + struct msm_audio_g711_enc_config *enc_cfg; + int rc = 0; + + audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL); + + if (audio == NULL) + return -ENOMEM; + /* Allocate memory for encoder config param */ + audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config), + GFP_KERNEL); + if (audio->enc_cfg == NULL) { + kfree(audio); + return -ENOMEM; + } + enc_cfg = audio->enc_cfg; + + mutex_init(&audio->lock); + mutex_init(&audio->read_lock); + mutex_init(&audio->write_lock); + spin_lock_init(&audio->dsp_lock); + init_waitqueue_head(&audio->read_wait); + init_waitqueue_head(&audio->write_wait); + + /* + * Settings will be re-config at AUDIO_SET_CONFIG, + * but at least we need to have initial config + */ + audio->str_cfg.buffer_size = FRAME_SIZE; + audio->str_cfg.buffer_count = FRAME_NUM; + audio->min_frame_size = 320; + audio->max_frames_per_buf = 10; + audio->pcm_cfg.buffer_size = PCM_BUF_SIZE; + audio->pcm_cfg.buffer_count = PCM_BUF_COUNT; + enc_cfg->sample_rate = 8000; + audio->pcm_cfg.channel_count = 1; + audio->pcm_cfg.sample_rate = 8000; + audio->buf_cfg.meta_info_enable = 0x01; + audio->buf_cfg.frames_per_buf = 0x01; + audio->event_abort = 0; + + audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb, + (void *)audio); + + if (!audio->ac) { + kfree(audio->enc_cfg); + kfree(audio); + return -ENOMEM; + } + + /* open g711 encoder in T/NT mode */ + if ((file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = NON_TUNNEL_MODE; + rc = q6asm_open_read_write(audio->ac, FORMAT_G711_MLAW_FS, + FORMAT_LINEAR_PCM); + if (rc < 0) { + pr_err("%s:session id %d: NT mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else if (!(file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = TUNNEL_MODE; + rc = q6asm_open_read(audio->ac, FORMAT_G711_MLAW_FS); + if (rc < 0) { + pr_err("%s:session id %d: T mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + /* register for tx overflow (valid for tunnel mode only) */ + rc = q6asm_reg_tx_overflow(audio->ac, 0x01); + if (rc < 0) { + pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else { + pr_err("%s:session id %d: Unexpected mode\n", __func__, + audio->ac->session); + rc = -EACCES; + goto fail; + } + + audio->opened = 1; + audio->reset_event = false; + atomic_set(&audio->in_count, PCM_BUF_COUNT); + atomic_set(&audio->out_count, 0x00); + audio->enc_compat_ioctl = g711_in_compat_ioctl; + audio->enc_ioctl = g711_in_ioctl; + file->private_data = audio; + + pr_info("%s:session id %d: success\n", __func__, audio->ac->session); + return 0; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->enc_cfg); + kfree(audio); + return rc; +} + +static const struct file_operations audio_in_fops = { + .owner = THIS_MODULE, + .open = g711_in_open, + .release = audio_in_release, + .read = audio_in_read, + .write = audio_in_write, + .unlocked_ioctl = audio_in_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = audio_in_compat_ioctl, +#endif +}; + +struct miscdevice audio_g711mlaw_in_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711mlaw_in", + .fops = &audio_in_fops, +}; + +static int __init g711mlaw_in_init(void) +{ + return misc_register(&audio_g711mlaw_in_misc); +} + +device_initcall(g711mlaw_in_init); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 457629ee4bf5..4fd845ab4086 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1293,9 +1293,11 @@ static int __qseecom_set_msm_bus_request(uint32_t mode) pr_err("Bandwidth req failed(%d) MODE (%d)\n", ret, mode); if (qclk->ce_core_src_clk != NULL) { - if (mode == INACTIVE) - __qseecom_enable_clk(CLK_QSEE); - else + if (mode == INACTIVE) { + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + pr_err("CLK enable failed\n"); + } else __qseecom_disable_clk(CLK_QSEE); } } @@ -1603,12 +1605,21 @@ static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data, if (ptr_svc) pr_warn("listener_id:%x, lstnr: %x\n", ptr_svc->svc.listener_id, lstnr); - if (ptr_svc && ptr_svc->ihandle) - msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, + if (ptr_svc && ptr_svc->ihandle) { + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, ION_IOC_CLEAN_INV_CACHES); - if (lstnr == RPMB_SERVICE) - __qseecom_enable_clk(CLK_QSEE); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } + } + + if (lstnr == RPMB_SERVICE) { + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; + } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp, sizeof(send_data_rsp), resp, sizeof(*resp)); if (ret) { @@ -1764,13 +1775,22 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) - msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, + if (ptr_svc) { + ret = msm_ion_do_cache_op(qseecom.ion_clnt, + ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, - ION_IOC_CLEAN_INV_CACHES); + ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } + } - if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) - __qseecom_enable_clk(CLK_QSEE); + if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; + } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); @@ -2005,13 +2025,21 @@ static int __qseecom_reentrancy_process_incomplete_cmd( else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) - msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, + if (ptr_svc) { + ret = msm_ion_do_cache_op(qseecom.ion_clnt, + ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, - ION_IOC_CLEAN_INV_CACHES); - - if (lstnr == RPMB_SERVICE) - __qseecom_enable_clk(CLK_QSEE); + ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } + } + if (lstnr == RPMB_SERVICE) { + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; + } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); @@ -2297,8 +2325,12 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) cmd_len = sizeof(struct qseecom_load_app_64bit_ireq); } - msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto loadapp_err; + } /* SCM_CALL to load the app and get the app_id back */ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, @@ -2776,15 +2808,16 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, } } - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto exit; + } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)send_req_ptr, req_buf_size, &resp, sizeof(resp)); - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, - data->client.sb_virt, data->client.sb_length, - ION_IOC_INV_CACHES); if (ret) { pr_err("qseecom_scm_call failed with err: %d\n", ret); if (!qseecom.support_bus_scaling) { @@ -2796,7 +2829,13 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, } goto exit; } - + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + data->client.sb_virt, data->client.sb_length, + ION_IOC_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto exit; + } switch (resp.result) { case QSEOS_RESULT_SUCCESS: break; @@ -3029,10 +3068,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, else *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } __qseecom_reentrancy_check_if_this_app_blocked(ptr_app); @@ -3063,9 +3106,11 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, } } } - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); + if (ret) + pr_err("cache operation failed %d\n", ret); return ret; } @@ -3177,7 +3222,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, } /* Populate the cmd data structure with the phys_addr */ sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle); - if (sg_ptr == NULL) { + if (IS_ERR_OR_NULL(sg_ptr)) { pr_err("IOn client could not retrieve sg table\n"); goto err; } @@ -3285,13 +3330,21 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, } if (cleanup) { - msm_ion_do_cache_op(qseecom.ion_clnt, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto err; + } } else { - msm_ion_do_cache_op(qseecom.ion_clnt, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto err; + } if (data->type == QSEECOM_CLIENT_APP) { offset = req->ifd_data[i].cmd_buf_offset; data->sglistinfo_ptr[i].indexAndFlags = @@ -3432,7 +3485,7 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, } /* Populate the cmd data structure with the phys_addr */ sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle); - if (sg_ptr == NULL) { + if (IS_ERR_OR_NULL(sg_ptr)) { pr_err("IOn client could not retrieve sg table\n"); goto err; } @@ -3515,13 +3568,21 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, } cleanup: if (cleanup) { - msm_ion_do_cache_op(qseecom.ion_clnt, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto err; + } } else { - msm_ion_do_cache_op(qseecom.ion_clnt, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto err; + } if (data->type == QSEECOM_CLIENT_APP) { offset = req->ifd_data[i].cmd_buf_offset; data->sglistinfo_ptr[i].indexAndFlags = @@ -4010,9 +4071,13 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) goto exit_unregister_bus_bw_need; } - msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, img_data, fw_size, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto exit_disable_clk_vote; + } /* SCM_CALL to load the image */ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, @@ -4126,9 +4191,13 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data, goto exit_unregister_bus_bw_need; } - msm_ion_do_cache_op(qseecom.ion_clnt, qseecom.cmnlib_ion_handle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, qseecom.cmnlib_ion_handle, img_data, fw_size, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto exit_disable_clk_vote; + } /* SCM_CALL to load the image */ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, @@ -4694,9 +4763,10 @@ static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce) } mutex_lock(&clk_access_lock); - if (qclk->clk_access_cnt == ULONG_MAX) + if (qclk->clk_access_cnt == ULONG_MAX) { + pr_err("clk_access_cnt beyond limitation\n"); goto err; - + } if (qclk->clk_access_cnt > 0) { qclk->clk_access_cnt++; mutex_unlock(&clk_access_lock); @@ -5009,9 +5079,12 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, ret = -EIO; goto exit_register_bus_bandwidth_needs; } - msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); - + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto exit_disable_clock; + } /* SCM_CALL to load the external elf */ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); @@ -5257,7 +5330,9 @@ static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data, pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } - __qseecom_enable_clk(CLK_QSEE); + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, ireq, sizeof(struct qseecom_key_generate_ireq), @@ -5315,7 +5390,9 @@ static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data, pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } - __qseecom_enable_clk(CLK_QSEE); + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, ireq, sizeof(struct qseecom_key_delete_ireq), @@ -5374,10 +5451,15 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; - __qseecom_enable_clk(CLK_QSEE); - if (qseecom.qsee.instance != qseecom.ce_drv.instance) - __qseecom_enable_clk(CLK_CE_DRV); + if (qseecom.qsee.instance != qseecom.ce_drv.instance) { + ret = __qseecom_enable_clk(CLK_CE_DRV); + if (ret) + return ret; + } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, ireq, sizeof(struct qseecom_key_select_ireq), @@ -5452,8 +5534,9 @@ static int __qseecom_update_current_key_user_info( pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } - - __qseecom_enable_clk(CLK_QSEE); + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + return ret; ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, ireq, sizeof(struct qseecom_key_userinfo_update_ireq), @@ -5994,7 +6077,9 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) desc.args[3] = req.out_buf_size; desc.args[4] = req.direction; - __qseecom_enable_clk(CLK_QSEE); + ret = __qseecom_enable_clk(CLK_QSEE); + if (ret) + break; ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc); @@ -6181,7 +6266,7 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req, } /* Populate the cmd data structure with the phys_addr */ sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle); - if (sg_ptr == NULL) { + if (IS_ERR_OR_NULL(sg_ptr)) { pr_err("IOn client could not retrieve sg table\n"); goto err; } @@ -6237,13 +6322,21 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req, } clean: if (cleanup) { - msm_ion_do_cache_op(qseecom.ion_clnt, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, sg->length, ION_IOC_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto err; + } } else { - msm_ion_do_cache_op(qseecom.ion_clnt, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, sg->length, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + goto err; + } data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 0, @@ -6356,10 +6449,14 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, *(uint32_t *)cmd_buf = cmd_id; reqd_len_sb_in = req->req_len + req->resp_len; - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } __qseecom_reentrancy_check_if_this_app_blocked(ptr_app); @@ -6390,9 +6487,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, } } } - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { @@ -6536,10 +6637,14 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, else *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND; - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, ION_IOC_CLEAN_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } __qseecom_reentrancy_check_if_this_app_blocked(ptr_app); @@ -6574,9 +6679,13 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, if (ret) return ret; - msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } return 0; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 6eee4aa0e574..39cb46a5ce11 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3456,7 +3456,8 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq) struct mmc_request *mrq = host->err_mrq; struct mmc_cmdq_context_info *ctx_info = &host->cmdq_ctx; struct request_queue *q; - int err; + int err, ret; + u32 status = 0; mmc_host_clk_hold(host); host->cmdq_ops->dumpstate(host); @@ -3475,8 +3476,14 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq) /* RED error - Fatal: requires reset */ if (mrq->cmdq_req->resp_err) { err = mrq->cmdq_req->resp_err; - pr_crit("%s: Response error detected: Device in bad state\n", - mmc_hostname(host)); + if (mmc_host_halt(host) || mmc_host_cq_disable(host)) { + ret = get_card_status(host->card, &status, 0); + if (ret) + pr_err("%s: CMD13 failed with err %d\n", + mmc_hostname(host), ret); + } + pr_err("%s: Response error detected with device status 0x%08x\n", + mmc_hostname(host), status); goto reset; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 828d2b85f6e4..6ad91042409e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1552,6 +1552,12 @@ int mmc_cmdq_halt(struct mmc_host *host, bool halt) { int err = 0; + if (mmc_host_cq_disable(host)) { + pr_debug("%s: %s: CQE is already disabled\n", + mmc_hostname(host), __func__); + return 0; + } + if ((halt && mmc_host_halt(host)) || (!halt && !mmc_host_halt(host))) { pr_debug("%s: %s: CQE is already %s\n", mmc_hostname(host), diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 0e0a018f39be..52427815722b 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -863,8 +863,16 @@ skip_cqterri: * If CQE halt fails then, disable CQE * from processing any further requests */ - if (ret) + if (ret) { cmdq_disable_nosync(mmc, true); + /* + * Enable legacy interrupts as CQE halt has failed. + * This is needed to send legacy commands like status + * cmd as part of error handling work. + */ + if (cq_host->ops->clear_set_irqs) + cq_host->ops->clear_set_irqs(mmc, false); + } /* * CQE detected a reponse error from device diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0542ba51445f..886229317fea 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3157,7 +3157,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) do { if (host->mmc->card && mmc_card_cmdq(host->mmc->card) && - !mmc_host_halt(host->mmc)) { + !mmc_host_halt(host->mmc) && !mmc_host_cq_disable(host->mmc)) { pr_debug("*** %s: cmdq intr: 0x%08x\n", mmc_hostname(host->mmc), intmask); diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c index 5cf07343a33c..6891a38d7a59 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.c +++ b/drivers/net/wireless/ath/wil6210/ftm.c @@ -52,6 +52,7 @@ nla_policy wil_nl80211_loc_policy[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN] = { .type = NLA_U8 }, [QCA_WLAN_VENDOR_ATTR_AOA_TYPE] = { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_FREQ] = { .type = NLA_U32 }, }; static const struct @@ -61,6 +62,7 @@ nla_policy wil_nl80211_ftm_peer_policy[ [QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED }, [QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 }, }; static const struct @@ -72,6 +74,37 @@ nla_policy wil_nl80211_ftm_meas_param_policy[ [QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD] = { .type = NLA_U16 }, }; +static u8 wil_ftm_get_channel(struct wil6210_priv *wil, + const u8 *mac_addr, u32 freq) +{ + struct wiphy *wiphy = wil_to_wiphy(wil); + struct cfg80211_bss *bss; + struct ieee80211_channel *chan; + u8 channel; + + if (freq) { + chan = ieee80211_get_channel(wiphy, freq); + if (!chan) { + wil_err(wil, "invalid freq: %d\n", freq); + return 0; + } + channel = chan->hw_value; + } else { + bss = cfg80211_get_bss(wiphy, NULL, mac_addr, + NULL, 0, IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY_ANY); + if (!bss) { + wil_err(wil, "Unable to find BSS\n"); + return 0; + } + channel = bss->channel->hw_value; + cfg80211_put_bss(wiphy, bss); + } + + wil_dbg_misc(wil, "target %pM at channel %d\n", mac_addr, channel); + return channel; +} + static int wil_ftm_parse_meas_params(struct wil6210_priv *wil, struct nlattr *attr, struct wil_ftm_meas_params *params) @@ -273,7 +306,7 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, { int rc = 0; bool has_lci = false, has_lcr = false; - u8 max_meas = 0, *ptr; + u8 max_meas = 0, channel, *ptr; u32 i, cmd_len; struct wmi_tof_session_start_cmd *cmd; @@ -283,12 +316,6 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, rc = -EAGAIN; goto out; } - /* for now allow measurement to associated AP only */ - if (!test_bit(wil_status_fwconnected, wil->status)) { - wil_err(wil, "must be associated\n"); - rc = -ENOTSUPP; - goto out; - } for (i = 0; i < request->n_peers; i++) { if (request->peers[i].flags & @@ -333,7 +360,14 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, for (i = 0; i < request->n_peers; i++) { ether_addr_copy(cmd->ftm_dest_info[i].dst_mac, request->peers[i].mac_addr); - cmd->ftm_dest_info[i].channel = request->peers[i].channel; + channel = wil_ftm_get_channel(wil, request->peers[i].mac_addr, + request->peers[i].freq); + if (!channel) { + wil_err(wil, "can't find FTM target at index %d\n", i); + rc = -EINVAL; + goto out_cmd; + } + cmd->ftm_dest_info[i].channel = channel - 1; if (request->peers[i].flags & QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE) { cmd->ftm_dest_info[i].flags |= @@ -367,14 +401,13 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil, } rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, cmd, cmd_len); - kfree(cmd); - - if (rc) - goto out_ftm_res; - - wil->ftm.session_cookie = request->session_cookie; - wil->ftm.session_started = 1; + if (!rc) { + wil->ftm.session_cookie = request->session_cookie; + wil->ftm.session_started = 1; + } +out_cmd: + kfree(cmd); out_ftm_res: if (rc) { kfree(wil->ftm.ftm_res); @@ -444,8 +477,8 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil, struct wil_aoa_meas_request *request) { int rc = 0; - struct cfg80211_bss *bss; struct wmi_aoa_meas_cmd cmd; + u8 channel; mutex_lock(&wil->ftm.lock); @@ -460,30 +493,25 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil, goto out; } - bss = cfg80211_get_bss(wil_to_wiphy(wil), NULL, request->mac_addr, - NULL, 0, - IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss) { - wil_err(wil, "Unable to find BSS\n"); - rc = -ENOENT; + channel = wil_ftm_get_channel(wil, request->mac_addr, request->freq); + if (!channel) { + rc = -EINVAL; goto out; } memset(&cmd, 0, sizeof(cmd)); ether_addr_copy(cmd.mac_addr, request->mac_addr); - cmd.channel = bss->channel->hw_value - 1; + cmd.channel = channel - 1; cmd.aoa_meas_type = request->type; rc = wmi_send(wil, WMI_AOA_MEAS_CMDID, &cmd, sizeof(cmd)); if (rc) - goto out_bss; + goto out; ether_addr_copy(wil->ftm.aoa_peer_mac_addr, request->mac_addr); mod_timer(&wil->ftm.aoa_timer, jiffies + msecs_to_jiffies(WIL_AOA_MEASUREMENT_TIMEOUT)); wil->ftm.aoa_started = 1; -out_bss: - cfg80211_put_bss(wil_to_wiphy(wil), bss); out: mutex_unlock(&wil->ftm.lock); return rc; @@ -721,7 +749,6 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1]; struct nlattr *peer; int rc, n_peers = 0, index = 0, tmp; - struct cfg80211_bss *bss; if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities)) return -ENOTSUPP; @@ -785,17 +812,9 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, memcpy(request->peers[index].mac_addr, nla_data(tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR]), ETH_ALEN); - bss = cfg80211_get_bss(wiphy, NULL, - request->peers[index].mac_addr, NULL, 0, - IEEE80211_BSS_TYPE_ANY, - IEEE80211_PRIVACY_ANY); - if (!bss) { - wil_err(wil, "invalid bss at index %d\n", index); - rc = -ENOENT; - goto out; - } - request->peers[index].channel = bss->channel->hw_value - 1; - cfg80211_put_bss(wiphy, bss); + if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ]) + request->peers[index].freq = nla_get_u32( + tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ]); if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS]) request->peers[index].flags = nla_get_u32( tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS]); @@ -868,6 +887,8 @@ int wil_aoa_start_measurement(struct wiphy *wiphy, struct wireless_dev *wdev, ether_addr_copy(request.mac_addr, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR])); request.type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]); + if (tb[QCA_WLAN_VENDOR_ATTR_FREQ]) + request.freq = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_FREQ]); rc = wil_aoa_cfg80211_start_measurement(wil, &request); return rc; diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h index 9721344579aa..ea186d641d59 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.h +++ b/drivers/net/wireless/ath/wil6210/ftm.h @@ -77,6 +77,8 @@ * %QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16 * values, phase and amplitude of the strongest CIR path for each * antenna in the measured array(s) + * @QCA_WLAN_VENDOR_ATTR_FREQ: Frequency where peer is listening, in MHz. + * Unsigned 32 bit value. */ enum qca_wlan_vendor_attr_loc { /* we reuse these attributes */ @@ -94,6 +96,7 @@ enum qca_wlan_vendor_attr_loc { QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23, QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24, QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25, + QCA_WLAN_VENDOR_ATTR_FREQ = 26, /* keep last */ QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_LOC_MAX = QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST - 1, @@ -176,6 +179,9 @@ enum qca_wlan_vendor_attr_loc_capa_flags { * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA * measurement every _value_ bursts. If 0 or not specified, * AOA measurements will be disabled for this peer. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ: Frequency in MHz where + * peer is listening. Optional; if not specified, use the + * entry from the kernel scan results cache. */ enum qca_wlan_vendor_attr_ftm_peer_info { QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID, @@ -184,6 +190,7 @@ enum qca_wlan_vendor_attr_ftm_peer_info { QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS, QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID, QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ, /* keep last */ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX = @@ -426,7 +433,7 @@ struct wil_ftm_meas_params { /* measurement request for a single peer */ struct wil_ftm_meas_peer_info { u8 mac_addr[ETH_ALEN]; - u8 channel; + u32 freq; u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_meas_flags */ struct wil_ftm_meas_params params; u8 secure_token_id; @@ -465,6 +472,7 @@ struct wil_ftm_peer_meas_res { /* standalone AOA measurement request */ struct wil_aoa_meas_request { u8 mac_addr[ETH_ALEN]; + u32 freq; u32 type; }; diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c index e983bcc8e47d..c4882f244d3f 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8998.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c @@ -92,6 +92,31 @@ .intr_detection_bit = -1, \ .intr_detection_width = -1, \ } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } static const struct pinctrl_pin_desc msm8998_pins[] = { PINCTRL_PIN(0, "GPIO_0"), PINCTRL_PIN(1, "GPIO_1"), @@ -246,6 +271,7 @@ static const struct pinctrl_pin_desc msm8998_pins[] = { PINCTRL_PIN(150, "SDC2_CLK"), PINCTRL_PIN(151, "SDC2_CMD"), PINCTRL_PIN(152, "SDC2_DATA"), + PINCTRL_PIN(153, "UFS_RESET"), }; #define DECLARE_MSM_GPIO_PINS(pin) \ @@ -404,6 +430,7 @@ DECLARE_MSM_GPIO_PINS(149); static const unsigned int sdc2_clk_pins[] = { 150 }; static const unsigned int sdc2_cmd_pins[] = { 151 }; static const unsigned int sdc2_data_pins[] = { 152 }; +static const unsigned int ufs_reset_pins[] = { 153 }; enum msm8998_functions { msm_mux_blsp_spi1, @@ -1856,6 +1883,7 @@ static const struct msm_pingroup msm8998_groups[] = { SDC_QDSD_PINGROUP(sdc2_clk, 0x999000, 14, 6), SDC_QDSD_PINGROUP(sdc2_cmd, 0x999000, 11, 3), SDC_QDSD_PINGROUP(sdc2_data, 0x999000, 9, 0), + UFS_RESET(ufs_reset, 0x19d000), }; static const struct msm_pinctrl_soc_data msm8998_pinctrl = { diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index df3901093006..a617c9e8e11f 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -105,6 +105,8 @@ static void gsi_handle_ch_ctrl(int ee) ch = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(ee)); + gsi_writel(ch, gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(ee)); GSIDBG("ch %x\n", ch); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { @@ -124,9 +126,6 @@ static void gsi_handle_ch_ctrl(int ee) gsi_ctx->ch_dbg[i].cmd_completed++; } } - - gsi_writel(ch, gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(ee)); } static void gsi_handle_ev_ctrl(int ee) @@ -138,6 +137,8 @@ static void gsi_handle_ev_ctrl(int ee) ch = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(ee)); + gsi_writel(ch, gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(ee)); GSIDBG("ev %x\n", ch); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { @@ -156,9 +157,6 @@ static void gsi_handle_ev_ctrl(int ee) complete(&ctx->compl); } } - - gsi_writel(ch, gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(ee)); } static void gsi_handle_glob_err(uint32_t err) @@ -439,9 +437,16 @@ static void gsi_handle_ieob(int ee) GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(ee)); msk = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee)); + gsi_writel(ch & msk, gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(ee)); for (i = 0; i < 32; i++) { if ((1 << i) & ch & msk) { + if (i >= gsi_ctx->max_ev || i >= GSI_EVT_RING_MAX) { + GSIERR("invalid event %d\n", i); + break; + } + ctx = &gsi_ctx->evtr[i]; BUG_ON(ctx->props.intf != GSI_EVT_CHTYPE_GPI_EV); spin_lock_irqsave(&ctx->ring.slock, flags); @@ -467,9 +472,6 @@ check_again: spin_unlock_irqrestore(&ctx->ring.slock, flags); } } - - gsi_writel(ch & msk, gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(ee)); } static void gsi_handle_inter_ee_ch_ctrl(int ee) @@ -479,15 +481,14 @@ static void gsi_handle_inter_ee_ch_ctrl(int ee) ch = gsi_readl(gsi_ctx->base + GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(ee)); + gsi_writel(ch, gsi_ctx->base + + GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(ee)); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { /* not currently expected */ GSIERR("ch %u was inter-EE changed\n", i); } } - - gsi_writel(ch, gsi_ctx->base + - GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(ee)); } static void gsi_handle_inter_ee_ev_ctrl(int ee) @@ -497,15 +498,14 @@ static void gsi_handle_inter_ee_ev_ctrl(int ee) ch = gsi_readl(gsi_ctx->base + GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(ee)); + gsi_writel(ch, gsi_ctx->base + + GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(ee)); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { /* not currently expected */ GSIERR("evt %u was inter-EE changed\n", i); } } - - gsi_writel(ch, gsi_ctx->base + - GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(ee)); } static void gsi_handle_general(int ee) diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 75b193def36e..159452c6e3bd 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -2907,6 +2907,22 @@ int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, return ret; } +/** + * ipa_get_pdev() - return a pointer to IPA dev struct + * + * Return value: a pointer to IPA dev struct + * + */ +struct device *ipa_get_pdev(void) +{ + struct device *ret; + + IPA_API_DISPATCH_RETURN_PTR(ipa_get_pdev); + + return ret; +} +EXPORT_SYMBOL(ipa_get_pdev); + static const struct dev_pm_ops ipa_pm_ops = { .suspend_noirq = ipa_ap_suspend, .resume_noirq = ipa_ap_resume, diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index eab048323bd5..78fcdeb4b7a0 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -369,6 +369,8 @@ struct ipa_api_controller { int (*ipa_tear_down_uc_offload_pipes)(int ipa_ep_idx_ul, int ipa_ep_idx_dl); + + struct device *(*ipa_get_pdev)(void); }; #ifdef CONFIG_IPA diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 866170d3324d..fd61435db5e2 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -1847,4 +1847,5 @@ int ipa_ntn_init(void); int ipa2_get_ntn_stats(struct IpaHwStatsNTNInfoData_t *stats); int ipa2_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data); +struct device *ipa2_get_pdev(void); #endif /* _IPA_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index b627cd1fc833..9813fa417c3a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -5102,6 +5102,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_setup_uc_ntn_pipes = ipa2_setup_uc_ntn_pipes; api_ctrl->ipa_tear_down_uc_offload_pipes = ipa2_tear_down_uc_offload_pipes; + api_ctrl->ipa_get_pdev = ipa2_get_pdev; return 0; } @@ -5181,3 +5182,17 @@ void ipa_suspend_apps_pipes(bool suspend) } } } + +/** + * ipa2_get_pdev() - return a pointer to IPA dev struct + * + * Return value: a pointer to IPA dev struct + * + */ +struct device *ipa2_get_pdev(void) +{ + if (!ipa_ctx) + return NULL; + + return ipa_ctx->pdev; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 8676b35914e2..2101147e7d24 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -624,16 +624,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd)); - if (!ipa3_is_ready()) { - IPAERR("IPA not ready, waiting for init completion\n"); - wait_for_completion(&ipa3_ctx->init_completion_obj); - } - if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) >= IPA_IOCTL_MAX) return -ENOTTY; + if (!ipa3_is_ready()) { + IPAERR("IPA not ready, waiting for init completion\n"); + wait_for_completion(&ipa3_ctx->init_completion_obj); + } + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); switch (cmd) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 1b78835cda6b..3a666419385e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2027,4 +2027,5 @@ int ipa3_ntn_init(void); int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats); struct dentry *ipa_debugfs_get_root(void); bool ipa3_is_msm_device(void); +struct device *ipa3_get_pdev(void); #endif /* _IPA3_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 4ea68ae1e95c..db60829bce69 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3199,6 +3199,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_setup_uc_ntn_pipes = ipa3_setup_uc_ntn_pipes; api_ctrl->ipa_tear_down_uc_offload_pipes = ipa3_tear_down_uc_offload_pipes; + api_ctrl->ipa_get_pdev = ipa3_get_pdev; return 0; } @@ -3637,3 +3638,17 @@ bool ipa3_is_msm_device(void) return false; } + +/** + * ipa3_get_pdev() - return a pointer to IPA dev struct + * + * Return value: a pointer to IPA dev struct + * + */ +struct device *ipa3_get_pdev(void) +{ + if (!ipa3_ctx) + return NULL; + + return ipa3_ctx->pdev; +} diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h index d612016b1b79..f0de532f196c 100644 --- a/drivers/power/qcom-charger/fg-core.h +++ b/drivers/power/qcom-charger/fg-core.h @@ -151,6 +151,7 @@ enum fg_sram_param_id { FG_SRAM_CHG_TERM_CURR, FG_SRAM_DELTA_SOC_THR, FG_SRAM_RECHARGE_SOC_THR, + FG_SRAM_RECHARGE_VBATT_THR, FG_SRAM_KI_COEFF_MED_DISCHG, FG_SRAM_KI_COEFF_HI_DISCHG, FG_SRAM_MAX, @@ -198,6 +199,7 @@ struct fg_dt_props { int sys_term_curr_ma; int delta_soc_thr; int recharge_soc_thr; + int recharge_volt_thr_mv; int rsense_sel; int jeita_thresholds[NUM_JEITA_LEVELS]; int esr_timer_charging; diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c index 6ff0e9e45b00..4d2cfc84d455 100644 --- a/drivers/power/qcom-charger/qpnp-fg-gen3.c +++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c @@ -112,6 +112,8 @@ #define EMPTY_VOLT_v2_OFFSET 3 #define VBATT_LOW_v2_WORD 16 #define VBATT_LOW_v2_OFFSET 0 +#define RECHARGE_VBATT_THR_v2_WORD 16 +#define RECHARGE_VBATT_THR_v2_OFFSET 1 #define FLOAT_VOLT_v2_WORD 16 #define FLOAT_VOLT_v2_OFFSET 2 @@ -236,6 +238,9 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD, RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), + PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD, + RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000, + fg_encode_voltage, NULL), PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD, ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), @@ -2395,8 +2400,8 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - /* This SRAM register is only present in v2.0 */ - if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4 && + /* This SRAM register is only present in v2.0 and above */ + if (chip->pmic_rev_id->rev4 >= PMI8998_V2P0_REV4 && chip->bp.float_volt_uv > 0) { fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT, chip->bp.float_volt_uv / 1000, buf); @@ -2476,6 +2481,23 @@ static int fg_hw_init(struct fg_chip *chip) } } + /* This configuration is available only for pmicobalt v2.0 and above */ + if (chip->pmic_rev_id->rev4 >= PMI8998_V2P0_REV4 && + chip->dt.recharge_volt_thr_mv > 0) { + fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, + chip->dt.recharge_volt_thr_mv, buf); + rc = fg_sram_write(chip, + chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word, + chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte, + buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len, + FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing recharge_vbatt_thr, rc=%d\n", + rc); + return rc; + } + } + if (chip->dt.rsense_sel >= SRC_SEL_BATFET && chip->dt.rsense_sel < SRC_SEL_RESERVED) { rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip), @@ -2935,6 +2957,7 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip) #define DEFAULT_CUTOFF_VOLT_MV 3200 #define DEFAULT_EMPTY_VOLT_MV 2800 +#define DEFAULT_RECHARGE_VOLT_MV 4250 #define DEFAULT_CHG_TERM_CURR_MA 100 #define DEFAULT_SYS_TERM_CURR_MA -125 #define DEFAULT_DELTA_SOC_THR 1 @@ -3096,6 +3119,12 @@ static int fg_parse_dt(struct fg_chip *chip) else chip->dt.recharge_soc_thr = temp; + rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp); + if (rc < 0) + chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV; + else + chip->dt.recharge_volt_thr_mv = temp; + rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp); if (rc < 0) chip->dt.rsense_sel = SRC_SEL_BATFET_SMB; diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 7accaa3a1673..f7a54f71a28a 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -214,7 +214,6 @@ static struct smb_params v1_params = { #define STEP_CHARGING_MAX_STEPS 5 struct smb_dt_props { - bool no_battery; int fcc_ua; int usb_icl_ua; int otg_cl_ua; @@ -226,7 +225,9 @@ struct smb_dt_props { struct device_node *revid_dev_node; int float_option; int chg_inhibit_thr_mv; + bool no_battery; bool hvdcp_disable; + bool auto_recharge_soc; }; struct smb2 { @@ -344,6 +345,8 @@ static int smb2_parse_dt(struct smb2 *chip) return -EINVAL; } + chip->dt.auto_recharge_soc = of_property_read_bool(node, + "qcom,auto-recharge-soc"); return 0; } @@ -1169,12 +1172,14 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } - /* disable Type-C factory mode */ + /* + * disable Type-C factory mode and stay in Attached.SRC state when VCONN + * over-current happens + */ rc = smblib_masked_write(chg, TYPE_C_CFG_REG, - FACTORY_MODE_DETECTION_EN_BIT, 0); + FACTORY_MODE_DETECTION_EN_BIT | VCONN_OC_CFG_BIT, 0); if (rc < 0) { - dev_err(chg->dev, - "Couldn't disable Type-C factory mode rc=%d\n", rc); + dev_err(chg->dev, "Couldn't configure Type-C rc=%d\n", rc); return rc; } @@ -1295,6 +1300,28 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + if (chip->dt.auto_recharge_soc) { + rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG, + SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT | + VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT, + VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n", + rc); + return rc; + } + } else { + rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG, + SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT | + VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT, + SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n", + rc); + return rc; + } + } + return rc; } @@ -1837,8 +1864,13 @@ static void smb2_shutdown(struct platform_device *pdev) struct smb2 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; + /* configure power role for UFP */ + smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT); + + /* force HVDCP to 5V */ smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0); + HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0); smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT); } diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 3403474565be..0faf8aee8aa0 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -505,15 +505,14 @@ static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg) static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) { - const struct apsd_result *apsd_result; + const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* if PD is active, APSD is disabled so won't have a valid result */ if (chg->pd_active) { chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; - return 0; + return apsd_result; } - apsd_result = smblib_get_apsd_result(chg); chg->usb_psy_desc.type = apsd_result->pst; return apsd_result; } @@ -2866,39 +2865,39 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; int rc; - u8 stat; + u8 stat4, stat5; bool debounce_done, sink_attached, legacy_cable; /* WA - not when PD hard_reset WIP on cc2 in sink mode */ if (chg->cc2_sink_detach_flag == CC2_SINK_STD) return IRQ_HANDLED; - rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); + rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return IRQ_HANDLED; } - smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat); - debounce_done = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT); - sink_attached = (bool)(stat & UFP_DFP_MODE_STATUS_BIT); - rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat); + rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc); return IRQ_HANDLED; } - smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat); - legacy_cable = (bool)(stat & TYPEC_LEGACY_CABLE_STATUS_BIT); + + debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT); + sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT); + legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT); smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached, legacy_cable); - power_supply_changed(chg->usb_psy); - - if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) + if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n", irq_data->name); + power_supply_changed(chg->usb_psy); + smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4); + smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5); return IRQ_HANDLED; } diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index ac571271b0d5..3c652ca8d489 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -565,6 +565,11 @@ struct cpr3_panic_regs_info { * @mem_acc_corner_map: mem-acc regulator corners mapping to low and high * voltage mem-acc settings for the memories powered by * this CPR3 controller and its associated CPR3 regulators + * @mem_acc_crossover_volt: Voltage in microvolts corresponding to the voltage + * that the VDD supply must be set to while a MEM ACC + * switch is in progress. This element must be initialized + * for CPRh controllers when a MEM ACC threshold voltage is + * defined. * @core_clk: Pointer to the CPR3 controller core clock * @iface_clk: Pointer to the CPR3 interface clock (platform specific) * @bus_clk: Pointer to the CPR3 bus clock (platform specific) @@ -744,6 +749,7 @@ struct cpr3_controller { int system_supply_max_volt; int mem_acc_threshold_volt; int mem_acc_corner_map[CPR3_MEM_ACC_CORNERS]; + int mem_acc_crossover_volt; struct clk *core_clk; struct clk *iface_clk; struct clk *bus_clk; @@ -876,6 +882,7 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg, 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); #else @@ -1052,6 +1059,10 @@ static inline void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg) { } +static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg) +{ +} + #endif /* CONFIG_REGULATOR_CPR3 */ #endif /* __REGULATOR_CPR_REGULATOR_H__ */ diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index c377a65a6393..60fe825ca013 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -680,12 +680,13 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) } /* - * In CPRh compliant controllers an additional corner is - * allocated to correspond to the APM crossover voltage + * For CPRh compliant controllers two additional corners are + * allocated to correspond to the APM crossover voltage and the MEM ACC + * crossover voltage. */ vreg->corner = devm_kcalloc(ctrl->dev, ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH ? - vreg->corner_count + 1 : + vreg->corner_count + 2 : vreg->corner_count, sizeof(*vreg->corner), GFP_KERNEL); temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL); @@ -2083,3 +2084,66 @@ void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg) corner->ceiling_volt, corner->open_loop_volt); } } + +/** + * cprh_adjust_voltages_for_mem_acc() - adjust per-corner floor and ceiling + * voltages so that they do not intersect the MEM ACC threshold + * voltage + * @vreg: Pointer to the CPR3 regulator + * + * The following algorithm is applied: + * if floor < threshold <= ceiling: + * if open_loop >= threshold, then floor = threshold + * else ceiling = threshold - step + * where: + * step = voltage in microvolts of a single step of the VDD supply + * + * The open-loop voltage is also bounded by the new floor or ceiling value as + * needed. + * + * Return: none + */ +void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg) +{ + struct cpr3_controller *ctrl = vreg->thread->ctrl; + struct cpr3_corner *corner; + int i, threshold, prev_ceiling, prev_floor, prev_open_loop; + + if (!ctrl->mem_acc_threshold_volt) { + /* MEM ACC not being used. */ + return; + } + + ctrl->mem_acc_threshold_volt = CPR3_ROUND(ctrl->mem_acc_threshold_volt, + ctrl->step_volt); + + threshold = ctrl->mem_acc_threshold_volt; + + for (i = 0; i < vreg->corner_count; i++) { + corner = &vreg->corner[i]; + + if (threshold <= corner->floor_volt + || threshold > corner->ceiling_volt) + continue; + + prev_floor = corner->floor_volt; + prev_ceiling = corner->ceiling_volt; + prev_open_loop = corner->open_loop_volt; + + if (corner->open_loop_volt >= threshold) { + corner->floor_volt = max(corner->floor_volt, threshold); + if (corner->open_loop_volt < corner->floor_volt) + corner->open_loop_volt = corner->floor_volt; + } else { + corner->ceiling_volt = threshold - ctrl->step_volt; + } + + if (corner->floor_volt != prev_floor + || corner->ceiling_volt != prev_ceiling + || corner->open_loop_volt != prev_open_loop) + cpr3_debug(vreg, "MEM ACC threshold=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n", + threshold, i, prev_floor, prev_ceiling, + prev_open_loop, corner->floor_volt, + corner->ceiling_volt, corner->open_loop_volt); + } +} diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index 2608cc4a430a..9cbd1ee18ec3 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -73,8 +73,10 @@ struct cprh_msm8998_kbss_fuses { /* * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0. * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1. + * Fuse combos 16 - 23 map to CPR fusing revision 0 - 7 with speed bin fuse = 2. + * Fuse combos 24 - 31 map to CPR fusing revision 0 - 7 with speed bin fuse = 3. */ -#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 16 +#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32 /* * Constants which define the name of each fuse corner. @@ -866,6 +868,44 @@ static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg) } /** + * cprh_kbss_mem_acc_crossover_as_corner() - introduce a corner whose floor, + * open-loop, and ceiling voltages correspond to the MEM ACC + * crossover voltage. + * @vreg: Pointer to the CPR3 regulator + * + * The MEM ACC corner is utilized as a crossover corner by OSM and CPRh + * hardware to set the VDD supply voltage during the MEM ACC switch + * routine. + * + * Return: 0 on success, errno on failure + */ +static int cprh_kbss_mem_acc_crossover_as_corner(struct cpr3_regulator *vreg) +{ + struct cpr3_controller *ctrl = vreg->thread->ctrl; + struct cpr3_corner *corner; + + if (!ctrl->mem_acc_crossover_volt) { + /* MEM ACC voltage crossover corner not required. */ + return 0; + } + + corner = &vreg->corner[vreg->corner_count]; + /* + * 0 MHz indicates this corner is not to be + * used as active DCVS set point. + */ + corner->proc_freq = 0; + corner->floor_volt = ctrl->mem_acc_crossover_volt; + corner->ceiling_volt = ctrl->mem_acc_crossover_volt; + corner->open_loop_volt = ctrl->mem_acc_crossover_volt; + corner->abs_ceiling_volt = ctrl->mem_acc_crossover_volt; + corner->use_open_loop = true; + vreg->corner_count++; + + return 0; +} + +/** * cprh_msm8998_kbss_set_no_interpolation_quotients() - use the fused target * quotient values for lower frequencies. * @vreg: Pointer to the CPR3 regulator @@ -1196,6 +1236,7 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg) } cprh_adjust_voltages_for_apm(vreg); + cprh_adjust_voltages_for_mem_acc(vreg); cpr3_open_loop_voltage_as_ceiling(vreg); @@ -1248,6 +1289,13 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg) return rc; } + rc = cprh_kbss_mem_acc_crossover_as_corner(vreg); + if (rc) { + cpr3_err(vreg, "unable to introduce MEM ACC voltage crossover corner, rc=%d\n", + rc); + return rc; + } + cprh_kbss_print_settings(vreg); return 0; @@ -1420,6 +1468,25 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl) ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node, "qcom,cpr-saw-use-unit-mV"); + rc = of_property_read_u32(ctrl->dev->of_node, + "qcom,mem-acc-threshold-voltage", + &ctrl->mem_acc_threshold_volt); + if (!rc) { + ctrl->mem_acc_threshold_volt + = CPR3_ROUND(ctrl->mem_acc_threshold_volt, ctrl->step_volt); + + rc = of_property_read_u32(ctrl->dev->of_node, + "qcom,mem-acc-crossover-voltage", + &ctrl->mem_acc_crossover_volt); + if (rc) { + cpr3_err(ctrl, "error reading property qcom,mem-acc-crossover-voltage, rc=%d\n", + rc); + return rc; + } + ctrl->mem_acc_crossover_volt + = CPR3_ROUND(ctrl->mem_acc_crossover_volt, ctrl->step_volt); + } + /* * Use fixed step quotient if specified otherwise use dynamically * calculated per RO step quotient @@ -1475,6 +1542,14 @@ static int cprh_kbss_populate_opp_table(struct cpr3_controller *ctrl) for (i = 0; i < vreg->corner_count; i++) { corner = &vreg->corner[i]; + if (!corner->proc_freq) { + /* + * 0 MHz indicates this corner is not to be + * used as active DCVS set point. Don't add it + * to the OPP table. + */ + continue; + } rc = dev_pm_opp_add(dev, corner->proc_freq, i + 1); if (rc) { cpr3_err(ctrl, "could not add OPP for corner %d with frequency %u MHz, rc=%d\n", diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 603cbe65825b..1e200370deea 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -791,8 +791,12 @@ static int ufs_qcom_full_reset(struct ufs_hba *hba) goto out; } - /* Very small delay, per the documented requirement */ - usleep_range(1, 2); + /* + * The hardware requirement for delay between assert/deassert + * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to + * ~125us (4/32768). To be on the safe side add 200us delay. + */ + usleep_range(200, 210); ret = reset_control_deassert(hba->core_reset); if (ret) diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 5a9564326099..41684dca6baa 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -250,6 +250,20 @@ static void ufshcd_parse_pm_levels(struct ufs_hba *hba) } } +static int ufshcd_parse_pinctrl_info(struct ufs_hba *hba) +{ + int ret = 0; + + /* Try to obtain pinctrl handle */ + hba->pctrl = devm_pinctrl_get(hba->dev); + if (IS_ERR(hba->pctrl)) { + ret = PTR_ERR(hba->pctrl); + hba->pctrl = NULL; + } + + return ret; +} + #ifdef CONFIG_SMP /** * ufshcd_pltfrm_suspend - suspend power management function @@ -361,6 +375,13 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, goto dealloc_host; } + err = ufshcd_parse_pinctrl_info(hba); + if (err) { + dev_dbg(&pdev->dev, "%s: unable to parse pinctrl data %d\n", + __func__, err); + /* let's not fail the probe */ + } + ufshcd_parse_pm_levels(hba); if (!dev->dma_mask) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 67e1636c25ec..06defae6d5ba 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -446,6 +446,63 @@ void ufshcd_scsi_block_requests(struct ufs_hba *hba) } EXPORT_SYMBOL(ufshcd_scsi_block_requests); +static int ufshcd_device_reset_ctrl(struct ufs_hba *hba, bool ctrl) +{ + int ret = 0; + + if (!hba->pctrl) + return 0; + + /* Assert reset if ctrl == true */ + if (ctrl) + ret = pinctrl_select_state(hba->pctrl, + pinctrl_lookup_state(hba->pctrl, "dev-reset-assert")); + else + ret = pinctrl_select_state(hba->pctrl, + pinctrl_lookup_state(hba->pctrl, "dev-reset-deassert")); + + if (ret < 0) + dev_err(hba->dev, "%s: %s failed with err %d\n", + __func__, ctrl ? "Assert" : "Deassert", ret); + + return ret; +} + +static inline int ufshcd_assert_device_reset(struct ufs_hba *hba) +{ + return ufshcd_device_reset_ctrl(hba, true); +} + +static inline int ufshcd_deassert_device_reset(struct ufs_hba *hba) +{ + return ufshcd_device_reset_ctrl(hba, false); +} + +static int ufshcd_reset_device(struct ufs_hba *hba) +{ + int ret; + + /* reset the connected UFS device */ + ret = ufshcd_assert_device_reset(hba); + if (ret) + goto out; + /* + * The reset signal is active low. + * The UFS device shall detect more than or equal to 1us of positive + * or negative RST_n pulse width. + * To be on safe side, keep the reset low for atleast 10us. + */ + usleep_range(10, 15); + + ret = ufshcd_deassert_device_reset(hba); + if (ret) + goto out; + /* same as assert, wait for atleast 10us after deassert */ + usleep_range(10, 15); +out: + return ret; +} + /* replace non-printable or non-ASCII characters with spaces */ static inline void ufshcd_remove_non_printable(char *val) { @@ -6520,6 +6577,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) dev_warn(hba->dev, "%s: full reset returned %d\n", __func__, err); + err = ufshcd_reset_device(hba); + if (err) + dev_warn(hba->dev, "%s: device reset failed. err %d\n", + __func__, err); + err = ufshcd_host_reset_and_restore(hba); } while (err && --retries); @@ -8220,13 +8282,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) hba->clk_gating.is_suspended = true; hba->hibern8_on_idle.is_suspended = true; - /* - * Disable auto hibern8 to prevent unnecessary hibern8 enter/exit - * during suspend path - */ - if (ufshcd_is_auto_hibern8_supported(hba)) - ufshcd_set_auto_hibern8_timer(hba, 0); - if (hba->clk_scaling.is_allowed) { cancel_work_sync(&hba->clk_scaling.suspend_work); cancel_work_sync(&hba->clk_scaling.resume_work); @@ -8334,10 +8389,6 @@ enable_gating: ufshcd_resume_clkscaling(hba); hba->hibern8_on_idle.is_suspended = false; hba->clk_gating.is_suspended = false; - /* Re-enable auto hibern8 in case of suspend failure */ - if (ufshcd_is_auto_hibern8_supported(hba)) - ufshcd_set_auto_hibern8_timer(hba, - hba->hibern8_on_idle.delay_ms); ufshcd_release_all(hba); out: hba->pm_op_in_progress = 0; @@ -8431,13 +8482,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); - /* - * Enable auto hibern8 after successful resume to prevent - * unnecessary hibern8 enter/exit during resume path - */ - if (ufshcd_is_auto_hibern8_supported(hba)) - ufshcd_set_auto_hibern8_timer(hba, - hba->hibern8_on_idle.delay_ms); /* Schedule clock gating in case of no access to UFS device yet */ ufshcd_release_all(hba); goto out; @@ -9419,6 +9463,15 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto exit_gating; } + /* Reset controller to power on reset (POR) state */ + ufshcd_vops_full_reset(hba); + + /* reset connected UFS device */ + err = ufshcd_reset_device(hba); + if (err) + dev_warn(hba->dev, "%s: device reset failed. err %d\n", + __func__, err); + /* Host controller enable */ err = ufshcd_hba_enable(hba); if (err) { diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 9f2b04c8ff82..c5eb21d8a0fe 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -907,6 +907,7 @@ struct ufs_hba { int scsi_block_reqs_cnt; bool full_init_linereset; + struct pinctrl *pctrl; }; static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index d3f967319d21..21733633cb6c 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -628,12 +628,10 @@ config MSM_PERFORMANCE config MSM_PERFORMANCE_HOTPLUG_ON bool "Hotplug functionality through msm_performance turned on" depends on MSM_PERFORMANCE - default y help - If some other core-control driver is present turn off the core-control - capability of msm_performance driver. Setting this flag to false will - compile out the nodes needed for core-control functionality through - msm_performance. + Setting this flag to true will enable the nodes needed for core-control + functionality of hot plugging cores through msm_performance if there is + no default core-control driver available. endif # ARCH_QCOM diff --git a/drivers/soc/qcom/gladiator_erp_v2.c b/drivers/soc/qcom/gladiator_erp_v2.c index 25c7bd77ae96..91b5d39be242 100644 --- a/drivers/soc/qcom/gladiator_erp_v2.c +++ b/drivers/soc/qcom/gladiator_erp_v2.c @@ -628,9 +628,11 @@ static irqreturn_t msm_gladiator_isr(int irq, void *dev_id) msm_gld_data->gladiator_virt_base + get_gld_offset(err_log)); } - pr_alert("Main log register data:\n%08x %08x %08x %08x\n%08x %08x %08x %08x\n%08x %08x %08x\n", - err_buf[0], err_buf[1], err_buf[2], err_buf[3], err_buf[4], err_buf[5], err_buf[6], - err_buf[7], err_buf[8], err_buf[9], err_buf[10]); + pr_alert("Main log register data:\n%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n%08x %08x %08x %08x\n", + err_buf[2], err_buf[3], err_buf[4], err_buf[5], + err_buf[6], err_buf[7], err_buf[8], err_buf[9], + err_buf[10], err_buf[11], err_buf[12], err_buf[13]); } if (obsrv_err_valid) { diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c index deb7231a4ed1..10fb4cc8ebff 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c @@ -869,7 +869,7 @@ static void unregister_client_adhoc(uint32_t cl) } curr = client->curr; - if (curr >= pdata->num_usecases) { + if ((curr < 0) || (curr >= pdata->num_usecases)) { MSM_BUS_ERR("Invalid index Defaulting curr to 0"); curr = 0; } diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 242071f52811..20f406b9a2f7 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -83,7 +83,7 @@ static struct glink_apps_rpm_data *glink_data; #define DEFAULT_BUFFER_SIZE 256 #define DEBUG_PRINT_BUFFER_SIZE 512 #define MAX_SLEEP_BUFFER 128 -#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOFS) +#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOIO) #define INV_RSC "resource does not exist" #define ERR "err\0" #define MAX_ERR_BUFFER_SIZE 128 diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index b4713ac1b68b..f2216f968319 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -665,10 +665,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) desc->ret[0] = desc->ret[1] = desc->ret[2] = 0; - pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n", - x0, desc->arginfo, desc->args[0], desc->args[1], - desc->args[2], desc->x5); - trace_scm_call_start(x0, desc); if (scm_version == SCM_ARMV8_64) @@ -698,10 +694,8 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); if (ret < 0) - pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", - x0, desc->arginfo, desc->args[0], desc->args[1], - desc->args[2], desc->x5, ret, desc->ret[0], - desc->ret[1], desc->ret[2]); + pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", + x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]); if (arglen > N_REGISTER_ARGS) kfree(desc->extra_arg_buf); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 826a22355429..f93ee29123fe 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -42,8 +42,8 @@ #define SMEM_IMAGE_VERSION_NAME_SIZE 75 #define SMEM_IMAGE_VERSION_VARIANT_SIZE 20 #define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75 -#define SMEM_IMAGE_VERSION_OEM_SIZE 32 -#define SMEM_IMAGE_VERSION_OEM_OFFSET 96 +#define SMEM_IMAGE_VERSION_OEM_SIZE 33 +#define SMEM_IMAGE_VERSION_OEM_OFFSET 95 #define SMEM_IMAGE_VERSION_PARTITION_APPS 10 enum { @@ -974,7 +974,7 @@ msm_get_image_crm_version(struct device *dev, } string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; string_address += SMEM_IMAGE_VERSION_OEM_OFFSET; - return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n", + return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s\n", string_address); } @@ -995,7 +995,7 @@ msm_set_image_crm_version(struct device *dev, } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; store_address += SMEM_IMAGE_VERSION_OEM_OFFSET; - snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf); + snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s", buf); return count; } @@ -1049,7 +1049,8 @@ msm_get_images(struct device *dev, image_address); pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVariant:\t%-.20s\n", image_address + SMEM_IMAGE_VERSION_VARIANT_OFFSET); - pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVersion:\t%-.32s\n\n", + pos += snprintf(buf + pos, PAGE_SIZE - pos, + "\tVersion:\t%-.33s\n", image_address + SMEM_IMAGE_VERSION_OEM_OFFSET); image_address += SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index b2e1a4c1b170..b5905fc81147 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -274,11 +274,16 @@ static int ion_secure_cma_allocate(struct ion_heap *heap, source_vm = VMID_HLOS; dest_vm = get_secure_vmid(flags); + if (dest_vm < 0) { pr_err("%s: Failed to get secure vmid\n", __func__); return -EINVAL; } - dest_perms = PERM_READ | PERM_WRITE; + + if (dest_vm == VMID_CP_SEC_DISPLAY) + dest_perms = PERM_READ; + else + dest_perms = PERM_READ | PERM_WRITE; ret = ion_cma_allocate(heap, buffer, len, align, flags); if (ret) { diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 629e3c865072..9bee25cfa0be 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -417,6 +417,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * they are not on hot paths so a little discipline won't do * any harm. * + * The line discipline-related tty_struct fields are reset to + * prevent the ldisc driver from re-using stale information for + * the new ldisc instance. + * * Locking: takes termios_rwsem */ @@ -425,6 +429,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) down_write(&tty->termios_rwsem); tty->termios.c_line = num; up_write(&tty->termios_rwsem); + + tty->disc_data = NULL; + tty->receive_room = 0; } /** diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index add035269ae7..a21f6735808b 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1465,11 +1465,10 @@ static void dwc3_restart_usb_work(struct work_struct *w) pm_runtime_suspend(mdwc->dev); } + mdwc->in_restart = false; /* Force reconnect only if cable is still connected */ - if (mdwc->vbus_active) { - mdwc->in_restart = false; + if (mdwc->vbus_active) dwc3_resume_work(&mdwc->resume_work); - } dwc->err_evt_seen = false; flush_delayed_work(&mdwc->sm_work); @@ -1781,7 +1780,7 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) u32 reg = 0; if ((mdwc->in_host_mode || mdwc->vbus_active) - && dwc3_msm_is_superspeed(mdwc)) { + && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) { if (!atomic_read(&mdwc->in_p3)) { dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n"); return -EBUSY; @@ -1967,7 +1966,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) clk_disable_unprepare(mdwc->xo_clk); /* Perform controller power collapse */ - if (!mdwc->in_host_mode && !mdwc->vbus_active) { + if (!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) { mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE; dev_dbg(mdwc->dev, "%s: power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 0); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 9ef57e5d7d64..9d9eed2d5d68 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -178,6 +178,9 @@ config USB_F_RNDIS config USB_F_QCRNDIS tristate +config USB_F_RMNET_BAM + tristate + config USB_F_MASS_STORAGE tristate @@ -345,6 +348,12 @@ config USB_CONFIGFS_RNDIS XP, you'll need to download drivers from Microsoft's website; a URL is given in comments found in that info file. +config USB_CONFIGFS_RMNET_BAM + bool "RMNET" + depends on USB_CONFIGFS + depends on IPA + select USB_F_RMNET_BAM + config USB_CONFIGFS_EEM bool "Ethernet Emulation Model (EEM)" depends on USB_CONFIGFS diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index a213cd4c8377..511909fb78f6 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -62,3 +62,5 @@ usb_f_qdss-y := f_qdss.o u_qdss.o obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o +usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o +obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index eb2409dda50d..19d6a997ee6c 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -760,8 +760,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ssize_t ret, data_len = -EINVAL; int halt; - ffs_log("enter: epfile name %s epfile err %d", epfile->name, - atomic_read(&epfile->error)); + ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name, + atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE"); smp_mb__before_atomic(); if (atomic_read(&epfile->error)) @@ -781,6 +781,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) goto error; } + /* Don't wait on write if device is offline */ + if (!io_data->read) { + ret = -EINTR; + goto error; + } + /* * If ep is disabled, this fails all current IOs * and wait for next epfile open to happen. diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 738f20d935d6..af20033b621f 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1984,6 +1984,10 @@ static int gsi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) atomic_set(&gsi->connected, 1); + /* send 0 len pkt to qti to notify state change */ + if (gsi->prot_id == IPA_USB_DIAG) + gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0); + return 0; notify_ep_disable: diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index c4af5ac839cd..e3fe8ae03775 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -21,6 +21,8 @@ #include <linux/usb/composite.h> #include <linux/usb/usb_qdss.h> +#include "u_rmnet.h" + struct usb_qdss_bam_connect_info { u32 usb_bam_pipe_idx; u32 peer_pipe_idx; @@ -33,8 +35,8 @@ struct gqdss { struct usb_ep *ctrl_out; struct usb_ep *ctrl_in; struct usb_ep *data; - int (*send_encap_cmd)(u8 port_num, void *buf, size_t len); - void (*notify_modem)(void *g, u8 port_num, int cbits); + int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len); + void (*notify_modem)(void *g, enum qti_port_type qport, int cbits); }; /* struct f_qdss - USB qdss function driver private structure */ diff --git a/drivers/usb/gadget/function/f_rmnet.c b/drivers/usb/gadget/function/f_rmnet.c index d84b55cef666..0fd7e213ef99 100644 --- a/drivers/usb/gadget/function/f_rmnet.c +++ b/drivers/usb/gadget/function/f_rmnet.c @@ -17,16 +17,11 @@ #include <linux/netdevice.h> #include <linux/spinlock.h> #include <linux/usb_bam.h> +#include <linux/module.h> -#include "usb_gadget_xport.h" -#include "u_ether.h" #include "u_rmnet.h" -#include "gadget_chips.h" - -static unsigned int rmnet_dl_max_pkt_per_xfer = 7; -module_param(rmnet_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer, - "Maximum packets per transfer for DL aggregation"); +#include "u_data_ipa.h" +#include "configfs.h" #define RMNET_NOTIFY_INTERVAL 5 #define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification) @@ -38,10 +33,9 @@ MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer, * control paths */ struct f_rmnet { - struct gether gether_port; + struct usb_function func; struct grmnet port; int ifc_id; - u8 port_num; atomic_t online; atomic_t ctrl_online; struct usb_composite_dev *cdev; @@ -53,30 +47,11 @@ struct f_rmnet { struct usb_request *notify_req; /* control info */ + struct gadget_ipa_port ipa_port; struct list_head cpkt_resp_q; unsigned long notify_count; unsigned long cpkts_len; - const struct usb_endpoint_descriptor *in_ep_desc_backup; - const struct usb_endpoint_descriptor *out_ep_desc_backup; -}; - -static unsigned int nr_rmnet_ports; -static unsigned int no_ctrl_smd_ports; -static unsigned int no_ctrl_qti_ports; -static unsigned int no_ctrl_hsic_ports; -static unsigned int no_ctrl_hsuart_ports; -static unsigned int no_data_bam_ports; -static unsigned int no_data_bam2bam_ports; -static unsigned int no_data_hsic_ports; -static unsigned int no_data_hsuart_ports; -static struct rmnet_ports { - enum transport_type data_xport; - enum transport_type ctrl_xport; - unsigned data_xport_num; - unsigned ctrl_xport_num; - unsigned port_num; - struct f_rmnet *port; -} rmnet_ports[NR_RMNET_PORTS]; +} *rmnet_port; static struct usb_interface_descriptor rmnet_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, @@ -244,7 +219,7 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev); static inline struct f_rmnet *func_to_rmnet(struct usb_function *f) { - return container_of(f, struct f_rmnet, gether_port.func); + return container_of(f, struct f_rmnet, func); } static inline struct f_rmnet *port_to_rmnet(struct grmnet *r) @@ -253,8 +228,7 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r) } static struct usb_request * -frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc, - gfp_t flags) +frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags) { struct usb_request *req; @@ -262,7 +236,7 @@ frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc, if (!req) return ERR_PTR(-ENOMEM); - req->buf = kmalloc(len + extra_buf_alloc, flags); + req->buf = kmalloc(len, flags); if (!req->buf) { usb_ep_free_request(ep, req); return ERR_PTR(-ENOMEM); @@ -305,198 +279,42 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt) /* -------------------------------------------*/ -static int rmnet_gport_setup(void) -{ - int ret; - int port_idx; - int i; - u8 base; - - pr_debug("%s: bam ports:%u bam2bam ports:%u data hsic ports:%u\n", - __func__, no_data_bam_ports, no_data_bam2bam_ports, - no_data_hsic_ports); - - pr_debug("%s: data hsuart ports:%u smd ports:%u ctrl hsic ports:%u\n", - __func__, no_data_hsuart_ports, no_ctrl_smd_ports, - no_ctrl_hsic_ports); - - pr_debug("%s: ctrl hsuart ports:%u nr_rmnet_ports:%u\n", - __func__, no_ctrl_hsuart_ports, nr_rmnet_ports); - - if (no_data_bam_ports) { - ret = gbam_setup(no_data_bam_ports); - if (ret < 0) - return ret; - } - - if (no_data_bam2bam_ports) { - ret = gbam2bam_setup(no_data_bam2bam_ports); - if (ret < 0) - return ret; - } - - if (no_ctrl_smd_ports) { - ret = gsmd_ctrl_setup(FRMNET_CTRL_CLIENT, - no_ctrl_smd_ports, &base); - if (ret) - return ret; - for (i = 0; i < nr_rmnet_ports; i++) - if (rmnet_ports[i].port) - rmnet_ports[i].port->port_num += base; - } - - if (no_data_hsic_ports) { - port_idx = ghsic_data_setup(no_data_hsic_ports, - USB_GADGET_RMNET); - if (port_idx < 0) - return port_idx; - for (i = 0; i < nr_rmnet_ports; i++) { - if (rmnet_ports[i].data_xport == - USB_GADGET_XPORT_HSIC) { - rmnet_ports[i].data_xport_num = port_idx; - port_idx++; - } - } - } - - if (no_ctrl_hsic_ports) { - port_idx = ghsic_ctrl_setup(no_ctrl_hsic_ports, - USB_GADGET_RMNET); - if (port_idx < 0) - return port_idx; - for (i = 0; i < nr_rmnet_ports; i++) { - if (rmnet_ports[i].ctrl_xport == - USB_GADGET_XPORT_HSIC) { - rmnet_ports[i].ctrl_xport_num = port_idx; - port_idx++; - } - } - } - - return 0; -} - static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf) { int ret; - unsigned port_num; - enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; int src_connection_idx = 0, dst_connection_idx = 0; struct usb_gadget *gadget = dev->cdev->gadget; enum usb_ctrl usb_bam_type; - void *net; - - pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n", - __func__, xport_to_str(cxport), xport_to_str(dxport), - dev, dev->port_num); - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - switch (cxport) { - case USB_GADGET_XPORT_SMD: - ret = gsmd_ctrl_connect(&dev->port, port_num); - if (ret) { - pr_err("%s: gsmd_ctrl_connect failed: err:%d\n", - __func__, ret); - return ret; - } - break; - case USB_GADGET_XPORT_QTI: - ret = gqti_ctrl_connect(&dev->port, port_num, dev->ifc_id, - dxport, USB_GADGET_RMNET); - if (ret) { - pr_err("%s: gqti_ctrl_connect failed: err:%d\n", - __func__, ret); - return ret; - } - break; - case USB_GADGET_XPORT_HSIC: - ret = ghsic_ctrl_connect(&dev->port, port_num); - if (ret) { - pr_err("%s: ghsic_ctrl_connect failed: err:%d\n", - __func__, ret); - return ret; - } - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(cxport)); - return -ENODEV; + ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id); + if (ret) { + pr_err("%s: gqti_ctrl_connect failed: err:%d\n", + __func__, ret); + return ret; } - port_num = rmnet_ports[dev->port_num].data_xport_num; - - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - ret = gbam_connect(&dev->port, port_num, - dxport, src_connection_idx, dst_connection_idx); - if (ret) { - pr_err("%s: gbam_connect failed: err:%d\n", - __func__, ret); - gsmd_ctrl_disconnect(&dev->port, port_num); - return ret; - } - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - usb_bam_type = usb_bam_get_bam_type(gadget->name); - src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, - IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, - port_num); - dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, - IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, - port_num); - if (dst_connection_idx < 0 || src_connection_idx < 0) { - pr_err("%s: usb_bam_get_connection_idx failed\n", - __func__); - gsmd_ctrl_disconnect(&dev->port, port_num); - return -EINVAL; - } - ret = gbam_connect(&dev->port, port_num, - dxport, src_connection_idx, dst_connection_idx); - if (ret) { - pr_err("%s: gbam_connect failed: err:%d\n", - __func__, ret); - if (cxport == USB_GADGET_XPORT_QTI) - gqti_ctrl_disconnect(&dev->port, port_num); - else - gsmd_ctrl_disconnect(&dev->port, port_num); - return ret; - } - break; - case USB_GADGET_XPORT_HSIC: - ret = ghsic_data_connect(&dev->port, port_num); - if (ret) { - pr_err("%s: ghsic_data_connect failed: err:%d\n", - __func__, ret); - ghsic_ctrl_disconnect(&dev->port, port_num); - return ret; - } - break; - case USB_GADGET_XPORT_ETHER: - gether_enable_sg(&dev->gether_port, true); - net = gether_connect(&dev->gether_port); - if (IS_ERR(net)) { - pr_err("%s: gether_connect failed: err:%ld\n", - __func__, PTR_ERR(net)); - if (cxport == USB_GADGET_XPORT_QTI) - gqti_ctrl_disconnect(&dev->port, port_num); - else - gsmd_ctrl_disconnect(&dev->port, port_num); - - return PTR_ERR(net); - } - gether_update_dl_max_pkts_per_xfer(&dev->gether_port, - rmnet_dl_max_pkt_per_xfer); - gether_update_dl_max_xfer_size(&dev->gether_port, 16384); - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - return -ENODEV; + dev->ipa_port.cdev = dev->cdev; + ipa_data_port_select(USB_IPA_FUNC_RMNET); + usb_bam_type = usb_bam_get_bam_type(gadget->name); + src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, + IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, + QTI_PORT_RMNET); + dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, + IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, + QTI_PORT_RMNET); + if (dst_connection_idx < 0 || src_connection_idx < 0) { + pr_err("%s: usb_bam_get_connection_idx failed\n", + __func__); + gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); + return -EINVAL; + } + ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET, + src_connection_idx, dst_connection_idx); + if (ret) { + pr_err("%s: ipa_data_connect failed: err:%d\n", + __func__, ret); + gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); + return ret; } return 0; @@ -504,61 +322,26 @@ static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf) static int gport_rmnet_disconnect(struct f_rmnet *dev) { - unsigned port_num; - enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - - pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n", - __func__, xport_to_str(cxport), xport_to_str(dxport), - dev, dev->port_num); - - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - switch (cxport) { - case USB_GADGET_XPORT_SMD: - gsmd_ctrl_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_QTI: - gqti_ctrl_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_HSIC: - ghsic_ctrl_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(cxport)); - return -ENODEV; - } + gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); + ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET); + return 0; +} - port_num = rmnet_ports[dev->port_num].data_xport_num; - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - case USB_GADGET_XPORT_BAM2BAM_IPA: - gbam_disconnect(&dev->port, port_num, dxport); - break; - case USB_GADGET_XPORT_HSIC: - ghsic_data_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_ETHER: - gether_disconnect(&dev->gether_port); - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - return -ENODEV; - } +static void frmnet_free(struct usb_function *f) +{ + struct f_rmnet_opts *opts; - return 0; + opts = container_of(f->fi, struct f_rmnet_opts, func_inst); + opts->refcnt--; + kfree(rmnet_port); + rmnet_port = NULL; } static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rmnet *dev = func_to_rmnet(f); - pr_debug("%s: portno:%d\n", __func__, dev->port_num); + pr_debug("%s: start unbinding\n", __func__); if (gadget_is_superspeed(c->cdev->gadget)) usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) @@ -575,8 +358,7 @@ static void frmnet_purge_responses(struct f_rmnet *dev) unsigned long flags; struct rmnet_ctrl_pkt *cpkt; - pr_debug("%s: port#%d\n", __func__, dev->port_num); - + pr_debug("%s: Purging responses\n", __func__); spin_lock_irqsave(&dev->lock, flags); while (!list_empty(&dev->cpkt_resp_q)) { cpkt = list_first_entry(&dev->cpkt_resp_q, @@ -591,117 +373,46 @@ static void frmnet_purge_responses(struct f_rmnet *dev) static void frmnet_suspend(struct usb_function *f) { - struct f_rmnet *dev = func_to_rmnet(f); - unsigned port_num; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - bool remote_wakeup_allowed; + struct f_rmnet *dev = func_to_rmnet(f); + bool remote_wakeup_allowed; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; - pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n", - __func__, xport_to_str(dxport), - dev, dev->port_num, remote_wakeup_allowed); + pr_debug("%s: dev: %p remote_wakeup: %d\n", + __func__, dev, remote_wakeup_allowed); usb_ep_fifo_flush(dev->notify); frmnet_purge_responses(dev); - port_num = rmnet_ports[dev->port_num].data_xport_num; - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - if (remote_wakeup_allowed) { - gbam_suspend(&dev->port, port_num, dxport); - } else { - /* - * When remote wakeup is disabled, IPA is disconnected - * because it cannot send new data until the USB bus is - * resumed. Endpoint descriptors info is saved before it - * gets reset by the BAM disconnect API. This lets us - * restore this info when the USB bus is resumed. - */ - dev->in_ep_desc_backup = dev->port.in->desc; - dev->out_ep_desc_backup = dev->port.out->desc; - pr_debug("in_ep_desc_bkup = %p, out_ep_desc_bkup = %p", - dev->in_ep_desc_backup, dev->out_ep_desc_backup); - pr_debug("%s(): Disconnecting\n", __func__); - gport_rmnet_disconnect(dev); - } - break; - case USB_GADGET_XPORT_HSIC: - break; - case USB_GADGET_XPORT_HSUART: - break; - case USB_GADGET_XPORT_ETHER: - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - } + ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET, + remote_wakeup_allowed); } static void frmnet_resume(struct usb_function *f) { - struct f_rmnet *dev = func_to_rmnet(f); - unsigned port_num; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - int ret; - bool remote_wakeup_allowed; + struct f_rmnet *dev = func_to_rmnet(f); + bool remote_wakeup_allowed; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; - pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n", - __func__, xport_to_str(dxport), - dev, dev->port_num, remote_wakeup_allowed); + pr_debug("%s: dev: %p remote_wakeup: %d\n", + __func__, dev, remote_wakeup_allowed); - port_num = rmnet_ports[dev->port_num].data_xport_num; - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - if (remote_wakeup_allowed) { - gbam_resume(&dev->port, port_num, dxport); - } else { - dev->port.in->desc = dev->in_ep_desc_backup; - dev->port.out->desc = dev->out_ep_desc_backup; - pr_debug("%s(): Connecting\n", __func__); - ret = gport_rmnet_connect(dev, dev->ifc_id); - if (ret) { - pr_err("%s: gport_rmnet_connect failed: err:%d\n", - __func__, ret); - } - } - break; - case USB_GADGET_XPORT_HSIC: - break; - case USB_GADGET_XPORT_HSUART: - break; - case USB_GADGET_XPORT_ETHER: - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - } + ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET, + remote_wakeup_allowed); } static void frmnet_disable(struct usb_function *f) { - struct f_rmnet *dev = func_to_rmnet(f); - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - struct usb_composite_dev *cdev = dev->cdev; - - pr_debug("%s: port#%d\n", __func__, dev->port_num); + struct f_rmnet *dev = func_to_rmnet(f); + pr_debug("%s: Disabling\n", __func__); usb_ep_disable(dev->notify); dev->notify->driver_data = NULL; @@ -709,11 +420,8 @@ static void frmnet_disable(struct usb_function *f) frmnet_purge_responses(dev); - if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA && - gadget_is_dwc3(cdev->gadget)) { - msm_ep_unconfig(dev->port.out); - msm_ep_unconfig(dev->port.in); - } + msm_ep_unconfig(dev->ipa_port.out); + msm_ep_unconfig(dev->ipa_port.in); gport_rmnet_disconnect(dev); } @@ -721,14 +429,14 @@ static int frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_rmnet *dev = func_to_rmnet(f); - struct usb_composite_dev *cdev = dev->cdev; + struct usb_composite_dev *cdev = f->config->cdev; int ret; - struct list_head *cpkt; - - pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num); + struct list_head *cpkt; + pr_debug("%s: dev: %p\n", __func__, dev); + dev->cdev = cdev; if (dev->notify->driver_data) { - pr_debug("%s: reset port:%d\n", __func__, dev->port_num); + pr_debug("%s: reset port\n", __func__); usb_ep_disable(dev->notify); } @@ -749,14 +457,14 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } dev->notify->driver_data = dev; - if (!dev->port.in->desc || !dev->port.out->desc) { - if (config_ep_by_speed(cdev->gadget, f, dev->port.in) || - config_ep_by_speed(cdev->gadget, f, dev->port.out)) { + if (!dev->ipa_port.in->desc || !dev->ipa_port.out->desc) { + if (config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in) || + config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); ret = -EINVAL; goto err_disable_ep; } - dev->port.gadget = dev->cdev->gadget; + dev->ipa_port.cdev = dev->cdev; } ret = gport_rmnet_connect(dev, intf); @@ -777,8 +485,8 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) return ret; err_disable_ep: - dev->port.in->desc = NULL; - dev->port.out->desc = NULL; + dev->ipa_port.in->desc = NULL; + dev->ipa_port.out->desc = NULL; usb_ep_disable(dev->notify); return ret; @@ -790,10 +498,9 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev) struct usb_cdc_notification *event; unsigned long flags; int ret; - struct rmnet_ctrl_pkt *cpkt; - - pr_debug("%s:dev:%p portno#%d\n", __func__, dev, dev->port_num); + struct rmnet_ctrl_pkt *cpkt; + pr_debug("%s: dev: %p\n", __func__, dev); spin_lock_irqsave(&dev->lock, flags); if (!atomic_read(&dev->online) || !req || !req->buf) { spin_unlock_irqrestore(&dev->lock, flags); @@ -913,8 +620,7 @@ frmnet_send_cpkt_response(void *gr, void *buf, size_t len) dev = port_to_rmnet(gr); - pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); if (!atomic_read(&dev->online) || !atomic_read(&dev->ctrl_online)) { rmnet_free_ctrl_pkt(cpkt); return 0; @@ -934,32 +640,27 @@ frmnet_cmd_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rmnet *dev = req->context; struct usb_composite_dev *cdev; - unsigned port_num; if (!dev) { pr_err("%s: rmnet dev is null\n", __func__); return; } - - pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); cdev = dev->cdev; if (dev->port.send_encap_cmd) { - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - dev->port.send_encap_cmd(port_num, req->buf, req->actual); + dev->port.send_encap_cmd(QTI_PORT_RMNET, req->buf, req->actual); } } static void frmnet_notify_complete(struct usb_ep *ep, struct usb_request *req) { - struct f_rmnet *dev = req->context; - int status = req->status; + struct f_rmnet *dev = req->context; + int status = req->status; unsigned long flags; struct rmnet_ctrl_pkt *cpkt; - pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); switch (status) { case -ECONNRESET: case -ESHUTDOWN: @@ -1021,14 +722,12 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) struct f_rmnet *dev = func_to_rmnet(f); struct usb_composite_dev *cdev = dev->cdev; struct usb_request *req = cdev->req; - unsigned port_num; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); int ret = -EOPNOTSUPP; - pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); if (!atomic_read(&dev->online)) { pr_warn("%s: usb cable is not connected\n", __func__); return -ENOTCONN; @@ -1085,8 +784,8 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d\n", __func__, w_value & ACM_CTRL_DTR ? 1 : 0); if (dev->port.notify_modem) { - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - dev->port.notify_modem(&dev->port, port_num, w_value); + dev->port.notify_modem(&dev->port, + QTI_PORT_RMNET, w_value); } ret = 0; @@ -1121,6 +820,16 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; int ret = -ENODEV; + if (rmnet_string_defs[0].id == 0) { + ret = usb_string_id(c->cdev); + if (ret < 0) { + pr_err("%s: failed to get string id, err:%d\n", + __func__, ret); + return ret; + } + rmnet_string_defs[0].id = ret; + } + pr_debug("%s: start binding\n", __func__); dev->ifc_id = usb_interface_id(c, f); if (dev->ifc_id < 0) { @@ -1135,9 +844,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) pr_err("%s: usb epin autoconfig failed\n", __func__); return -ENODEV; } - dev->port.in = ep; - /* Update same for u_ether which uses gether port struct */ - dev->gether_port.in_ep = ep; + dev->ipa_port.in = ep; ep->driver_data = cdev; ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc); @@ -1146,9 +853,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) ret = -ENODEV; goto ep_auto_out_fail; } - dev->port.out = ep; - /* Update same for u_ether which uses gether port struct */ - dev->gether_port.out_ep = ep; + dev->ipa_port.out = ep; ep->driver_data = cdev; ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc); @@ -1162,7 +867,6 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) dev->notify_req = frmnet_alloc_req(ep, sizeof(struct usb_cdc_notification), - cdev->gadget->extra_buf_alloc, GFP_KERNEL); if (IS_ERR(dev->notify_req)) { pr_err("%s: unable to allocate memory for notify req\n", @@ -1218,10 +922,9 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) } } - pr_debug("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n", - __func__, dev->port_num, - gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", - dev->port.in->name, dev->port.out->name); + pr_debug("%s: RmNet %s Speed, IN:%s OUT:%s\n", + __func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", + dev->ipa_port.in->name, dev->ipa_port.out->name); return 0; @@ -1238,67 +941,35 @@ ep_notify_alloc_fail: dev->notify->driver_data = NULL; dev->notify = NULL; ep_auto_notify_fail: - dev->port.out->driver_data = NULL; - dev->port.out = NULL; + dev->ipa_port.out->driver_data = NULL; + dev->ipa_port.out = NULL; ep_auto_out_fail: - dev->port.in->driver_data = NULL; - dev->port.in = NULL; + dev->ipa_port.in->driver_data = NULL; + dev->ipa_port.in = NULL; return ret; } -static int frmnet_bind_config(struct usb_configuration *c, unsigned portno) +static struct usb_function *frmnet_bind_config(struct usb_function_instance *fi) { + struct f_rmnet_opts *opts; int status; struct f_rmnet *dev; struct usb_function *f; unsigned long flags; - pr_debug("%s: usb config:%p\n", __func__, c); - - if (portno >= nr_rmnet_ports) { - pr_err("%s: supporting ports#%u port_id:%u\n", __func__, - nr_rmnet_ports, portno); - return -ENODEV; - } - - dev = rmnet_ports[portno].port; - - if (rmnet_ports[portno].data_xport == USB_GADGET_XPORT_ETHER) { - struct net_device *net = gether_setup_name_default("usb_rmnet"); - - if (IS_ERR(net)) { - pr_err("%s: gether_setup failed\n", __func__); - return PTR_ERR(net); - } - dev->gether_port.ioport = netdev_priv(net); - gether_set_gadget(net, c->cdev->gadget); - status = gether_register_netdev(net); - if (status < 0) { - pr_err("%s: gether_register_netdev failed\n", __func__); - free_netdev(net); - return status; - } - } - - if (rmnet_string_defs[0].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) { - pr_err("%s: failed to get string id, err:%d\n", - __func__, status); - return status; - } - rmnet_string_defs[0].id = status; - } - + /* allocate and initialize one new instance */ + status = -ENOMEM; + opts = container_of(fi, struct f_rmnet_opts, func_inst); + opts->refcnt++; + dev = opts->dev; spin_lock_irqsave(&dev->lock, flags); - dev->cdev = c->cdev; - f = &dev->gether_port.func; - f->name = kasprintf(GFP_ATOMIC, "rmnet%d", portno); + f = &dev->func; + f->name = kasprintf(GFP_ATOMIC, "rmnet%d", 0); spin_unlock_irqrestore(&dev->lock, flags); if (!f->name) { pr_err("%s: cannot allocate memory for name\n", __func__); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } f->strings = rmnet_strings; @@ -1309,166 +980,123 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno) f->setup = frmnet_setup; f->suspend = frmnet_suspend; f->resume = frmnet_resume; + f->free_func = frmnet_free; dev->port.send_cpkt_response = frmnet_send_cpkt_response; dev->port.disconnect = frmnet_disconnect; dev->port.connect = frmnet_connect; - dev->gether_port.cdc_filter = 0; - - status = usb_add_function(c, f); - if (status) { - pr_err("%s: usb add function failed: %d\n", - __func__, status); - kfree(f->name); - return status; - } pr_debug("%s: complete\n", __func__); - return status; + return f; } -static void frmnet_unbind_config(void) +static int rmnet_init(void) { - int i; + return gqti_ctrl_init(); +} - for (i = 0; i < nr_rmnet_ports; i++) - if (rmnet_ports[i].data_xport == USB_GADGET_XPORT_ETHER) { - gether_cleanup(rmnet_ports[i].port->gether_port.ioport); - rmnet_ports[i].port->gether_port.ioport = NULL; - } +static void frmnet_cleanup(void) +{ + gqti_ctrl_cleanup(); } -static int rmnet_init(void) +static void rmnet_free_inst(struct usb_function_instance *f) { - return gqti_ctrl_init(); + struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts, + func_inst); + ipa_data_free(USB_IPA_FUNC_RMNET); + kfree(opts); } -static void frmnet_cleanup(void) +static int rmnet_set_inst_name(struct usb_function_instance *fi, + const char *name) { - int i; + int name_len; + int ret; - gqti_ctrl_cleanup(); + name_len = strlen(name) + 1; + if (name_len > MAX_INST_NAME_LEN) + return -ENAMETOOLONG; - for (i = 0; i < nr_rmnet_ports; i++) - kfree(rmnet_ports[i].port); - - gbam_cleanup(); - nr_rmnet_ports = 0; - no_ctrl_smd_ports = 0; - no_ctrl_qti_ports = 0; - no_data_bam_ports = 0; - no_data_bam2bam_ports = 0; - no_ctrl_hsic_ports = 0; - no_data_hsic_ports = 0; - no_ctrl_hsuart_ports = 0; - no_data_hsuart_ports = 0; + ret = ipa_data_setup(USB_IPA_FUNC_RMNET); + return ret; } -static int frmnet_init_port(const char *ctrl_name, const char *data_name, - const char *port_name) +static inline struct f_rmnet_opts *to_f_rmnet_opts(struct config_item *item) { - struct f_rmnet *dev; - struct rmnet_ports *rmnet_port; - int ret; - int i; + return container_of(to_config_group(item), struct f_rmnet_opts, + func_inst.group); +} - if (nr_rmnet_ports >= NR_RMNET_PORTS) { - pr_err("%s: Max-%d instances supported\n", - __func__, NR_RMNET_PORTS); - return -EINVAL; - } +static void rmnet_opts_release(struct config_item *item) +{ + struct f_rmnet_opts *opts = to_f_rmnet_opts(item); - pr_debug("%s: port#:%d, ctrl port: %s data port: %s\n", - __func__, nr_rmnet_ports, ctrl_name, data_name); + usb_put_function_instance(&opts->func_inst); +}; - dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); - if (!dev) - return -ENOMEM; +static struct configfs_item_operations rmnet_item_ops = { + .release = rmnet_opts_release, +}; - dev->port_num = nr_rmnet_ports; - spin_lock_init(&dev->lock); - INIT_LIST_HEAD(&dev->cpkt_resp_q); +static struct config_item_type rmnet_func_type = { + .ct_item_ops = &rmnet_item_ops, + .ct_owner = THIS_MODULE, +}; - rmnet_port = &rmnet_ports[nr_rmnet_ports]; - rmnet_port->port = dev; - rmnet_port->port_num = nr_rmnet_ports; - rmnet_port->ctrl_xport = str_to_xport(ctrl_name); - rmnet_port->data_xport = str_to_xport(data_name); +static struct usb_function_instance *rmnet_alloc_inst(void) +{ + struct f_rmnet_opts *opts; - switch (rmnet_port->ctrl_xport) { - case USB_GADGET_XPORT_SMD: - rmnet_port->ctrl_xport_num = no_ctrl_smd_ports; - no_ctrl_smd_ports++; - break; - case USB_GADGET_XPORT_QTI: - rmnet_port->ctrl_xport_num = no_ctrl_qti_ports; - no_ctrl_qti_ports++; - break; - case USB_GADGET_XPORT_HSIC: - ghsic_ctrl_set_port_name(port_name, ctrl_name); - rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports; - no_ctrl_hsic_ports++; - break; - case USB_GADGET_XPORT_HSUART: - rmnet_port->ctrl_xport_num = no_ctrl_hsuart_ports; - no_ctrl_hsuart_ports++; - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %u\n", __func__, - rmnet_port->ctrl_xport); - ret = -ENODEV; - goto fail_probe; - } + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); - switch (rmnet_port->data_xport) { - case USB_GADGET_XPORT_BAM2BAM: - /* Override BAM2BAM to BAM_DMUX for old ABI compatibility */ - rmnet_port->data_xport = USB_GADGET_XPORT_BAM_DMUX; - /* fall-through */ - case USB_GADGET_XPORT_BAM_DMUX: - rmnet_port->data_xport_num = no_data_bam_ports; - no_data_bam_ports++; - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - rmnet_port->data_xport_num = no_data_bam2bam_ports; - no_data_bam2bam_ports++; - break; - case USB_GADGET_XPORT_HSIC: - ghsic_data_set_port_name(port_name, data_name); - rmnet_port->data_xport_num = no_data_hsic_ports; - no_data_hsic_ports++; - break; - case USB_GADGET_XPORT_HSUART: - rmnet_port->data_xport_num = no_data_hsuart_ports; - no_data_hsuart_ports++; - break; - case USB_GADGET_XPORT_ETHER: - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %u\n", __func__, - rmnet_port->data_xport); - ret = -ENODEV; - goto fail_probe; - } - nr_rmnet_ports++; + opts->func_inst.set_inst_name = rmnet_set_inst_name; + opts->func_inst.free_func_inst = rmnet_free_inst; - return 0; + config_group_init_type_name(&opts->func_inst.group, "", + &rmnet_func_type); + return &opts->func_inst; +} + +static struct usb_function *rmnet_alloc(struct usb_function_instance *fi) +{ + struct f_rmnet_opts *opts = container_of(fi, + struct f_rmnet_opts, func_inst); + rmnet_port = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); + if (!rmnet_port) + return ERR_PTR(-ENOMEM); + opts->dev = rmnet_port; + spin_lock_init(&rmnet_port->lock); + INIT_LIST_HEAD(&rmnet_port->cpkt_resp_q); + return frmnet_bind_config(fi); +} -fail_probe: - for (i = 0; i < nr_rmnet_ports; i++) - kfree(rmnet_ports[i].port); +DECLARE_USB_FUNCTION(rmnet_bam, rmnet_alloc_inst, rmnet_alloc); - nr_rmnet_ports = 0; - no_ctrl_smd_ports = 0; - no_ctrl_qti_ports = 0; - no_data_bam_ports = 0; - no_ctrl_hsic_ports = 0; - no_data_hsic_ports = 0; - no_ctrl_hsuart_ports = 0; - no_data_hsuart_ports = 0; +static int __init usb_rmnet_init(void) +{ + int ret; + ret = rmnet_init(); + if (!ret) { + ret = usb_function_register(&rmnet_bamusb_func); + if (ret) { + pr_err("%s: failed to register rmnet %d\n", + __func__, ret); + return ret; + } + } return ret; } + +static void __exit usb_rmnet_exit(void) +{ + usb_function_unregister(&rmnet_bamusb_func); + frmnet_cleanup(); +} + +module_init(usb_rmnet_init); +module_exit(usb_rmnet_exit); +MODULE_DESCRIPTION("USB RMNET Function Driver"); diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c index 7ef56eca20b8..c0650b0abf8c 100644 --- a/drivers/usb/gadget/function/u_ctrl_qti.c +++ b/drivers/usb/gadget/function/u_ctrl_qti.c @@ -14,11 +14,11 @@ #include <linux/wait.h> #include <linux/poll.h> #include <linux/usb/usb_ctrl_qti.h> - -#include <soc/qcom/bam_dmux.h> +#include <linux/miscdevice.h> +#include <linux/debugfs.h> #include "u_rmnet.h" -#include "usb_gadget_xport.h" +#include "f_qdss.h" #define RMNET_CTRL_QTI_NAME "rmnet_ctrl" #define DPL_CTRL_QTI_NAME "dpl_ctrl" @@ -54,18 +54,18 @@ struct qti_ctrl_port { struct list_head cpkt_req_q; spinlock_t lock; - enum gadget_type gtype; + enum qti_port_type port_type; unsigned host_to_modem; unsigned copied_to_modem; unsigned copied_from_modem; unsigned modem_to_host; unsigned drp_cpkt_cnt; }; -static struct qti_ctrl_port *ctrl_port[NR_QTI_PORTS]; +static struct qti_ctrl_port *ctrl_port[QTI_NUM_PORTS]; static inline int qti_ctrl_lock(atomic_t *excl) { - if (atomic_inc_return(excl) == 1) { + if (atomic_inc_return(excl) == 1) return 0; atomic_dec(excl); return -EBUSY; @@ -76,6 +76,32 @@ static inline void qti_ctrl_unlock(atomic_t *excl) atomic_dec(excl); } +static struct rmnet_ctrl_pkt *alloc_rmnet_ctrl_pkt(unsigned len, gfp_t flags) +{ + struct rmnet_ctrl_pkt *pkt; + + pkt = kzalloc(sizeof(struct rmnet_ctrl_pkt), flags); + if (!pkt) + return ERR_PTR(-ENOMEM); + + pkt->buf = kmalloc(len, flags); + if (!pkt->buf) { + kfree(pkt); + return ERR_PTR(-ENOMEM); + } + + pkt->len = len; + + return pkt; +} + +static void free_rmnet_ctrl_pkt(struct rmnet_ctrl_pkt *pkt) +{ + kfree(pkt->buf); + kfree(pkt); +} + + static void qti_ctrl_queue_notify(struct qti_ctrl_port *port) { unsigned long flags; @@ -106,7 +132,8 @@ static void qti_ctrl_queue_notify(struct qti_ctrl_port *port) wake_up(&port->read_wq); } -static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) +static int gqti_ctrl_send_cpkt_tomodem(enum qti_port_type qport, + void *buf, size_t len) { unsigned long flags; struct qti_ctrl_port *port; @@ -118,12 +145,11 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) return -EINVAL; } - if (portno >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, portno); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return -ENODEV; } - port = ctrl_port[portno]; - + port = ctrl_port[qport]; cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC); if (IS_ERR(cpkt)) { pr_err("%s: Unable to allocate ctrl pkt\n", __func__); @@ -133,8 +159,8 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) memcpy(cpkt->buf, buf, len); cpkt->len = len; - pr_debug("%s: gtype:%d: Add to cpkt_req_q packet with len = %zu\n", - __func__, port->gtype, len); + pr_debug("%s: port type:%d: Add to cpkt_req_q packet with len = %zu\n", + __func__, port->port_type, len); spin_lock_irqsave(&port->lock, flags); /* drop cpkt if port is not open */ @@ -159,71 +185,51 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) } static void -gqti_ctrl_notify_modem(void *gptr, u8 portno, int val) +gqti_ctrl_notify_modem(void *gptr, enum qti_port_type qport, int val) { struct qti_ctrl_port *port; - if (portno >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, portno); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return; } - port = ctrl_port[portno]; - + port = ctrl_port[qport]; atomic_set(&port->line_state, val); /* send 0 len pkt to qti to notify state change */ qti_ctrl_queue_notify(port); } -int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf, - enum transport_type dxport, enum gadget_type gtype) +int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf) { struct qti_ctrl_port *port; struct grmnet *g_rmnet = NULL; struct gqdss *g_dpl = NULL; unsigned long flags; - pr_debug("%s: gtype:%d gadget:%p\n", __func__, gtype, gr); - if (port_num >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, port_num); + pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return -ENODEV; } - port = ctrl_port[port_num]; + port = ctrl_port[qport]; if (!port) { pr_err("%s: gadget port is null\n", __func__); return -ENODEV; } spin_lock_irqsave(&port->lock, flags); - port->gtype = gtype; - if (dxport == USB_GADGET_XPORT_BAM_DMUX) { - /* - * BAM-DMUX data transport is used for RMNET and DPL - * on some targets where IPA is not available. - * Set endpoint type as BAM-DMUX and interface - * id as channel number. This information is - * sent to user space via EP_LOOKUP ioctl. - * - */ - - port->ep_type = DATA_EP_TYPE_BAM_DMUX; - port->intf = (gtype == USB_GADGET_RMNET) ? - BAM_DMUX_USB_RMNET_0 : - BAM_DMUX_USB_DPL; - port->ipa_prod_idx = 0; - port->ipa_cons_idx = 0; - } else { - port->ep_type = DATA_EP_TYPE_HSUSB; - port->intf = intf; - } + port->port_type = qport; + port->ep_type = DATA_EP_TYPE_HSUSB; + port->intf = intf; - if (gr && port->gtype == USB_GADGET_RMNET) { + if (gr && port->port_type == QTI_PORT_RMNET) { port->port_usb = gr; g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; g_rmnet->notify_modem = gqti_ctrl_notify_modem; - } else if (gr && port->gtype == USB_GADGET_DPL) { + } else if (gr && port->port_type == QTI_PORT_DPL) { port->port_usb = gr; g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; @@ -231,7 +237,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf, atomic_set(&port->line_state, 1); } else { spin_unlock_irqrestore(&port->lock, flags); - pr_err("%s(): Port is used without gtype.\n", __func__); + pr_err("%s(): Port is used without port type.\n", __func__); return -ENODEV; } @@ -251,7 +257,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf, return 0; } -void gqti_ctrl_disconnect(void *gr, u8 port_num) +void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport) { struct qti_ctrl_port *port; unsigned long flags; @@ -261,13 +267,12 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num) pr_debug("%s: gadget:%p\n", __func__, gr); - if (port_num >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, port_num); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return; } - port = ctrl_port[port_num]; - + port = ctrl_port[qport]; if (!port) { pr_err("%s: gadget port is null\n", __func__); return; @@ -282,17 +287,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num) port->ipa_cons_idx = -1; port->port_usb = NULL; - if (gr && port->gtype == USB_GADGET_RMNET) { + if (gr && port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = NULL; g_rmnet->notify_modem = NULL; - } else if (gr && port->gtype == USB_GADGET_DPL) { + } else if (gr && port->port_type == QTI_PORT_DPL) { g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = NULL; g_dpl->notify_modem = NULL; } else { pr_err("%s(): unrecognized gadget type(%d).\n", - __func__, port->gtype); + __func__, port->port_type); } while (!list_empty(&port->cpkt_req_q)) { @@ -309,18 +314,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num) qti_ctrl_queue_notify(port); } -void gqti_ctrl_update_ipa_pipes(void *gr, u8 port_num, u32 ipa_prod, - u32 ipa_cons) +void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport, + u32 ipa_prod, u32 ipa_cons) { struct qti_ctrl_port *port; - if (port_num >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, port_num); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return; } - port = ctrl_port[port_num]; - + port = ctrl_port[qport]; port->ipa_prod_idx = ipa_prod; port->ipa_cons_idx = ipa_cons; @@ -492,12 +496,12 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count, spin_lock_irqsave(&port->lock, flags); if (port && port->port_usb) { - if (port->gtype == USB_GADGET_RMNET) { + if (port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)port->port_usb; } else { spin_unlock_irqrestore(&port->lock, flags); pr_err("%s(): unrecognized gadget type(%d).\n", - __func__, port->gtype); + __func__, port->port_type); return -EINVAL; } @@ -530,15 +534,15 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) struct ep_info info; int val, ret = 0; - pr_debug("%s: Received command %d for gtype:%d\n", - __func__, cmd, port->gtype); + pr_debug("%s: Received command %d for port type:%d\n", + __func__, cmd, port->port_type); if (qti_ctrl_lock(&port->ioctl_excl)) return -EBUSY; switch (cmd) { case QTI_CTRL_MODEM_OFFLINE: - if (port && (port->gtype == USB_GADGET_DPL)) { + if (port && (port->port_type == QTI_PORT_DPL)) { pr_err("%s(): Modem Offline not handled\n", __func__); goto exit_ioctl; } @@ -550,7 +554,7 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) gr->disconnect(gr); break; case QTI_CTRL_MODEM_ONLINE: - if (port && (port->gtype == USB_GADGET_DPL)) { + if (port && (port->port_type == QTI_PORT_DPL)) { pr_err("%s(): Modem Online not handled\n", __func__); goto exit_ioctl; } @@ -568,13 +572,13 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) pr_err("copying to user space failed"); ret = -EFAULT; } - pr_debug("%s: Sent line_state: %d for gtype:%d\n", __func__, - atomic_read(&port->line_state), port->gtype); + pr_debug("%s: Sent line_state: %d for port type:%d\n", __func__, + atomic_read(&port->line_state), port->port_type); break; case QTI_CTRL_EP_LOOKUP: - pr_debug("%s(): EP_LOOKUP for gtype:%d\n", __func__, - port->gtype); + pr_debug("%s(): EP_LOOKUP for port type:%d\n", __func__, + port->port_type); val = atomic_read(&port->connected); if (!val) { pr_err_ratelimited("EP_LOOKUP failed: not connected\n"); @@ -593,9 +597,9 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) info.ipa_ep_pair.cons_pipe_num = port->ipa_cons_idx; info.ipa_ep_pair.prod_pipe_num = port->ipa_prod_idx; - pr_debug("%s(): gtype:%d ep_type:%d intf:%d\n", - __func__, port->gtype, info.ph_ep_info.ep_type, - info.ph_ep_info.peripheral_iface_id); + pr_debug("%s(): port type:%d ep_type:%d intf:%d\n", + __func__, port->port_type, info.ph_ep_info.ep_type, + info.ph_ep_info.peripheral_iface_id); pr_debug("%s(): ipa_cons_idx:%d ipa_prod_idx:%d\n", __func__, info.ipa_ep_pair.cons_pipe_num, @@ -650,7 +654,7 @@ static int qti_ctrl_read_stats(struct seq_file *s, void *unused) unsigned long flags; int i; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { port = ctrl_port[i]; if (!port) continue; @@ -687,7 +691,7 @@ static ssize_t qti_ctrl_reset_stats(struct file *file, int i; unsigned long flags; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { port = ctrl_port[i]; if (!port) continue; @@ -762,10 +766,9 @@ int gqti_ctrl_init(void) int ret, i, sz = QTI_CTRL_NAME_LEN; struct qti_ctrl_port *port = NULL; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { port = kzalloc(sizeof(struct qti_ctrl_port), GFP_KERNEL); if (!port) { - pr_err("Failed to allocate rmnet control device\n"); ret = -ENOMEM; goto fail_init; } @@ -787,16 +790,16 @@ int gqti_ctrl_init(void) port->ipa_prod_idx = -1; port->ipa_cons_idx = -1; - if (i == 0) + if (i == QTI_PORT_RMNET) strlcat(port->name, RMNET_CTRL_QTI_NAME, sz); - else if (i == DPL_QTI_CTRL_PORT_NO) + else if (i == QTI_PORT_DPL) strlcat(port->name, DPL_CTRL_QTI_NAME, sz); else snprintf(port->name, sz, "%s%d", - RMNET_CTRL_QTI_NAME, i); + RMNET_CTRL_QTI_NAME, i); port->ctrl_device.name = port->name; - if (i == DPL_QTI_CTRL_PORT_NO) + if (i == QTI_PORT_DPL) port->ctrl_device.fops = &dpl_qti_ctrl_fops; else port->ctrl_device.fops = &qti_ctrl_fops; @@ -809,7 +812,6 @@ int gqti_ctrl_init(void) } } qti_ctrl_debugfs_init(); - return ret; fail_init: @@ -825,7 +827,7 @@ void gqti_ctrl_cleanup(void) { int i; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { misc_deregister(&ctrl_port[i]->ctrl_device); kfree(ctrl_port[i]); ctrl_port[i] = NULL; diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index 56e7dea427ec..2da0c59fdfc2 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -23,6 +23,7 @@ #include <linux/usb_bam.h> #include "u_data_ipa.h" +#include "u_rmnet.h" struct ipa_data_ch_info { struct usb_request *rx_req; @@ -564,6 +565,11 @@ static void ipa_data_connect_work(struct work_struct *w) atomic_set(&port->pipe_connect_notified, 1); } + if (port->func_type == USB_IPA_FUNC_RMNET) { + gqti_ctrl_update_ipa_pipes(port->port_usb, QTI_PORT_RMNET, + gport->ipa_producer_ep, gport->ipa_consumer_ep); + } + pr_debug("ipa_producer_ep:%d ipa_consumer_ep:%d\n", gport->ipa_producer_ep, gport->ipa_consumer_ep); @@ -1135,7 +1141,7 @@ int ipa_data_setup(enum ipa_func_type func) } if (ipa_data_wq) { pr_debug("ipa_data_wq is already setup."); - goto free_rndis_data; + return 0; } ipa_data_wq = alloc_workqueue("k_usb_ipa_data", diff --git a/drivers/usb/gadget/function/u_data_ipa.h b/drivers/usb/gadget/function/u_data_ipa.h index a1c1055bd8ef..14411575af22 100644 --- a/drivers/usb/gadget/function/u_data_ipa.h +++ b/drivers/usb/gadget/function/u_data_ipa.h @@ -20,6 +20,8 @@ #include <linux/ipa_usb.h> #include <linux/usb_bam.h> +#include "u_rmnet.h" + enum ipa_func_type { USB_IPA_FUNC_ECM, USB_IPA_FUNC_MBIM, @@ -57,6 +59,12 @@ struct f_rndis_qc_opts { int refcnt; }; +struct f_rmnet_opts { + struct usb_function_instance func_inst; + struct f_rmnet *dev; + int refcnt; +}; + void ipa_data_port_select(enum ipa_func_type func); void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func); int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func, @@ -87,4 +95,6 @@ void *rndis_qc_get_ipa_rx_cb(void); bool rndis_qc_get_skip_ep_config(void); void *rndis_qc_get_ipa_tx_cb(void); void rndis_ipa_reset_trigger(void); +void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport, + u32 ipa_prod, u32 ipa_cons); #endif diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h index 4336dbf26274..e0843794b594 100644 --- a/drivers/usb/gadget/function/u_rmnet.h +++ b/drivers/usb/gadget/function/u_rmnet.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -19,18 +19,19 @@ #include <linux/workqueue.h> struct rmnet_ctrl_pkt { - void *buf; - int len; + void *buf; + int len; struct list_head list; }; -struct grmnet { - struct usb_function func; +enum qti_port_type { + QTI_PORT_RMNET, + QTI_PORT_DPL, + QTI_NUM_PORTS +}; - struct usb_gadget *gadget; - struct usb_ep *in; - struct usb_ep *out; +struct grmnet { /* to usb host, aka laptop, windows pc etc. Will * be filled by usb driver of rmnet functionality */ @@ -39,18 +40,13 @@ struct grmnet { /* to modem, and to be filled by driver implementing * control function */ - int (*send_encap_cmd)(u8 port_num, void *buf, size_t len); - - void (*notify_modem)(void *g, u8 port_num, int cbits); + int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len); + void (*notify_modem)(void *g, enum qti_port_type qport, int cbits); void (*disconnect)(struct grmnet *g); void (*connect)(struct grmnet *g); }; -#define NR_QTI_PORTS (NR_RMNET_PORTS + NR_DPL_PORTS) -#define NR_RMNET_PORTS 4 -#define NR_DPL_PORTS 1 - enum ctrl_client { FRMNET_CTRL_CLIENT, GPS_CTRL_CLIENT, @@ -58,22 +54,8 @@ enum ctrl_client { NR_CTRL_CLIENTS }; -int gbam_setup(unsigned int no_bam_port); -int gbam2bam_setup(unsigned int no_bam2bam_port); -void gbam_cleanup(void); -int gbam_connect(struct grmnet *gr, u8 port_num, - enum transport_type trans, u8 src_connection_idx, - u8 dst_connection_idx); -void gbam_disconnect(struct grmnet *gr, u8 port_num, - enum transport_type trans); -void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans); -void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans); -int gbam_mbim_setup(void); -int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in, - struct usb_ep *out); -void gbam_mbim_disconnect(void); -int gsmd_ctrl_connect(struct grmnet *gr, int port_num); -void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num); -int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count, - u8 *first_port_idx); +int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf); +void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport); +int gqti_ctrl_init(void); +void gqti_ctrl_cleanup(void); #endif /* __U_RMNET_H*/ diff --git a/drivers/usb/pd/Kconfig b/drivers/usb/pd/Kconfig index dd2813000dec..cc88df495f6e 100644 --- a/drivers/usb/pd/Kconfig +++ b/drivers/usb/pd/Kconfig @@ -9,6 +9,7 @@ config USB_PD config USB_PD_POLICY tristate "USB Power Delivery Protocol and Policy Engine" depends on EXTCON + depends on DUAL_ROLE_USB_INTF select USB_PD help Say Y here to enable USB PD protocol and policy engine. diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index aa2e1d9f3c70..2fbe4c8faa79 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include <linux/completion.h> #include <linux/delay.h> #include <linux/hrtimer.h> #include <linux/ipc_logging.h> @@ -24,6 +25,7 @@ #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/extcon.h> +#include <linux/usb/class-dual-role.h> #include <linux/usb/usbpd.h> #include "usbpd.h" @@ -163,11 +165,11 @@ static void *usbpd_ipc_log; /* Timeouts (in ms) */ #define ERROR_RECOVERY_TIME 25 #define SENDER_RESPONSE_TIME 26 -#define SINK_WAIT_CAP_TIME 620 +#define SINK_WAIT_CAP_TIME 500 #define PS_TRANSITION_TIME 450 #define SRC_CAP_TIME 120 #define SRC_TRANSITION_TIME 25 -#define SRC_RECOVER_TIME 660 +#define SRC_RECOVER_TIME 750 #define PS_HARD_RESET_TIME 25 #define PS_SOURCE_ON 400 #define PS_SOURCE_OFF 750 @@ -175,8 +177,11 @@ static void *usbpd_ipc_log; #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 -/* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */ -#define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275) +/* tPSHardReset + tSafe0V */ +#define SNK_HARD_RESET_VBUS_OFF_TIME (35 + 650) + +/* tSrcRecover + tSrcTurnOn */ +#define SNK_HARD_RESET_VBUS_ON_TIME (1000 + 275) #define PD_CAPS_COUNT 50 @@ -308,15 +313,23 @@ struct usbpd { enum power_supply_typec_mode typec_mode; enum power_supply_type psy_type; + enum power_supply_typec_power_role forced_pr; bool vbus_present; enum data_role current_dr; enum power_role current_pr; bool in_pr_swap; bool pd_phy_opened; + struct completion swap_complete; + + struct dual_role_phy_instance *dual_role; + struct dual_role_phy_desc dr_desc; + bool send_pr_swap; + bool send_dr_swap; struct regulator *vbus; struct regulator *vconn; + bool vbus_enabled; bool vconn_enabled; bool vconn_is_external; @@ -409,6 +422,17 @@ static struct usbpd_svid_handler *find_svid_handler(struct usbpd *pd, u16 svid) return NULL; } +/* Reset protocol layer */ +static inline void pd_reset_protocol(struct usbpd *pd) +{ + /* + * first Rx ID should be 0; set this to a sentinel of -1 so that in + * phy_msg_received() we can check if we had seen it before. + */ + pd->rx_msgid = -1; + pd->tx_msgid = 0; +} + static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, size_t num_data, enum pd_msg_type type) { @@ -423,7 +447,9 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, /* MessageID incremented regardless of Tx error */ pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID; - if (ret != num_data * sizeof(u32)) + if (ret < 0) + return ret; + else if (ret != num_data * sizeof(u32)) return -EIO; return 0; } @@ -631,6 +657,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) switch (next_state) { case PE_ERROR_RECOVERY: /* perform hard disconnect/reconnect */ pd->in_pr_swap = false; + pd->current_pr = PR_NONE; set_power_role(pd, PR_NONE); pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; kick_sm(pd, 0); @@ -646,12 +673,14 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) */ } + dual_role_instance_changed(pd->dual_role); + /* Set CC back to DRP toggle for the next disconnect */ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val); - pd->rx_msgid = -1; + pd_reset_protocol(pd); if (!pd->in_pr_swap) { if (pd->pd_phy_opened) { @@ -677,6 +706,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->current_state = PE_SRC_SEND_CAPABILITIES; if (pd->in_pr_swap) { kick_sm(pd, SWAP_SOURCE_START_TIME); + pd->in_pr_swap = false; break; } @@ -758,6 +788,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); + complete(&pd->swap_complete); + dual_role_instance_changed(pd->dual_role); break; case PE_SRC_HARD_RESET: @@ -768,9 +800,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_SEND_SOFT_RESET: case PE_SNK_SEND_SOFT_RESET: - /* Reset protocol layer */ - pd->tx_msgid = 0; - pd->rx_msgid = -1; + pd_reset_protocol(pd); ret = pd_send_msg(pd, MSG_SOFT_RESET, NULL, 0, SOP_MSG); if (ret) { @@ -801,6 +831,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } } + dual_role_instance_changed(pd->dual_role); + ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ALLOWED, &val); if (ret) { @@ -812,9 +844,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (!val.intval) break; - /* Reset protocol layer */ - pd->tx_msgid = 0; - pd->rx_msgid = -1; + pd_reset_protocol(pd); if (!pd->in_pr_swap) { if (pd->pd_phy_opened) { @@ -837,7 +867,17 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->pd_phy_opened = true; } - pd->current_voltage = 5000000; + pd->current_voltage = pd->requested_voltage = 5000000; + val.intval = pd->requested_voltage; /* set max range to 5V */ + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); + + if (!pd->vbus_present) { + pd->current_state = PE_SNK_DISCOVERY; + /* max time for hard reset to turn vbus back on */ + kick_sm(pd, SNK_HARD_RESET_VBUS_ON_TIME); + break; + } pd->current_state = PE_SNK_WAIT_FOR_CAPABILITIES; /* fall-through */ @@ -882,6 +922,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_READY: pd->in_explicit_contract = true; kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); + complete(&pd->swap_complete); + dual_role_instance_changed(pd->dual_role); break; case PE_SNK_TRANSITION_TO_DEFAULT: @@ -901,13 +943,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->vconn_enabled = false; } - val.intval = pd->requested_voltage; /* set range back to 5V */ - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); - pd->current_voltage = pd->requested_voltage; - - /* max time for hard reset to toggle vbus off/on */ - kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME); + /* max time for hard reset to turn vbus off */ + kick_sm(pd, SNK_HARD_RESET_VBUS_OFF_TIME); break; case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: @@ -996,7 +1033,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) pd->vdm_tx = vdm_tx; /* slight delay before queuing to prioritize handling of incoming VDM */ - kick_sm(pd, 5); + kick_sm(pd, 2); return 0; } @@ -1214,21 +1251,32 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) static void handle_vdm_tx(struct usbpd *pd) { int ret; + unsigned long flags; /* only send one VDM at a time */ if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; + /* bail out and try again later if a message just arrived */ + spin_lock_irqsave(&pd->rx_lock, flags); + if (!list_empty(&pd->rx_q)) { + spin_unlock_irqrestore(&pd->rx_lock, flags); + return; + } + spin_unlock_irqrestore(&pd->rx_lock, flags); + ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, SOP_MSG); if (ret) { - usbpd_err(&pd->dev, "Error sending VDM command %d\n", - SVDM_HDR_CMD(pd->vdm_tx->data[0])); - usbpd_set_state(pd, pd->current_pr == PR_SRC ? + usbpd_err(&pd->dev, "Error (%d) sending VDM command %d\n", + ret, SVDM_HDR_CMD(pd->vdm_tx->data[0])); + + /* retry when hitting PE_SRC/SNK_Ready again */ + if (ret != -EBUSY) + usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); - /* retry when hitting PE_SRC/SNK_Ready again */ return; } @@ -1240,7 +1288,7 @@ static void handle_vdm_tx(struct usbpd *pd) SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (pd->vdm_tx_retry) { - usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", + usbpd_dbg(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", SVDM_HDR_CMD( pd->vdm_tx_retry->data[0])); kfree(pd->vdm_tx_retry); @@ -1319,6 +1367,13 @@ static void vconn_swap(struct usbpd *pd) pd->vconn_enabled = true; + /* + * Small delay to ensure Vconn has ramped up. This is well + * below tVCONNSourceOn (100ms) so we still send PS_RDY within + * the allowed time. + */ + usleep_range(5000, 10000); + ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending PS_RDY\n"); @@ -1366,7 +1421,7 @@ static void usbpd_sm(struct work_struct *w) spin_unlock_irqrestore(&pd->rx_lock, flags); /* Disconnect? */ - if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE && !pd->in_pr_swap) { + if (pd->current_pr == PR_NONE) { if (pd->current_state == PE_UNKNOWN) goto sm_done; @@ -1400,8 +1455,10 @@ static void usbpd_sm(struct work_struct *w) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); - if (pd->current_pr == PR_SRC) + if (pd->vbus_enabled) { regulator_disable(pd->vbus); + pd->vbus_enabled = false; + } if (pd->vconn_enabled) { regulator_disable(pd->vconn); @@ -1423,13 +1480,22 @@ static void usbpd_sm(struct work_struct *w) usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC, (ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC); - /* Set CC back to DRP toggle */ - val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; + /* set due to dual_role class "mode" change */ + if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE) + val.intval = pd->forced_pr; + else + /* Set CC back to DRP toggle */ + val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; + power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val); + pd->forced_pr = POWER_SUPPLY_TYPEC_PR_NONE; pd->current_state = PE_UNKNOWN; + kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); + dual_role_instance_changed(pd->dual_role); + goto sm_done; } @@ -1473,6 +1539,8 @@ static void usbpd_sm(struct work_struct *w) ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus\n"); + else + pd->vbus_enabled = true; if (!pd->vconn_enabled && pd->typec_mode == @@ -1521,10 +1589,6 @@ static void usbpd_sm(struct work_struct *w) break; } - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); - /* transmit was successful if GoodCRC was received */ pd->caps_count = 0; pd->hard_reset_count = 0; @@ -1533,6 +1597,10 @@ static void usbpd_sm(struct work_struct *w) /* wait for REQUEST */ pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; kick_sm(pd, SENDER_RESPONSE_TIME); + + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); break; case PE_SRC_SEND_CAPABILITIES_WAIT: @@ -1582,7 +1650,6 @@ static void usbpd_sm(struct work_struct *w) } dr_swap(pd); - kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); } else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) { /* lock in current mode */ set_power_role(pd, pd->current_pr); @@ -1607,18 +1674,40 @@ static void usbpd_sm(struct work_struct *w) } vconn_swap(pd); + } else if (IS_DATA(rx_msg, MSG_VDM)) { + handle_vdm_rx(pd, rx_msg); + } else if (pd->send_pr_swap) { + pd->send_pr_swap = false; + ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG); + if (ret) { + dev_err(&pd->dev, "Error sending PR Swap\n"); + usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); + break; + } + + pd->current_state = PE_PRS_SRC_SNK_SEND_SWAP; + kick_sm(pd, SENDER_RESPONSE_TIME); + } else if (pd->send_dr_swap) { + pd->send_dr_swap = false; + ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG); + if (ret) { + dev_err(&pd->dev, "Error sending DR Swap\n"); + usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); + break; + } + + pd->current_state = PE_DRS_SEND_DR_SWAP; + kick_sm(pd, SENDER_RESPONSE_TIME); } else { - if (IS_DATA(rx_msg, MSG_VDM)) - handle_vdm_rx(pd, rx_msg); - else - handle_vdm_tx(pd); + handle_vdm_tx(pd); } break; case PE_SRC_TRANSITION_TO_DEFAULT: if (pd->vconn_enabled) regulator_disable(pd->vconn); - regulator_disable(pd->vbus); + if (pd->vbus_enabled) + regulator_disable(pd->vbus); if (pd->current_dr != DR_DFP) { extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0); @@ -1628,9 +1717,12 @@ static void usbpd_sm(struct work_struct *w) msleep(SRC_RECOVER_TIME); + pd->vbus_enabled = false; ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus\n"); + else + pd->vbus_enabled = true; if (pd->vconn_enabled) { ret = regulator_enable(pd->vconn); @@ -1665,23 +1757,48 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SNK_STARTUP); break; + case PE_SNK_DISCOVERY: + if (!rx_msg) { + if (pd->vbus_present) + usbpd_set_state(pd, + PE_SNK_WAIT_FOR_CAPABILITIES); + + /* + * Handle disconnection in the middle of PR_Swap. + * Since in psy_changed() if pd->in_pr_swap is true + * we ignore the typec_mode==NONE change since that is + * expected to happen. However if the cable really did + * get disconnected we need to check for it here after + * waiting for VBUS presence times out. + */ + if (!pd->typec_mode) { + pd->current_pr = PR_NONE; + kick_sm(pd, 0); + } + + break; + } + /* else fall-through */ + case PE_SNK_WAIT_FOR_CAPABILITIES: + pd->in_pr_swap = false; + if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) { val.intval = 0; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); - /* save the PDOs so userspace can further evaluate */ memcpy(&pd->received_pdos, rx_msg->payload, sizeof(pd->received_pdos)); pd->src_cap_id++; usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); + + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); } else if (pd->hard_reset_count < 3) { usbpd_set_state(pd, PE_SNK_HARD_RESET); } else if (pd->pd_connected) { @@ -1821,7 +1938,6 @@ static void usbpd_sm(struct work_struct *w) } dr_swap(pd); - kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); } else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) { /* lock in current mode */ set_power_role(pd, pd->current_pr); @@ -1863,37 +1979,42 @@ static void usbpd_sm(struct work_struct *w) } vconn_swap(pd); + } else if (IS_DATA(rx_msg, MSG_VDM)) { + handle_vdm_rx(pd, rx_msg); + } else if (pd->send_pr_swap) { + pd->send_pr_swap = false; + ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG); + if (ret) { + dev_err(&pd->dev, "Error sending PR Swap\n"); + usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); + break; + } + + pd->current_state = PE_PRS_SNK_SRC_SEND_SWAP; + kick_sm(pd, SENDER_RESPONSE_TIME); + } else if (pd->send_dr_swap) { + pd->send_dr_swap = false; + ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG); + if (ret) { + dev_err(&pd->dev, "Error sending DR Swap\n"); + usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); + break; + } + + pd->current_state = PE_DRS_SEND_DR_SWAP; + kick_sm(pd, SENDER_RESPONSE_TIME); } else { - if (IS_DATA(rx_msg, MSG_VDM)) - handle_vdm_rx(pd, rx_msg); - else - handle_vdm_tx(pd); + handle_vdm_tx(pd); } break; case PE_SNK_TRANSITION_TO_DEFAULT: - val.intval = 0; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - - if (pd->vbus_present) { - usbpd_set_state(pd, PE_SNK_STARTUP); - } else { - /* Hard reset and VBUS didn't come back? */ - power_supply_get_property(pd->usb_psy, - POWER_SUPPLY_PROP_TYPEC_MODE, &val); - if (val.intval == POWER_SUPPLY_TYPEC_NONE) { - pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; - kick_sm(pd, 0); - } - } + usbpd_set_state(pd, PE_SNK_STARTUP); break; case PE_SRC_SOFT_RESET: case PE_SNK_SOFT_RESET: - /* Reset protocol layer */ - pd->tx_msgid = 0; - pd->rx_msgid = -1; + pd_reset_protocol(pd); ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { @@ -1969,7 +2090,10 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = true; pd->in_explicit_contract = false; - regulator_disable(pd->vbus); + if (pd->vbus_enabled) { + regulator_disable(pd->vbus); + pd->vbus_enabled = false; + } /* PE_PRS_SRC_SNK_Assert_Rd */ pd->current_pr = PR_SINK; @@ -2024,6 +2148,8 @@ static void usbpd_sm(struct work_struct *w) ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus\n"); + else + pd->vbus_enabled = true; msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */ @@ -2134,6 +2260,21 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) pd->psy_type = val.intval; + /* + * For sink hard reset, state machine needs to know when VBUS changes + * - when in PE_SNK_TRANSITION_TO_DEFAULT, notify when VBUS falls + * - when in PE_SNK_DISCOVERY, notify when VBUS rises + */ + if (typec_mode && ((!pd->vbus_present && + pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) || + (pd->vbus_present && pd->current_state == PE_SNK_DISCOVERY))) { + usbpd_dbg(&pd->dev, "hard reset: typec mode:%d present:%d\n", + typec_mode, pd->vbus_present); + pd->typec_mode = typec_mode; + kick_sm(pd, 0); + return 0; + } + if (pd->typec_mode == typec_mode) return 0; @@ -2151,32 +2292,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) return 0; } - /* - * Workaround for PMIC HW bug. - * - * During hard reset when VBUS goes to 0 the CC logic - * will report this as a disconnection. In those cases - * it can be ignored, however the downside is that - * we can also happen to be in the SNK_Transition_to_default - * state due to a hard reset attempt even with a non-PD - * capable source, in which a physical disconnect may get - * masked. In that case, allow for the common case of - * disconnecting from an SDP. - * - * The less common case is a PD-capable SDP which will - * result in a hard reset getting treated like a - * disconnect. We can live with this until the HW bug - * is fixed: in which disconnection won't be reported - * on VBUS loss alone unless pullup is also removed - * from CC. - */ - if (pd->psy_type != POWER_SUPPLY_TYPE_USB && - pd->current_state == - PE_SNK_TRANSITION_TO_DEFAULT) { - usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n"); - return 0; - } - + pd->current_pr = PR_NONE; break; /* Sink states */ @@ -2185,8 +2301,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) case POWER_SUPPLY_TYPEC_SOURCE_HIGH: usbpd_info(&pd->dev, "Type-C Source (%s) connected\n", src_current(typec_mode)); + + if (pd->current_pr == PR_SINK) + return 0; + pd->current_pr = PR_SINK; - pd->in_pr_swap = false; break; /* Source states */ @@ -2195,8 +2314,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) usbpd_info(&pd->dev, "Type-C Sink%s connected\n", typec_mode == POWER_SUPPLY_TYPEC_SINK ? "" : " (powered)"); + + if (pd->current_pr == PR_SRC) + return 0; + pd->current_pr = PR_SRC; - pd->in_pr_swap = false; break; case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY: @@ -2216,6 +2338,198 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) return 0; } +static enum dual_role_property usbpd_dr_properties[] = { + DUAL_ROLE_PROP_SUPPORTED_MODES, + DUAL_ROLE_PROP_MODE, + DUAL_ROLE_PROP_PR, + DUAL_ROLE_PROP_DR, +}; + +static int usbpd_dr_get_property(struct dual_role_phy_instance *dual_role, + enum dual_role_property prop, unsigned int *val) +{ + struct usbpd *pd = dual_role_get_drvdata(dual_role); + + if (!pd) + return -ENODEV; + + switch (prop) { + case DUAL_ROLE_PROP_MODE: + /* For now associate UFP/DFP with data role only */ + if (pd->current_dr == DR_UFP) + *val = DUAL_ROLE_PROP_MODE_UFP; + else if (pd->current_dr == DR_DFP) + *val = DUAL_ROLE_PROP_MODE_DFP; + else + *val = DUAL_ROLE_PROP_MODE_NONE; + break; + case DUAL_ROLE_PROP_PR: + if (pd->current_pr == PR_SRC) + *val = DUAL_ROLE_PROP_PR_SRC; + else if (pd->current_pr == PR_SINK) + *val = DUAL_ROLE_PROP_PR_SNK; + else + *val = DUAL_ROLE_PROP_PR_NONE; + break; + case DUAL_ROLE_PROP_DR: + if (pd->current_dr == DR_UFP) + *val = DUAL_ROLE_PROP_DR_DEVICE; + else if (pd->current_dr == DR_DFP) + *val = DUAL_ROLE_PROP_DR_HOST; + else + *val = DUAL_ROLE_PROP_DR_NONE; + break; + default: + usbpd_warn(&pd->dev, "unsupported property %d\n", prop); + return -ENODATA; + } + + return 0; +} + +static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role, + enum dual_role_property prop, const unsigned int *val) +{ + struct usbpd *pd = dual_role_get_drvdata(dual_role); + bool do_swap = false; + + if (!pd) + return -ENODEV; + + switch (prop) { + case DUAL_ROLE_PROP_MODE: + usbpd_dbg(&pd->dev, "Setting mode to %d\n", *val); + + /* + * Forces disconnect on CC and re-establishes connection. + * This does not use PD-based PR/DR swap + */ + if (*val == DUAL_ROLE_PROP_MODE_UFP) + pd->forced_pr = POWER_SUPPLY_TYPEC_PR_SINK; + else if (*val == DUAL_ROLE_PROP_MODE_DFP) + pd->forced_pr = POWER_SUPPLY_TYPEC_PR_SOURCE; + + /* new mode will be applied in disconnect handler */ + set_power_role(pd, PR_NONE); + + /* wait until it takes effect */ + while (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE) + msleep(20); + + break; + + case DUAL_ROLE_PROP_DR: + usbpd_dbg(&pd->dev, "Setting data_role to %d\n", *val); + + if (*val == DUAL_ROLE_PROP_DR_HOST) { + if (pd->current_dr == DR_UFP) + do_swap = true; + } else if (*val == DUAL_ROLE_PROP_DR_DEVICE) { + if (pd->current_dr == DR_DFP) + do_swap = true; + } else { + usbpd_warn(&pd->dev, "setting data_role to 'none' unsupported\n"); + return -ENOTSUPP; + } + + if (do_swap) { + if (pd->current_state != PE_SRC_READY && + pd->current_state != PE_SNK_READY) { + usbpd_err(&pd->dev, "data_role swap not allowed: PD not in Ready state\n"); + return -EAGAIN; + } + + reinit_completion(&pd->swap_complete); + pd->send_dr_swap = true; + kick_sm(pd, 0); + + /* wait for operation to complete */ + if (!wait_for_completion_timeout(&pd->swap_complete, + msecs_to_jiffies(100))) { + usbpd_err(&pd->dev, "data_role swap timed out\n"); + return -ETIMEDOUT; + } + + if ((*val == DUAL_ROLE_PROP_DR_HOST && + pd->current_dr != DR_DFP) || + (*val == DUAL_ROLE_PROP_DR_DEVICE && + pd->current_dr != DR_UFP)) { + usbpd_err(&pd->dev, "incorrect state (%s) after data_role swap\n", + pd->current_dr == DR_DFP ? + "dfp" : "ufp"); + return -EPROTO; + } + } + + break; + + case DUAL_ROLE_PROP_PR: + usbpd_dbg(&pd->dev, "Setting power_role to %d\n", *val); + + if (*val == DUAL_ROLE_PROP_PR_SRC) { + if (pd->current_pr == PR_SINK) + do_swap = true; + } else if (*val == DUAL_ROLE_PROP_PR_SNK) { + if (pd->current_pr == PR_SRC) + do_swap = true; + } else { + usbpd_warn(&pd->dev, "setting power_role to 'none' unsupported\n"); + return -ENOTSUPP; + } + + if (do_swap) { + if (pd->current_state != PE_SRC_READY && + pd->current_state != PE_SNK_READY) { + usbpd_err(&pd->dev, "power_role swap not allowed: PD not in Ready state\n"); + return -EAGAIN; + } + + reinit_completion(&pd->swap_complete); + pd->send_pr_swap = true; + kick_sm(pd, 0); + + /* wait for operation to complete */ + if (!wait_for_completion_timeout(&pd->swap_complete, + msecs_to_jiffies(2000))) { + usbpd_err(&pd->dev, "power_role swap timed out\n"); + return -ETIMEDOUT; + } + + if ((*val == DUAL_ROLE_PROP_PR_SRC && + pd->current_pr != PR_SRC) || + (*val == DUAL_ROLE_PROP_PR_SNK && + pd->current_pr != PR_SINK)) { + usbpd_err(&pd->dev, "incorrect state (%s) after power_role swap\n", + pd->current_pr == PR_SRC ? + "source" : "sink"); + return -EPROTO; + } + } + break; + + default: + usbpd_warn(&pd->dev, "unsupported property %d\n", prop); + return -ENOTSUPP; + } + + return 0; +} + +static int usbpd_dr_prop_writeable(struct dual_role_phy_instance *dual_role, + enum dual_role_property prop) +{ + switch (prop) { + case DUAL_ROLE_PROP_MODE: + case DUAL_ROLE_PROP_DR: + case DUAL_ROLE_PROP_PR: + return 1; + default: + break; + } + + return 0; +} + static int usbpd_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usbpd *pd = dev_get_drvdata(dev); @@ -2698,6 +3012,30 @@ struct usbpd *usbpd_create(struct device *parent) pd->vconn_is_external = device_property_present(parent, "qcom,vconn-uses-external-source"); + /* + * Register the Android dual-role class (/sys/class/dual_role_usb/). + * The first instance should be named "otg_default" as that's what + * Android expects. + * Note this is different than the /sys/class/usbpd/ created above. + */ + pd->dr_desc.name = (num_pd_instances == 1) ? + "otg_default" : dev_name(&pd->dev); + pd->dr_desc.supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP; + pd->dr_desc.properties = usbpd_dr_properties; + pd->dr_desc.num_properties = ARRAY_SIZE(usbpd_dr_properties); + pd->dr_desc.get_property = usbpd_dr_get_property; + pd->dr_desc.set_property = usbpd_dr_set_property; + pd->dr_desc.property_is_writeable = usbpd_dr_prop_writeable; + + pd->dual_role = devm_dual_role_instance_register(&pd->dev, + &pd->dr_desc); + if (IS_ERR(pd->dual_role)) { + usbpd_err(&pd->dev, "could not register dual_role instance\n"); + goto unreg_psy; + } else { + pd->dual_role->drv_data = pd; + } + pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; list_add_tail(&pd->instance, &_usbpd); @@ -2705,6 +3043,7 @@ struct usbpd *usbpd_create(struct device *parent) spin_lock_init(&pd->rx_lock); INIT_LIST_HEAD(&pd->rx_q); INIT_LIST_HEAD(&pd->svid_handlers); + init_completion(&pd->swap_complete); /* force read initial power_supply values */ psy_changed(&pd->psy_nb, PSY_EVENT_PROP_CHANGED, pd->usb_psy); diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 0b9b60c3ca45..1a03b0d71a18 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -71,6 +71,9 @@ #define USB_PDPHY_RX_BUFFER 0x80 +#define USB_PDPHY_SEC_ACCESS 0xD0 +#define USB_PDPHY_TRIM_3 0xF3 + /* VDD regulator */ #define VDD_PDPHY_VOL_MIN 3088000 /* uV */ #define VDD_PDPHY_VOL_MAX 3088000 /* uV */ @@ -673,6 +676,9 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data) if (ret) goto done; + /* ack to change ownership of rx buffer back to PDPHY RX HW */ + pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0); + if (((buf[0] & 0xf) == PD_MSG_BIST) && size >= 5) { /* BIST */ u8 mode = buf[5] >> 4; /* [31:28] of 1st data object */ @@ -689,9 +695,6 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data) if (pdphy->msg_rx_cb) pdphy->msg_rx_cb(pdphy->usbpd, frame_type, buf, size + 1); - /* ack to change ownership of rx buffer back to PDPHY RX HW */ - pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0); - print_hex_dump_debug("rx msg:", DUMP_PREFIX_NONE, 32, 4, buf, size + 1, false); pdphy->rx_bytes += size + 1; @@ -806,6 +809,14 @@ static int pdphy_probe(struct platform_device *pdev) if (ret < 0) return ret; + ret = pdphy_reg_write(pdphy, USB_PDPHY_SEC_ACCESS, 0xA5); + if (ret) + return ret; + + ret = pdphy_reg_write(pdphy, USB_PDPHY_TRIM_3, 0x2); + if (ret) + return ret; + /* usbpd_create() could call back to us, so have __pdphy ready */ __pdphy = pdphy; diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 31c0cd86df4b..da6c68d43b53 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -1603,10 +1603,6 @@ int mdp3_validate_scale_config(struct mdp_bl_scale_data *data) pr_err("%s invalid bl_scale\n", __func__); return -EINVAL; } - if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) { - pr_err("%s invalid bl_min_lvl\n", __func__); - return -EINVAL; - } return 0; } @@ -1810,9 +1806,7 @@ static int mdp3_bl_scale_config(struct msm_fb_data_type *mfd, mutex_lock(&mfd->bl_lock); curr_bl = mfd->bl_level; mfd->bl_scale = data->scale; - mfd->bl_min_lvl = data->min_lvl; - pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale, - mfd->bl_min_lvl); + pr_debug("update scale = %d\n", mfd->bl_scale); /* update current backlight to use new scaling*/ mdss_fb_set_backlight(mfd, curr_bl); diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 5a24a1995af9..5a6d7bc3ff78 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -164,6 +164,7 @@ enum mdss_hw_quirk { MDSS_QUIRK_NEED_SECURE_MAP, MDSS_QUIRK_SRC_SPLIT_ALWAYS, MDSS_QUIRK_MMSS_GDSC_COLLAPSE, + MDSS_QUIRK_MDP_CLK_SET_RATE, MDSS_QUIRK_MAX, }; @@ -289,6 +290,7 @@ struct mdss_data_type { bool en_svs_high; u32 max_mdp_clk_rate; struct mdss_util_intf *mdss_util; + unsigned long mdp_clk_rate; struct platform_device *pdev; struct dss_io_data mdss_io; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index 5ad51dd23f3b..d3eb3db48eb7 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -197,7 +197,7 @@ static struct mdp_input_layer *__create_layer_list( struct mdp_input_layer32 *layer_list32, u32 layer_count) { - int i, ret; + int i, ret = 0; u32 buffer_size; struct mdp_input_layer *layer, *layer_list; struct mdp_input_layer32 *layer32; diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c index fa78bd0166ea..76671b539aa7 100644 --- a/drivers/video/fbdev/msm/mdss_dba_utils.c +++ b/drivers/video/fbdev/msm/mdss_dba_utils.c @@ -323,7 +323,9 @@ static void mdss_dba_utils_dba_cb(void *data, enum msm_dba_callback_event event) if (!ret) { hdmi_edid_parser(udata->edid_data); hdmi_edid_get_audio_blk(udata->edid_data, &blk); - udata->ops.set_audio_block(udata->dba_data, + if (udata->ops.set_audio_block) + udata->ops.set_audio_block( + udata->dba_data, sizeof(blk), &blk); } else { pr_err("failed to get edid%d\n", ret); diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index 8663797f1730..6b455e0f1e6f 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -244,23 +244,19 @@ static ssize_t panel_debug_base_reg_read(struct file *file, mdss_dsi_panel_cmd_read(ctrl_pdata, panel_reg[0], panel_reg[1], NULL, rx_buf, dbg->cnt); - len = snprintf(panel_reg_buf, reg_buf_len, "0x%02zx: ", dbg->off); - if (len < 0) - goto read_reg_fail; + len = scnprintf(panel_reg_buf, reg_buf_len, "0x%02zx: ", dbg->off); for (i = 0; (len < reg_buf_len) && (i < ctrl_pdata->rx_len); i++) len += scnprintf(panel_reg_buf + len, reg_buf_len - len, "0x%02x ", rx_buf[i]); - panel_reg_buf[len - 1] = '\n'; + if (len) + panel_reg_buf[len - 1] = '\n'; if (mdata->debug_inf.debug_enable_clock) mdata->debug_inf.debug_enable_clock(0); - if (len < 0 || len >= sizeof(panel_reg_buf)) - return 0; - - if ((count < sizeof(panel_reg_buf)) + if ((count < reg_buf_len) || (copy_to_user(user_buf, panel_reg_buf, len))) goto read_reg_fail; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index b7561e49955b..132dc0e028ae 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -45,6 +45,8 @@ #define VDDA_UA_ON_LOAD 100000 /* uA units */ #define VDDA_UA_OFF_LOAD 100 /* uA units */ +#define DP_CRYPTO_CLK_RATE_KHZ 337500 + struct mdss_dp_attention_node { u32 vdo; struct list_head list; @@ -208,9 +210,9 @@ static int mdss_dp_get_dt_clk_data(struct device *dev, &ctrl_power_data->clk_config[ctrl_clk_index]; strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); ctrl_clk_index++; - if (!strcmp(clk_name, "ctrl_link_clk")) - clk->type = DSS_CLK_PCLK; - else if (!strcmp(clk_name, "ctrl_pixel_clk")) + if (!strcmp(clk_name, "ctrl_link_clk") || + !strcmp(clk_name, "ctrl_pixel_clk") || + !strcmp(clk_name, "ctrl_crypto_clk")) clk->type = DSS_CLK_PCLK; else clk->type = DSS_CLK_AHB; @@ -1089,6 +1091,23 @@ exit: return ret; } +static void mdss_dp_set_clock_rate(struct mdss_dp_drv_pdata *dp, + char *name, u32 rate) +{ + u32 num = dp->power_data[DP_CTRL_PM].num_clk; + struct dss_clk *cfg = dp->power_data[DP_CTRL_PM].clk_config; + + while (num && strcmp(cfg->clk_name, name)) { + num--; + cfg++; + } + + if (num) + cfg->rate = rate; + else + pr_err("%s clock could not be set with rate %d\n", name, rate); +} + /** * mdss_dp_enable_mainlink_clocks() - enables Display Port main link clocks * @dp: Display Port Driver data @@ -1099,12 +1118,14 @@ static int mdss_dp_enable_mainlink_clocks(struct mdss_dp_drv_pdata *dp) { int ret = 0; - dp->power_data[DP_CTRL_PM].clk_config[0].rate = - ((dp->link_rate * DP_LINK_RATE_MULTIPLIER) / 1000);/* KHz */ + mdss_dp_set_clock_rate(dp, "ctrl_link_clk", + (dp->link_rate * DP_LINK_RATE_MULTIPLIER) / DP_KHZ_TO_HZ); + + mdss_dp_set_clock_rate(dp, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ); dp->pixel_rate = dp->panel_data.panel_info.clk_rate; - dp->power_data[DP_CTRL_PM].clk_config[3].rate = - (dp->pixel_rate / 1000);/* KHz */ + mdss_dp_set_clock_rate(dp, "ctrl_pixel_clk", + (dp->pixel_rate / DP_KHZ_TO_HZ)); ret = mdss_dp_clk_ctrl(dp, DP_CTRL_PM, true); if (ret) { @@ -1286,12 +1307,8 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) link_training: dp_drv->power_on = true; - if (-EAGAIN == mdss_dp_train_main_link(dp_drv)) { - mutex_unlock(&dp_drv->train_mutex); - - mdss_dp_link_retraining(dp_drv); - return 0; - } + while (-EAGAIN == mdss_dp_train_main_link(dp_drv)) + pr_debug("MAIN LINK TRAINING RETRY\n"); dp_drv->cont_splash = 0; @@ -1622,13 +1639,27 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work) struct mdss_dp_drv_pdata *dp; struct delayed_work *dw = to_delayed_work(work); struct hdcp_ops *ops; + unsigned char *base; int rc = 0; + u32 hdcp_auth_state; dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work); + base = dp->base; + + hdcp_auth_state = (dp_read(base + DP_HDCP_STATUS) >> 20) & 0x3; + + pr_debug("hdcp auth state %d\n", hdcp_auth_state); ops = dp->hdcp.ops; switch (dp->hdcp_status) { + case HDCP_STATE_AUTHENTICATING: + pr_debug("start authenticaton\n"); + + if (dp->hdcp.ops && dp->hdcp.ops->authenticate) + rc = dp->hdcp.ops->authenticate(dp->hdcp.data); + + break; case HDCP_STATE_AUTHENTICATED: pr_debug("hdcp authenticated\n"); dp->hdcp.auth_state = true; @@ -1636,7 +1667,7 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work) case HDCP_STATE_AUTH_FAIL: dp->hdcp.auth_state = false; - if (dp->power_on) { + if (dp->alt_mode.dp_status.hpd_high && dp->power_on) { pr_debug("Reauthenticating\n"); if (ops && ops->reauthenticate) { rc = ops->reauthenticate(dp->hdcp.data); @@ -1664,7 +1695,8 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status) dp->hdcp_status = status; - queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4); + if (dp->alt_mode.dp_status.hpd_high) + queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4); } static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata) @@ -1927,20 +1959,28 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, rc = mdss_dp_on(pdata); break; case MDSS_EVENT_PANEL_ON: + mdss_dp_ack_state(dp, true); + mdss_dp_update_hdcp_info(dp); - if (dp->hdcp.ops && dp->hdcp.ops->authenticate) - rc = dp->hdcp.ops->authenticate(dp->hdcp.data); + if (dp_is_hdcp_enabled(dp)) { + cancel_delayed_work(&dp->hdcp_cb_work); - mdss_dp_ack_state(dp, true); + dp->hdcp_status = HDCP_STATE_AUTHENTICATING; + queue_delayed_work(dp->workq, + &dp->hdcp_cb_work, HZ / 2); + } break; case MDSS_EVENT_PANEL_OFF: rc = mdss_dp_off(pdata); break; case MDSS_EVENT_BLANK: - if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) { - flush_delayed_work(&dp->hdcp_cb_work); - dp->hdcp.ops->off(dp->hdcp.data); + if (dp_is_hdcp_enabled(dp)) { + dp->hdcp_status = HDCP_STATE_INACTIVE; + + cancel_delayed_work(&dp->hdcp_cb_work); + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); } mdss_dp_mainlink_push_idle(pdata); @@ -2152,8 +2192,9 @@ static void mdss_dp_event_work(struct work_struct *work) 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, 0x0, 0x0); + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); break; case EV_USBPD_DP_CONFIGURE: config = mdss_dp_usbpd_gen_config_pkt(dp); @@ -2188,9 +2229,6 @@ irqreturn_t dp_isr(int irq, void *ptr) isr1 &= ~mask1; /* remove masks bit */ - pr_debug("isr=%x mask=%x isr2=%x\n", - isr1, mask1, isr2); - ack = isr1 & EDP_INTR_STATUS1; ack <<= 1; /* ack bits */ ack |= mask1; @@ -2552,7 +2590,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, dp_drv->alt_mode.dp_cap.response = *vdos; mdss_dp_usbpd_ext_capabilities(&dp_drv->alt_mode.dp_cap); dp_drv->alt_mode.current_state |= DISCOVER_MODES_DONE; - dp_send_events(dp_drv, EV_USBPD_ENTER_MODE); + if (dp_drv->alt_mode.dp_cap.s_port & BIT(0)) + dp_send_events(dp_drv, EV_USBPD_ENTER_MODE); break; case USBPD_SVDM_ENTER_MODE: dp_drv->alt_mode.current_state |= ENTER_MODE_DONE; @@ -2574,7 +2613,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, if (!(dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)) { dp_drv->alt_mode.current_state |= DP_STATUS_DONE; - dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE); + if (dp_drv->alt_mode.dp_status.c_port & BIT(1)) + dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE); } break; case DP_VDM_CONFIGURE: @@ -2598,9 +2638,10 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (dp_drv->alt_mode.dp_status.hpd_irq) { pr_debug("Attention: hpd_irq high\n"); - if (dp_drv->power_on && dp_drv->hdcp.ops && - dp_drv->hdcp.ops->cp_irq) - dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data); + if (dp_drv->hdcp.ops && 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; @@ -2611,6 +2652,12 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (!dp_drv->alt_mode.dp_status.hpd_high) { pr_debug("Attention: HPD low\n"); + + if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->off) { + cancel_delayed_work(&dp_drv->hdcp_cb_work); + dp_drv->hdcp.ops->off(dp_drv->hdcp.data); + } + mdss_dp_update_cable_status(dp_drv, false); mdss_dp_notify_clients(dp_drv, false); pr_debug("Attention: Notified clients\n"); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index 04abe9221acc..dc84694f2238 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -228,6 +228,7 @@ struct dp_alt_mode { #define DP_LINK_RATE_MAX DP_LINK_RATE_540 #define DP_LINK_RATE_MULTIPLIER 27000000 +#define DP_KHZ_TO_HZ 1000 #define DP_MAX_PIXEL_CLK_KHZ 675000 struct downstream_port_config { /* Byte 02205h */ diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c index 79cd94cfbe88..73b9ad65482f 100644 --- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c @@ -23,6 +23,8 @@ #include "mdss_hdcp.h" #include "mdss_dp_util.h" +struct dp_hdcp2p2_ctrl; + enum dp_hdcp2p2_sink_status { SINK_DISCONNECTED, SINK_CONNECTED @@ -33,9 +35,21 @@ enum dp_auth_status { DP_HDCP_AUTH_STATUS_SUCCESS }; +struct dp_hdcp2p2_int_set { + u32 interrupt; + char *name; + void (*func)(struct dp_hdcp2p2_ctrl *ctrl); +}; + +struct dp_hdcp2p2_interrupts { + u32 reg; + struct dp_hdcp2p2_int_set *int_set; +}; + struct dp_hdcp2p2_ctrl { atomic_t auth_state; enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */ + struct dp_hdcp2p2_interrupts *intr; struct hdcp_init_data init_data; struct mutex mutex; /* mutex to protect access to ctrl */ struct mutex msg_lock; /* mutex to protect access to msg buffer */ @@ -172,7 +186,10 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) queue_kthread_work(&ctrl->worker, &ctrl->status); break; case HDMI_HDCP_WKUP_CMD_LINK_POLL: - ctrl->polling = true; + if (ctrl->cp_irq_done) + queue_kthread_work(&ctrl->worker, &ctrl->recv_msg); + else + ctrl->polling = true; break; case HDMI_HDCP_WKUP_CMD_AUTHENTICATE: queue_kthread_work(&ctrl->worker, &ctrl->auth); @@ -211,6 +228,31 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); } +static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable) +{ + unsigned char *base = ctrl->init_data.core_io->base; + struct dp_hdcp2p2_interrupts *intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + u32 interrupts = 0; + + while (int_set && int_set->interrupt) { + interrupts |= int_set->interrupt; + int_set++; + } + + if (enable) + dp_write(base + intr->reg, + dp_read(base + intr->reg) | interrupts); + else + dp_write(base + intr->reg, + dp_read(base + intr->reg) & ~interrupts); + + intr++; + } +} + static void dp_hdcp2p2_off(void *input) { struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; @@ -221,6 +263,13 @@ static void dp_hdcp2p2_off(void *input) return; } + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + return; + } + + dp_hdcp2p2_set_interrupts(ctrl, false); + dp_hdcp2p2_reset(ctrl); flush_kthread_worker(&ctrl->worker); @@ -237,6 +286,8 @@ static int dp_hdcp2p2_authenticate(void *input) flush_kthread_worker(&ctrl->worker); + dp_hdcp2p2_set_interrupts(ctrl, true); + ctrl->sink_status = SINK_CONNECTED; atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); @@ -317,6 +368,8 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) return; } + dp_hdcp2p2_set_interrupts(ctrl, false); + /* notify DP about HDCP failure */ ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTH_FAIL); @@ -574,18 +627,6 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work) cdata.context = ctrl->lib_ctx; - ctrl->sink_rx_status = 0; - rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data, - &ctrl->sink_rx_status); - - if (rc) { - pr_err("failed to read rx status\n"); - - cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED; - atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); - goto exit; - } - if (ctrl->sink_rx_status & ctrl->abort_mask) { if (ctrl->sink_rx_status & BIT(3)) pr_err("reauth_req set by sink\n"); @@ -636,6 +677,7 @@ static void dp_hdcp2p2_auth_work(struct kthread_work *work) static int dp_hdcp2p2_cp_irq(void *input) { + int rc = 0; struct dp_hdcp2p2_ctrl *ctrl = input; if (!ctrl) { @@ -643,9 +685,67 @@ static int dp_hdcp2p2_cp_irq(void *input) return -EINVAL; } + ctrl->sink_rx_status = 0; + rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data, + &ctrl->sink_rx_status); + if (rc) { + pr_err("failed to read rx status\n"); + goto error; + } + + pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status); + + if (!ctrl->sink_rx_status) { + pr_debug("not a hdcp 2.2 irq\n"); + rc = -EINVAL; + goto error; + } + queue_kthread_work(&ctrl->worker, &ctrl->link); return 0; +error: + return rc; +} + +static int dp_hdcp2p2_isr(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + int rc = 0; + struct dss_io_data *io; + struct dp_hdcp2p2_interrupts *intr; + u32 hdcp_int_val; + + if (!ctrl || !ctrl->init_data.core_io) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + io = ctrl->init_data.core_io; + intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + + hdcp_int_val = dp_read(io->base + intr->reg); + + while (int_set && int_set->interrupt) { + if (hdcp_int_val & (int_set->interrupt >> 2)) { + pr_debug("%s\n", int_set->name); + + if (int_set->func) + int_set->func(ctrl); + + dp_write(io->base + intr->reg, hdcp_int_val | + (int_set->interrupt >> 1)); + } + int_set++; + } + intr++; + } +end: + return rc; } void dp_hdcp2p2_deinit(void *input) @@ -679,6 +779,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) int rc; struct dp_hdcp2p2_ctrl *ctrl; static struct hdcp_ops ops = { + .isr = dp_hdcp2p2_isr, .reauthenticate = dp_hdcp2p2_reauthenticate, .authenticate = dp_hdcp2p2_authenticate, .feature_supported = dp_hdcp2p2_feature_supported, @@ -689,7 +790,22 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) static struct hdcp_client_ops client_ops = { .wakeup = dp_hdcp2p2_wakeup, }; - + static struct dp_hdcp2p2_int_set int_set1[] = { + {BIT(17), "authentication successful", 0}, + {BIT(20), "authentication failed", 0}, + {BIT(24), "encryption enabled", 0}, + {BIT(27), "encryption disabled", 0}, + {0}, + }; + static struct dp_hdcp2p2_int_set int_set2[] = { + {BIT(2), "key fifo underflow", 0}, + {0}, + }; + static struct dp_hdcp2p2_interrupts intr[] = { + {DP_INTR_STATUS2, int_set1}, + {DP_INTR_STATUS3, int_set2}, + {0} + }; static struct hdcp_txmtr_ops txmtr_ops; struct hdcp_register_data register_data = {0}; @@ -714,6 +830,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) } ctrl->sink_status = SINK_DISCONNECTED; + ctrl->intr = intr; atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c index 86edc4492599..10962548c3c5 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.c +++ b/drivers/video/fbdev/msm/mdss_dp_util.c @@ -266,8 +266,7 @@ void mdss_dp_sw_config_msa(struct dss_io_data *ctrl_io, mvid = (pixel_m & 0xFFFF) * 5; nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); - if (lrate == DP_LINK_RATE_540) - nvid = nvid * 2; + pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid); writel_relaxed(mvid, ctrl_io->base + DP_SOFTWARE_MVID); writel_relaxed(nvid, ctrl_io->base + DP_SOFTWARE_NVID); diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index 4b28d98177be..82e9f9417662 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -185,6 +185,7 @@ #define DP_HDCP_RCVPORT_DATA6 (0x0C4) #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028) #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004) #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008) #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 8dccab8a81be..423a15d82679 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1283,7 +1283,11 @@ int mdss_dsi_switch_mode(struct mdss_panel_data *pdata, int mode) MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON); if (dsi_ctrl_setup_needed) mdss_dsi_ctrl_setup(ctrl_pdata); + + ATRACE_BEGIN("switch_cmds"); ctrl_pdata->switch_mode(pdata, mode); + ATRACE_END("switch_cmds"); + mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle, MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF); @@ -1733,6 +1737,38 @@ int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata) return ret; } +static void __mdss_dsi_mask_dfps_errors(struct mdss_dsi_ctrl_pdata *ctrl, + bool mask) +{ + u32 data = 0; + + /* + * Assumption is that the DSI clocks will be enabled + * when this API is called from dfps thread + */ + if (mask) { + /* mask FIFO underflow and PLL unlock bits */ + mdss_dsi_set_reg(ctrl, 0x10c, 0x7c000000, 0x7c000000); + } else { + data = MIPI_INP((ctrl->ctrl_base) + 0x0120); + if (data & BIT(16)) { + pr_debug("pll unlocked: 0x%x\n", data); + /* clear PLL unlock bit */ + MIPI_OUTP((ctrl->ctrl_base) + 0x120, BIT(16)); + } + + data = MIPI_INP((ctrl->ctrl_base) + 0x00c); + if (data & 0x88880000) { + pr_debug("dsi fifo underflow: 0x%x\n", data); + /* clear DSI FIFO underflow and empty */ + MIPI_OUTP((ctrl->ctrl_base) + 0x00c, 0x99990000); + } + + /* restore FIFO underflow and PLL unlock bits */ + mdss_dsi_set_reg(ctrl, 0x10c, 0x7c000000, 0x0); + } +} + static void __mdss_dsi_update_video_mode_total(struct mdss_panel_data *pdata, int new_fps) { @@ -1935,7 +1971,6 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata, struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL; struct mdss_panel_info *pinfo, *spinfo; int rc = 0; - u32 data; if (pdata == NULL) { pr_err("%s Invalid pdata\n", __func__); @@ -2055,12 +2090,9 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata, MIPI_OUTP((sctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_CTRL, 0x00); - data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0120); - if (data & BIT(16)) { - pr_debug("pll unlocked: 0x%x\n", data); - /* clear PLL unlock bit */ - MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x120, BIT(16)); - } + __mdss_dsi_mask_dfps_errors(ctrl_pdata, false); + if (sctrl_pdata) + __mdss_dsi_mask_dfps_errors(sctrl_pdata, false); /* Move the mux clocks to main byte and pixel clocks */ rc = clk_set_parent(ctrl_pdata->mux_byte_clk, @@ -2188,6 +2220,9 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) __mdss_dsi_update_video_mode_total(pdata, new_fps); } else if (pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { /* Clock update method */ + + __mdss_dsi_mask_dfps_errors(ctrl_pdata, true); + if (phy_rev == DSI_PHY_REV_20) { rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, new_fps); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 3a347681f434..6c840c8459ae 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -692,6 +692,8 @@ void mdss_dsi_dsc_config(struct mdss_dsi_ctrl_pdata *ctrl, struct dsc_desc *dsc); void mdss_dsi_dfps_config_8996(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_set_burst_mode(struct mdss_dsi_ctrl_pdata *ctrl); +void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off, + u32 mask, u32 val); static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module) { diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 5f8b45413e32..d445f95924ef 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -134,7 +134,7 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev, } } -static void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off, +void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off, u32 mask, u32 val) { u32 data; @@ -2978,7 +2978,7 @@ bool mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl, bool print_en) static bool mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl) { - u32 status, isr; + u32 status; unsigned char *base; bool ret = false; @@ -2990,17 +2990,7 @@ static bool mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl) if (status & 0xcccc4409) { MIPI_OUTP(base + 0x000c, status); - /* - * When dynamic refresh operation is under progress, it is - * expected to have FIFO underflow error sometimes. In such - * cases, do not trigger the underflow recovery process and - * avoid printing the error status on console. - */ - isr = MIPI_INP(ctrl->ctrl_base + 0x0110); - if (isr & DSI_INTR_DYNAMIC_REFRESH_MASK) - status &= ~(0x88880000); - else - pr_err("%s: status=%x\n", __func__, status); + pr_err("%s: status=%x\n", __func__, status); if (status & 0x44440000) {/* DLNx_HS_FIFO_OVERFLOW */ dsi_send_events(ctrl, DSI_EV_DLNx_FIFO_OVERFLOW, 0); @@ -3048,6 +3038,10 @@ static bool mdss_dsi_clk_status(struct mdss_dsi_ctrl_pdata *ctrl) if (status & 0x10000) { /* DSI_CLK_PLL_UNLOCKED */ MIPI_OUTP(base + 0x0120, status); + /* If PLL unlock is masked, do not report error */ + if (MIPI_INP(base + 0x10c) & BIT(28)) + return false; + dsi_send_events(ctrl, DSI_EV_PLL_UNLOCKED, 0); pr_err("%s: status=%x\n", __func__, status); ret = true; @@ -3134,6 +3128,11 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); + if (isr & DSI_INTR_ERROR) { + MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97); + mdss_dsi_error(ctrl); + } + if (isr & DSI_INTR_BTA_DONE) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x96); spin_lock(&ctrl->mdp_lock); @@ -3158,11 +3157,6 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) spin_unlock(&ctrl->mdp_lock); } - if (isr & DSI_INTR_ERROR) { - MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97); - mdss_dsi_error(ctrl); - } - if (isr & DSI_INTR_VIDEO_DONE) { spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM); diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 7c36bb627043..8fbf2544f487 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -1960,6 +1960,9 @@ static int mdss_dsi_parse_panel_features(struct device_node *np, pinfo->panel_ack_disabled = pinfo->sim_panel_mode ? 1 : of_property_read_bool(np, "qcom,panel-ack-disabled"); + pinfo->allow_phy_power_off = of_property_read_bool(np, + "qcom,panel-allow-phy-poweroff"); + mdss_dsi_parse_esd_params(np, ctrl); if (pinfo->panel_ack_disabled && pinfo->esd_check_enabled) { diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index d528305af798..98ca6c3da20b 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1134,10 +1134,10 @@ static int mdss_fb_probe(struct platform_device *pdev) mfd->bl_level = 0; mfd->bl_scale = 1024; - mfd->bl_min_lvl = 30; mfd->ad_bl_level = 0; mfd->fb_imgType = MDP_RGBA_8888; mfd->calib_mode_bl = 0; + mfd->unset_bl_level = U32_MAX; mfd->pdev = pdev; @@ -1511,27 +1511,22 @@ static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl) u32 temp = *bl_lvl; pr_debug("input = %d, scale = %d\n", temp, mfd->bl_scale); - if (temp >= mfd->bl_min_lvl) { - if (temp > mfd->panel_info->bl_max) { - pr_warn("%s: invalid bl level\n", + if (temp > mfd->panel_info->bl_max) { + pr_warn("%s: invalid bl level\n", __func__); - temp = mfd->panel_info->bl_max; - } - if (mfd->bl_scale > 1024) { - pr_warn("%s: invalid bl scale\n", + temp = mfd->panel_info->bl_max; + } + if (mfd->bl_scale > 1024) { + pr_warn("%s: invalid bl scale\n", __func__); - mfd->bl_scale = 1024; - } - /* - * bl_scale is the numerator of - * scaling fraction (x/1024) - */ - temp = (temp * mfd->bl_scale) / 1024; - - /*if less than minimum level, use min level*/ - if (temp < mfd->bl_min_lvl) - temp = mfd->bl_min_lvl; + mfd->bl_scale = 1024; } + /* + * bl_scale is the numerator of + * scaling fraction (x/1024) + */ + temp = (temp * mfd->bl_scale) / 1024; + pr_debug("output = %d\n", temp); (*bl_lvl) = temp; @@ -1553,7 +1548,7 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl) } else if (mdss_fb_is_power_on(mfd) && mfd->panel_info->panel_dead) { mfd->unset_bl_level = mfd->bl_level; } else { - mfd->unset_bl_level = 0; + mfd->unset_bl_level = U32_MAX; } pdata = dev_get_platdata(&mfd->pdev->dev); @@ -1597,7 +1592,7 @@ void mdss_fb_update_backlight(struct msm_fb_data_type *mfd) u32 temp; bool bl_notify = false; - if (!mfd->unset_bl_level) + if (mfd->unset_bl_level == U32_MAX) return; mutex_lock(&mfd->bl_lock); if (!mfd->allow_bl_update) { @@ -1808,7 +1803,8 @@ static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd) */ if (IS_CALIB_MODE_BL(mfd)) mdss_fb_set_backlight(mfd, mfd->calib_mode_bl); - else if (!mfd->panel_info->mipi.post_init_delay) + else if ((!mfd->panel_info->mipi.post_init_delay) && + (mfd->unset_bl_level != U32_MAX)) mdss_fb_set_backlight(mfd, mfd->unset_bl_level); /* diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 56997e40d244..2eb6c6456f29 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -299,7 +299,6 @@ struct msm_fb_data_type { u32 ad_bl_level; u32 bl_level; u32 bl_scale; - u32 bl_min_lvl; u32 unset_bl_level; bool allow_bl_update; u32 bl_level_scaled; diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c index a8182c2f0e76..44a3ad993909 100644 --- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c +++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c @@ -10,13 +10,14 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + #include <linux/io.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/stat.h> #include <linux/iopoll.h> -#include <soc/qcom/scm.h> #include <linux/hdcp_qseecom.h> #include "mdss_hdcp.h" #include "mdss_fb.h" @@ -51,10 +52,6 @@ #define HDCP_POLL_SLEEP_US (20 * 1000) #define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100) -#define reg_set_data(x) \ - (hdcp_ctrl->init_data.sec_access ? reg_set->sec_data##x : \ - reg_set->data##x) - struct hdcp_sink_addr { char *name; u32 addr; @@ -72,6 +69,7 @@ struct hdcp_sink_addr_map { struct hdcp_sink_addr bksv; struct hdcp_sink_addr r0; struct hdcp_sink_addr bstatus; + struct hdcp_sink_addr cp_irq_status; struct hdcp_sink_addr ksv_fifo; struct hdcp_sink_addr v_h0; struct hdcp_sink_addr v_h1; @@ -82,7 +80,6 @@ struct hdcp_sink_addr_map { /* addresses to write to sink */ struct hdcp_sink_addr an; struct hdcp_sink_addr aksv; - struct hdcp_sink_addr rep; }; struct hdcp_int_set { @@ -125,23 +122,15 @@ struct hdcp_reg_set { u32 aksv_msb; u32 entropy_ctrl0; u32 entropy_ctrl1; - u32 sha_ctrl; u32 sec_sha_ctrl; + u32 sec_sha_data; u32 sha_status; - u32 data0; - u32 data1; u32 data2_0; u32 data3; u32 data4; u32 data5; u32 data6; - u32 data7; - u32 data8; - u32 data9; - u32 data10; - u32 data11; - u32 data12; u32 sec_data0; u32 sec_data1; @@ -154,20 +143,19 @@ struct hdcp_reg_set { u32 reset; u32 reset_bit; + + u32 repeater; }; #define HDCP_REG_SET_CLIENT_HDMI \ {HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \ HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \ HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \ - HDMI_HDCP_SHA_CTRL, HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \ - HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \ - HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, \ + HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA2_0, \ HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \ HDMI_HDCP_RCVPORT_DATA5, HDMI_HDCP_RCVPORT_DATA6, \ - HDMI_HDCP_RCVPORT_DATA7, HDMI_HDCP_RCVPORT_DATA8, \ - HDMI_HDCP_RCVPORT_DATA9, HDMI_HDCP_RCVPORT_DATA10, \ - HDMI_HDCP_RCVPORT_DATA11, HDMI_HDCP_RCVPORT_DATA12, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ @@ -176,17 +164,17 @@ struct hdcp_reg_set { HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \ - HDMI_HDCP_RESET, BIT(0)} + HDMI_HDCP_RESET, BIT(0), BIT(6)} #define HDCP_REG_SET_CLIENT_DP \ {DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \ DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \ DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \ - 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ - DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \ + DP_HDCP_SHA_STATUS, DP_HDCP_RCVPORT_DATA2_0, \ DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \ DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \ - 0, 0, 0, 0, 0, 0, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ @@ -195,21 +183,21 @@ struct hdcp_reg_set { HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \ - DP_SW_RESET, BIT(1)} + DP_SW_RESET, BIT(1), BIT(1)} #define HDCP_HDMI_SINK_ADDR_MAP \ {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \ - {"bstatus", 0x41, 2}, {"ksv-fifo", 0x43, 0}, {"v_h0", 0x20, 4}, \ - {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, {"v_h3", 0x2c, 4}, \ - {"v_h4", 0x30, 4}, {"an", 0x18, 8}, {"aksv", 0x10, 5}, \ - {"repeater", 0x00, 0} } + {"bstatus", 0x41, 2}, {"??", 0x0, 0}, {"ksv-fifo", 0x43, 0}, \ + {"v_h0", 0x20, 4}, {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, \ + {"v_h3", 0x2c, 4}, {"v_h4", 0x30, 4}, {"an", 0x18, 8}, \ + {"aksv", 0x10, 5} } #define HDCP_DP_SINK_ADDR_MAP \ {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \ - {"bstatus", 0x6802A, 2}, {"ksv-fifo", 0x6802A, 0}, \ - {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, {"v_h2", 0x6801C, 4}, \ - {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, {"an", 0x6800C, 8}, \ - {"aksv", 0x68007, 5}, {"repeater", 0x68028, 1} } + {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 2}, \ + {"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \ + {"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \ + {"an", 0x6800C, 8}, {"aksv", 0x68007, 5} } #define HDCP_HDMI_INT_SET \ {HDMI_HDCP_INT_CTRL, \ @@ -226,18 +214,22 @@ struct hdcp_reg_set { struct hdcp_1x_ctrl { u32 auth_retries; u32 tp_msgid; - u32 tz_hdcp; + bool sink_r0_ready; + bool reauth; enum hdcp_states hdcp_state; struct HDCP_V2V1_MSG_TOPOLOGY cached_tp; struct HDCP_V2V1_MSG_TOPOLOGY current_tp; struct delayed_work hdcp_auth_work; struct work_struct hdcp_int_work; struct completion r0_checked; + struct completion sink_r0_available; + struct completion sink_rep_ready; struct hdcp_init_data init_data; struct hdcp_ops *ops; struct hdcp_reg_set reg_set; struct hdcp_int_set int_set; struct hdcp_sink_addr_map sink_addr; + struct workqueue_struct *workq; }; const char *hdcp_state_name(enum hdcp_states hdcp_state) @@ -269,7 +261,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) struct dss_io_data *io; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -279,8 +271,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS); failure = (hdcp_ddc_status >> 16) & 0x1; nack0 = (hdcp_ddc_status >> 14) & 0x1; - DEV_DBG("%s: %s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", - __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); + pr_debug("%s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", + HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); if (failure == 0x1) { /* @@ -290,8 +282,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) * matches HDCP_DDC_RETRY_CNT. * Failure occured, let's clear it. */ - DEV_DBG("%s: %s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n", - __func__, HDCP_STATE_NAME, hdcp_ddc_status); + pr_debug("%s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n", + HDCP_STATE_NAME, hdcp_ddc_status); /* First, Disable DDC */ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, BIT(0)); @@ -305,18 +297,18 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS); hdcp_ddc_status = (hdcp_ddc_status >> 16) & BIT(0); if (hdcp_ddc_status == 0x0) - DEV_DBG("%s: %s: HDCP DDC Failure cleared\n", __func__, + pr_debug("%s: HDCP DDC Failure cleared\n", HDCP_STATE_NAME); else - DEV_WARN("%s: %s: Unable to clear HDCP DDC Failure", - __func__, HDCP_STATE_NAME); + pr_debug("%s: Unable to clear HDCP DDC Failure", + HDCP_STATE_NAME); /* Re-Enable HDCP DDC */ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, 0); } if (nack0 == 0x1) { - DEV_DBG("%s: %s: Before: HDMI_DDC_SW_STATUS=0x%08x\n", __func__, + pr_debug("%s: Before: HDMI_DDC_SW_STATUS=0x%08x\n", HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS)); /* Reset HDMI DDC software status */ DSS_REG_W_ND(io, HDMI_DDC_CTRL, @@ -331,7 +323,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) msleep(20); DSS_REG_W_ND(io, HDMI_DDC_CTRL, DSS_REG_R(io, HDMI_DDC_CTRL) & ~BIT(1)); - DEV_DBG("%s: %s: After: HDMI_DDC_SW_STATUS=0x%08x\n", __func__, + pr_debug("%s: After: HDMI_DDC_SW_STATUS=0x%08x\n", HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS)); } @@ -339,8 +331,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) failure = (hdcp_ddc_status >> 16) & BIT(0); nack0 = (hdcp_ddc_status >> 14) & BIT(0); - DEV_DBG("%s: %s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", - __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); + pr_debug("%s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", + HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); } /* reset_hdcp_ddc_failures */ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl) @@ -353,14 +345,14 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl) u32 timeout_count; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } io = hdcp_ctrl->init_data.core_io; if (!io->base) { - DEV_ERR("%s: core io not inititalized\n", __func__); - return; + pr_err("core io not inititalized\n"); + return; } /* Wait to be clean on DDC HW engine */ @@ -382,49 +374,16 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl) ddc_hw_not_ready = xfer_not_done || hw_not_done; - DEV_DBG("%s: %s: timeout count(%d): ddc hw%sready\n", - __func__, HDCP_STATE_NAME, timeout_count, + pr_debug("%s: timeout count(%d): ddc hw%sready\n", + HDCP_STATE_NAME, timeout_count, ddc_hw_not_ready ? " not " : " "); - DEV_DBG("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n", + pr_debug("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n", hdcp_ddc_status, ddc_hw_status); if (ddc_hw_not_ready) msleep(20); } while (ddc_hw_not_ready && --timeout_count); } /* hdcp_1x_hw_ddc_clean */ -static int hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp) -{ - int ret = 0; - - if (!is_scm_armv8()) { - ret = scm_call(SCM_SVC_HDCP, SCM_CMD_HDCP, (void *) req, - SCM_HDCP_MAX_REG * sizeof(struct scm_hdcp_req), - &resp, sizeof(*resp)); - } else { - struct scm_desc desc; - - desc.args[0] = req[0].addr; - desc.args[1] = req[0].val; - desc.args[2] = req[1].addr; - desc.args[3] = req[1].val; - desc.args[4] = req[2].addr; - desc.args[5] = req[2].val; - desc.args[6] = req[3].addr; - desc.args[7] = req[3].val; - desc.args[8] = req[4].addr; - desc.args[9] = req[4].val; - desc.arginfo = SCM_ARGS(10); - - ret = scm_call2(SCM_SIP_FNID(SCM_SVC_HDCP, SCM_CMD_HDCP), - &desc); - *resp = desc.ret[0]; - if (ret) - return ret; - } - - return ret; -} - static int hdcp_1x_load_keys(void *input) { int rc = 0; @@ -440,14 +399,14 @@ static int hdcp_1x_load_keys(void *input) if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io || !hdcp_ctrl->init_data.qfprom_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto end; } if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) && (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state)) { - DEV_ERR("%s: %s: invalid state. returning\n", __func__, + pr_err("%s: invalid state. returning\n", HDCP_STATE_NAME); rc = -EINVAL; goto end; @@ -470,7 +429,7 @@ static int hdcp_1x_load_keys(void *input) if (use_sw_keys) { if (hdcp1_set_keys(&aksv_msb, &aksv_lsb)) { - pr_err("%s: setting hdcp SW keys failed\n", __func__); + pr_err("setting hdcp SW keys failed\n"); rc = -EINVAL; goto end; } @@ -488,7 +447,7 @@ static int hdcp_1x_load_keys(void *input) aksv_msb = DSS_REG_R(qfprom_io, ksv_msb_addr); } - DEV_DBG("%s: %s: AKSV=%02x%08x\n", __func__, HDCP_STATE_NAME, + pr_debug("%s: AKSV=%02x%08x\n", HDCP_STATE_NAME, aksv_msb, aksv_lsb); aksv[0] = aksv_lsb & 0xFF; @@ -499,7 +458,7 @@ static int hdcp_1x_load_keys(void *input) /* check there are 20 ones in AKSV */ if (hdcp_1x_count_one(aksv, 5) != 20) { - DEV_ERR("%s: AKSV bit count failed\n", __func__); + pr_err("AKSV bit count failed\n"); rc = -EINVAL; goto end; } @@ -527,6 +486,7 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl, u8 *buf, bool realign) { u32 rc = 0; + int const max_size = 15, edid_read_delay_us = 20; struct hdmi_tx_ddc_data ddc_data; if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { @@ -546,21 +506,34 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl, rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); if (rc) - DEV_ERR("%s: %s: %s read failed\n", __func__, + pr_err("%s: %s read failed\n", HDCP_STATE_NAME, sink->name); } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { - struct edp_cmd cmd = {0}; + int size = sink->len; - cmd.read = 1; - cmd.addr = sink->addr; - cmd.out_buf = buf; - cmd.len = sink->len; + do { + struct edp_cmd cmd = {0}; + int read_size; - rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd); - if (rc) - DEV_ERR("%s: %s: %s read failed\n", __func__, - HDCP_STATE_NAME, sink->name); + read_size = min(size, max_size); + + cmd.read = 1; + cmd.addr = sink->addr; + cmd.len = read_size; + cmd.out_buf = buf; + + rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd); + if (rc) { + pr_err("Aux read failed\n"); + break; + } + + /* give sink/repeater time to ready edid */ + msleep(edid_read_delay_us); + buf += read_size; + size -= read_size; + } while (size > 0); } return rc; @@ -584,7 +557,7 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl, rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); if (rc) - DEV_ERR("%s: %s: %s write failed\n", __func__, + pr_err("%s: %s write failed\n", HDCP_STATE_NAME, sink->name); } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { @@ -596,7 +569,7 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl, rc = dp_aux_write(hdcp_ctrl->init_data.cb_data, &cmd); if (rc) - DEV_ERR("%s: %s: %s read failed\n", __func__, + pr_err("%s: %s read failed\n", HDCP_STATE_NAME, sink->name); } @@ -621,28 +594,26 @@ static void hdcp_1x_enable_interrupts(struct hdcp_1x_ctrl *hdcp_ctrl) static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) { - int rc; + int rc, r0_retry = 3; + u32 const r0_read_delay_us = 1; + u32 const r0_read_timeout_us = r0_read_delay_us * 10; u32 link0_aksv_0, link0_aksv_1; u32 link0_bksv_0, link0_bksv_1; u32 link0_an_0, link0_an_1; u32 timeout_count; - bool is_match; struct dss_io_data *io; struct dss_io_data *hdcp_io; struct hdcp_reg_set *reg_set; u8 aksv[5], *bksv = NULL; u8 an[8]; u8 bcaps = 0; - u32 link0_status; + u32 link0_status = 0; u8 buf[0xFF]; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; - u32 ret = 0; - u32 resp = 0; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io || !hdcp_ctrl->init_data.qfprom_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto error; } @@ -654,7 +625,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { - DEV_ERR("%s: %s: invalid state. returning\n", __func__, + pr_err("%s: invalid state. returning\n", HDCP_STATE_NAME); rc = -EINVAL; goto error; @@ -663,35 +634,17 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bcaps\n", __func__); + pr_err("error reading bcaps\n"); goto error; } hdcp_1x_enable_interrupts(hdcp_ctrl); - /* receiver (0), repeater (1) */ - hdcp_ctrl->current_tp.ds_type = - (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER; + hdcp_ctrl->current_tp.ds_type = bcaps & reg_set->repeater ? + DS_REPEATER : DS_RECEIVER; /* Write BCAPS to the hardware */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->data12; - scm_buf[0].val = bcaps; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps); - } else { - DSS_REG_W(io, reg_set->data12, bcaps); - } + DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps); /* Wait for HDCP keys to be checked and validated */ rc = readl_poll_timeout(io->base + reg_set->status, link0_status, @@ -699,7 +652,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) == HDCP_KEYS_STATE_VALID, HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: key not ready\n", __func__); + pr_err("key not ready\n"); goto error; } @@ -714,7 +667,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) (link0_status & (BIT(8) | BIT(9))), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: An not ready\n", __func__); + pr_err("An not ready\n"); goto error; } @@ -757,30 +710,18 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) an[6] = (link0_an_1 >> 16) & 0xFF; an[7] = (link0_an_1 >> 24) & 0xFF; - rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an); - if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error writing an to sink\n", __func__); - goto error; - } - - rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv); - if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error writing aksv to sink\n", __func__); - goto error; - } - rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bksv from sink\n", __func__); + pr_err("error reading bksv from sink\n"); goto error; } /* check there are 20 ones in BKSV */ if (hdcp_1x_count_one(bksv, 5) != 20) { - DEV_ERR("%s: %s: BKSV doesn't have 20 1's and 20 0's\n", - __func__, HDCP_STATE_NAME); - DEV_ERR("%s: %s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n", - __func__, HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2], + pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n", + HDCP_STATE_NAME); + pr_err("%s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n", + HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]); rc = -EINVAL; goto error; @@ -791,90 +732,87 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1]; link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0]; link0_bksv_1 = bksv[4]; - DEV_DBG("%s: %s: BKSV=%02x%08x\n", __func__, HDCP_STATE_NAME, + pr_debug("%s: BKSV=%02x%08x\n", HDCP_STATE_NAME, link0_bksv_1, link0_bksv_0); - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); + DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); + DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); - scm_buf[0].addr = phy_addr + reg_set->data0; - scm_buf[0].val = link0_bksv_0; - scm_buf[1].addr = phy_addr + reg_set->data1; - scm_buf[1].val = link0_bksv_1; + /* 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), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + pr_err("R0 not ready\n"); + goto error; + } - ret = hdcp_scm_call(scm_buf, &resp); + rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an); + if (IS_ERR_VALUE(rc)) { + pr_err("error writing an to sink\n"); + goto error; + } - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); - DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); - } else { - DSS_REG_W(io, reg_set->data0, link0_bksv_0); - DSS_REG_W(io, reg_set->data1, link0_bksv_1); + rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv); + if (IS_ERR_VALUE(rc)) { + pr_err("error writing aksv to sink\n"); + goto error; } /* * HDCP Compliace Test case 1A-01: * Wait here at least 100ms before reading R0' */ - msleep(125); + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + msleep(125); + } else { + if (!hdcp_ctrl->sink_r0_ready) { + reinit_completion(&hdcp_ctrl->sink_r0_available); + timeout_count = wait_for_completion_timeout( + &hdcp_ctrl->sink_r0_available, HZ / 2); - /* 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), - HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); - if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: R0 not ready\n", __func__); - goto error; + if (!timeout_count || hdcp_ctrl->reauth) { + pr_err("sink R0 not ready\n"); + rc = -EINVAL; + goto error; + } + } } - +r0_read_retry: memset(buf, 0, sizeof(buf)); rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading R0' from sink\n", __func__); + pr_err("error reading R0' from sink\n"); goto error; } - DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME, + pr_debug("%s: R0'=%02x%02x\n", HDCP_STATE_NAME, buf[1], buf[0]); /* Write R0' to HDCP registers and check to see if it is a match */ - reinit_completion(&hdcp_ctrl->r0_checked); DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]); - timeout_count = wait_for_completion_timeout( - &hdcp_ctrl->r0_checked, HZ*2); - link0_status = DSS_REG_R(io, reg_set->status); - is_match = link0_status & BIT(12); - if (!is_match) { - DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__, - HDCP_STATE_NAME, link0_status); - if (!timeout_count) { - DEV_ERR("%s: %s: Timeout. No R0 mtch. R0'=%02x%02x\n", - __func__, HDCP_STATE_NAME, buf[1], buf[0]); - rc = -ETIMEDOUT; - goto error; - } else { - DEV_ERR("%s: %s: R0 mismatch. R0'=%02x%02x\n", __func__, - HDCP_STATE_NAME, buf[1], buf[0]); - rc = -EINVAL; - goto error; - } - } else { - DEV_DBG("%s: %s: R0 matches\n", __func__, HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + link0_status & BIT(12), + r0_read_delay_us, r0_read_timeout_us); + if (IS_ERR_VALUE(rc)) { + pr_err("R0 mismatch\n"); + if (--r0_retry) + goto r0_read_retry; + + goto error; } + hdcp1_set_enc(true); + + pr_debug("%s: Authentication Part I successful\n", + hdcp_ctrl ? HDCP_STATE_NAME : "???"); + + return 0; + error: - if (rc) - DEV_ERR("%s: %s: Authentication Part I failed\n", __func__, - hdcp_ctrl ? HDCP_STATE_NAME : "???"); - else - DEV_INFO("%s: %s: Authentication Part I successful\n", - __func__, HDCP_STATE_NAME); + pr_err("%s: Authentication Part I failed\n", + hdcp_ctrl ? HDCP_STATE_NAME : "???"); + return rc; } /* hdcp_1x_authentication_part1 */ @@ -884,24 +822,16 @@ static int hdcp_1x_set_v_h(struct hdcp_1x_ctrl *hdcp_ctrl, int rc; struct dss_io_data *io; - if (!hdcp_ctrl->tz_hdcp && hdcp_ctrl->init_data.sec_access) - io = hdcp_ctrl->init_data.hdcp_io; - else - io = hdcp_ctrl->init_data.core_io; + io = hdcp_ctrl->init_data.hdcp_io; rc = hdcp_1x_read(hdcp_ctrl, rd->sink, buf, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading %s\n", __func__, rd->sink->name); + pr_err("error reading %s\n", rd->sink->name); goto end; } - DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", - __func__, HDCP_STATE_NAME, rd->sink->name, buf[0], buf[1], - buf[2], buf[3]); - - if (!hdcp_ctrl->tz_hdcp) - DSS_REG_W(io, rd->reg_id, - (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + DSS_REG_W(io, rd->reg_id, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); end: return rc; } @@ -910,46 +840,27 @@ static int hdcp_1x_transfer_v_h(struct hdcp_1x_ctrl *hdcp_ctrl) { int rc = 0; u8 buf[4]; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set; struct hdcp_1x_reg_data reg_data[] = { - {reg_set_data(7), &hdcp_ctrl->sink_addr.v_h0}, - {reg_set_data(8), &hdcp_ctrl->sink_addr.v_h1}, - {reg_set_data(9), &hdcp_ctrl->sink_addr.v_h2}, - {reg_set_data(10), &hdcp_ctrl->sink_addr.v_h3}, - {reg_set_data(11), &hdcp_ctrl->sink_addr.v_h4}, + {reg_set->sec_data7, &hdcp_ctrl->sink_addr.v_h0}, + {reg_set->sec_data8, &hdcp_ctrl->sink_addr.v_h1}, + {reg_set->sec_data9, &hdcp_ctrl->sink_addr.v_h2}, + {reg_set->sec_data10, &hdcp_ctrl->sink_addr.v_h3}, + {reg_set->sec_data11, &hdcp_ctrl->sink_addr.v_h4}, }; u32 size = ARRAY_SIZE(reg_data); - u32 iter = 0, ret = 0, resp = 0; + u32 iter = 0; phy_addr = hdcp_ctrl->init_data.phy_addr; - memset(scm_buf, 0x00, sizeof(scm_buf)); - for (iter = 0; iter < size; iter++) { struct hdcp_1x_reg_data *rd = reg_data + iter; memset(buf, 0, sizeof(buf)); hdcp_1x_set_v_h(hdcp_ctrl, rd, buf); - - if (hdcp_ctrl->tz_hdcp) { - u32 reg_val = buf[3] << 24 | buf[2] << 16 | - buf[1] << 8 | buf[0]; - - scm_buf[iter].addr = phy_addr + reg_data[iter].reg_id; - scm_buf[iter].val = reg_val; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: scm err: ret=%d, resp=%d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } } -error: + return rc; } @@ -966,14 +877,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) u32 ksv_bytes; struct dss_io_data *io; struct hdcp_reg_set *reg_set; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; - u32 ret = 0; - u32 resp = 0; u32 ksv_read_retry = 20; + int v_retry = 3; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto error; } @@ -982,7 +891,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: invalid state. returning\n", __func__, + pr_debug("%s: invalid state. returning\n", HDCP_STATE_NAME); rc = -EINVAL; goto error; @@ -999,64 +908,53 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) * Wait until READY bit is set in BCAPS, as per HDCP specifications * maximum permitted time to check for READY bit is five seconds. */ - timeout_count = 50; - do { - rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, - &bcaps, true); - if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bcaps\n", __func__); - goto error; - } - msleep(100); - } while (!(bcaps & BIT(5)) && --timeout_count); - - rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus, - buf, true); + rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, true); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bstatus\n", __func__); + pr_err("error reading bcaps\n"); goto error; } - bstatus = buf[1]; - bstatus = (bstatus << 8) | buf[0]; - - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + timeout_count = 50; - /* Write BSTATUS and BCAPS to HDCP registers */ - scm_buf[0].addr = phy_addr + reg_set->data12; - scm_buf[0].val = bcaps | (bstatus << 8); + while (!(bcaps & BIT(5)) && --timeout_count) { + rc = hdcp_1x_read(hdcp_ctrl, + &hdcp_ctrl->sink_addr.bcaps, &bcaps, true); + if (IS_ERR_VALUE(rc)) { + pr_err("error reading bcaps\n"); + goto error; + } + msleep(100); + } + } else { + reinit_completion(&hdcp_ctrl->sink_rep_ready); + timeout_count = wait_for_completion_timeout( + &hdcp_ctrl->sink_rep_ready, HZ * 5); - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); + if (!timeout_count || hdcp_ctrl->reauth) { + pr_err("sink not ready with DS KSV list\n"); rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_data12, - bcaps | (bstatus << 8)); - } else { - DSS_REG_W(io, reg_set->data12, bcaps | (bstatus << 8)); } - down_stream_devices = bstatus & 0x7F; - if (down_stream_devices == 0) { - /* - * If no downstream devices are attached to the repeater - * then part II fails. - * todo: The other approach would be to continue PART II. - */ - DEV_ERR("%s: %s: No downstream devices\n", __func__, - HDCP_STATE_NAME); - rc = -EINVAL; + rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus, + buf, true); + if (IS_ERR_VALUE(rc)) { + pr_err("error reading bstatus\n"); goto error; } + bstatus = buf[1]; + bstatus = (bstatus << 8) | buf[0]; + + down_stream_devices = bstatus & 0x7F; + + pr_debug("DEVICE_COUNT %d\n", down_stream_devices); + /* Cascaded repeater depth */ repeater_cascade_depth = (bstatus >> 8) & 0x7; + pr_debug("DEPTH %d\n", repeater_cascade_depth); /* * HDCP Compliance 1B-05: @@ -1064,9 +962,10 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) * exceed max_devices_connected from bit 7 of Bstatus. */ max_devs_exceeded = (bstatus & BIT(7)) >> 7; + pr_debug("MAX_DEVS_EXCEEDED %d\n", max_devs_exceeded); if (max_devs_exceeded == 0x01) { - DEV_ERR("%s: %s: no. of devs connected exceeds max allowed", - __func__, HDCP_STATE_NAME); + pr_err("%s: no. of devs connected exceeds max allowed", + HDCP_STATE_NAME); rc = -EINVAL; goto error; } @@ -1077,9 +976,11 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) * exceed max_cascade_connected from bit 11 of Bstatus. */ max_cascade_exceeded = (bstatus & BIT(11)) >> 11; + pr_debug("MAX CASCADE_EXCEEDED %d\n", + max_cascade_exceeded); if (max_cascade_exceeded == 0x01) { - DEV_ERR("%s: %s: no. of cascade conn exceeds max allowed", - __func__, HDCP_STATE_NAME); + pr_err("%s: no. of cascade conn exceeds max allowed", + HDCP_STATE_NAME); rc = -EINVAL; goto error; } @@ -1096,31 +997,39 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) ksv_bytes = 5 * down_stream_devices; hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes; - do { + while (ksv_bytes && --ksv_read_retry) { rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo, ksv_fifo, false); if (IS_ERR_VALUE(rc)) { - DEV_DBG("%s: could not read ksv fifo (%d)\n", - __func__, ksv_read_retry); + pr_debug("could not read ksv fifo (%d)\n", + ksv_read_retry); /* * HDCP Compliace Test case 1B-01: * Wait here until all the ksv bytes have been * read from the KSV FIFO register. */ msleep(25); - + } else { + break; } - } while (rc && --ksv_read_retry); + } if (rc) { - DEV_ERR("%s: error reading ksv_fifo\n", __func__); + pr_err("error reading ksv_fifo\n"); goto error; } + DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_data12, bcaps | (bstatus << 8)); +v_read_retry: rc = hdcp_1x_transfer_v_h(hdcp_ctrl); if (rc) goto error; + /* do not proceed further if no downstream device connected */ + if (!ksv_bytes) + goto error; + /* * Write KSV FIFO to HDCP_SHA_DATA. * This is done 1 byte at time starting with the LSB. @@ -1129,55 +1038,15 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) /* First, reset SHA engine */ /* Next, enable SHA engine, SEL=DIGA_HDCP */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; - scm_buf[0].val = HDCP_REG_ENABLE; - scm_buf[1].addr = phy_addr + reg_set->sha_ctrl; - scm_buf[1].val = HDCP_REG_DISABLE; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_ctrl, - HDCP_REG_ENABLE); - DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_ctrl, - HDCP_REG_DISABLE); - } else { - DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_ENABLE); - DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_DISABLE); - } + DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_ctrl, HDCP_REG_ENABLE); + DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_ctrl, HDCP_REG_DISABLE); for (i = 0; i < ksv_bytes - 1; i++) { /* Write KSV byte and do not set DONE bit[0] */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; - scm_buf[0].val = ksv_fifo[i] << 16; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_ctrl, - ksv_fifo[i] << 16); - } else { - DSS_REG_W_ND(io, reg_set->sha_ctrl, ksv_fifo[i] << 16); - } + DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_data, ksv_fifo[i] << 16); /* * Once 64 bytes have been written, we need to poll for @@ -1189,41 +1058,22 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: block not done\n", __func__); + pr_err("block not done\n"); goto error; } } } /* Write l to DONE bit[0] */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; - scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_ctrl, - (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); - } else { - DSS_REG_W_ND(io, reg_set->sha_ctrl, - (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); - } + DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_data, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); /* Now wait for HDCP_SHA_COMP_DONE */ rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status, sha_status & BIT(4), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: comp not done\n", __func__); + pr_err("V computation not done\n"); goto error; } @@ -1232,20 +1082,20 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) status & BIT(reg_set->v_offset), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: V not ready\n", __func__); - goto error; + pr_err("V mismatch\n"); + if (--v_retry) + goto v_read_retry; } error: if (rc) - DEV_ERR("%s: %s: Authentication Part II failed\n", __func__, + pr_err("%s: Authentication Part II failed\n", hdcp_ctrl ? HDCP_STATE_NAME : "???"); else - DEV_INFO("%s: %s: Authentication Part II successful\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: Authentication Part II successful\n", + HDCP_STATE_NAME); if (!hdcp_ctrl) { - DEV_ERR("%s: hdcp_ctrl null. Topology not updated\n", - __func__); + pr_err("hdcp_ctrl null. Topology not updated\n"); return rc; } /* Update topology information */ @@ -1260,7 +1110,7 @@ error: static void hdcp_1x_cache_topology(struct hdcp_1x_ctrl *hdcp_ctrl) { if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1283,7 +1133,7 @@ static void hdcp_1x_notify_topology(struct hdcp_1x_ctrl *hdcp_ctrl) snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX); kobject_uevent_env(hdcp_ctrl->init_data.sysfs_kobj, KOBJ_CHANGE, envp); - DEV_DBG("%s Event Sent: %s msgID = %s srcID = %s\n", __func__, + pr_debug("Event Sent: %s msgID = %s srcID = %s\n", envp[0], envp[1], envp[2]); } @@ -1293,7 +1143,7 @@ static void hdcp_1x_int_work(struct work_struct *work) struct hdcp_1x_ctrl, hdcp_int_work); if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1320,16 +1170,19 @@ static void hdcp_1x_auth_work(struct work_struct *work) struct dss_io_data *io; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: invalid state. returning\n", __func__, + pr_debug("%s: invalid state. returning\n", HDCP_STATE_NAME); return; } + hdcp_ctrl->sink_r0_ready = false; + hdcp_ctrl->reauth = false; + io = hdcp_ctrl->init_data.core_io; /* Enabling Software DDC for HDMI and REF timer for DP */ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) @@ -1340,7 +1193,7 @@ static void hdcp_1x_auth_work(struct work_struct *work) rc = hdcp_1x_authentication_part1(hdcp_ctrl); if (rc) { - DEV_DBG("%s: %s: HDCP Auth Part I failed\n", __func__, + pr_debug("%s: HDCP Auth Part I failed\n", HDCP_STATE_NAME); goto error; } @@ -1348,12 +1201,12 @@ static void hdcp_1x_auth_work(struct work_struct *work) if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) { rc = hdcp_1x_authentication_part2(hdcp_ctrl); if (rc) { - DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__, + pr_debug("%s: HDCP Auth Part II failed\n", HDCP_STATE_NAME); goto error; } } else { - DEV_INFO("%s: Downstream device is not a repeater\n", __func__); + pr_debug("Downstream device is not a repeater\n"); } /* Disabling software DDC before going into part3 to make sure * there is no Arbitration between software and hardware for DDC */ @@ -1381,18 +1234,16 @@ error: mutex_unlock(hdcp_ctrl->init_data.mutex); /* Notify HDMI Tx controller of the result */ - DEV_DBG("%s: %s: Notifying HDMI Tx of auth result\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: Notifying HDMI Tx of auth result\n", + HDCP_STATE_NAME); if (hdcp_ctrl->init_data.notify_status) { hdcp_ctrl->init_data.notify_status( hdcp_ctrl->init_data.cb_data, hdcp_ctrl->hdcp_state); } - - hdcp1_set_enc(true); } else { - DEV_DBG("%s: %s: HDCP state changed during authentication\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: HDCP state changed during authentication\n", + HDCP_STATE_NAME); mutex_unlock(hdcp_ctrl->init_data.mutex); } return; @@ -1403,28 +1254,28 @@ int hdcp_1x_authenticate(void *input) struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } if (HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: already active or activating. returning\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: already active or activating. returning\n", + HDCP_STATE_NAME); return 0; } - DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__, + pr_debug("%s: Queuing work to start HDCP authentication", HDCP_STATE_NAME); if (!hdcp_1x_load_keys(input)) { flush_delayed_work(&hdcp_ctrl->hdcp_auth_work); - queue_delayed_work(hdcp_ctrl->init_data.workq, + queue_delayed_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_auth_work, HZ/2); } else { flush_work(&hdcp_ctrl->hdcp_int_work); - queue_work(hdcp_ctrl->init_data.workq, + queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work); } @@ -1441,7 +1292,7 @@ int hdcp_1x_reauthenticate(void *input) u32 ret = 0, reg; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } @@ -1450,7 +1301,7 @@ int hdcp_1x_reauthenticate(void *input) isr = &hdcp_ctrl->int_set; if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: invalid state. returning\n", __func__, + pr_debug("%s: invalid state. returning\n", HDCP_STATE_NAME); return 0; } @@ -1478,10 +1329,10 @@ int hdcp_1x_reauthenticate(void *input) DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); if (!hdcp_1x_load_keys(input)) - queue_delayed_work(hdcp_ctrl->init_data.workq, + queue_delayed_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_auth_work, HZ); else - queue_work(hdcp_ctrl->init_data.workq, + queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work); return ret; @@ -1497,7 +1348,7 @@ void hdcp_1x_off(void *input) u32 reg; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1506,7 +1357,7 @@ void hdcp_1x_off(void *input) isr = &hdcp_ctrl->int_set; if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: inactive. returning\n", __func__, + pr_debug("%s: inactive. returning\n", HDCP_STATE_NAME); return; } @@ -1531,13 +1382,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_sync(&hdcp_ctrl->hdcp_auth_work); + rc = cancel_delayed_work(&hdcp_ctrl->hdcp_auth_work); if (rc) - DEV_DBG("%s: %s: Deleted hdcp auth work\n", __func__, + pr_debug("%s: Deleted hdcp auth work\n", HDCP_STATE_NAME); rc = cancel_work_sync(&hdcp_ctrl->hdcp_int_work); if (rc) - DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__, + pr_debug("%s: Deleted hdcp int work\n", HDCP_STATE_NAME); @@ -1549,7 +1400,9 @@ void hdcp_1x_off(void *input) DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); - DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME); + hdcp_ctrl->sink_r0_ready = false; + + pr_debug("%s: HDCP: Off\n", HDCP_STATE_NAME); } /* hdcp_1x_off */ int hdcp_1x_isr(void *input) @@ -1562,7 +1415,7 @@ int hdcp_1x_isr(void *input) struct hdcp_int_set *isr; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto error; } @@ -1583,7 +1436,7 @@ int hdcp_1x_isr(void *input) /* AUTH_SUCCESS_INT */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->auth_success_ack)); - DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__, + pr_debug("%s: AUTH_SUCCESS_INT received\n", HDCP_STATE_NAME); if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) complete_all(&hdcp_ctrl->r0_checked); @@ -1595,11 +1448,11 @@ int hdcp_1x_isr(void *input) DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->auth_fail_ack)); - DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n", - __func__, HDCP_STATE_NAME, link_status); + pr_debug("%s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n", + HDCP_STATE_NAME, link_status); if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) { /* Inform HDMI Tx of the failure */ - queue_work(hdcp_ctrl->init_data.workq, + queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work); /* todo: print debug log with auth fail reason */ } else if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) { @@ -1615,7 +1468,7 @@ int hdcp_1x_isr(void *input) /* DDC_XFER_REQ_INT */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->tx_req_ack)); - DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__, + pr_debug("%s: DDC_XFER_REQ_INT received\n", HDCP_STATE_NAME); } @@ -1623,7 +1476,7 @@ int hdcp_1x_isr(void *input) /* DDC_XFER_DONE_INT */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->tx_req_done_ack)); - DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__, + pr_debug("%s: DDC_XFER_DONE received\n", HDCP_STATE_NAME); } @@ -1631,7 +1484,7 @@ int hdcp_1x_isr(void *input) /* Encryption enabled */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->encryption_ready_ack)); - DEV_INFO("%s: %s: encryption ready received\n", __func__, + pr_debug("%s: encryption ready received\n", HDCP_STATE_NAME); } @@ -1639,7 +1492,7 @@ int hdcp_1x_isr(void *input) /* Encryption enabled */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->encryption_not_ready_ack)); - DEV_INFO("%s: %s: encryption not ready received\n", __func__, + pr_debug("%s: encryption not ready received\n", HDCP_STATE_NAME); } @@ -1688,13 +1541,13 @@ static ssize_t hdcp_1x_sysfs_rda_status(struct device *dev, struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev); if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } mutex_lock(hdcp_ctrl->init_data.mutex); ret = snprintf(buf, PAGE_SIZE, "%d\n", hdcp_ctrl->hdcp_state); - DEV_DBG("%s: '%d'\n", __func__, hdcp_ctrl->hdcp_state); + pr_debug("'%d'\n", hdcp_ctrl->hdcp_state); mutex_unlock(hdcp_ctrl->init_data.mutex); return ret; @@ -1707,7 +1560,7 @@ static ssize_t hdcp_1x_sysfs_rda_tp(struct device *dev, struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev); if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } @@ -1741,7 +1594,7 @@ static ssize_t hdcp_1x_sysfs_wta_tp(struct device *dev, struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev); if (!hdcp_ctrl || !buf) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } @@ -1781,10 +1634,13 @@ void hdcp_1x_deinit(void *input) struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } + if (hdcp_ctrl->workq) + destroy_workqueue(hdcp_ctrl->workq); + sysfs_remove_group(hdcp_ctrl->init_data.sysfs_kobj, &hdcp_1x_fs_attr_group); @@ -1812,12 +1668,67 @@ static void hdcp_1x_update_client_reg_set(struct hdcp_1x_ctrl *hdcp_ctrl) } } +static int hdcp_1x_cp_irq(void *input) +{ + struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input; + u8 buf = 0; + int ret = -EINVAL; + + if (!hdcp_ctrl) { + pr_err("invalid input\n"); + goto end; + } + + ret = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.cp_irq_status, + &buf, false); + if (IS_ERR_VALUE(ret)) { + pr_err("error reading cp_irq_status\n"); + goto end; + } + + if (!buf) { + pr_debug("not a hdcp 1.x irq\n"); + ret = -EINVAL; + goto end; + } + + if ((buf & BIT(2)) || (buf & BIT(3))) { + pr_err("%s\n", + buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" : + "REAUTHENTICATION_REQUEST"); + + hdcp_ctrl->reauth = true; + + complete_all(&hdcp_ctrl->sink_rep_ready); + complete_all(&hdcp_ctrl->sink_r0_available); + + queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work); + goto end; + } + + if (buf & BIT(1)) { + pr_debug("R0' AVAILABLE\n"); + hdcp_ctrl->sink_r0_ready = true; + complete_all(&hdcp_ctrl->sink_r0_available); + goto end; + } + + if (buf & BIT(0)) { + pr_debug("KSVs READY\n"); + complete_all(&hdcp_ctrl->sink_rep_ready); + goto end; + } +end: + return ret; +} + void *hdcp_1x_init(struct hdcp_init_data *init_data) { struct hdcp_1x_ctrl *hdcp_ctrl = NULL; - int ret; + char name[20]; static struct hdcp_ops ops = { .isr = hdcp_1x_isr, + .cp_irq = hdcp_1x_cp_irq, .reauthenticate = hdcp_1x_reauthenticate, .authenticate = hdcp_1x_authenticate, .off = hdcp_1x_off @@ -1826,29 +1737,36 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) if (!init_data || !init_data->core_io || !init_data->qfprom_io || !init_data->mutex || !init_data->notify_status || !init_data->workq || !init_data->cb_data) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); goto error; } if (init_data->sec_access && !init_data->hdcp_io) { - DEV_ERR("%s: hdcp_io required\n", __func__); + pr_err("hdcp_io required\n"); goto error; } hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL); - if (!hdcp_ctrl) { - DEV_ERR("%s: Out of memory\n", __func__); + if (!hdcp_ctrl) goto error; - } hdcp_ctrl->init_data = *init_data; hdcp_ctrl->ops = &ops; + snprintf(name, sizeof(name), "hdcp_1x_%d", + hdcp_ctrl->init_data.client_id); + + hdcp_ctrl->workq = create_workqueue(name); + if (!hdcp_ctrl->workq) { + pr_err("Error creating workqueue\n"); + goto error; + } + hdcp_1x_update_client_reg_set(hdcp_ctrl); if (sysfs_create_group(init_data->sysfs_kobj, &hdcp_1x_fs_attr_group)) { - DEV_ERR("%s: hdcp sysfs group creation failed\n", __func__); + pr_err("hdcp sysfs group creation failed\n"); goto error; } @@ -1857,19 +1775,10 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE; init_completion(&hdcp_ctrl->r0_checked); + init_completion(&hdcp_ctrl->sink_r0_available); + init_completion(&hdcp_ctrl->sink_rep_ready); - if (!hdcp_ctrl->init_data.sec_access) { - ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP); - if (ret <= 0) { - DEV_ERR("%s: secure hdcp service unavailable, ret = %d", - __func__, ret); - } else { - DEV_DBG("%s: tz_hdcp = 1\n", __func__); - hdcp_ctrl->tz_hdcp = 1; - } - } - - DEV_DBG("%s: HDCP module initialized. HDCP_STATE=%s", __func__, + pr_debug("HDCP module initialized. HDCP_STATE=%s\n", HDCP_STATE_NAME); error: diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index b90ac82049c6..0a316fa19909 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -134,6 +134,7 @@ struct hdmi_edid_ctrl { u8 it_scan_info; u8 ce_scan_info; u8 cea_blks; + /* DC: MSB -> LSB: Y420_48|Y420_36|Y420_30|RGB48|RGB36|RGB30|Y444 */ u8 deep_color; u16 physical_address; u32 video_resolution; /* selected by user */ @@ -858,6 +859,43 @@ static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset, return NULL; } /* hdmi_edid_find_block */ +static const u8 *hdmi_edid_find_hfvsdb(const u8 *in_buf) +{ + u8 len = 0, i = 0; + const u8 *vsd = NULL; + u32 vsd_offset = DBC_START_OFFSET; + u32 hf_ieee_oui = 0; + + /* Find HF-VSDB with HF-OUI */ + do { + vsd = hdmi_edid_find_block(in_buf, vsd_offset, + VENDOR_SPECIFIC_DATA_BLOCK, &len); + + if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) { + if (i == 0) + pr_debug("%s: VSDB not found\n", __func__); + else + pr_debug("%s: no more VSDB found\n", __func__); + + return NULL; + } + + hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3]; + + if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) { + pr_debug("%s: found HF-VSDB\n", __func__); + break; + } + + pr_debug("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui); + + i++; + vsd_offset = vsd - in_buf + len + 1; + } while (1); + + return vsd; +} + static void hdmi_edid_set_y420_support(struct hdmi_edid_ctrl *edid_ctrl, u32 video_format) { @@ -1251,62 +1289,32 @@ static void hdmi_edid_extract_speaker_allocation_data( static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf) { - u8 len = 0, i = 0; const u8 *vsd = NULL; - u32 vsd_offset = DBC_START_OFFSET; - u32 hf_ieee_oui = 0; if (!edid_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("%s: invalid input\n", __func__); return; } - /* Find HF-VSDB with HF-OUI */ - do { - vsd = hdmi_edid_find_block(in_buf, vsd_offset, - VENDOR_SPECIFIC_DATA_BLOCK, &len); - - if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) { - if (i == 0) - DEV_ERR("%s: VSDB not found\n", __func__); - else - DEV_DBG("%s: no more VSDB found\n", __func__); - break; - } - - hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3]; - - if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) { - DEV_DBG("%s: found HF-VSDB\n", __func__); - break; - } - - DEV_DBG("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui); - - i++; - vsd_offset = vsd - in_buf + len + 1; - } while (1); - - if (!vsd) { - DEV_DBG("%s: HF-VSDB not found\n", __func__); - return; + vsd = hdmi_edid_find_hfvsdb(in_buf); + + if (vsd) { + /* Max pixel clock is in multiples of 5Mhz. */ + edid_ctrl->sink_caps.max_pclk_in_hz = + vsd[5]*5000000; + edid_ctrl->sink_caps.scdc_present = + (vsd[6] & 0x80) ? true : false; + edid_ctrl->sink_caps.scramble_support = + (vsd[6] & 0x08) ? true : false; + edid_ctrl->sink_caps.read_req_support = + (vsd[6] & 0x40) ? true : false; + edid_ctrl->sink_caps.osd_disparity = + (vsd[6] & 0x01) ? true : false; + edid_ctrl->sink_caps.dual_view_support = + (vsd[6] & 0x02) ? true : false; + edid_ctrl->sink_caps.ind_view_support = + (vsd[6] & 0x04) ? true : false; } - - /* Max pixel clock is in multiples of 5Mhz. */ - edid_ctrl->sink_caps.max_pclk_in_hz = - vsd[5]*5000000; - edid_ctrl->sink_caps.scdc_present = - (vsd[6] & 0x80) ? true : false; - edid_ctrl->sink_caps.scramble_support = - (vsd[6] & 0x08) ? true : false; - edid_ctrl->sink_caps.read_req_support = - (vsd[6] & 0x40) ? true : false; - edid_ctrl->sink_caps.osd_disparity = - (vsd[6] & 0x01) ? true : false; - edid_ctrl->sink_caps.dual_view_support = - (vsd[6] & 0x02) ? true : false; - edid_ctrl->sink_caps.ind_view_support = - (vsd[6] & 0x04) ? true : false; } static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl, @@ -1404,12 +1412,19 @@ static void hdmi_edid_extract_dc(struct hdmi_edid_ctrl *edid_ctrl, edid_ctrl->deep_color = (vsd[6] >> 0x3) & 0xF; - DEV_DBG("%s: deep color: Y444|RGB30|RGB36|RGB48: (%d|%d|%d|%d)\n", - __func__, + vsd = hdmi_edid_find_hfvsdb(in_buf); + + if (vsd) + edid_ctrl->deep_color |= (vsd[7] & 0x07) << 4; + + pr_debug("deep color: Y444|RGB30|RGB36|RGB48|Y420_30|Y420_36|Y420_48: (%d|%d|%d|%d|%d|%d|%d)\n", (int) (edid_ctrl->deep_color & BIT(0)) >> 0, (int) (edid_ctrl->deep_color & BIT(1)) >> 1, (int) (edid_ctrl->deep_color & BIT(2)) >> 2, - (int) (edid_ctrl->deep_color & BIT(3)) >> 3); + (int) (edid_ctrl->deep_color & BIT(3)) >> 3, + (int) (edid_ctrl->deep_color & BIT(4)) >> 4, + (int) (edid_ctrl->deep_color & BIT(5)) >> 5, + (int) (edid_ctrl->deep_color & BIT(6)) >> 6); } static u32 hdmi_edid_check_header(const u8 *edid_buf) @@ -2398,8 +2413,8 @@ u32 hdmi_edid_get_sink_mode(void *input) * * This API returns deep color for different formats supported by sink. * Deep color support for Y444 (BIT(0)), RGB30 (BIT(1)), RGB36 (BIT(2), - * RGB 48 (BIT(3)) is provided in a 8 bit integer. The MSB 8 bits are - * not used. + * RGB 48 (BIT(3)), Y420_30 (BIT(4)), Y420_36 (BIT(5)), Y420_48 (BIT(6)) + * is provided in a 8 bit integer. The MSB 8 bits are not used. * * Return: deep color data. */ @@ -2416,6 +2431,25 @@ u8 hdmi_edid_get_deep_color(void *input) } /** + * hdmi_edid_get_max_pclk() - get max pclk supported. Sink side's limitation + * should be concerned as well. + * @input: edid parser data + * + * Return: max pclk rate + */ +u32 hdmi_edid_get_max_pclk(void *input) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return 0; + } + + return edid_ctrl->init_data.max_pclk_khz; +} + +/** * hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink * @input: edid parser data * diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index ce6cecbb2e03..43e1adb1f139 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -60,6 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data); bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode); 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); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index 481fc118c7ad..7934e4cf3bc4 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -666,7 +666,7 @@ static void hdmi_hdcp2p2_link_cb(void *data) static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl) { - int rc, timeout_hsync; + int rc = 0, timeout_hsync; char *recvd_msg_buf = NULL; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; struct hdmi_tx_ddc_ctrl *ddc_ctrl; @@ -689,6 +689,7 @@ 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_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c index 522debfba8ce..a8a56e3a8745 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c @@ -602,14 +602,51 @@ end: return rc; } +static int hdmi_panel_setup_dc(struct hdmi_panel *panel) +{ + u32 hdmi_ctrl_reg; + u32 vbi_pkt_reg; + int rc = 0; + + pr_debug("Deep Color: %s\n", panel->data->dc_enable ? "ON" : "OFF"); + + /* enable deep color if supported */ + if (panel->data->dc_enable) { + hdmi_ctrl_reg = DSS_REG_R(panel->io, HDMI_CTRL); + + /* GC CD override */ + hdmi_ctrl_reg |= BIT(27); + + /* enable deep color for RGB888 30 bits */ + hdmi_ctrl_reg |= BIT(24); + DSS_REG_W(panel->io, HDMI_CTRL, hdmi_ctrl_reg); + + /* Enable GC_CONT and GC_SEND in General Control Packet + * (GCP) register so that deep color data is + * transmitted to the sink on every frame, allowing + * the sink to decode the data correctly. + * + * GC_CONT: 0x1 - Send GCP on every frame + * GC_SEND: 0x1 - Enable GCP Transmission + */ + vbi_pkt_reg = DSS_REG_R(panel->io, HDMI_VBI_PKT_CTRL); + vbi_pkt_reg |= BIT(5) | BIT(4); + DSS_REG_W(panel->io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg); + } + + return rc; +} + static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel) { int rc = 0; int timeout_hsync; u32 reg_val = 0; u32 tmds_clock_ratio = 0; + u32 tmds_clock = 0; bool scrambler_on = false; struct msm_hdmi_mode_timing_info *timing = NULL; + struct mdss_panel_info *pinfo = NULL; if (!panel) { pr_err("invalid input\n"); @@ -622,13 +659,22 @@ static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel) return -EINVAL; } + pinfo = panel->data->pinfo; + if (!pinfo) { + pr_err("invalid panel data\n"); + return -EINVAL; + } + /* Scrambling is supported from HDMI TX 4.0 */ if (panel->version < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) { pr_debug("scrambling not supported by tx\n"); return 0; } - if (timing->pixel_freq > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { + tmds_clock = hdmi_tx_setup_tmds_clk_rate(timing->pixel_freq, + pinfo->out_format, panel->data->dc_enable); + + if (tmds_clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { scrambler_on = true; tmds_clock_ratio = 1; } else { @@ -798,6 +844,12 @@ static int hdmi_panel_power_on(void *input) pr_err("scrambler setup failed. rc=%d\n", rc); goto err; } + + rc = hdmi_panel_setup_dc(panel); + if (rc) { + pr_err("Deep Color setup failed. rc=%d\n", rc); + goto err; + } end: panel->on = true; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h index 6fa9af13d46e..cb40f0cad55e 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h @@ -28,6 +28,7 @@ * @infoframe: set to true if infoframes should be sent to sink * @is_it_content: set to true if content is IT * @scrambler: set to true if scrambler needs to be enabled + * @dc_enable: set to true if deep color is enabled */ struct hdmi_panel_data { struct mdss_panel_info *pinfo; @@ -39,6 +40,7 @@ struct hdmi_panel_data { bool infoframe; bool is_it_content; bool scrambler; + bool dc_enable; }; /** diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index d01d163af5fa..e9ae30bb6914 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -35,6 +35,7 @@ #include "mdss.h" #include "mdss_panel.h" #include "mdss_hdmi_mhl.h" +#include "mdss_hdmi_util.h" #define DRV_NAME "hdmi-tx" #define COMPATIBLE_NAME "qcom,hdmi-tx" @@ -58,13 +59,6 @@ #define AUDIO_POLL_SLEEP_US (5 * 1000) #define AUDIO_POLL_TIMEOUT_US (AUDIO_POLL_SLEEP_US * 1000) -#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 -#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 -#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 - -#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000 -#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200 - /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 #define HDMI_TX_3_MAX_PCLK_RATE 297000 @@ -77,6 +71,7 @@ #define HDMI_TX_MIN_FPS 20000 #define HDMI_TX_MAX_FPS 120000 +#define HDMI_KHZ_TO_HZ 1000 #define HDMI_TX_VERSION_403 0x40000003 /* msm8998 */ #define HDMI_GET_MSB(x) (x >> 8) @@ -111,7 +106,6 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data); static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, int enable); -static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl); static void hdmi_tx_fps_work(struct work_struct *work); static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, bool active); @@ -121,6 +115,7 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev, static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev, struct msm_ext_disp_audio_edid_blk *blk); static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote); +static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm); static struct mdss_hw hdmi_tx_hw = { .hw_ndx = MDSS_HW_HDMI, @@ -318,11 +313,29 @@ static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl) return hdr_data->metadata_type_one; } +static inline bool hdmix_tx_sink_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); + + if (hdmi_ctrl->panel_data.panel_info.out_format == MDP_Y_CBCR_H2V2) + return (hdmi_edid_get_deep_color(edid_fd) & BIT(4)); + else + return (hdmi_edid_get_deep_color(edid_fd) & BIT(1)); +} + static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl) { - return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support && - (hdmi_edid_get_deep_color( - hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)) & BIT(1)); + /* actual pixel clock if deep color is enabled */ + void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); + u32 tmds_clk_with_dc = hdmi_tx_setup_tmds_clk_rate( + hdmi_ctrl->timing.pixel_freq, + hdmi_ctrl->panel.pinfo->out_format, + true); + + return hdmi_ctrl->dc_feature_on && + hdmi_ctrl->dc_support && + hdmix_tx_sink_dc_support(hdmi_ctrl) && + (tmds_clk_with_dc <= hdmi_edid_get_max_pclk(edid_fd)); } static const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module) @@ -349,7 +362,10 @@ static const char *hdmi_tx_io_name(u32 type) static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl) { if (hdmi_ctrl && hdmi_ctrl->audio_ops.on) { - u32 pclk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl); + u32 pclk = hdmi_tx_setup_tmds_clk_rate( + hdmi_ctrl->timing.pixel_freq, + hdmi_ctrl->panel.pinfo->out_format, + hdmi_ctrl->panel.dc_enable); hdmi_ctrl->audio_ops.on(hdmi_ctrl->audio_data, pclk, &hdmi_ctrl->audio_params); @@ -369,9 +385,14 @@ static inline bool hdmi_tx_is_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) static inline bool hdmi_tx_is_cec_wakeup_en(struct hdmi_tx_ctrl *hdmi_ctrl) { - void *fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); + void *fd = NULL; - if (!hdmi_ctrl || !fd) + if (!hdmi_ctrl) + return false; + + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); + + if (!fd) return false; return hdmi_cec_is_wakeup_en(fd); @@ -379,9 +400,14 @@ static inline bool hdmi_tx_is_cec_wakeup_en(struct hdmi_tx_ctrl *hdmi_ctrl) static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl) { - void *fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); + void *fd = NULL; + + if (!hdmi_ctrl) + return; + + fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW); - if (!hdmi_ctrl || !fd) + if (!fd) return; hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend); @@ -399,7 +425,8 @@ static inline void hdmi_tx_send_cable_notification( static inline void hdmi_tx_set_audio_switch_node( struct hdmi_tx_ctrl *hdmi_ctrl, int val) { - if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify) + if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify && + !hdmi_tx_is_dvi_mode(hdmi_ctrl)) hdmi_ctrl->ext_audio_data.intf_ops.notify(hdmi_ctrl->ext_pdev, val); } @@ -634,10 +661,11 @@ static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl) { struct dss_module_power *power_data = NULL; struct mdss_panel_info *pinfo; + u32 new_clk_rate = 0; int rc = 0; if (!hdmi_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto end; } @@ -646,21 +674,25 @@ static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl) power_data = &hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM]; if (!power_data) { - DEV_ERR("%s: Error: invalid power data\n", __func__); + pr_err("Error: invalid power data\n"); rc = -EINVAL; goto end; } - if (power_data->clk_config->rate == pinfo->clk_rate) { - rc = -EINVAL; + new_clk_rate = hdmi_tx_setup_tmds_clk_rate(pinfo->clk_rate, + pinfo->out_format, hdmi_ctrl->panel.dc_enable); + + if (power_data->clk_config->rate == new_clk_rate) goto end; - } - power_data->clk_config->rate = pinfo->clk_rate; + power_data->clk_config->rate = new_clk_rate; - DEV_DBG("%s: rate %ld\n", __func__, power_data->clk_config->rate); + pr_debug("rate %ld\n", power_data->clk_config->rate); - msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk); + rc = msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk); + if (rc < 0) + pr_err("failed to set clock rate %lu\n", + power_data->clk_config->rate); end: return rc; } @@ -1212,11 +1244,23 @@ static ssize_t hdmi_tx_sysfs_wta_5v(struct device *dev, hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev); if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); - ret = -EINVAL; - goto end; + return -EINVAL; + } + + pd = &hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM]; + + if (!pd || !pd->gpio_config) { + DEV_ERR("%s: Error: invalid power data\n", __func__); + return -EINVAL; } mutex_lock(&hdmi_ctrl->tx_lock); + pd = &hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM]; + if (!pd || !pd->gpio_config) { + DEV_ERR("%s: Error: invalid power data\n", __func__); + ret = -EINVAL; + goto end; + } ret = kstrtoint(buf, 10, &read); if (ret) { @@ -1302,6 +1346,35 @@ end: return ret; } +static ssize_t hdmi_tx_sysfs_wta_hdmi_ppm(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret, ppm; + struct hdmi_tx_ctrl *hdmi_ctrl + = hdmi_tx_get_drvdata_from_sysfs_dev(dev); + + if (!hdmi_ctrl) { + pr_err("invalid input\n"); + return -EINVAL; + } + + mutex_lock(&hdmi_ctrl->tx_lock); + + ret = kstrtoint(buf, 10, &ppm); + if (ret) { + pr_err("kstrtoint failed. rc=%d\n", ret); + goto end; + } + + hdmi_tx_update_ppm(hdmi_ctrl, ppm); + + ret = strnlen(buf, PAGE_SIZE); + pr_debug("write ppm %d\n", ppm); +end: + mutex_unlock(&hdmi_ctrl->tx_lock); + return ret; +} + static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL); static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug); static DEVICE_ATTR(sim_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_sim_mode, @@ -1322,6 +1395,8 @@ static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_s3d_mode, hdmi_tx_sysfs_wta_s3d_mode); static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v); static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream); +static DEVICE_ATTR(hdmi_ppm, S_IRUGO | S_IWUSR, NULL, + hdmi_tx_sysfs_wta_hdmi_ppm); static struct attribute *hdmi_tx_fs_attrs[] = { &dev_attr_connected.attr, @@ -1337,6 +1412,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = { &dev_attr_s3d_mode.attr, &dev_attr_5v.attr, &dev_attr_hdr_stream.attr, + &dev_attr_hdmi_ppm.attr, NULL, }; static struct attribute_group hdmi_tx_fs_attrs_group = { @@ -2100,6 +2176,7 @@ static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl) pinfo->type = DTV_PANEL; pinfo->pdest = DISPLAY_3; pinfo->wait_cycle = 0; + pinfo->out_format = MDP_RGB_888; pinfo->bpp = 24; pinfo->fb_num = 1; @@ -2345,7 +2422,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) struct dss_io_data *io = NULL; /* Defaults: Disable block, HDMI mode */ u32 hdmi_ctrl_reg = BIT(1); - u32 vbi_pkt_reg; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); @@ -2383,27 +2459,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) * longer be used */ hdmi_ctrl_reg |= BIT(31); - - /* enable deep color if supported */ - if (hdmi_tx_dc_support(hdmi_ctrl)) { - /* GC CD override */ - hdmi_ctrl_reg |= BIT(27); - - /* enable deep color for RGB888 30 bits */ - hdmi_ctrl_reg |= BIT(24); - - /* Enable GC_CONT and GC_SEND in General Control Packet - * (GCP) register so that deep color data is - * transmitted to the sink on every frame, allowing - * the sink to decode the data correctly. - * - * GC_CONT: 0x1 - Send GCP on every frame - * GC_SEND: 0x1 - Enable GCP Transmission - */ - vbi_pkt_reg = DSS_REG_R(io, HDMI_VBI_PKT_CTRL); - vbi_pkt_reg |= BIT(5) | BIT(4); - DSS_REG_W(io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg); - } } DSS_REG_W(io, HDMI_CTRL, hdmi_ctrl_reg); @@ -2973,44 +3028,6 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote) return hpd; } -static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl) -{ - u32 rate = 0; - struct msm_hdmi_mode_timing_info *timing = NULL; - u32 rate_ratio; - - if (!hdmi_ctrl) { - DEV_ERR("%s: Bad input parameters\n", __func__); - goto end; - } - - timing = &hdmi_ctrl->timing; - if (!timing) { - DEV_ERR("%s: Invalid timing info\n", __func__); - goto end; - } - - switch (hdmi_ctrl->panel_data.panel_info.out_format) { - case MDP_Y_CBCR_H2V2: - rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; - break; - case MDP_Y_CBCR_H2V1: - rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO; - break; - default: - rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; - break; - } - - rate = timing->pixel_freq / rate_ratio; - - if (hdmi_tx_dc_support(hdmi_ctrl)) - rate += rate >> 2; - -end: - return rate; -} - static inline bool hdmi_tx_hw_is_cable_connected(struct hdmi_tx_ctrl *hdmi_ctrl) { return DSS_REG_R(&hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO], @@ -3059,7 +3076,12 @@ static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl, static inline void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl) { - if (hdmi_ctrl && hdmi_ctrl->audio_ops.off) + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (hdmi_ctrl->audio_ops.off) hdmi_ctrl->audio_ops.off(hdmi_ctrl->audio_data); memset(&hdmi_ctrl->audio_params, 0, @@ -3069,13 +3091,19 @@ static inline void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl) static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl) { struct dss_io_data *io = NULL; - void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); + void *pdata = NULL; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return -EINVAL; } + pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); + if (!pdata) { + DEV_ERR("%s: invalid panel data\n", __func__); + return -EINVAL; + } + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; if (!io->base) { DEV_ERR("%s: Core io is not initialized\n", __func__); @@ -3117,7 +3145,7 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); void *edata = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); - hdmi_panel_get_vic(&panel_data->panel_info, + hdmi_ctrl->vic = hdmi_panel_get_vic(&panel_data->panel_info, &hdmi_ctrl->ds_data); if (hdmi_ctrl->vic <= 0) { @@ -3144,16 +3172,14 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->vic); hdmi_ctrl->panel.scrambler = hdmi_edid_get_sink_scrambler_support( edata); + hdmi_ctrl->panel.dc_enable = hdmi_tx_dc_support(hdmi_ctrl); if (hdmi_ctrl->panel_ops.on) hdmi_ctrl->panel_ops.on(pdata); - pixel_clk = hdmi_ctrl->timing.pixel_freq * 1000; - - if (panel_data->panel_info.out_format == MDP_Y_CBCR_H2V2) - pixel_clk >>= 1; - else if (hdmi_tx_dc_support(hdmi_ctrl)) - pixel_clk += pixel_clk >> 2; + pixel_clk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl->timing.pixel_freq, + hdmi_ctrl->panel.pinfo->out_format, + hdmi_ctrl->panel.dc_enable) * 1000; DEV_DBG("%s: setting pixel clk %d\n", __func__, pixel_clk); @@ -3215,7 +3241,7 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->mdss_util->disable_irq(&hdmi_tx_hw); hdmi_tx_set_mode(hdmi_ctrl, false); } - + hdmi_tx_config_5v(hdmi_ctrl, false); rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0); if (rc) DEV_INFO("%s: Failed to disable hpd power. Error=%d\n", @@ -3568,7 +3594,7 @@ static int hdmi_tx_hdcp_off(struct hdmi_tx_ctrl *hdmi_ctrl) static void hdmi_tx_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl) { - void *pdata = pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); + void *pdata = NULL; struct mdss_panel_info *pinfo; if (!hdmi_ctrl) { @@ -3576,8 +3602,15 @@ static void hdmi_tx_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl) return; } - pinfo = &hdmi_ctrl->panel_data.panel_info; + pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); + pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); + if (!pdata) { + DEV_ERR("%s: invalid panel data\n", __func__); + return; + } + + pinfo = &hdmi_ctrl->panel_data.panel_info; if (!pinfo->dynamic_fps) { DEV_DBG("%s: Dynamic fps not enabled\n", __func__); return; @@ -3614,6 +3647,80 @@ static void hdmi_tx_fps_work(struct work_struct *work) hdmi_tx_update_fps(hdmi_ctrl); } +static u64 hdmi_tx_clip_valid_pclk(struct hdmi_tx_ctrl *hdmi_ctrl, u64 pclk_in) +{ + struct msm_hdmi_mode_timing_info timing = {0}; + u32 pclk_delta, pclk; + u64 pclk_clip = pclk_in; + + hdmi_get_supported_mode(&timing, + &hdmi_ctrl->ds_data, hdmi_ctrl->vic); + + /* as per standard, 0.5% of deviation is allowed */ + pclk = timing.pixel_freq * HDMI_KHZ_TO_HZ; + pclk_delta = pclk * 5 / 1000; + + if (pclk_in < (pclk - pclk_delta)) + pclk_clip = pclk - pclk_delta; + else if (pclk_in > (pclk + pclk_delta)) + pclk_clip = pclk + pclk_delta; + + if (pclk_in != pclk_clip) + pr_debug("the deviation is too big, so clip pclk from %lld to %lld\n", + pclk_in, pclk_clip); + + return pclk_clip; +} + +/** + * hdmi_tx_update_ppm() - Update the HDMI pixel clock as per the input ppm + * + * @ppm: ppm is parts per million multiplied by 1000. + * return: 0 on success, non-zero in case of failure. + */ +static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm) +{ + struct mdss_panel_info *pinfo = NULL; + u64 cur_pclk, dst_pclk; + u64 clip_pclk; + int rc = 0; + + if (!hdmi_ctrl) { + pr_err("invalid hdmi_ctrl\n"); + return -EINVAL; + } + + pinfo = &hdmi_ctrl->panel_data.panel_info; + + /* only available in case HDMI is up */ + if (!hdmi_tx_is_panel_on(hdmi_ctrl)) { + pr_err("hdmi is not on\n"); + return -EINVAL; + } + + /* get current pclk */ + cur_pclk = pinfo->clk_rate; + /* get desired pclk */ + dst_pclk = cur_pclk * (1000000000 + ppm); + do_div(dst_pclk, 1000000000); + + clip_pclk = hdmi_tx_clip_valid_pclk(hdmi_ctrl, dst_pclk); + + /* update pclk */ + if (clip_pclk != cur_pclk) { + pr_debug("pclk changes from %llu to %llu when ppm is %d\n", + cur_pclk, clip_pclk, ppm); + pinfo->clk_rate = clip_pclk; + rc = hdmi_tx_update_pixel_clk(hdmi_ctrl); + if (rc < 0) { + pr_err("PPM update failed, reset clock rate\n"); + pinfo->clk_rate = cur_pclk; + } + } + + return rc; +} + static int hdmi_tx_evt_handle_register(struct hdmi_tx_ctrl *hdmi_ctrl) { int rc = 0; @@ -3844,6 +3951,13 @@ static int hdmi_tx_evt_handle_deep_color(struct hdmi_tx_ctrl *hdmi_ctrl) return 0; } +static int hdmi_tx_evt_handle_hdmi_ppm(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + s32 ppm = (s32) (unsigned long)hdmi_ctrl->evt_arg; + + return hdmi_tx_update_ppm(hdmi_ctrl, ppm); +} + static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data, int event, void *arg) { @@ -4545,6 +4659,7 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_evt_handle_panel_off; handler[MDSS_EVENT_CLOSE] = hdmi_tx_evt_handle_close; handler[MDSS_EVENT_DEEP_COLOR] = hdmi_tx_evt_handle_deep_color; + handler[MDSS_EVENT_UPDATE_PANEL_PPM] = hdmi_tx_evt_handle_hdmi_ppm; return 0; } diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index c9fc8ba8bfdb..89890bcf68df 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/delay.h> +#include <linux/msm_mdp.h> #include "mdss_hdmi_util.h" #define RESOLUTION_NAME_STR_LEN 30 @@ -26,6 +27,10 @@ #define HDMI_SCDC_UNKNOWN_REGISTER "Unknown register" +#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 +#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 +#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 + static char res_buf[RESOLUTION_NAME_STR_LEN]; enum trigger_mode { @@ -738,6 +743,30 @@ ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size) return len; } /* hdmi_get_video_3d_fmt_2string */ +int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable) +{ + u32 rate_ratio; + + switch (out_format) { + case MDP_Y_CBCR_H2V2: + rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; + break; + case MDP_Y_CBCR_H2V1: + rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO; + break; + default: + rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; + break; + } + + pixel_freq /= rate_ratio; + + if (dc_enable) + pixel_freq += pixel_freq >> 2; + + return pixel_freq; +} + static void hdmi_ddc_trigger(struct hdmi_tx_ddc_ctrl *ddc_ctrl, enum trigger_mode mode, bool seg) { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index 8a7e4d1ebafc..4fd659616bcc 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -16,6 +16,7 @@ #include "video/msm_hdmi_modes.h" #include "mdss_panel.h" +#include "mdss_hdmi_panel.h" /* HDMI_TX Registers */ #define HDMI_CTRL (0x00000000) @@ -495,6 +496,7 @@ bool hdmi_is_valid_resv_timing(int mode); void hdmi_reset_resv_timing_info(void); int hdmi_panel_get_vic(struct mdss_panel_info *pinfo, struct hdmi_util_ds_data *ds_data); +int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable); /* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */ void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type); diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 1dae41391795..58e0d9676736 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1139,12 +1139,31 @@ static int mdss_mdp_clk_update(u32 clk_idx, u32 enable) { int ret = -ENODEV; struct clk *clk = mdss_mdp_get_clk(clk_idx); + struct mdss_data_type *mdata = mdss_res; if (clk) { pr_debug("clk=%d en=%d\n", clk_idx, enable); if (enable) { if (clk_idx == MDSS_CLK_MDP_VSYNC) clk_set_rate(clk, 19200000); + if (mdss_has_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE) + && (clk_idx == MDSS_CLK_MDP_CORE)) { + + if (WARN_ON(!mdata->mdp_clk_rate)) { + /* + * rate should have been set in probe + * or during clk scaling; but if this + * is not the case, set max clk rate. + */ + pr_warn("set max mdp clk rate:%u\n", + mdata->max_mdp_clk_rate); + mdss_mdp_set_clk_rate( + mdata->max_mdp_clk_rate, true); + } else { + clk_set_rate(clk, mdata->mdp_clk_rate); + } + } + ret = clk_prepare_enable(clk); } else { clk_disable_unprepare(clk); @@ -1172,7 +1191,7 @@ int mdss_mdp_vsync_clk_enable(int enable, bool locked) return ret; } -void mdss_mdp_set_clk_rate(unsigned long rate) +void mdss_mdp_set_clk_rate(unsigned long rate, bool locked) { struct mdss_data_type *mdata = mdss_res; unsigned long clk_rate; @@ -1182,7 +1201,9 @@ void mdss_mdp_set_clk_rate(unsigned long rate) min_clk_rate = max(rate, mdata->perf_tune.min_mdp_clk); if (clk) { - mutex_lock(&mdp_clk_lock); + + if (!locked) + mutex_lock(&mdp_clk_lock); if (min_clk_rate < mdata->max_mdp_clk_rate) clk_rate = clk_round_rate(clk, min_clk_rate); else @@ -1190,12 +1211,15 @@ void mdss_mdp_set_clk_rate(unsigned long rate) if (IS_ERR_VALUE(clk_rate)) { pr_err("unable to round rate err=%ld\n", clk_rate); } else if (clk_rate != clk_get_rate(clk)) { + + mdata->mdp_clk_rate = clk_rate; if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate))) pr_err("clk_set_rate failed\n"); else pr_debug("mdp clk rate=%lu\n", clk_rate); } - mutex_unlock(&mdp_clk_lock); + if (!locked) + mutex_unlock(&mdp_clk_lock); } else { pr_err("mdp src clk not setup properly\n"); } @@ -1779,7 +1803,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) mdss_mdp_irq_clk_register(mdata, "mnoc_clk", MDSS_CLK_MNOC_AHB); /* Setting the default clock rate to the max supported.*/ - mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate); + mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate, false); pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE, false)); @@ -1816,8 +1840,10 @@ static int mdss_mdp_debug_init(struct platform_device *pdev, mdss_debug_register_dump_range(pdev, dbg_blk, "qcom,regs-dump-mdp", "qcom,regs-dump-names-mdp", "qcom,regs-dump-xin-id-mdp"); - mdss_debug_register_io("vbif", &mdata->vbif_io, NULL); - mdss_debug_register_io("vbif_nrt", &mdata->vbif_nrt_io, NULL); + if (mdata->vbif_io.base) + mdss_debug_register_io("vbif", &mdata->vbif_io, NULL); + if (mdata->vbif_nrt_io.base) + mdss_debug_register_io("vbif_nrt", &mdata->vbif_nrt_io, NULL); return 0; } @@ -2020,6 +2046,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT); mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE); + mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE); mdata->has_wb_ubwc = true; set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map); set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map); @@ -2409,12 +2436,12 @@ static void __update_sspp_info(struct mdss_mdp_pipe *pipe, #define SPRINT(fmt, ...) \ (*cnt += scnprintf(buf + *cnt, len - *cnt, fmt, ##__VA_ARGS__)) - for (i = 0; i < pipe_cnt; i++) { + for (i = 0; i < pipe_cnt && pipe; i++) { SPRINT("pipe_num:%d pipe_type:%s pipe_ndx:%d rects:%d pipe_is_handoff:%d display_id:%d ", pipe->num, type, pipe->ndx, pipe->multirect.max_rects, pipe->is_handed_off, mdss_mdp_get_display_id(pipe)); SPRINT("fmts_supported:"); - for (j = 0; j < num_bytes && pipe; j++) + for (j = 0; j < num_bytes; j++) SPRINT("%d,", pipe->supported_formats[j]); SPRINT("\n"); pipe += pipe->multirect.max_rects; @@ -3391,15 +3418,18 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-sw-reset-off", &sw_reset_offset, 1); if (sw_reset_offset) { - mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, - "qcom,mdss-pipe-vig-sw-reset-map", mdata->vig_pipes, - mdata->nvig_pipes); - mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, - "qcom,mdss-pipe-rgb-sw-reset-map", mdata->rgb_pipes, - mdata->nrgb_pipes); - mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, - "qcom,mdss-pipe-dma-sw-reset-map", mdata->dma_pipes, - mdata->ndma_pipes); + if (mdata->vig_pipes) + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-vig-sw-reset-map", + mdata->vig_pipes, mdata->nvig_pipes); + if (mdata->rgb_pipes) + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-rgb-sw-reset-map", + mdata->rgb_pipes, mdata->nrgb_pipes); + if (mdata->dma_pipes) + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-dma-sw-reset-map", + mdata->dma_pipes, mdata->ndma_pipes); } mdata->has_panic_ctrl = of_property_read_bool(pdev->dev.of_node, @@ -3584,6 +3614,7 @@ static int mdss_mdp_cdm_addr_setup(struct mdss_data_type *mdata, head[i].base = (mdata->mdss_io.base) + cdm_offsets[i]; atomic_set(&head[i].kref.refcount, 0); mutex_init(&head[i].lock); + init_completion(&head[i].free_comp); pr_debug("%s: cdm off (%d) = %pK\n", __func__, i, head[i].base); } diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index e1c3841c82de..20aeabfdf9a4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -22,6 +22,7 @@ #include <linux/notifier.h> #include <linux/irqreturn.h> #include <linux/kref.h> +#include <linux/kthread.h> #include "mdss.h" #include "mdss_mdp_hwio.h" @@ -465,6 +466,9 @@ struct mdss_mdp_ctl { u32 vsync_cnt; u32 underrun_cnt; + struct work_struct cpu_pm_work; + int autorefresh_frame_cnt; + u16 width; u16 height; u16 border_x_off; @@ -473,6 +477,7 @@ struct mdss_mdp_ctl { /* used for WFD */ u32 dst_format; + enum mdss_mdp_csc_type csc_type; struct mult_factor dst_comp_ratio; u32 clk_rate; @@ -546,6 +551,7 @@ struct mdss_mdp_ctl { /* dynamic resolution switch during cont-splash handoff */ bool switch_with_handoff; struct mdss_mdp_avr_info avr_info; + bool commit_in_progress; }; struct mdss_mdp_mixer { @@ -927,7 +933,6 @@ struct mdss_overlay_private { struct sw_sync_timeline *vsync_timeline; struct mdss_mdp_vsync_handler vsync_retire_handler; - struct work_struct retire_work; int retire_cnt; bool kickoff_released; u32 cursor_ndx[2]; @@ -939,6 +944,11 @@ struct mdss_overlay_private { struct mdss_mdp_cwb cwb; wait_queue_head_t wb_waitq; atomic_t wb_busy; + bool allow_kickoff; + + struct kthread_worker worker; + struct kthread_work vsync_work; + struct task_struct *thread; }; struct mdss_mdp_set_ot_params { @@ -1586,7 +1596,7 @@ u32 mdss_mdp_get_irq_mask(u32 intr_type, u32 intf_num); void mdss_mdp_footswitch_ctrl_splash(int on); void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable); -void mdss_mdp_set_clk_rate(unsigned long min_clk_rate); +void mdss_mdp_set_clk_rate(unsigned long min_clk_rate, bool locked); unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked); int mdss_mdp_vsync_clk_enable(int enable, bool locked); void mdss_mdp_clk_ctrl(int enable); @@ -1910,6 +1920,7 @@ int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt); int mdss_mdp_ctl_cmd_get_autorefresh(struct mdss_mdp_ctl *ctl); int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd, bool disable_panel); +void mdss_mdp_ctl_event_timer(void *data); int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version); int mdss_mdp_layer_pre_commit_cwb(struct msm_fb_data_type *mfd, struct mdp_layer_commit_v1 *commit); diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.c b/drivers/video/fbdev/msm/mdss_mdp_cdm.c index e0bf1cdf1361..f1d1bdd301e3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_cdm.c +++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,8 @@ static u32 cdm_cdwn2_offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; static u32 cdm_cdwn2_cosite_v_coeff[] = {0x00080004}; static u32 cdm_cdwn2_offsite_v_coeff[] = {0x00060002}; +#define VSYNC_TIMEOUT_US 16000 + /** * @mdss_mdp_cdm_alloc() - Allocates a cdm block by parsing the list of * available cdm blocks. @@ -66,6 +68,7 @@ static void mdss_mdp_cdm_free(struct kref *kref) if (!cdm) return; + complete_all(&cdm->free_comp); pr_debug("free cdm_num = %d\n", cdm->num); } @@ -84,6 +87,28 @@ struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, u32 intf_type) cdm = mdss_mdp_cdm_alloc(mdata); + /** + * give hdmi interface priority to alloc the cdm block. It will wait + * for one vsync cycle to allow wfd to finish its job and try to reserve + * the block the again. + */ + if (!cdm && (intf_type == MDP_CDM_CDWN_OUTPUT_HDMI)) { + /* always wait for first cdm block */ + cdm = mdata->cdm_off; + if (cdm) { + reinit_completion(&cdm->free_comp); + /* + * no need to check the return status of completion + * timeout. Next cdm_alloc call will try to reserve + * the cdm block and returns failure if allocation + * fails. + */ + wait_for_completion_timeout(&cdm->free_comp, + usecs_to_jiffies(VSYNC_TIMEOUT_US)); + cdm = mdss_mdp_cdm_alloc(mdata); + } + } + if (!cdm) { pr_err("%s: Unable to allocate cdm\n", __func__); return ERR_PTR(-EBUSY); @@ -110,7 +135,9 @@ static int mdss_mdp_cdm_csc_setup(struct mdss_mdp_cdm *cdm, mdss_mdp_csc_setup(MDSS_MDP_BLOCK_CDM, cdm->num, data->csc_type); - if (data->csc_type == MDSS_MDP_CSC_RGB2YUV_601L) { + if ((data->csc_type == MDSS_MDP_CSC_RGB2YUV_601L) || + (data->csc_type == MDSS_MDP_CSC_RGB2YUV_601FR) || + (data->csc_type == MDSS_MDP_CSC_RGB2YUV_709L)) { op_mode |= BIT(2); /* DST_DATA_FORMAT = YUV */ op_mode &= ~BIT(1); /* SRC_DATA_FORMAT = RGB */ op_mode |= BIT(0); /* EN = 1 */ @@ -350,17 +377,6 @@ int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm) return -EINVAL; } - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); - mutex_lock(&cdm->lock); - /* Disable HDMI packer */ - writel_relaxed(0x0, cdm->base + MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE); - - /* Put CDM in bypass */ - writel_relaxed(0x0, cdm->mdata->mdp_base + MDSS_MDP_MDP_OUT_CTL_0); - - mutex_unlock(&cdm->lock); - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); - kref_put(&cdm->kref, mdss_mdp_cdm_free); return rc; diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.h b/drivers/video/fbdev/msm/mdss_mdp_cdm.h index 4515628da0e7..3b7fdced6623 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_cdm.h +++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -59,6 +59,7 @@ struct mdss_mdp_cdm { u32 out_intf; bool is_bypassed; struct mdp_cdm_cfg setup; + struct completion free_comp; }; struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 6b71025229a0..c80d8f47bbb7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/bitmap.h> +#include <soc/qcom/event_timer.h> #include "mdss_fb.h" #include "mdss_mdp.h" #include "mdss_mdp_trace.h" @@ -2374,7 +2375,7 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, */ if (update_clk) { ATRACE_INT("mdp_clk", clk_rate); - mdss_mdp_set_clk_rate(clk_rate); + mdss_mdp_set_clk_rate(clk_rate, false); pr_debug("update clk rate = %d HZ\n", clk_rate); } @@ -2681,12 +2682,122 @@ int mdss_mdp_block_mixer_destroy(struct mdss_mdp_mixer *mixer) return 0; } +int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl, + ktime_t *wakeup_time) +{ + struct mdss_panel_info *pinfo; + u64 clk_rate; + u32 clk_period; + u32 current_line, total_line; + u32 time_of_line, time_to_vsync, adjust_line_ns; + + ktime_t current_time = ktime_get(); + + if (!ctl->ops.read_line_cnt_fnc) + return -EINVAL; + + pinfo = &ctl->panel_data->panel_info; + if (!pinfo) + return -ENODEV; + + clk_rate = mdss_mdp_get_pclk_rate(ctl); + + clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */ + if (!clk_rate) + return -EINVAL; + + /* + * calculate clk_period as pico second to maintain good + * accuracy with high pclk rate and this number is in 17 bit + * range. + */ + clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate); + if (!clk_period) + return -EINVAL; + + time_of_line = (pinfo->lcdc.h_back_porch + + pinfo->lcdc.h_front_porch + + pinfo->lcdc.h_pulse_width + + pinfo->xres) * clk_period; + + time_of_line /= 1000; /* in nano second */ + if (!time_of_line) + return -EINVAL; + + current_line = ctl->ops.read_line_cnt_fnc(ctl); + + total_line = pinfo->lcdc.v_back_porch + + pinfo->lcdc.v_front_porch + + pinfo->lcdc.v_pulse_width + + pinfo->yres; + + if (current_line >= total_line) + time_to_vsync = time_of_line * total_line; + else + time_to_vsync = time_of_line * (total_line - current_line); + + if (pinfo->adjust_timer_delay_ms) { + adjust_line_ns = pinfo->adjust_timer_delay_ms + * 1000000; /* convert to ns */ + + /* Ignore large values of adjust_line_ns\ */ + if (time_to_vsync > adjust_line_ns) + time_to_vsync -= adjust_line_ns; + } + + if (!time_to_vsync) + return -EINVAL; + + *wakeup_time = ktime_add_ns(current_time, time_to_vsync); + + pr_debug("clk_rate=%lldkHz clk_period=%d cur_line=%d tot_line=%d\n", + clk_rate, clk_period, current_line, total_line); + pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n", + time_to_vsync, (int)ktime_to_ms(current_time), + (int)ktime_to_ms(*wakeup_time)); + + return 0; +} + +static void __cpu_pm_work_handler(struct work_struct *work) +{ + struct mdss_mdp_ctl *ctl = + container_of(work, typeof(*ctl), cpu_pm_work); + ktime_t wakeup_time; + struct mdss_overlay_private *mdp5_data; + + if (!ctl) + return; + + if (mdss_mdp_display_wakeup_time(ctl, &wakeup_time)) + return; + + mdp5_data = mfd_to_mdp5_data(ctl->mfd); + activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time); +} + +void mdss_mdp_ctl_event_timer(void *data) +{ + struct mdss_overlay_private *mdp5_data = + (struct mdss_overlay_private *)data; + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + + if (mdp5_data->cpu_pm_hdl && ctl && ctl->autorefresh_frame_cnt) + schedule_work(&ctl->cpu_pm_work); +} + int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt) { int ret = 0; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd); if (ctl->panel_data->panel_info.type == MIPI_CMD_PANEL) { ret = mdss_mdp_cmd_set_autorefresh_mode(ctl, frame_cnt); + if (!ret) { + ctl->autorefresh_frame_cnt = frame_cnt; + if (frame_cnt) + mdss_mdp_ctl_event_timer(mdp5_data); + } } else { pr_err("Mode not supported for this panel\n"); ret = -EINVAL; @@ -3824,6 +3935,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, ctl->intf_type = MDSS_INTF_DSI; ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE; ctl->ops.start_fnc = mdss_mdp_cmd_start; + INIT_WORK(&ctl->cpu_pm_work, __cpu_pm_work_handler); break; case DTV_PANEL: ctl->is_video_mode = true; @@ -5383,8 +5495,13 @@ int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl) (pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) || (pinfo->dfps_update == DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) || + (pinfo->dfps_update == + DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) || pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { - new_fps = mdss_panel_get_framerate(pinfo); + if (pinfo->type == DTV_PANEL) + new_fps = pinfo->lcdc.frame_rate; + else + new_fps = mdss_panel_get_framerate(pinfo); } else { new_fps = pinfo->new_fps; } @@ -5410,83 +5527,6 @@ exit: return ret; } -int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl, - ktime_t *wakeup_time) -{ - struct mdss_panel_info *pinfo; - u64 clk_rate; - u32 clk_period; - u32 current_line, total_line; - u32 time_of_line, time_to_vsync, adjust_line_ns; - - ktime_t current_time = ktime_get(); - - if (!ctl->ops.read_line_cnt_fnc) - return -ENOSYS; - - pinfo = &ctl->panel_data->panel_info; - if (!pinfo) - return -ENODEV; - - clk_rate = mdss_mdp_get_pclk_rate(ctl); - - clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */ - if (!clk_rate) - return -EINVAL; - - /* - * calculate clk_period as pico second to maintain good - * accuracy with high pclk rate and this number is in 17 bit - * range. - */ - clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate); - if (!clk_period) - return -EINVAL; - - time_of_line = (pinfo->lcdc.h_back_porch + - pinfo->lcdc.h_front_porch + - pinfo->lcdc.h_pulse_width + - pinfo->xres) * clk_period; - - time_of_line /= 1000; /* in nano second */ - if (!time_of_line) - return -EINVAL; - - current_line = ctl->ops.read_line_cnt_fnc(ctl); - - total_line = pinfo->lcdc.v_back_porch + - pinfo->lcdc.v_front_porch + - pinfo->lcdc.v_pulse_width + - pinfo->yres; - - if (current_line > total_line) - return -EINVAL; - - time_to_vsync = time_of_line * (total_line - current_line); - - if (pinfo->adjust_timer_delay_ms) { - adjust_line_ns = pinfo->adjust_timer_delay_ms - * 1000000; /* convert to ns */ - - /* Ignore large values of adjust_line_ns\ */ - if (time_to_vsync > adjust_line_ns) - time_to_vsync -= adjust_line_ns; - } - - if (!time_to_vsync) - return -EINVAL; - - *wakeup_time = ktime_add_ns(current_time, time_to_vsync); - - pr_debug("clk_rate=%lldkHz clk_period=%d cur_line=%d tot_line=%d\n", - clk_rate, clk_period, current_line, total_line); - pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n", - time_to_vsync, (int)ktime_to_ms(current_time), - (int)ktime_to_ms(*wakeup_time)); - - return 0; -} - int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl) { int ret; @@ -5748,7 +5788,9 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, } else { sctl_flush_bits = sctl->flush_bits; } + sctl->commit_in_progress = true; } + ctl->commit_in_progress = true; ctl_flush_bits = ctl->flush_bits; ATRACE_END("postproc_programming"); @@ -5876,11 +5918,16 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, ATRACE_BEGIN("flush_kickoff"); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits); - if (sctl && sctl_flush_bits) { - mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH, - sctl_flush_bits); - sctl->flush_bits = 0; + if (sctl) { + if (sctl_flush_bits) { + mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH, + sctl_flush_bits); + sctl->flush_bits = 0; + } + sctl->commit_in_progress = false; } + ctl->commit_in_progress = false; + MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits, split_lm_valid); wmb(); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index a71c7254de7c..4852fc73f040 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1267,7 +1267,8 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) atomic_read(&ctx->koff_cnt)); if (sync_ppdone) { atomic_inc(&ctx->pp_done_cnt); - schedule_work(&ctx->pp_done_work); + if (!ctl->commit_in_progress) + schedule_work(&ctx->pp_done_work); mdss_mdp_resource_control(ctl, MDP_RSRC_CTL_EVENT_PP_DONE); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 70b36a08d5ca..5d5515a91572 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -1424,7 +1424,9 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps) pdata->panel_info.dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP || pdata->panel_info.dfps_update - == DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) { + == DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP || + pdata->panel_info.dfps_update + == DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) { unsigned long flags; if (!ctx->timegen_en) { pr_err("TG is OFF. DFPS mode invalid\n"); @@ -1793,21 +1795,12 @@ static inline bool mdss_mdp_video_need_pixel_drop(u32 vic) } static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm, - struct mdss_panel_info *pinfo) + struct mdss_panel_info *pinfo, struct mdss_mdp_format_params *fmt) { - struct mdss_mdp_format_params *fmt; struct mdp_cdm_cfg setup; - fmt = mdss_mdp_get_format_params(pinfo->out_format); - - if (!fmt) { - pr_err("%s: format %d not supported\n", __func__, - pinfo->out_format); - return -EINVAL; - } - setup.out_format = pinfo->out_format; if (fmt->is_yuv) - setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; + setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601FR; else setup.csc_type = MDSS_MDP_CSC_RGB2RGB; @@ -1835,6 +1828,7 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm, return -EINVAL; } + setup.out_format = pinfo->out_format; setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT; setup.output_width = pinfo->xres + pinfo->lcdc.xres_pad; setup.output_height = pinfo->yres + pinfo->lcdc.yres_pad; @@ -1868,6 +1862,7 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl, { struct intf_timing_params *itp = &ctx->itp; u32 dst_bpp; + struct mdss_mdp_format_params *fmt; struct mdss_data_type *mdata = ctl->mdata; struct dsc_desc *dsc = NULL; u32 hdmi_dp_core; @@ -1902,17 +1897,32 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl, } if (mdss_mdp_is_cdm_supported(mdata, ctl->intf_type, 0)) { - ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI); - if (!IS_ERR_OR_NULL(ctl->cdm)) { - if (mdss_mdp_video_cdm_setup(ctl->cdm, pinfo)) { - pr_err("%s: setting up cdm failed\n", - __func__); + + fmt = mdss_mdp_get_format_params(pinfo->out_format); + if (!fmt) { + pr_err("%s: format %d not supported\n", __func__, + pinfo->out_format); + return -EINVAL; + } + if (fmt->is_yuv) { + ctl->cdm = + mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI); + if (!IS_ERR_OR_NULL(ctl->cdm)) { + if (mdss_mdp_video_cdm_setup(ctl->cdm, + pinfo, fmt)) { + pr_err("%s: setting up cdm failed\n", + __func__); + return -EINVAL; + } + ctl->flush_bits |= BIT(26); + } else { + pr_err("%s: failed to initialize cdm\n", + __func__); return -EINVAL; } - ctl->flush_bits |= BIT(26); } else { - pr_err("%s: failed to initialize cdm\n", __func__); - return -EINVAL; + pr_debug("%s: Format is not YUV,cdm not required\n", + __func__); } } else { pr_debug("%s: cdm not supported\n", __func__); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c index e6e03e7d54b2..80549908beb6 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c @@ -57,6 +57,7 @@ struct mdss_mdp_writeback_ctx { u16 width; u16 height; u16 frame_rate; + enum mdss_mdp_csc_type csc_type; struct mdss_rect dst_rect; u32 dnsc_factor_w; @@ -202,17 +203,10 @@ static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx, } static int mdss_mdp_writeback_cdm_setup(struct mdss_mdp_writeback_ctx *ctx, - struct mdss_mdp_cdm *cdm, u32 format) + struct mdss_mdp_cdm *cdm, struct mdss_mdp_format_params *fmt) { - struct mdss_mdp_format_params *fmt; struct mdp_cdm_cfg setup; - fmt = mdss_mdp_get_format_params(format); - if (!fmt) { - pr_err("%s: format %d not supported\n", __func__, format); - return -EINVAL; - } - if (fmt->is_yuv) setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; else @@ -237,10 +231,11 @@ static int mdss_mdp_writeback_cdm_setup(struct mdss_mdp_writeback_ctx *ctx, return -EINVAL; } - setup.out_format = format; + setup.out_format = fmt->format; setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT; setup.output_width = ctx->width; setup.output_height = ctx->height; + setup.csc_type = ctx->csc_type; return mdss_mdp_cdm_setup(cdm, &setup); } @@ -260,10 +255,19 @@ static void mdss_mdp_writeback_cwb_overflow(void *arg) mdp5_data->cwb.valid = 0; mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num); + mdss_mdp_set_intr_callback_nosync(ctx->intr_type, ctx->intf_num, + NULL, NULL); + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0); - if (mdss_mdp_get_split_ctl(ctl)) + mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, + CWB_PPB_0, NULL, NULL); + + if (mdss_mdp_get_split_ctl(ctl)) { mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, - CWB_PPB_1); + CWB_PPB_1); + mdss_mdp_set_intr_callback_nosync( + MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1, NULL, NULL); + } if (!atomic_add_unless(&mdp5_data->wb_busy, -1, 0)) pr_err("Invalid state for WB\n"); @@ -285,10 +289,20 @@ static void mdss_mdp_writeback_cwb_intr_done(void *arg) mdp5_data->cwb.valid = 0; mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num); - mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0); - if (mdss_mdp_get_split_ctl(ctl)) + mdss_mdp_set_intr_callback_nosync(ctx->intr_type, ctx->intf_num, + NULL, NULL); + + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, + CWB_PPB_0); + mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, + CWB_PPB_0, NULL, NULL); + + if (mdss_mdp_get_split_ctl(ctl)) { mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, - CWB_PPB_1); + CWB_PPB_1); + mdss_mdp_set_intr_callback_nosync( + MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1, NULL, NULL); + } queue_work(mdp5_data->cwb.cwb_work_queue, &mdp5_data->cwb.cwb_work); @@ -353,10 +367,9 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx, chroma_samp = fmt->chroma_sample; if (ctl->cdm) { - - rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, format); + rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, fmt); if (rc) { - pr_err("%s: CDM configuration failed with error %d\n", + pr_err("%s: CDM config failed with error %d\n", __func__, rc); return rc; } @@ -495,21 +508,20 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl, pr_err("cwb writeback data setup error\n"); return ret; } - mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num); mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num, mdss_mdp_writeback_cwb_intr_done, ctl); + mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num); - mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, ctl->intf_num); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, - ctl->intf_num, - mdss_mdp_writeback_cwb_overflow, ctl); + CWB_PPB_0, mdss_mdp_writeback_cwb_overflow, ctl); + mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0); + sctl = mdss_mdp_get_split_ctl(ctl); if (sctl) { - mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, - sctl->intf_num); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, - sctl->intf_num, - mdss_mdp_writeback_cwb_overflow, sctl); + CWB_PPB_1, mdss_mdp_writeback_cwb_overflow, + sctl); + mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1); } if (test_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, ctl->mdata->mdss_qos_map)) @@ -544,6 +556,7 @@ static int mdss_mdp_writeback_prepare_wfd(struct mdss_mdp_ctl *ctl, void *arg) ctx->width = ctl->width; ctx->height = ctl->height; ctx->frame_rate = ctl->frame_rate; + ctx->csc_type = ctl->csc_type; ctx->dst_rect.x = 0; ctx->dst_rect.y = 0; ctx->dst_rect.w = ctx->width; @@ -1014,6 +1027,7 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl) struct mdss_mdp_writeback_ctx *ctx; struct mdss_mdp_writeback *wb; u32 mixer_type = MDSS_MDP_MIXER_TYPE_UNUSED; + struct mdss_mdp_format_params *fmt = NULL; bool is_rot; pr_debug("start ctl=%d\n", ctl->num); @@ -1037,6 +1051,10 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl) return -EINVAL; } + fmt = mdss_mdp_get_format_params(ctl->dst_format); + if (!fmt) + return -EINVAL; + is_rot = (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) ? true : false; if (ctl->mixer_left) { @@ -1050,15 +1068,13 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl) } if (mdss_mdp_is_cdm_supported(ctl->mdata, ctl->intf_type, - mixer_type)) { + mixer_type) && fmt->is_yuv) { ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_WB); if (IS_ERR_OR_NULL(ctl->cdm)) { - pr_err("%s failed to init cdm\n", __func__); + pr_err("cdm block already in use\n"); + ctl->cdm = NULL; return -EBUSY; } - } else { - ctl->cdm = NULL; - pr_debug("%s: cdm not supported\n", __func__); } ctl->priv_data = ctx; ctx->wb_num = wb->num; diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 73350b3a5a6f..3fc8e3883250 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -71,6 +71,7 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) { struct mdss_data_type *mdata = ctl->mdata; struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; + struct mdss_mdp_ctl *split_ctl; if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map)) { if (ctl->mixer_left && ctl->mixer_right && @@ -80,9 +81,11 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) /* * DUAL mode disable */ + split_ctl = mdss_mdp_get_split_ctl(ctl); ctl->mixer_left->width = get_panel_width(ctl); ctl->mixer_left->height = get_panel_yres(pinfo); - ctl->mixer_left->width /= 2; + if (!split_ctl) + ctl->mixer_left->width /= 2; ctl->mixer_right->width = ctl->mixer_left->width; ctl->mixer_right->height = ctl->mixer_left->height; ctl->mixer_left->roi = (struct mdss_rect) { 0, 0, @@ -2136,7 +2139,7 @@ static int __validate_multirect(struct msm_fb_data_type *mfd, static int __validate_layers(struct msm_fb_data_type *mfd, struct file *file, struct mdp_layer_commit_v1 *commit) { - int ret, i; + int ret, i = 0; int rec_ndx[MDSS_MDP_PIPE_MAX_RECTS] = { 0 }; int rec_release_ndx[MDSS_MDP_PIPE_MAX_RECTS] = { 0 }; int rec_destroy_ndx[MDSS_MDP_PIPE_MAX_RECTS] = { 0 }; @@ -2660,13 +2663,22 @@ int mdss_mdp_layer_pre_commit(struct msm_fb_data_type *mfd, if (mdp5_data->cwb.valid) { struct sync_fence *retire_fence = NULL; + if (!commit->output_layer) { + pr_err("cwb request without setting output layer\n"); + goto map_err; + } + retire_fence = __create_fence(mfd, &mdp5_data->cwb.cwb_sync_pt_data, MDSS_MDP_CWB_RETIRE_FENCE, &commit->output_layer->buffer.fence, 0); if (IS_ERR_OR_NULL(retire_fence)) { pr_err("failed to handle cwb fence"); + goto map_err; } + + sync_fence_install(retire_fence, + commit->output_layer->buffer.fence); } map_err: diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 298b8743f0a6..bf8130b35a57 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1404,14 +1404,6 @@ int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) mdss_iommu_ctrl(0); } - /* Restore any previously configured PP features by resetting the dirty - * bits for enabled features. The dirty bits will be consumed during the - * first display commit when the PP hardware blocks are updated - */ - rc = mdss_mdp_pp_resume(mfd); - if (rc && (rc != -EPERM) && (rc != -ENODEV)) - pr_err("PP resume err %d\n", rc); - /* * Increment the overlay active count prior to calling ctl_start. * This is needed to ensure that if idle power collapse kicks in @@ -1427,6 +1419,14 @@ int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) goto ctl_error; } + /* Restore any previously configured PP features by resetting the dirty + * bits for enabled features. The dirty bits will be consumed during the + * first display commit when the PP hardware blocks are updated + */ + rc = mdss_mdp_pp_resume(mfd); + if (rc && (rc != -EPERM) && (rc != -ENODEV)) + pr_err("PP resume err %d\n", rc); + rc = mdss_mdp_splash_cleanup(mfd, true); if (!rc) goto end; @@ -1453,6 +1453,21 @@ static void mdss_mdp_overlay_update_pm(struct mdss_overlay_private *mdp5_data) activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time); } +static void __unstage_pipe_and_clean_buf(struct msm_fb_data_type *mfd, + struct mdss_mdp_pipe *pipe, struct mdss_mdp_data *buf) +{ + + pr_debug("unstaging pipe:%d rect:%d buf:%d\n", + pipe->num, pipe->multirect.num, !buf); + MDSS_XLOG(pipe->num, pipe->multirect.num, !buf); + mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); + mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); + pipe->dirty = true; + + if (buf) + __pipe_buf_mark_cleanup(mfd, buf); +} + static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -1573,14 +1588,36 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) ret = mdss_mdp_pipe_queue_data(pipe, buf); if (IS_ERR_VALUE(ret)) { - pr_warn("Unable to queue data for pnum=%d\n", - pipe->num); - mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); - mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); - pipe->dirty = true; + pr_warn("Unable to queue data for pnum=%d rect=%d\n", + pipe->num, pipe->multirect.num); - if (buf) - __pipe_buf_mark_cleanup(mfd, buf); + /* + * If we fail for a multi-rect pipe, unstage both rects + * so we don't leave the pipe configured in multi-rect + * mode with only one rectangle staged. + */ + if (pipe->multirect.mode != + MDSS_MDP_PIPE_MULTIRECT_NONE) { + struct mdss_mdp_pipe *next_pipe = + (struct mdss_mdp_pipe *) + pipe->multirect.next; + + if (next_pipe) { + struct mdss_mdp_data *next_buf = + list_first_entry_or_null( + &next_pipe->buf_queue, + struct mdss_mdp_data, + pipe_list); + + __unstage_pipe_and_clean_buf(mfd, + next_pipe, next_buf); + } else { + pr_warn("cannot find rect pnum=%d\n", + pipe->num); + } + } + + __unstage_pipe_and_clean_buf(mfd, pipe, buf); } } @@ -1886,6 +1923,8 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe) pipe->dst.y = pipe->layer.dst_rect.y; pipe->dst.w = pipe->layer.dst_rect.w; pipe->dst.h = pipe->layer.dst_rect.h; + + pipe->restore_roi = false; } /** @@ -1909,7 +1948,6 @@ static int __crop_adjust_pipe_rect(struct mdss_mdp_pipe *pipe, u32 roi_y_pos; int ret = 0; - pipe->restore_roi = false; if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->first_roi)) { mdss_mdp_crop_rect(&pipe->src, &pipe->dst, &dual_roi->first_roi, false); @@ -2055,6 +2093,13 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd, } list_for_each_entry(pipe, &mdp5_data->pipes_used, list) { + /* + * Restore the pipe src/dst ROI if it was altered + * in the previous kickoff. + */ + if (pipe->restore_roi) + __restore_pipe(pipe); + pr_debug("pipe:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d}\n", pipe->num, pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h, pipe->dst.x, @@ -3027,16 +3072,23 @@ static void cache_initial_timings(struct mdss_panel_data *pdata) * This value will change dynamically once the * actual dfps update happen in hw. */ - pdata->panel_info.current_fps = - mdss_panel_get_framerate(&pdata->panel_info); - + if (pdata->panel_info.type == DTV_PANEL) + pdata->panel_info.current_fps = + pdata->panel_info.lcdc.frame_rate; + else + pdata->panel_info.current_fps = + mdss_panel_get_framerate(&pdata->panel_info); /* * Keep the initial fps and porch values for this panel before * any dfps update happen, this is to prevent losing precision * in further calculations. */ - pdata->panel_info.default_fps = - mdss_panel_get_framerate(&pdata->panel_info); + if (pdata->panel_info.type == DTV_PANEL) + pdata->panel_info.default_fps = + pdata->panel_info.lcdc.frame_rate; + else + pdata->panel_info.default_fps = + mdss_panel_get_framerate(&pdata->panel_info); if (pdata->panel_info.dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) { @@ -3048,7 +3100,9 @@ static void cache_initial_timings(struct mdss_panel_data *pdata) } else if (pdata->panel_info.dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP || pdata->panel_info.dfps_update == - DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) { + DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP || + pdata->panel_info.dfps_update == + DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) { pdata->panel_info.saved_total = mdss_panel_get_htotal(&pdata->panel_info, true); pdata->panel_info.saved_fporch = @@ -3117,8 +3171,25 @@ static void dfps_update_panel_params(struct mdss_panel_data *pdata, pdata->panel_info.lcdc.h_pulse_width = data->hpw; pdata->panel_info.clk_rate = data->clk_rate; + if (pdata->panel_info.type == DTV_PANEL) + pdata->panel_info.clk_rate *= 1000; dfps_update_fps(&pdata->panel_info, new_fps); + } else if (pdata->panel_info.dfps_update == + DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) { + + pr_debug("hfp=%d, hbp=%d, hpw=%d, clk=%d, fps=%d\n", + data->hfp, data->hbp, data->hpw, + data->clk_rate, data->fps); + + pdata->panel_info.lcdc.h_front_porch = data->hfp; + pdata->panel_info.lcdc.h_back_porch = data->hbp; + pdata->panel_info.lcdc.h_pulse_width = data->hpw; + + pdata->panel_info.clk_rate = data->clk_rate; + + dfps_update_fps(&pdata->panel_info, new_fps); + mdss_panel_update_clk_rate(&pdata->panel_info, new_fps); } else { dfps_update_fps(&pdata->panel_info, new_fps); mdss_panel_update_clk_rate(&pdata->panel_info, new_fps); @@ -3193,7 +3264,9 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev, } if (pdata->panel_info.dfps_update == - DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) { + DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP || + pdata->panel_info.dfps_update == + DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) { if (sscanf(buf, "%u %u %u %u %u", &data.hfp, &data.hbp, &data.hpw, &data.clk_rate, &data.fps) != 5) { @@ -3208,7 +3281,10 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev, } } - panel_fps = mdss_panel_get_framerate(&pdata->panel_info); + if (pdata->panel_info.type == DTV_PANEL) + panel_fps = pdata->panel_info.lcdc.frame_rate; + else + panel_fps = mdss_panel_get_framerate(&pdata->panel_info); if (data.fps == panel_fps) { pr_debug("%s: FPS is already %d\n", @@ -3271,7 +3347,7 @@ static ssize_t mdss_mdp_lineptr_show_event(struct device *dev, if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) - return -EAGAIN; + return -EPERM; lineptr_ticks = ktime_to_ns(mdp5_data->lineptr_time); @@ -3292,7 +3368,7 @@ static ssize_t mdss_mdp_lineptr_show_value(struct device *dev, if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) - return -EAGAIN; + return -EPERM; lineptr_val = mfd->panel_info->te.wr_ptr_irq; @@ -3728,6 +3804,9 @@ static ssize_t mdss_mdp_misr_store(struct device *dev, return rc; } + req.block_id = DISPLAY_MISR_MAX; + sreq.block_id = DISPLAY_MISR_MAX; + pr_debug("intf_type:%d enable:%d\n", ctl->intf_type, enable_misr); if (ctl->intf_type == MDSS_INTF_DSI) { @@ -4365,9 +4444,7 @@ static int mdss_bl_scale_config(struct msm_fb_data_type *mfd, mutex_lock(&mfd->bl_lock); curr_bl = mfd->bl_level; mfd->bl_scale = data->scale; - mfd->bl_min_lvl = data->min_lvl; - pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale, - mfd->bl_min_lvl); + pr_debug("update scale = %d\n", mfd->bl_scale); /* update current backlight to use new scaling*/ mdss_fb_set_backlight(mfd, curr_bl); @@ -4577,6 +4654,20 @@ static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd, return ret; } +static int mdss_fb_set_panel_ppm(struct msm_fb_data_type *mfd, s32 ppm) +{ + struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); + int ret = 0; + + if (!ctl) + return -EPERM; + + ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UPDATE_PANEL_PPM, + (void *) (unsigned long) ppm, + CTL_INTF_EVENT_FLAG_DEFAULT); + return ret; +} + static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd, struct mdss_hw_caps *caps) { @@ -5123,6 +5214,16 @@ static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd, } ret = mdss_mdp_set_cfg(mfd, &cfg); break; + case MSMFB_MDP_SET_PANEL_PPM: + ret = copy_from_user(&val, argp, sizeof(val)); + if (ret) { + pr_err("copy failed MSMFB_MDP_SET_PANEL_PPM ret %d\n", + ret); + ret = -EFAULT; + break; + } + ret = mdss_fb_set_panel_ppm(mfd, val); + break; default: break; @@ -5487,7 +5588,7 @@ ctl_stop: * retire_signal api checks for retire_cnt with sync_mutex lock. */ - flush_work(&mdp5_data->retire_work); + flush_kthread_work(&mdp5_data->vsync_work); } mutex_lock(&mdp5_data->ov_lock); @@ -5690,13 +5791,13 @@ static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t) } mdp5_data = mfd_to_mdp5_data(mfd); - schedule_work(&mdp5_data->retire_work); + queue_kthread_work(&mdp5_data->worker, &mdp5_data->vsync_work); } -static void __vsync_retire_work_handler(struct work_struct *work) +static void __vsync_retire_work_handler(struct kthread_work *work) { struct mdss_overlay_private *mdp5_data = - container_of(work, typeof(*mdp5_data), retire_work); + container_of(work, typeof(*mdp5_data), vsync_work); if (!mdp5_data->ctl || !mdp5_data->ctl->mfd) return; @@ -5796,6 +5897,7 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); char name[24]; + struct sched_param param = { .sched_priority = 5 }; snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index); mdp5_data->vsync_timeline = sw_sync_timeline_create(name); @@ -5803,12 +5905,26 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) pr_err("cannot vsync create time line"); return -ENOMEM; } + + init_kthread_worker(&mdp5_data->worker); + init_kthread_work(&mdp5_data->vsync_work, __vsync_retire_work_handler); + + mdp5_data->thread = kthread_run(kthread_worker_fn, + &mdp5_data->worker, "vsync_retire_work"); + + if (IS_ERR(mdp5_data->thread)) { + pr_err("unable to start vsync thread\n"); + mdp5_data->thread = NULL; + return -ENOMEM; + } + + sched_setscheduler(mdp5_data->thread, SCHED_FIFO, ¶m); + mfd->mdp_sync_pt_data.get_retire_fence = __vsync_retire_get_fence; mdp5_data->vsync_retire_handler.vsync_handler = __vsync_retire_handle_vsync; mdp5_data->vsync_retire_handler.cmd_post_flush = false; - INIT_WORK(&mdp5_data->retire_work, __vsync_retire_work_handler); return 0; } @@ -6111,8 +6227,8 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) /* Adding event timer only for primary panel */ if ((mfd->index == 0) && (mfd->panel_info->type != WRITEBACK_PANEL)) { - mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq, NULL, - (void *)mdp5_data); + mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq, + mdss_mdp_ctl_event_timer, (void *)mdp5_data); if (!mdp5_data->cpu_pm_hdl) pr_warn("%s: unable to add event timer\n", __func__); } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index bcf5309993b9..4d42e42035c3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -1114,6 +1114,7 @@ static void mdss_mdp_init_pipe_params(struct mdss_mdp_pipe *pipe) pipe->is_right_blend = false; pipe->src_split_req = false; pipe->bwc_mode = 0; + pipe->restore_roi = false; pipe->mfd = NULL; pipe->mixer_left = pipe->mixer_right = NULL; @@ -2599,7 +2600,8 @@ static int mdss_mdp_set_ts_pipe(struct mdss_mdp_pipe *pipe) __get_ordered_rects(pipe, &low_pipe, &high_pipe); ts_count_low = __get_ts_count(low_pipe, mixer, true); - ts_count_high = __get_ts_count(high_pipe, mixer, false); + if (high_pipe != NULL) + ts_count_high = __get_ts_count(high_pipe, mixer, false); ts_bytes = __get_ts_bytes(pipe, mixer); if (low_pipe->multirect.num == MDSS_MDP_PIPE_RECT0) { @@ -2702,8 +2704,8 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, if (ret) { pr_err("pipe pp setup error for pnum=%d\n", pipe->num); - MDSS_XLOG(pipe->num, pipe->mixer_left->num, - pipe->play_cnt, 0xbad); + MDSS_XLOG(pipe->num, pipe->multirect.num, + pipe->mixer_left->num, pipe->play_cnt, 0xbad); goto done; } @@ -2714,13 +2716,14 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, pipe->params_changed = 0; mdss_mdp_pipe_solidfill_setup(pipe); - MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt, - 0x111); + MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num, + pipe->play_cnt, 0x111); goto update_nobuf; } - MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt, 0x222); + MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num, + pipe->play_cnt, 0x222); if (params_changed) { pipe->params_changed = 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 248492b28ce2..5a8438caba4b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -2519,7 +2519,9 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer) DSPP); } - pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode); + if (pp_sts != NULL) + pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, + &opmode); if (ad_hw) { mutex_lock(&ad->lock); @@ -6984,9 +6986,6 @@ static int is_valid_calib_addr(void *addr, u32 operation) int ret = 0; char __iomem *ptr = addr; char __iomem *mixer_base = mdss_res->mixer_intf->base; - char __iomem *rgb_base = mdss_res->rgb_pipes->base; - char __iomem *dma_base = mdss_res->dma_pipes->base; - char __iomem *vig_base = mdss_res->vig_pipes->base; char __iomem *ctl_base = mdss_res->ctl_off->base; char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base; @@ -7018,17 +7017,20 @@ static int is_valid_calib_addr(void *addr, u32 operation) if (ret) goto valid_addr; } - if (ptr >= vig_base) { + if (mdss_res->vig_pipes && + ptr >= mdss_res->vig_pipes->base) { ret = is_valid_calib_vig_addr(ptr); if (ret) goto valid_addr; } - if (ptr >= rgb_base) { + if (mdss_res->rgb_pipes && + ptr >= mdss_res->rgb_pipes->base) { ret = is_valid_calib_rgb_addr(ptr); if (ret) goto valid_addr; } - if (ptr >= dma_base) { + if (mdss_res->dma_pipes && + ptr >= mdss_res->dma_pipes->base) { ret = is_valid_calib_dma_addr(ptr); if (ret) goto valid_addr; diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index 199c2b66d90e..c14840ffd08d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -573,13 +573,6 @@ int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h, chroma_samp = fmt->chroma_sample; - if (rotation) { - if (chroma_samp == MDSS_MDP_CHROMA_H2V1) - chroma_samp = MDSS_MDP_CHROMA_H1V2; - else if (chroma_samp == MDSS_MDP_CHROMA_H1V2) - chroma_samp = MDSS_MDP_CHROMA_H2V1; - } - mdss_mdp_get_v_h_subsample_rate(chroma_samp, &v_subsample, &h_subsample); @@ -1027,7 +1020,7 @@ static int mdss_mdp_get_img(struct msmfb_data *img, } else if (iclient) { if (mdss_mdp_is_map_needed(mdata, data)) { data->srcp_dma_buf = dma_buf_get(img->memory_id); - if (IS_ERR(data->srcp_dma_buf)) { + if (IS_ERR_OR_NULL(data->srcp_dma_buf)) { pr_err("error on ion_import_fd\n"); ret = PTR_ERR(data->srcp_dma_buf); data->srcp_dma_buf = NULL; diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.c b/drivers/video/fbdev/msm/mdss_mdp_wfd.c index f04450e9974c..71a07f6b7d39 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_wfd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.c @@ -152,6 +152,7 @@ int mdss_mdp_wfd_setup(struct mdss_mdp_wfd *wfd, u32 wb_idx = layer->writeback_ndx; struct mdss_mdp_ctl *ctl = wfd->ctl; struct mdss_mdp_writeback *wb = NULL; + struct mdss_mdp_format_params *fmt = NULL; int ret = 0; u32 width, height, max_mixer_width; @@ -192,6 +193,32 @@ int mdss_mdp_wfd_setup(struct mdss_mdp_wfd *wfd, ctl->roi = (struct mdss_rect) {0, 0, width, height}; ctl->is_secure = (layer->flags & MDP_LAYER_SECURE_SESSION); + fmt = mdss_mdp_get_format_params(layer->buffer.format); + + if (fmt == NULL) { + pr_err("invalid buffer format\n"); + ret = -EINVAL; + goto wfd_setup_error; + } + + /* only 3 csc type supported */ + if (fmt->is_yuv) { + switch (layer->color_space) { + case MDP_CSC_ITU_R_601: + ctl->csc_type = MDSS_MDP_CSC_RGB2YUV_601L; + break; + case MDP_CSC_ITU_R_709: + ctl->csc_type = MDSS_MDP_CSC_RGB2YUV_709L; + break; + case MDP_CSC_ITU_R_601_FR: + default: + ctl->csc_type = MDSS_MDP_CSC_RGB2YUV_601FR; + break; + } + } else { + ctl->csc_type = MDSS_MDP_CSC_RGB2RGB; + } + if (ctl->mdata->wfd_mode == MDSS_MDP_WFD_INTERFACE) { ctl->mixer_left = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF, (width > max_mixer_width), 0); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 0483e3d42873..16bb48e22bee 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -255,6 +255,8 @@ struct mdss_intf_recovery { * Argument provided is new panel timing. * @MDSS_EVENT_DEEP_COLOR: Set deep color. * Argument provided is bits per pixel (8/10/12) + * @MDSS_EVENT_UPDATE_PANEL_PPM: update pixel clock by input PPM. + * Argument provided is parts per million. */ enum mdss_intf_events { MDSS_EVENT_RESET = 1, @@ -287,6 +289,7 @@ enum mdss_intf_events { MDSS_EVENT_PANEL_TIMING_SWITCH, MDSS_EVENT_DEEP_COLOR, MDSS_EVENT_DISABLE_PANEL, + MDSS_EVENT_UPDATE_PANEL_PPM, MDSS_EVENT_MAX, }; @@ -537,7 +540,10 @@ struct dynamic_fps_data { * @DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP: update fps using vertical timings * @DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP: update fps using horizontal timings * @DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP: update fps using both horizontal - * timings and clock. + * timings and clock. + * @DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK: update fps using both + * horizontal timings, clock need to be caculate base on new clock and + * porches. * @DFPS_MODE_MAX: defines maximum limit of supported modes. */ enum dynamic_fps_update { @@ -546,6 +552,7 @@ enum dynamic_fps_update { DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP, DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP, DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP, + DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK, DFPS_MODE_MAX }; @@ -761,6 +768,7 @@ struct mdss_panel_info { bool ulps_suspend_enabled; bool panel_ack_disabled; bool esd_check_enabled; + bool allow_phy_power_off; char dfps_update; /* new requested fps before it is updated in hw */ int new_fps; @@ -974,7 +982,9 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info) break; case DTV_PANEL: if (panel_info->dynamic_fps) { - frame_rate = panel_info->lcdc.frame_rate; + frame_rate = panel_info->lcdc.frame_rate / 1000; + if (panel_info->lcdc.frame_rate % 1000) + frame_rate += 1; break; } default: diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 0c43a2642ede..fdd888edc2fb 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -960,13 +960,22 @@ static void mdss_dsi_8996_phy_power_off( static void mdss_dsi_phy_power_off( struct mdss_dsi_ctrl_pdata *ctrl) { + struct mdss_panel_info *pinfo; + if (ctrl->phy_power_off) return; - /* supported for phy rev 2.0 */ - if (ctrl->shared_data->phy_rev != DSI_PHY_REV_20) + pinfo = &ctrl->panel_data.panel_info; + + if ((ctrl->shared_data->phy_rev != DSI_PHY_REV_20) || + !pinfo->allow_phy_power_off) { + pr_debug("%s: ctrl%d phy rev:%d panel support for phy off:%d\n", + __func__, ctrl->ndx, ctrl->shared_data->phy_rev, + pinfo->allow_phy_power_off); return; + } + /* supported for phy rev 2.0 and if panel allows it*/ mdss_dsi_8996_phy_power_off(ctrl); ctrl->phy_power_off = true; @@ -1003,7 +1012,7 @@ static void mdss_dsi_8996_phy_power_on( static void mdss_dsi_phy_power_on( struct mdss_dsi_ctrl_pdata *ctrl, bool mmss_clamp) { - if (mmss_clamp && (ctrl->shared_data->phy_rev != DSI_PHY_REV_20)) + if (mmss_clamp && !ctrl->phy_power_off) mdss_dsi_phy_init(ctrl); else if ((ctrl->shared_data->phy_rev == DSI_PHY_REV_20) && ctrl->phy_power_off) diff --git a/fs/proc/array.c b/fs/proc/array.c index b6c00ce0e29e..d5c6f5b38617 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -171,15 +171,15 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, seq_printf(m, "State:\t%s\n" "Tgid:\t%d\n" - "Ngid:\t%d\n" "Pid:\t%d\n" "PPid:\t%d\n" "TracerPid:\t%d\n" "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n" + "Ngid:\t%d\n" "FDSize:\t%d\nGroups:\t", get_task_state(p), - tgid, ngid, pid_nr_ns(pid, ns), ppid, tpid, + tgid, pid_nr_ns(pid, ns), ppid, tpid, from_kuid_munged(user_ns, cred->uid), from_kuid_munged(user_ns, cred->euid), from_kuid_munged(user_ns, cred->suid), @@ -188,7 +188,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, from_kgid_munged(user_ns, cred->egid), from_kgid_munged(user_ns, cred->sgid), from_kgid_munged(user_ns, cred->fsgid), - max_fds); + ngid, max_fds); group_info = cred->group_info; for (g = 0; g < group_info->ngroups; g++) diff --git a/include/dt-bindings/clock/audio-ext-clk.h b/include/dt-bindings/clock/audio-ext-clk.h index 6e4932342751..c9a8286d7c7f 100644 --- a/include/dt-bindings/clock/audio-ext-clk.h +++ b/include/dt-bindings/clock/audio-ext-clk.h @@ -14,9 +14,19 @@ #define __AUDIO_EXT_CLK_H /* Audio External Clocks */ +#ifdef CONFIG_COMMON_CLK_QCOM +#define AUDIO_PMI_CLK 0 +#define AUDIO_PMIC_LNBB_CLK 1 +#define AUDIO_AP_CLK 2 +#define AUDIO_AP_CLK2 3 +#define AUDIO_LPASS_MCLK 4 +#define AUDIO_LPASS_MCLK2 5 +#else #define clk_audio_ap_clk 0x9b5727cb #define clk_audio_pmi_clk 0xcbfe416d #define clk_audio_ap_clk2 0x454d1e91 #define clk_audio_lpass_mclk 0xf0f2a284 #define clk_audio_pmi_lnbb_clk 0x57312343 #endif + +#endif diff --git a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h index ffb80a128dd6..7a6ec2bf2418 100644 --- a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h +++ b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h @@ -159,46 +159,47 @@ #define MMSS_MDSS_AXI_CLK 142 #define MMSS_MDSS_BYTE0_CLK 143 #define MMSS_MDSS_BYTE0_INTF_CLK 144 -#define MMSS_MDSS_BYTE1_CLK 145 -#define MMSS_MDSS_BYTE1_INTF_CLK 146 -#define MMSS_MDSS_DP_AUX_CLK 147 -#define MMSS_MDSS_DP_CRYPTO_CLK 148 -#define MMSS_MDSS_DP_GTC_CLK 149 -#define MMSS_MDSS_DP_LINK_CLK 150 -#define MMSS_MDSS_DP_LINK_INTF_CLK 151 -#define MMSS_MDSS_DP_PIXEL_CLK 152 -#define MMSS_MDSS_ESC0_CLK 153 -#define MMSS_MDSS_ESC1_CLK 154 -#define MMSS_MDSS_HDMI_DP_AHB_CLK 155 -#define MMSS_MDSS_MDP_CLK 156 -#define MMSS_MDSS_PCLK0_CLK 157 -#define MMSS_MDSS_PCLK1_CLK 158 -#define MMSS_MDSS_ROT_CLK 159 -#define MMSS_MDSS_VSYNC_CLK 160 -#define MMSS_MISC_AHB_CLK 161 -#define MMSS_MISC_CXO_CLK 162 -#define MMSS_MNOC_AHB_CLK 163 -#define MMSS_SNOC_DVM_AXI_CLK 164 -#define MMSS_THROTTLE_CAMSS_AHB_CLK 165 -#define MMSS_THROTTLE_CAMSS_AXI_CLK 166 -#define MMSS_THROTTLE_CAMSS_CXO_CLK 167 -#define MMSS_THROTTLE_MDSS_AHB_CLK 168 -#define MMSS_THROTTLE_MDSS_AXI_CLK 169 -#define MMSS_THROTTLE_MDSS_CXO_CLK 170 -#define MMSS_THROTTLE_VIDEO_AHB_CLK 171 -#define MMSS_THROTTLE_VIDEO_AXI_CLK 172 -#define MMSS_THROTTLE_VIDEO_CXO_CLK 173 -#define MMSS_VIDEO_AHB_CLK 174 -#define MMSS_VIDEO_AXI_CLK 175 -#define MMSS_VIDEO_CORE_CLK 176 -#define MMSS_VIDEO_SUBCORE0_CLK 177 -#define PCLK0_CLK_SRC 178 -#define PCLK1_CLK_SRC 179 -#define ROT_CLK_SRC 180 -#define VFE0_CLK_SRC 181 -#define VFE1_CLK_SRC 182 -#define VIDEO_CORE_CLK_SRC 183 -#define VSYNC_CLK_SRC 184 +#define MMSS_MDSS_BYTE0_INTF_DIV_CLK 145 +#define MMSS_MDSS_BYTE1_CLK 146 +#define MMSS_MDSS_BYTE1_INTF_CLK 147 +#define MMSS_MDSS_DP_AUX_CLK 148 +#define MMSS_MDSS_DP_CRYPTO_CLK 149 +#define MMSS_MDSS_DP_GTC_CLK 150 +#define MMSS_MDSS_DP_LINK_CLK 151 +#define MMSS_MDSS_DP_LINK_INTF_CLK 152 +#define MMSS_MDSS_DP_PIXEL_CLK 153 +#define MMSS_MDSS_ESC0_CLK 154 +#define MMSS_MDSS_ESC1_CLK 155 +#define MMSS_MDSS_HDMI_DP_AHB_CLK 156 +#define MMSS_MDSS_MDP_CLK 157 +#define MMSS_MDSS_PCLK0_CLK 158 +#define MMSS_MDSS_PCLK1_CLK 159 +#define MMSS_MDSS_ROT_CLK 160 +#define MMSS_MDSS_VSYNC_CLK 161 +#define MMSS_MISC_AHB_CLK 162 +#define MMSS_MISC_CXO_CLK 163 +#define MMSS_MNOC_AHB_CLK 164 +#define MMSS_SNOC_DVM_AXI_CLK 165 +#define MMSS_THROTTLE_CAMSS_AHB_CLK 166 +#define MMSS_THROTTLE_CAMSS_AXI_CLK 167 +#define MMSS_THROTTLE_CAMSS_CXO_CLK 168 +#define MMSS_THROTTLE_MDSS_AHB_CLK 169 +#define MMSS_THROTTLE_MDSS_AXI_CLK 170 +#define MMSS_THROTTLE_MDSS_CXO_CLK 171 +#define MMSS_THROTTLE_VIDEO_AHB_CLK 172 +#define MMSS_THROTTLE_VIDEO_AXI_CLK 173 +#define MMSS_THROTTLE_VIDEO_CXO_CLK 174 +#define MMSS_VIDEO_AHB_CLK 175 +#define MMSS_VIDEO_AXI_CLK 176 +#define MMSS_VIDEO_CORE_CLK 177 +#define MMSS_VIDEO_SUBCORE0_CLK 178 +#define PCLK0_CLK_SRC 179 +#define PCLK1_CLK_SRC 180 +#define ROT_CLK_SRC 181 +#define VFE0_CLK_SRC 182 +#define VFE1_CLK_SRC 183 +#define VIDEO_CORE_CLK_SRC 184 +#define VSYNC_CLK_SRC 185 #define BIMC_SMMU_GDSC 0 #define CAMSS_CPP_GDSC 1 @@ -209,5 +210,6 @@ #define VIDEO_SUBCORE0_GDSC 6 #define VIDEO_TOP_GDSC 7 +#define CAMSS_MICRO_BCR 0 #endif diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index fd2eb059b991..aed90a4902c7 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -32,6 +32,7 @@ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ #define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */ +#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ struct clk; struct clk_hw; @@ -787,7 +788,8 @@ int of_clk_get_parent_count(struct device_node *np); int of_clk_parent_fill(struct device_node *np, const char **parents, unsigned int size); const char *of_clk_get_parent_name(struct device_node *np, int index); - +int of_clk_detect_critical(struct device_node *np, int index, + unsigned long *flags); void of_clk_init(const struct of_device_id *matches); #else /* !CONFIG_OF */ @@ -825,6 +827,13 @@ static inline const char *of_clk_get_parent_name(struct device_node *np, { return NULL; } + +static inline int of_clk_detect_critical(struct device_node *np, int index, + unsigned long *flags) +{ + return 0; +} + #define of_clk_init(matches) \ { while (0); } #endif /* CONFIG_OF */ diff --git a/include/linux/clk/msm-clk-provider.h b/include/linux/clk/msm-clk-provider.h index a09ce5c3b156..2fa8916ad356 100644 --- a/include/linux/clk/msm-clk-provider.h +++ b/include/linux/clk/msm-clk-provider.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-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 @@ -29,6 +29,7 @@ #include <linux/seq_file.h> #include <linux/clk/msm-clk.h> +#if defined(CONFIG_COMMON_CLK_MSM) /* * Bit manipulation macros */ @@ -265,4 +266,5 @@ static inline const char *clk_name(struct clk *c) return "(null)"; return c->dbg_name; }; +#endif /* CONFIG_COMMON_CLK_MSM */ #endif diff --git a/include/linux/clk/msm-clk.h b/include/linux/clk/msm-clk.h index 964909d25021..8455fd776246 100644 --- a/include/linux/clk/msm-clk.h +++ b/include/linux/clk/msm-clk.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2012-2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2009, 2012-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 @@ -23,6 +23,9 @@ enum branch_mem_flags { CLKFLAG_PERIPH_OFF_SET, CLKFLAG_PERIPH_OFF_CLEAR, }; + +#include <linux/clk.h> + #elif defined(CONFIG_COMMON_CLK_MSM) #define CLKFLAG_INVERT 0x00000001 #define CLKFLAG_NOINVERT 0x00000002 @@ -42,7 +45,6 @@ enum branch_mem_flags { #define CLKFLAG_EPROBE_DEFER 0x00010000 #define CLKFLAG_PERIPH_OFF_SET 0x00020000 #define CLKFLAG_PERIPH_OFF_CLEAR 0x00040000 -#endif struct clk_lookup; struct clk; @@ -132,4 +134,5 @@ int msm_clk_notif_register(struct clk *clk, struct notifier_block *nb); int msm_clk_notif_unregister(struct clk *clk, struct notifier_block *nb); +#endif /* CONFIG_COMMON_CLK_MSM */ #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 4f6711f31939..9c3be2d56ac5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2401,6 +2401,8 @@ struct cpu_cycle_counter_cb { u64 (*get_cpu_cycle_counter)(int cpu); }; +#define MAX_NUM_CGROUP_COLOC_ID 20 + #ifdef CONFIG_SCHED_HMP extern void free_task_load_ptrs(struct task_struct *p); extern int sched_set_window(u64 window_start, unsigned int window_size); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b89c9c2f7f6e..cc1e8d6b3454 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -796,19 +796,15 @@ struct cfg80211_csa_settings { * @iftype_num: array with the number of interfaces of each interface * type. The index is the interface type as specified in &enum * nl80211_iftype. - * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces, - * the GCD of a single value is considered the value itself, so for - * a single interface this should be set to that interface's beacon - * interval - * @beacon_int_different: a flag indicating whether or not all beacon - * intervals (of beaconing interfaces) are different or not. + * @new_beacon_int: set this to the beacon interval of a new interface + * that's not operating yet, if such is to be checked as part of + * the verification */ struct iface_combination_params { int num_different_channels; u8 radar_detect; int iftype_num[NUM_NL80211_IFTYPES]; - u32 beacon_int_gcd; - bool beacon_int_different; + u32 new_beacon_int; }; /** @@ -3219,6 +3215,9 @@ struct wiphy_iftype_ext_capab { * @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden. * If null, then none can be over-ridden. * + * @wdev_list: the list of associated (virtual) interfaces; this list must + * not be modified by the driver, but can be read with RTNL/RCU protection. + * * @max_acl_mac_addrs: Maximum number of MAC addresses that the device * supports for ACL. * @@ -3363,6 +3362,8 @@ struct wiphy { const struct ieee80211_ht_cap *ht_capa_mod_mask; const struct ieee80211_vht_cap *vht_capa_mod_mask; + struct list_head wdev_list; + /* the network namespace this phy lives in currently */ possible_net_t _net; diff --git a/include/net/sock.h b/include/net/sock.h index fca6e414f844..0e49452f5c48 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -457,6 +457,7 @@ struct sock { int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); void (*sk_destruct)(struct sock *sk); + struct rcu_head sk_rcu; }; #define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data))) @@ -739,6 +740,7 @@ enum sock_flags { */ SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ + SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ }; #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) diff --git a/include/net/tcp.h b/include/net/tcp.h index 213601d620e0..52402ab90c57 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1528,6 +1528,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli { if (sk->sk_send_head == skb_unlinked) sk->sk_send_head = NULL; + if (tcp_sk(sk)->highest_sack == skb_unlinked) + tcp_sk(sk)->highest_sack = NULL; } static inline void tcp_init_send_head(struct sock *sk) diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index e713641cc3ec..e01e16e5cebe 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -3609,6 +3609,10 @@ struct asm_alac_cfg { u32 channel_layout_tag; }; +struct asm_g711_dec_cfg { + u32 sample_rate; +}; + struct asm_vorbis_cfg { u32 bit_stream_fmt; }; @@ -4220,6 +4224,22 @@ struct asm_aac_enc_cfg_v2 { } __packed; +#define ASM_MEDIA_FMT_G711_ALAW_FS 0x00010BF7 +#define ASM_MEDIA_FMT_G711_MLAW_FS 0x00010C2E + +struct asm_g711_enc_cfg_v2 { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + + u32 sample_rate; +/* + * Number of samples per second. + * Supported values: 8000, 16000 Hz + */ + +} __packed; + struct asm_vorbis_fmt_blk_v2 { struct apr_hdr hdr; struct asm_data_cmd_media_fmt_update_v2 fmtblk; @@ -4321,6 +4341,12 @@ struct asm_alac_fmt_blk_v2 { } __packed; +struct asm_g711_dec_fmt_blk_v2 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmtblk; + u32 sample_rate; +} __packed; + struct asm_ape_fmt_blk_v2 { struct apr_hdr hdr; struct asm_data_cmd_media_fmt_update_v2 fmtblk; @@ -8811,6 +8837,7 @@ struct afe_param_id_clip_bank_sel { /* Supported OSR clock values */ #define Q6AFE_LPASS_OSR_CLK_12_P288_MHZ 0xBB8000 +#define Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ 0xAC4400 #define Q6AFE_LPASS_OSR_CLK_9_P600_MHZ 0x927C00 #define Q6AFE_LPASS_OSR_CLK_8_P192_MHZ 0x7D0000 #define Q6AFE_LPASS_OSR_CLK_6_P144_MHZ 0x5DC000 diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index f08bd73edb59..efa5af8e661c 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -73,6 +73,11 @@ /* bit 4 represents META enable of encoded data buffer */ #define BUFFER_META_ENABLE 0x0010 +/* bit 5 represents timestamp */ +/* bit 5 - 0 -- ASM_DATA_EVENT_READ_DONE will have relative time-stamp*/ +/* bit 5 - 1 -- ASM_DATA_EVENT_READ_DONE will have absolute time-stamp*/ +#define ABSOLUTE_TIMESTAMP_ENABLE 0x0020 + /* Enable Sample_Rate/Channel_Mode notification event from Decoder */ #define SR_CM_NOTIFY_ENABLE 0x0004 @@ -175,6 +180,7 @@ struct audio_aio_read_param { phys_addr_t paddr; uint32_t len; uint32_t uid; + uint32_t flags;/*meta data flags*/ }; struct audio_port_data { @@ -382,6 +388,10 @@ int q6asm_enc_cfg_blk_aac(struct audio_client *ac, uint32_t bit_rate, uint32_t mode, uint32_t format); +int q6asm_enc_cfg_blk_g711(struct audio_client *ac, + uint32_t frames_per_buf, + uint32_t sample_rate); + int q6asm_enc_cfg_blk_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels); @@ -530,6 +540,9 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac, int q6asm_media_format_block_alac(struct audio_client *ac, struct asm_alac_cfg *cfg, int stream_id); +int q6asm_media_format_block_g711(struct audio_client *ac, + struct asm_g711_dec_cfg *cfg, int stream_id); + int q6asm_stream_media_format_block_vorbis(struct audio_client *ac, struct asm_vorbis_cfg *cfg, int stream_id); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 14bd1e806ad7..748b7c277a3c 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -302,6 +302,8 @@ header-y += msm_audio_wma.h header-y += msm_audio_wmapro.h header-y += msm_audio_alac.h header-y += msm_audio_ape.h +header-y += msm_audio_g711.h +header-y += msm_audio_g711_dec.h header-y += msm_ion.h header-y += msm_kgsl.h header-y += msm_pft.h diff --git a/include/uapi/linux/msm_audio_g711.h b/include/uapi/linux/msm_audio_g711.h new file mode 100644 index 000000000000..48ebd6a1131e --- /dev/null +++ b/include/uapi/linux/msm_audio_g711.h @@ -0,0 +1,17 @@ +#ifndef _UAPI_MSM_AUDIO_G711_H +#define _UAPI_MSM_AUDIO_G711_H + +#include <linux/msm_audio.h> + +struct msm_audio_g711_enc_config { + uint32_t sample_rate; +}; + +#define AUDIO_SET_G711_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config) + +#define AUDIO_GET_G711_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config) + + +#endif /* _UAPI_MSM_AUDIO_G711_H */ diff --git a/include/uapi/linux/msm_audio_g711_dec.h b/include/uapi/linux/msm_audio_g711_dec.h new file mode 100644 index 000000000000..ff7e4ce39fd5 --- /dev/null +++ b/include/uapi/linux/msm_audio_g711_dec.h @@ -0,0 +1,16 @@ +#ifndef _UAPI_MSM_AUDIO_G711_H +#define _UAPI_MSM_AUDIO_G711_H + +#include <linux/msm_audio.h> + +struct msm_audio_g711_dec_config { + uint32_t sample_rate; +}; + +#define AUDIO_SET_G711_DEC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config) + +#define AUDIO_GET_G711_DEC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config) + +#endif /* _UAPI_MSM_AUDIO_G711_H */ diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 1a71e860ba48..24f1e7c7b742 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -31,6 +31,12 @@ struct mdp_set_cfg) /* + * Ioctl for setting the PLL PPM. + * PLL PPM is passed by the user space using this IOCTL. + */ +#define MSMFB_MDP_SET_PANEL_PPM _IOW(MDP_IOCTL_MAGIC, 131, int) + +/* * To allow proper structure padding for 64bit/32bit target */ #ifdef __LP64 @@ -165,6 +171,8 @@ VALIDATE/COMMIT FLAG CONFIGURATION #define MDP_COMMIT_VERSION_1_0 0x00010000 +#define OUT_LAYER_COLOR_SPACE + /********************************************************************** Configuration structures All parameters are input to driver unless mentioned output parameter @@ -357,8 +365,11 @@ struct mdp_output_layer { /* Buffer attached with output layer. Device uses it for commit call */ struct mdp_layer_buffer buffer; + /* color space of the destination */ + enum mdp_color_space color_space; + /* 32bits reserved value for future usage. */ - uint32_t reserved[6]; + uint32_t reserved[5]; }; /* diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index e9b5501c697b..50b8fc32b129 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -2,7 +2,9 @@ #define __MEDIA_INFO_H__ #ifndef MSM_MEDIA_ALIGN -#define MSM_MEDIA_ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1))) +#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\ + ((((__sz) + (__align) - 1) / (__align)) * (__align)) :\ + (((__sz) + (__align) - 1) & (~((__align) - 1)))) #endif #ifndef MSM_MEDIA_ROUNDUP @@ -399,8 +401,195 @@ enum color_fmts { * Extradata, 4096) */ COLOR_FMT_RGBA8888_UBWC, + /* Venus RGBA1010102 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGBA plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 4, 256) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGBA1010102_UBWC, + /* Venus RGB565 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGB plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 2, 128) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGB565_UBWC, + /* P010 UBWC: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride -----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * + * Y_Stride = align(Width * 2, 256) + * UV_Stride = align(Width * 2, 256) + * Y_Scanlines = align(Height, 16) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) + */ + COLOR_FMT_P010_UBWC, }; +#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC +#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC +#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC + static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height) { (void)height; @@ -433,6 +622,10 @@ static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width) stride = MSM_MEDIA_ALIGN(width, 192); stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); break; + case COLOR_FMT_P010_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; default: break; } @@ -460,6 +653,10 @@ static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width) stride = MSM_MEDIA_ALIGN(width, 192); stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); break; + case COLOR_FMT_P010_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; default: break; } @@ -482,6 +679,7 @@ static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height) alignment = 32; break; case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: alignment = 16; break; default: @@ -504,6 +702,7 @@ static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height) case COLOR_FMT_NV12: case COLOR_FMT_NV12_MVTB: case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: alignment = 16; break; case COLOR_FMT_NV12_UBWC: @@ -528,6 +727,7 @@ static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width) switch (color_fmt) { case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010_UBWC: y_tile_width = 32; break; case COLOR_FMT_NV12_BPP10_UBWC: @@ -556,6 +756,7 @@ static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height) y_tile_height = 8; break; case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: y_tile_height = 4; break; default: @@ -578,6 +779,7 @@ static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width) switch (color_fmt) { case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010_UBWC: uv_tile_width = 16; break; case COLOR_FMT_NV12_BPP10_UBWC: @@ -606,6 +808,7 @@ static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height) uv_tile_height = 8; break; case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: uv_tile_height = 4; break; default: @@ -621,7 +824,7 @@ invalid_input: static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width) { - unsigned int alignment = 0, stride = 0; + unsigned int alignment = 0, stride = 0, bpp = 4; if (!width) goto invalid_input; @@ -630,14 +833,19 @@ static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width) case COLOR_FMT_RGBA8888: alignment = 128; break; + case COLOR_FMT_RGB565_UBWC: + alignment = 128; + bpp = 2; + break; case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: alignment = 256; break; default: goto invalid_input; } - stride = MSM_MEDIA_ALIGN(width * 4, alignment); + stride = MSM_MEDIA_ALIGN(width * bpp, alignment); invalid_input: return stride; @@ -655,6 +863,8 @@ static inline unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height) alignment = 32; break; case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: alignment = 16; break; default: @@ -676,6 +886,8 @@ static inline unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width) switch (color_fmt) { case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: rgb_tile_width = 16; break; default: @@ -698,6 +910,8 @@ static inline unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height) switch (color_fmt) { case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: rgb_tile_height = 4; break; default: diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index cdb85170919a..e4d41d4072c5 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -261,6 +261,26 @@ struct msm_vfe_fetch_eng_start { uint32_t frame_id; }; +enum msm_vfe_fetch_eng_pass { + OFFLINE_FIRST_PASS, + OFFLINE_SECOND_PASS, + OFFLINE_MAX_PASS, +}; + +struct msm_vfe_fetch_eng_multi_pass_start { + uint32_t session_id; + uint32_t stream_id; + uint32_t buf_idx; + uint8_t offline_mode; + uint32_t fd; + uint32_t buf_addr; + uint32_t frame_id; + uint32_t output_buf_idx; + uint32_t input_buf_offset; + enum msm_vfe_fetch_eng_pass offline_pass; + uint32_t output_stream_id; +}; + struct msm_vfe_axi_plane_cfg { uint32_t output_width; /*Include padding*/ uint32_t output_height; @@ -328,6 +348,7 @@ enum msm_vfe_axi_stream_update_type { UPDATE_STREAM_REMOVE_BUFQ, UPDATE_STREAM_SW_FRAME_DROP, UPDATE_STREAM_REQUEST_FRAMES_VER2, + UPDATE_STREAM_OFFLINE_AXI_CONFIG, }; #define UPDATE_STREAM_REQUEST_FRAMES_VER2 UPDATE_STREAM_REQUEST_FRAMES_VER2 @@ -853,6 +874,8 @@ enum msm_isp_ioctl_cmd_code { MSM_ISP_SET_DUAL_HW_MASTER_SLAVE, MSM_ISP_MAP_BUF_START_FE, MSM_ISP_UNMAP_BUF, + MSM_ISP_FETCH_ENG_MULTI_PASS_START, + MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, }; #define VIDIOC_MSM_VFE_REG_CFG \ @@ -958,4 +981,11 @@ enum msm_isp_ioctl_cmd_code { #define VIDIOC_MSM_ISP_AHB_CLK_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE+25, struct msm_isp_ahb_clk_cfg) +#define VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START \ + _IOWR('V', MSM_ISP_FETCH_ENG_MULTI_PASS_START, \ + struct msm_vfe_fetch_eng_multi_pass_start) + +#define VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE \ + _IOWR('V', MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, \ + struct msm_vfe_fetch_eng_multi_pass_start) #endif /* __MSMB_ISP__ */ diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 47367c663011..ef96966b2bbe 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -70,6 +70,11 @@ #define Q6_DTS 0x00010D88 #define Q6_DTS_LBR 0x00010DBB +/* Timestamp flsg */ +/* Bit-0 - 1 : Enable Timestamp mode */ +/* Bit-0 - 0 : Disable Timestamp mode */ +#define COMPRESSED_TIMESTAMP_FLAG 0x0001 + /* Codecs are listed linearly to allow for extensibility */ #define SND_AUDIOCODEC_PCM ((__u32) 0x00000001) #define SND_AUDIOCODEC_MP3 ((__u32) 0x00000002) @@ -480,7 +485,24 @@ struct snd_codec { __u32 align; __u32 compr_passthr; union snd_codec_options options; - __u32 reserved[3]; + __u32 flags; + __u32 reserved[2]; } __attribute__((packed, aligned(4))); + +/** struct snd_codec_metadata + * @length: Length of the encoded buffer. + * @offset: Offset from the buffer address to the first byte of the first + * encoded frame. All encoded frames are consecutive starting + * from this offset. + * @timestamp: Session time in microseconds of the first sample in the buffer. + * @reserved: Reserved for future use. + */ +struct snd_codec_metadata { + __u32 length; + __u32 offset; + __u64 timestamp; + __u32 reserved[4]; +}; + #endif diff --git a/kernel/auditsc.c b/kernel/auditsc.c index b86cc04959de..48f45987dc6c 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -73,6 +73,7 @@ #include <linux/compat.h> #include <linux/ctype.h> #include <linux/string.h> +#include <linux/uaccess.h> #include <uapi/linux/limits.h> #include "audit.h" @@ -82,7 +83,8 @@ #define AUDITSC_SUCCESS 1 #define AUDITSC_FAILURE 2 -/* no execve audit message should be longer than this (userspace limits) */ +/* no execve audit message should be longer than this (userspace limits), + * see the note near the top of audit_log_execve_info() about this value */ #define MAX_EXECVE_AUDIT_LEN 7500 /* max length to print of cmdline/proctitle value during audit */ @@ -988,184 +990,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid, return rc; } -/* - * to_send and len_sent accounting are very loose estimates. We aren't - * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being - * within about 500 bytes (next page boundary) - * - * why snprintf? an int is up to 12 digits long. if we just assumed when - * logging that a[%d]= was going to be 16 characters long we would be wasting - * space in every audit message. In one 7500 byte message we can log up to - * about 1000 min size arguments. That comes down to about 50% waste of space - * if we didn't do the snprintf to find out how long arg_num_len was. - */ -static int audit_log_single_execve_arg(struct audit_context *context, - struct audit_buffer **ab, - int arg_num, - size_t *len_sent, - const char __user *p, - char *buf) +static void audit_log_execve_info(struct audit_context *context, + struct audit_buffer **ab) { - char arg_num_len_buf[12]; - const char __user *tmp_p = p; - /* how many digits are in arg_num? 5 is the length of ' a=""' */ - size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5; - size_t len, len_left, to_send; - size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN; - unsigned int i, has_cntl = 0, too_long = 0; - int ret; - - /* strnlen_user includes the null we don't want to send */ - len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1; - - /* - * We just created this mm, if we can't find the strings - * we just copied into it something is _very_ wrong. Similar - * for strings that are too long, we should not have created - * any. - */ - if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) { - send_sig(SIGKILL, current, 0); - return -1; + long len_max; + long len_rem; + long len_full; + long len_buf; + long len_abuf; + long len_tmp; + bool require_data; + bool encode; + unsigned int iter; + unsigned int arg; + char *buf_head; + char *buf; + const char __user *p = (const char __user *)current->mm->arg_start; + + /* NOTE: this buffer needs to be large enough to hold all the non-arg + * data we put in the audit record for this argument (see the + * code below) ... at this point in time 96 is plenty */ + char abuf[96]; + + /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the + * current value of 7500 is not as important as the fact that it + * is less than 8k, a setting of 7500 gives us plenty of wiggle + * room if we go over a little bit in the logging below */ + WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500); + len_max = MAX_EXECVE_AUDIT_LEN; + + /* scratch buffer to hold the userspace args */ + buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); + if (!buf_head) { + audit_panic("out of memory for argv string"); + return; } + buf = buf_head; - /* walk the whole argument looking for non-ascii chars */ + audit_log_format(*ab, "argc=%d", context->execve.argc); + + len_rem = len_max; + len_buf = 0; + len_full = 0; + require_data = true; + encode = false; + iter = 0; + arg = 0; do { - if (len_left > MAX_EXECVE_AUDIT_LEN) - to_send = MAX_EXECVE_AUDIT_LEN; - else - to_send = len_left; - ret = copy_from_user(buf, tmp_p, to_send); - /* - * There is no reason for this copy to be short. We just - * copied them here, and the mm hasn't been exposed to user- - * space yet. - */ - if (ret) { - WARN_ON(1); - send_sig(SIGKILL, current, 0); - return -1; - } - buf[to_send] = '\0'; - has_cntl = audit_string_contains_control(buf, to_send); - if (has_cntl) { - /* - * hex messages get logged as 2 bytes, so we can only - * send half as much in each message - */ - max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2; - break; - } - len_left -= to_send; - tmp_p += to_send; - } while (len_left > 0); - - len_left = len; - - if (len > max_execve_audit_len) - too_long = 1; - - /* rewalk the argument actually logging the message */ - for (i = 0; len_left > 0; i++) { - int room_left; - - if (len_left > max_execve_audit_len) - to_send = max_execve_audit_len; - else - to_send = len_left; - - /* do we have space left to send this argument in this ab? */ - room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent; - if (has_cntl) - room_left -= (to_send * 2); - else - room_left -= to_send; - if (room_left < 0) { - *len_sent = 0; - audit_log_end(*ab); - *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); - if (!*ab) - return 0; - } + /* NOTE: we don't ever want to trust this value for anything + * serious, but the audit record format insists we + * provide an argument length for really long arguments, + * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but + * to use strncpy_from_user() to obtain this value for + * recording in the log, although we don't use it + * anywhere here to avoid a double-fetch problem */ + if (len_full == 0) + len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1; + + /* read more data from userspace */ + if (require_data) { + /* can we make more room in the buffer? */ + if (buf != buf_head) { + memmove(buf_head, buf, len_buf); + buf = buf_head; + } + + /* fetch as much as we can of the argument */ + len_tmp = strncpy_from_user(&buf_head[len_buf], p, + len_max - len_buf); + if (len_tmp == -EFAULT) { + /* unable to copy from userspace */ + send_sig(SIGKILL, current, 0); + goto out; + } else if (len_tmp == (len_max - len_buf)) { + /* buffer is not large enough */ + require_data = true; + /* NOTE: if we are going to span multiple + * buffers force the encoding so we stand + * a chance at a sane len_full value and + * consistent record encoding */ + encode = true; + len_full = len_full * 2; + p += len_tmp; + } else { + require_data = false; + if (!encode) + encode = audit_string_contains_control( + buf, len_tmp); + /* try to use a trusted value for len_full */ + if (len_full < len_max) + len_full = (encode ? + len_tmp * 2 : len_tmp); + p += len_tmp + 1; + } + len_buf += len_tmp; + buf_head[len_buf] = '\0'; - /* - * first record needs to say how long the original string was - * so we can be sure nothing was lost. - */ - if ((i == 0) && (too_long)) - audit_log_format(*ab, " a%d_len=%zu", arg_num, - has_cntl ? 2*len : len); - - /* - * normally arguments are small enough to fit and we already - * filled buf above when we checked for control characters - * so don't bother with another copy_from_user - */ - if (len >= max_execve_audit_len) - ret = copy_from_user(buf, p, to_send); - else - ret = 0; - if (ret) { - WARN_ON(1); - send_sig(SIGKILL, current, 0); - return -1; + /* length of the buffer in the audit record? */ + len_abuf = (encode ? len_buf * 2 : len_buf + 2); } - buf[to_send] = '\0'; - - /* actually log it */ - audit_log_format(*ab, " a%d", arg_num); - if (too_long) - audit_log_format(*ab, "[%d]", i); - audit_log_format(*ab, "="); - if (has_cntl) - audit_log_n_hex(*ab, buf, to_send); - else - audit_log_string(*ab, buf); - - p += to_send; - len_left -= to_send; - *len_sent += arg_num_len; - if (has_cntl) - *len_sent += to_send * 2; - else - *len_sent += to_send; - } - /* include the null we didn't log */ - return len + 1; -} -static void audit_log_execve_info(struct audit_context *context, - struct audit_buffer **ab) -{ - int i, len; - size_t len_sent = 0; - const char __user *p; - char *buf; + /* write as much as we can to the audit log */ + if (len_buf > 0) { + /* NOTE: some magic numbers here - basically if we + * can't fit a reasonable amount of data into the + * existing audit buffer, flush it and start with + * a new buffer */ + if ((sizeof(abuf) + 8) > len_rem) { + len_rem = len_max; + audit_log_end(*ab); + *ab = audit_log_start(context, + GFP_KERNEL, AUDIT_EXECVE); + if (!*ab) + goto out; + } - p = (const char __user *)current->mm->arg_start; + /* create the non-arg portion of the arg record */ + len_tmp = 0; + if (require_data || (iter > 0) || + ((len_abuf + sizeof(abuf)) > len_rem)) { + if (iter == 0) { + len_tmp += snprintf(&abuf[len_tmp], + sizeof(abuf) - len_tmp, + " a%d_len=%lu", + arg, len_full); + } + len_tmp += snprintf(&abuf[len_tmp], + sizeof(abuf) - len_tmp, + " a%d[%d]=", arg, iter++); + } else + len_tmp += snprintf(&abuf[len_tmp], + sizeof(abuf) - len_tmp, + " a%d=", arg); + WARN_ON(len_tmp >= sizeof(abuf)); + abuf[sizeof(abuf) - 1] = '\0'; + + /* log the arg in the audit record */ + audit_log_format(*ab, "%s", abuf); + len_rem -= len_tmp; + len_tmp = len_buf; + if (encode) { + if (len_abuf > len_rem) + len_tmp = len_rem / 2; /* encoding */ + audit_log_n_hex(*ab, buf, len_tmp); + len_rem -= len_tmp * 2; + len_abuf -= len_tmp * 2; + } else { + if (len_abuf > len_rem) + len_tmp = len_rem - 2; /* quotes */ + audit_log_n_string(*ab, buf, len_tmp); + len_rem -= len_tmp + 2; + /* don't subtract the "2" because we still need + * to add quotes to the remaining string */ + len_abuf -= len_tmp; + } + len_buf -= len_tmp; + buf += len_tmp; + } - audit_log_format(*ab, "argc=%d", context->execve.argc); + /* ready to move to the next argument? */ + if ((len_buf == 0) && !require_data) { + arg++; + iter = 0; + len_full = 0; + require_data = true; + encode = false; + } + } while (arg < context->execve.argc); - /* - * we need some kernel buffer to hold the userspace args. Just - * allocate one big one rather than allocating one of the right size - * for every single argument inside audit_log_single_execve_arg() - * should be <8k allocation so should be pretty safe. - */ - buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); - if (!buf) { - audit_panic("out of memory for argv string"); - return; - } + /* NOTE: the caller handles the final audit_log_end() call */ - for (i = 0; i < context->execve.argc; i++) { - len = audit_log_single_execve_arg(context, ab, i, - &len_sent, p, buf); - if (len <= 0) - break; - p += len; - } - kfree(buf); +out: + kfree(buf_head); } static void show_special(struct audit_context *context, int *call_panic) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ae83d9602aa0..8c9823947c7a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -6002,7 +6002,7 @@ static int cgroup_css_links_read(struct seq_file *seq, void *v) struct task_struct *task; int count = 0; - seq_printf(seq, "css_set %p\n", cset); + seq_printf(seq, "css_set %pK\n", cset); list_for_each_entry(task, &cset->tasks, cg_list) { if (count++ > MAX_TASKS_SHOWN_PER_CSS) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 69c32c42080f..582b66e882ce 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -358,7 +358,11 @@ int pm_qos_update_target(struct pm_qos_constraints *c, spin_unlock_irqrestore(&pm_qos_lock, flags); trace_pm_qos_update_target(action, prev_value, curr_value); - if (prev_value != curr_value) { + /* + * if cpu mask bits are set, call the notifier call chain + * to update the new qos restriction for the cores + */ + if (!cpumask_empty(&cpus)) { ret = 1; if (c->notifiers) blocking_notifier_call_chain(c->notifiers, @@ -592,7 +596,6 @@ void pm_qos_add_request(struct pm_qos_request *req, #ifdef CONFIG_SMP case PM_QOS_REQ_AFFINE_IRQ: if (irq_can_set_affinity(req->irq)) { - int ret = 0; struct irq_desc *desc = irq_to_desc(req->irq); struct cpumask *mask = desc->irq_data.common->affinity; @@ -602,13 +605,6 @@ void pm_qos_add_request(struct pm_qos_request *req, req->irq_notify.notify = pm_qos_irq_notify; req->irq_notify.release = pm_qos_irq_release; - ret = irq_set_affinity_notifier(req->irq, - &req->irq_notify); - if (ret) { - WARN(1, KERN_ERR "IRQ affinity notify set failed\n"); - req->type = PM_QOS_REQ_ALL_CORES; - cpumask_setall(&req->cpus_affine); - } } else { req->type = PM_QOS_REQ_ALL_CORES; cpumask_setall(&req->cpus_affine); @@ -630,6 +626,24 @@ void pm_qos_add_request(struct pm_qos_request *req, trace_pm_qos_add_request(pm_qos_class, value); pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, req, PM_QOS_ADD_REQ, value); + +#ifdef CONFIG_SMP + if (req->type == PM_QOS_REQ_AFFINE_IRQ && + irq_can_set_affinity(req->irq)) { + int ret = 0; + + ret = irq_set_affinity_notifier(req->irq, + &req->irq_notify); + if (ret) { + WARN(1, "IRQ affinity notify set failed\n"); + req->type = PM_QOS_REQ_ALL_CORES; + cpumask_setall(&req->cpus_affine); + pm_qos_update_target( + pm_qos_array[pm_qos_class]->constraints, + req, PM_QOS_UPDATE_REQ, value); + } + } +#endif } EXPORT_SYMBOL_GPL(pm_qos_add_request); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a5d101e8a5f2..d7846edd7a79 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5600,7 +5600,6 @@ int do_isolation_work_cpu_stop(void *data) */ nohz_balance_clear_nohz_mask(cpu); - clear_hmp_request(cpu); local_irq_enable(); return 0; } @@ -5682,7 +5681,7 @@ int sched_isolate_cpu(int cpu) if (trace_sched_isolate_enabled()) start_time = sched_clock(); - lock_device_hotplug(); + cpu_maps_update_begin(); cpumask_andnot(&avail_cpus, cpu_online_mask, cpu_isolated_mask); @@ -5725,13 +5724,14 @@ int sched_isolate_cpu(int cpu) migrate_sync_cpu(cpu, cpumask_first(&avail_cpus)); stop_cpus(cpumask_of(cpu), do_isolation_work_cpu_stop, 0); + clear_hmp_request(cpu); calc_load_migrate(rq); update_max_interval(); sched_update_group_capacities(cpu); out: - unlock_device_hotplug(); + cpu_maps_update_done(); trace_sched_isolate(cpu, cpumask_bits(cpu_isolated_mask)[0], start_time, 1); return ret_code; @@ -5752,8 +5752,6 @@ int sched_unisolate_cpu_unlocked(int cpu) if (trace_sched_isolate_enabled()) start_time = sched_clock(); - lock_device_hotplug_assert(); - if (!cpu_isolation_vote[cpu]) { ret_code = -EINVAL; goto out; @@ -5792,9 +5790,9 @@ int sched_unisolate_cpu(int cpu) { int ret_code; - lock_device_hotplug(); + cpu_maps_update_begin(); ret_code = sched_unisolate_cpu_unlocked(cpu); - unlock_device_hotplug(); + cpu_maps_update_done(); return ret_code; } @@ -8073,6 +8071,9 @@ void __init sched_init(void) atomic_set(&rq->nr_iowait, 0); } + i = alloc_related_thread_groups(); + BUG_ON(i); + set_hmp_defaults(); set_load_weight(&init_task); diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index 9b21a09ec4ba..aac12bfc2ae6 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -893,14 +893,10 @@ static int __ref cpu_callback(struct notifier_block *nfb, unsigned int need; int ret = NOTIFY_OK; - /* Don't affect suspend resume */ - if (action & CPU_TASKS_FROZEN) - return NOTIFY_OK; - if (unlikely(!cluster || !cluster->inited)) return NOTIFY_OK; - switch (action) { + switch (action & ~CPU_TASKS_FROZEN) { case CPU_UP_PREPARE: /* If online state of CPU somehow got out of sync, fix it. */ @@ -1095,7 +1091,7 @@ static int __init core_ctl_init(void) cpufreq_register_notifier(&cpufreq_pol_nb, CPUFREQ_POLICY_NOTIFIER); cpufreq_register_notifier(&cpufreq_gov_nb, CPUFREQ_GOVINFO_NOTIFIER); - lock_device_hotplug(); + cpu_maps_update_begin(); for_each_online_cpu(cpu) { struct cpufreq_policy *policy; int ret; @@ -1109,7 +1105,7 @@ static int __init core_ctl_init(void) cpufreq_cpu_put(policy); } } - unlock_device_hotplug(); + cpu_maps_update_done(); initialized = true; return 0; } diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 968a41e0e81e..6304c5030137 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -641,14 +641,18 @@ void clear_hmp_request(int cpu) clear_boost_kick(cpu); clear_reserved(cpu); if (rq->push_task) { + struct task_struct *push_task = NULL; + raw_spin_lock_irqsave(&rq->lock, flags); if (rq->push_task) { clear_reserved(rq->push_cpu); - put_task_struct(rq->push_task); + push_task = rq->push_task; rq->push_task = NULL; } rq->active_balance = 0; raw_spin_unlock_irqrestore(&rq->lock, flags); + if (push_task) + put_task_struct(push_task); } } @@ -784,11 +788,12 @@ __read_mostly unsigned int sched_major_task_runtime = 10000000; static unsigned int sync_cpu; -static LIST_HEAD(related_thread_groups); +struct related_thread_group *related_thread_groups[MAX_NUM_CGROUP_COLOC_ID]; +static LIST_HEAD(active_related_thread_groups); static DEFINE_RWLOCK(related_thread_group_lock); #define for_each_related_thread_group(grp) \ - list_for_each_entry(grp, &related_thread_groups, list) + list_for_each_entry(grp, &active_related_thread_groups, list) /* * Task load is categorized into buckets for the purpose of top task tracking. @@ -1767,20 +1772,20 @@ static int send_notification(struct rq *rq, int check_pred, int check_groups) if (freq_required < cur_freq + sysctl_sched_pred_alert_freq) return 0; } else { - read_lock(&related_thread_group_lock); + read_lock_irqsave(&related_thread_group_lock, flags); /* * Protect from concurrent update of rq->prev_runnable_sum and * group cpu load */ - raw_spin_lock_irqsave(&rq->lock, flags); + raw_spin_lock(&rq->lock); if (check_groups) _group_load_in_cpu(cpu_of(rq), &group_load, NULL); new_load = rq->prev_runnable_sum + group_load; new_load = freq_policy_load(rq, new_load); - raw_spin_unlock_irqrestore(&rq->lock, flags); - read_unlock(&related_thread_group_lock); + raw_spin_unlock(&rq->lock); + read_unlock_irqrestore(&related_thread_group_lock, flags); cur_freq = load_to_freq(rq, rq->old_busy_time); freq_required = load_to_freq(rq, new_load); @@ -3052,7 +3057,7 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) read_unlock(&tasklist_lock); - list_for_each_entry(grp, &related_thread_groups, list) { + list_for_each_entry(grp, &active_related_thread_groups, list) { int j; for_each_possible_cpu(j) { @@ -3202,14 +3207,16 @@ void sched_get_cpus_busy(struct sched_load *busy, if (unlikely(cpus == 0)) return; + local_irq_save(flags); + + read_lock(&related_thread_group_lock); + /* * This function could be called in timer context, and the * current task may have been executing for a long time. Ensure * that the window stats are current by doing an update. */ - read_lock(&related_thread_group_lock); - local_irq_save(flags); for_each_cpu(cpu, query_cpus) raw_spin_lock(&cpu_rq(cpu)->lock); @@ -3309,10 +3316,11 @@ skip_early: for_each_cpu(cpu, query_cpus) raw_spin_unlock(&(cpu_rq(cpu))->lock); - local_irq_restore(flags); read_unlock(&related_thread_group_lock); + local_irq_restore(flags); + i = 0; for_each_cpu(cpu, query_cpus) { rq = cpu_rq(cpu); @@ -3965,47 +3973,54 @@ _group_cpu_time(struct related_thread_group *grp, int cpu) return grp ? per_cpu_ptr(grp->cpu_time, cpu) : NULL; } -struct related_thread_group *alloc_related_thread_group(int group_id) +static inline struct related_thread_group* +lookup_related_thread_group(unsigned int group_id) { - struct related_thread_group *grp; - - grp = kzalloc(sizeof(*grp), GFP_ATOMIC); - if (!grp) - return ERR_PTR(-ENOMEM); - - if (alloc_group_cputime(grp)) { - kfree(grp); - return ERR_PTR(-ENOMEM); - } - - grp->id = group_id; - INIT_LIST_HEAD(&grp->tasks); - INIT_LIST_HEAD(&grp->list); - raw_spin_lock_init(&grp->lock); - - return grp; + return related_thread_groups[group_id]; } -struct related_thread_group *lookup_related_thread_group(unsigned int group_id) +int alloc_related_thread_groups(void) { + int i, ret; struct related_thread_group *grp; - list_for_each_entry(grp, &related_thread_groups, list) { - if (grp->id == group_id) - return grp; + /* groupd_id = 0 is invalid as it's special id to remove group. */ + for (i = 1; i < MAX_NUM_CGROUP_COLOC_ID; i++) { + grp = kzalloc(sizeof(*grp), GFP_NOWAIT); + if (!grp) { + ret = -ENOMEM; + goto err; + } + + if (alloc_group_cputime(grp)) { + kfree(grp); + ret = -ENOMEM; + goto err; + } + + grp->id = i; + INIT_LIST_HEAD(&grp->tasks); + INIT_LIST_HEAD(&grp->list); + raw_spin_lock_init(&grp->lock); + + related_thread_groups[i] = grp; } - return NULL; -} + return 0; -/* See comments before preferred_cluster() */ -static void free_related_thread_group(struct rcu_head *rcu) -{ - struct related_thread_group *grp = container_of(rcu, struct - related_thread_group, rcu); +err: + for (i = 1; i < MAX_NUM_CGROUP_COLOC_ID; i++) { + grp = lookup_related_thread_group(i); + if (grp) { + free_group_cputime(grp); + kfree(grp); + related_thread_groups[i] = NULL; + } else { + break; + } + } - free_group_cputime(grp); - kfree(grp); + return ret; } static void remove_task_from_group(struct task_struct *p) @@ -4030,10 +4045,12 @@ static void remove_task_from_group(struct task_struct *p) raw_spin_unlock(&grp->lock); /* Reserved groups cannot be destroyed */ - if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID) { - list_del(&grp->list); - call_rcu(&grp->rcu, free_related_thread_group); - } + if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID) + /* + * We test whether grp->list is attached with list_empty() + * hence re-init the list after deletion. + */ + list_del_init(&grp->list); } static int @@ -4105,53 +4122,15 @@ void add_new_task_to_grp(struct task_struct *new) write_unlock_irqrestore(&related_thread_group_lock, flags); } -#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE) -/* - * We create a default colocation group at boot. There is no need to - * synchronize tasks between cgroups at creation time because the - * correct cgroup hierarchy is not available at boot. Therefore cgroup - * colocation is turned off by default even though the colocation group - * itself has been allocated. Furthermore this colocation group cannot - * be destroyted once it has been created. All of this has been as part - * of runtime optimizations. - * - * The job of synchronizing tasks to the colocation group is done when - * the colocation flag in the cgroup is turned on. - */ -static int __init create_default_coloc_group(void) -{ - struct related_thread_group *grp = NULL; - unsigned long flags; - - grp = alloc_related_thread_group(DEFAULT_CGROUP_COLOC_ID); - if (IS_ERR(grp)) { - WARN_ON(1); - return -ENOMEM; - } - - write_lock_irqsave(&related_thread_group_lock, flags); - list_add(&grp->list, &related_thread_groups); - write_unlock_irqrestore(&related_thread_group_lock, flags); - - update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH); - return 0; -} -late_initcall(create_default_coloc_group); - -int sync_cgroup_colocation(struct task_struct *p, bool insert) -{ - unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0; - - return sched_set_group_id(p, grp_id); -} -#endif - -int sched_set_group_id(struct task_struct *p, unsigned int group_id) +static int __sched_set_group_id(struct task_struct *p, unsigned int group_id) { int rc = 0; unsigned long flags; struct related_thread_group *grp = NULL; + if (group_id >= MAX_NUM_CGROUP_COLOC_ID) + return -EINVAL; + raw_spin_lock_irqsave(&p->pi_lock, flags); write_lock(&related_thread_group_lock); @@ -4167,29 +4146,26 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id) } grp = lookup_related_thread_group(group_id); - if (!grp) { - /* This is a reserved id */ - if (group_id == DEFAULT_CGROUP_COLOC_ID) { - rc = -EINVAL; - goto done; - } - - grp = alloc_related_thread_group(group_id); - if (IS_ERR(grp)) { - rc = -ENOMEM; - goto done; - } - - list_add(&grp->list, &related_thread_groups); - } + if (list_empty(&grp->list)) + list_add(&grp->list, &active_related_thread_groups); rc = add_task_to_group(p, grp); done: write_unlock(&related_thread_group_lock); raw_spin_unlock_irqrestore(&p->pi_lock, flags); + return rc; } +int sched_set_group_id(struct task_struct *p, unsigned int group_id) +{ + /* DEFAULT_CGROUP_COLOC_ID is a reserved id */ + if (group_id == DEFAULT_CGROUP_COLOC_ID) + return -EINVAL; + + return __sched_set_group_id(p, group_id); +} + unsigned int sched_get_group_id(struct task_struct *p) { unsigned int group_id; @@ -4203,6 +4179,42 @@ unsigned int sched_get_group_id(struct task_struct *p) return group_id; } +#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE) +/* + * We create a default colocation group at boot. There is no need to + * synchronize tasks between cgroups at creation time because the + * correct cgroup hierarchy is not available at boot. Therefore cgroup + * colocation is turned off by default even though the colocation group + * itself has been allocated. Furthermore this colocation group cannot + * be destroyted once it has been created. All of this has been as part + * of runtime optimizations. + * + * The job of synchronizing tasks to the colocation group is done when + * the colocation flag in the cgroup is turned on. + */ +static int __init create_default_coloc_group(void) +{ + struct related_thread_group *grp = NULL; + unsigned long flags; + + grp = lookup_related_thread_group(DEFAULT_CGROUP_COLOC_ID); + write_lock_irqsave(&related_thread_group_lock, flags); + list_add(&grp->list, &active_related_thread_groups); + write_unlock_irqrestore(&related_thread_group_lock, flags); + + update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH); + return 0; +} +late_initcall(create_default_coloc_group); + +int sync_cgroup_colocation(struct task_struct *p, bool insert) +{ + unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0; + + return __sched_set_group_id(p, grp_id); +} +#endif + static void update_cpu_cluster_capacity(const cpumask_t *cpus) { int i; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 30838bb9b442..f569c6fe3cbb 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1448,6 +1448,8 @@ static inline void update_cgroup_boost_settings(void) { } static inline void restore_cgroup_boost_settings(void) { } #endif +extern int alloc_related_thread_groups(void); + #else /* CONFIG_SCHED_HMP */ struct hmp_sched_stats; @@ -1638,6 +1640,7 @@ static inline void set_hmp_defaults(void) { } static inline void clear_reserved(int cpu) { } static inline void sched_boost_parse_dt(void) {} +static inline int alloc_related_thread_groups(void) { return 0; } #define trace_sched_cpu_load(...) #define trace_sched_cpu_load_lb(...) diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 00c96462cc36..3ecd3807c2c2 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -7,6 +7,7 @@ #include <linux/pageblock-flags.h> #include <linux/memory.h> #include <linux/hugetlb.h> +#include <linux/kasan.h> #include "internal.h" static int set_migratetype_isolate(struct page *page, @@ -105,6 +106,8 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype) if (pfn_valid_within(page_to_pfn(buddy)) && !is_migrate_isolate_page(buddy)) { __isolate_free_page(page, order); + kasan_alloc_pages(page, order); + arch_alloc_page(page, order); kernel_map_pages(page, (1 << order), 1); set_page_refcounted(page); isolated_page = page; diff --git a/net/core/sock.c b/net/core/sock.c index 0d91f7dca751..fed6f3462c95 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1439,8 +1439,12 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, } EXPORT_SYMBOL(sk_alloc); -void sk_destruct(struct sock *sk) +/* Sockets having SOCK_RCU_FREE will call this function after one RCU + * grace period. This is the case for UDP sockets and TCP listeners. + */ +static void __sk_destruct(struct rcu_head *head) { + struct sock *sk = container_of(head, struct sock, sk_rcu); struct sk_filter *filter; if (sk->sk_destruct) @@ -1467,6 +1471,14 @@ void sk_destruct(struct sock *sk) sk_prot_free(sk->sk_prot_creator, sk); } +void sk_destruct(struct sock *sk) +{ + if (sock_flag(sk, SOCK_RCU_FREE)) + call_rcu(&sk->sk_rcu, __sk_destruct); + else + __sk_destruct(&sk->sk_rcu); +} + static void __sk_free(struct sock *sk) { if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt)) diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 77afe913d03d..9adedba78eea 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -326,10 +326,12 @@ replay: nlh = nlmsg_hdr(skb); err = 0; - if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) || - skb->len < nlh->nlmsg_len) { - err = -EINVAL; - goto ack; + if (nlh->nlmsg_len < NLMSG_HDRLEN || + skb->len < nlh->nlmsg_len || + nlmsg_len(nlh) < sizeof(struct nfgenmsg)) { + nfnl_err_reset(&err_list); + status |= NFNL_BATCH_FAILURE; + goto done; } /* Only requests are handled by the kernel */ diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7a5fa0c98377..2b67ae1c53e4 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -926,16 +926,6 @@ static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) static void netlink_sock_destruct(struct sock *sk) { - struct netlink_sock *nlk = nlk_sk(sk); - - if (nlk->cb_running) { - if (nlk->cb.done) - nlk->cb.done(&nlk->cb); - - module_put(nlk->cb.module); - kfree_skb(nlk->cb.skb); - } - skb_queue_purge(&sk->sk_receive_queue); #ifdef CONFIG_NETLINK_MMAP if (1) { @@ -1070,8 +1060,9 @@ static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) rcu_read_lock(); sk = __netlink_lookup(table, portid, net); - if (sk) - sock_hold(sk); + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + rcu_read_unlock(); return sk; @@ -1198,6 +1189,7 @@ static int __netlink_create(struct net *net, struct socket *sock, mutex_init(&nlk->pg_vec_lock); #endif + sock_set_flag(sk, SOCK_RCU_FREE); sk->sk_destruct = netlink_sock_destruct; sk->sk_protocol = protocol; return 0; @@ -1262,13 +1254,6 @@ out_module: goto out; } -static void deferred_put_nlk_sk(struct rcu_head *head) -{ - struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu); - - sock_put(&nlk->sk); -} - static int netlink_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -1341,7 +1326,19 @@ static int netlink_release(struct socket *sock) local_bh_disable(); sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1); local_bh_enable(); - call_rcu(&nlk->rcu, deferred_put_nlk_sk); + if (nlk->cb_running) { + mutex_lock(nlk->cb_mutex); + if (nlk->cb_running) { + if (nlk->cb.done) + nlk->cb.done(&nlk->cb); + + module_put(nlk->cb.module); + kfree_skb(nlk->cb.skb); + nlk->cb_running = false; + } + mutex_unlock(nlk->cb_mutex); + } + sock_put(sk); return 0; } diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 14437d9b1965..6acee01a419f 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -52,7 +52,6 @@ struct netlink_sock { #endif /* CONFIG_NETLINK_MMAP */ struct rhash_head node; - struct rcu_head rcu; }; static inline struct netlink_sock *nlk_sk(struct sock *sk) diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c index 185b609e637f..35b94e9da0d9 100644 --- a/net/rmnet_data/rmnet_data_handlers.c +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -505,6 +505,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) { LOGD("Failed to add headroom of %d bytes", required_headroom); + kfree_skb(skb); return 1; } } @@ -528,6 +529,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, if (!map_header) { LOGD("%s", "Failed to add MAP header to egress packet"); + kfree_skb(skb); return 1; } diff --git a/net/wireless/chan.c b/net/wireless/chan.c index cf14c7e22fb3..d5ccaeaa76e0 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -749,7 +749,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy, * and thus fail the GO instantiation, consider only the interfaces of * the current registered device. */ - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { struct ieee80211_channel *other_chan = NULL; int r1, r2; diff --git a/net/wireless/core.c b/net/wireless/core.c index 6d3402434a63..16043faba52c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -3,6 +3,7 @@ * * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright 2015 Intel Deutschland GmbH */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -157,7 +158,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) return -EOPNOTSUPP; - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (!wdev->netdev) continue; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; @@ -171,7 +172,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, /* failed -- clean up to old netns */ net = wiphy_net(&rdev->wiphy); - list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, + list_for_each_entry_continue_reverse(wdev, + &rdev->wiphy.wdev_list, list) { if (!wdev->netdev) continue; @@ -230,7 +232,7 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) ASSERT_RTNL(); - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (wdev->netdev) { dev_close(wdev->netdev); continue; @@ -298,7 +300,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) kfree(item); spin_unlock_irq(&rdev->destroy_list_lock); - list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) { + list_for_each_entry_safe(wdev, tmp, + &rdev->wiphy.wdev_list, list) { if (nlportid == wdev->owner_nlportid) rdev_del_virtual_intf(rdev, wdev); } @@ -400,7 +403,7 @@ use_default_name: dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); } - INIT_LIST_HEAD(&rdev->wdev_list); + INIT_LIST_HEAD(&rdev->wiphy.wdev_list); INIT_LIST_HEAD(&rdev->beacon_registrations); spin_lock_init(&rdev->beacon_registrations_lock); spin_lock_init(&rdev->bss_lock); @@ -812,7 +815,7 @@ void wiphy_unregister(struct wiphy *wiphy) nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); rdev->wiphy.registered = false; - WARN_ON(!list_empty(&rdev->wdev_list)); + WARN_ON(!list_empty(&rdev->wiphy.wdev_list)); /* * First remove the hardware from everywhere, this makes @@ -949,7 +952,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, spin_lock_init(&wdev->mgmt_registrations_lock); wdev->identifier = ++rdev->wdev_id; - list_add_rcu(&wdev->list, &rdev->wdev_list); + list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); rdev->devlist_generation++; /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; diff --git a/net/wireless/core.h b/net/wireless/core.h index fcd59e76a8e5..a06a1056f726 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -50,8 +50,7 @@ struct cfg80211_registered_device { /* wiphy index, internal only */ int wiphy_idx; - /* associated wireless interfaces, protected by rtnl or RCU */ - struct list_head wdev_list; + /* protected by RTNL */ int devlist_generation, wdev_id; int opencount; /* also protected by devlist_mtx */ wait_queue_head_t dev_wait; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 40299f19c09b..375d6c1732fa 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -103,7 +103,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) continue; - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (have_ifidx && wdev->netdev && wdev->netdev->ifindex == ifidx) { result = wdev; @@ -149,7 +149,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); if (tmp) { /* make sure wdev exists */ - list_for_each_entry(wdev, &tmp->wdev_list, list) { + list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) { if (wdev->identifier != (u32)wdev_id) continue; found = true; @@ -524,7 +524,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, *rdev = wiphy_to_rdev(wiphy); *wdev = NULL; - list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { + list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) { if (tmp->identifier == cb->args[1]) { *wdev = tmp; break; @@ -2504,7 +2504,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * } if_idx = 0; - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (if_idx < if_start) { if_idx++; continue; @@ -2776,7 +2776,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) spin_lock_init(&wdev->mgmt_registrations_lock); wdev->identifier = ++rdev->wdev_id; - list_add_rcu(&wdev->list, &rdev->wdev_list); + list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); rdev->devlist_generation++; break; default: @@ -3585,7 +3585,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev; bool ret = false; - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO) continue; @@ -7770,12 +7770,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.beacon_interval = 100; - if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { + if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) ibss.beacon_interval = nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); - if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) - return -EINVAL; - } + + err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC, + ibss.beacon_interval); + if (err) + return err; if (!rdev->ops->join_ibss) return -EOPNOTSUPP; @@ -9013,9 +9015,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { setup.beacon_interval = nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); - if (setup.beacon_interval < 10 || - setup.beacon_interval > 10000) - return -EINVAL; + + err = cfg80211_validate_beacon_int(rdev, + NL80211_IFTYPE_MESH_POINT, + setup.beacon_interval); + if (err) + return err; } if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { @@ -10328,7 +10333,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, *wdev = NULL; if (cb->args[1]) { - list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { + list_for_each_entry(tmp, &wiphy->wdev_list, list) { if (tmp->identifier == cb->args[1] - 1) { *wdev = tmp; break; @@ -13339,7 +13344,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, sched_scan_req->owner_nlportid == notify->portid) schedule_scan_stop = true; - list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { + list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) { cfg80211_mlme_unregister_socket(wdev, notify->portid); if (wdev->owner_nlportid == notify->portid) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2fed05f2edf8..050d7948dd68 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1685,7 +1685,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy) struct cfg80211_sched_scan_request *sched_scan_req; ASSERT_RTNL(); - list_for_each_entry(wdev, &rdev->wdev_list, list) + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) if (!reg_wdev_chan_valid(wiphy, wdev)) { dev = wdev->netdev; switch (wdev->iftype) { diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 37d8ab3a71be..e5b962d2ffe7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -54,7 +54,7 @@ static bool cfg80211_is_all_countryie_ignore(void) bool is_all_countryie_ignore = true; list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { wdev_lock(wdev); if (!(wdev->wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE)) { @@ -246,7 +246,7 @@ void cfg80211_conn_work(struct work_struct *work) rtnl_lock(); - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (!wdev->netdev) continue; @@ -630,7 +630,7 @@ static bool cfg80211_is_all_idle(void) * count as new regulatory hints. */ list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { wdev_lock(wdev); if (wdev->conn || wdev->current_bss) is_all_idle = false; diff --git a/net/wireless/util.c b/net/wireless/util.c index acff02fcc281..ef394e8a42bc 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -13,6 +13,7 @@ #include <net/dsfield.h> #include <linux/if_vlan.h> #include <linux/mpls.h> +#include <linux/gcd.h> #include "core.h" #include "rdev-ops.h" @@ -910,7 +911,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) ASSERT_RTNL(); - list_for_each_entry(wdev, &rdev->wdev_list, list) + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) cfg80211_process_wdev_events(wdev); } @@ -1482,47 +1483,53 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, } EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); -int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, - enum nl80211_iftype iftype, u32 beacon_int) +static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, + u32 *beacon_int_gcd, + bool *beacon_int_different) { struct wireless_dev *wdev; - struct iface_combination_params params = { - .beacon_int_gcd = beacon_int, /* GCD(n) = n */ - }; - if (!beacon_int) - return -EINVAL; + *beacon_int_gcd = 0; + *beacon_int_different = false; - params.iftype_num[iftype] = 1; - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &wiphy->wdev_list, list) { if (!wdev->beacon_interval) continue; - params.iftype_num[wdev->iftype]++; - } - - list_for_each_entry(wdev, &rdev->wdev_list, list) { - u32 bi_prev = wdev->beacon_interval; - - if (!wdev->beacon_interval) + if (!*beacon_int_gcd) { + *beacon_int_gcd = wdev->beacon_interval; continue; + } - /* slight optimisation - skip identical BIs */ - if (wdev->beacon_interval == beacon_int) + if (wdev->beacon_interval == *beacon_int_gcd) continue; - params.beacon_int_different = true; - - /* Get the GCD */ - while (bi_prev != 0) { - u32 tmp_bi = bi_prev; + *beacon_int_different = true; + *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval); + } - bi_prev = params.beacon_int_gcd % bi_prev; - params.beacon_int_gcd = tmp_bi; - } + if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { + if (*beacon_int_gcd) + *beacon_int_different = true; + *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int); } +} - return cfg80211_check_combinations(&rdev->wiphy, ¶ms); +int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype, u32 beacon_int) +{ + /* + * This is just a basic pre-condition check; if interface combinations + * are possible the driver must already be checking those with a call + * to cfg80211_check_combinations(), in which case we'll validate more + * through the cfg80211_calculate_bi_data() call and code in + * cfg80211_iter_combinations(). + */ + + if (beacon_int < 10 || beacon_int > 10000) + return -EINVAL; + + return 0; } int cfg80211_iter_combinations(struct wiphy *wiphy, @@ -1536,6 +1543,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, int i, j, iftype; int num_interfaces = 0; u32 used_iftypes = 0; + u32 beacon_int_gcd; + bool beacon_int_different; + + /* + * This is a bit strange, since the iteration used to rely only on + * the data given by the driver, but here it now relies on context, + * in form of the currently operating interfaces. + * This is OK for all current users, and saves us from having to + * push the GCD calculations into all the drivers. + * In the future, this should probably rely more on data that's in + * cfg80211 already - the only thing not would appear to be any new + * interfaces (while being brought up) and channel/radar data. + */ + cfg80211_calculate_bi_data(wiphy, params->new_beacon_int, + &beacon_int_gcd, &beacon_int_different); if (params->radar_detect) { rcu_read_lock(); @@ -1598,14 +1620,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, if ((all_iftypes & used_iftypes) != used_iftypes) goto cont; - if (params->beacon_int_gcd) { + if (beacon_int_gcd) { if (c->beacon_int_min_gcd && - params->beacon_int_gcd < c->beacon_int_min_gcd) { - kfree(limits); - return -EINVAL; - } - if (!c->beacon_int_min_gcd && - params->beacon_int_different) + beacon_int_gcd < c->beacon_int_min_gcd) + goto cont; + if (!c->beacon_int_min_gcd && beacon_int_different) goto cont; } @@ -1701,7 +1720,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, break; } - list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { + list_for_each_entry(wdev_iter, &rdev->wiphy.wdev_list, list) { if (wdev_iter == wdev) continue; if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f580a1048d65..5f21eb37eae4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -139,6 +139,10 @@ snd-soc-wcd9xxx-v2-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o ifeq ($(CONFIG_COMMON_CLK_MSM), y) audio-ext-clock-objs := audio-ext-clk.o endif + +ifeq ($(CONFIG_COMMON_CLK_QCOM), y) + audio-ext-clock-up-objs := audio-ext-clk-up.o +endif snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o @@ -349,6 +353,9 @@ obj-$(CONFIG_SND_SOC_WCD934X) += wcd934x/ ifeq ($(CONFIG_COMMON_CLK_MSM), y) obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock.o endif +ifeq ($(CONFIG_COMMON_CLK_QCOM), y) + obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock-up.o +endif obj-$(CONFIG_SND_SOC_WCD9XXX) += snd-soc-wcd9xxx.o obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o obj-$(CONFIG_SND_SOC_WCD_CPE) += snd-soc-wcd-cpe.o diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c new file mode 100644 index 000000000000..f989498e9c32 --- /dev/null +++ b/sound/soc/codecs/audio-ext-clk-up.c @@ -0,0 +1,577 @@ +/* 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 <linux/init.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include "../../../drivers/clk/qcom/common.h" +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <dt-bindings/clock/audio-ext-clk.h> +#include <sound/q6afe-v2.h> + +enum audio_clk_mux { + AP_CLK2, + LPASS_MCLK, + LPASS_MCLK2, +}; + +struct pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *sleep; + struct pinctrl_state *active; +}; + +struct audio_ext_ap_clk { + bool enabled; + int gpio; + struct clk_fixed_factor fact; +}; + +struct audio_ext_pmi_clk { + int gpio; + struct clk_fixed_factor fact; +}; + +struct audio_ext_ap_clk2 { + bool enabled; + struct pinctrl_info pnctrl_info; + struct clk_fixed_factor fact; +}; + +struct audio_ext_lpass_mclk { + struct pinctrl_info pnctrl_info; + struct clk_fixed_factor fact; +}; + +static struct afe_clk_set clk2_config = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR, + Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set lpass_default = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR, + Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set lpass_mclk = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_MCLK_1, + Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_ap_clk, fact.hw); +} + +static int audio_ext_clk_prepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw); + + pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio); + if (gpio_is_valid(audio_clk->gpio)) + return gpio_direction_output(audio_clk->gpio, 1); + return 0; +} + +static void audio_ext_clk_unprepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw); + + pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio); + if (gpio_is_valid(audio_clk->gpio)) + gpio_direction_output(audio_clk->gpio, 0); +} + +static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_ap_clk2, fact.hw); +} + +static int audio_ext_clk2_prepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw); + struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info; + int ret; + + + if (!pnctrl_info->pinctrl || !pnctrl_info->active) + return 0; + + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + + clk2_config.enable = 1; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config); + if (ret < 0) { + pr_err("%s: failed to set clock, ret = %d\n", __func__, ret); + return -EINVAL; + } + + return 0; +} + +static void audio_ext_clk2_unprepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw); + struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info; + int ret; + + if (!pnctrl_info->pinctrl || !pnctrl_info->sleep) + return; + + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) + pr_err("%s: sleep state select failed with %d\n", + __func__, ret); + + clk2_config.enable = 0; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config); + if (ret < 0) + pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret); +} + +static inline struct audio_ext_lpass_mclk *to_audio_lpass_mclk( + struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_lpass_mclk, fact.hw); +} + +static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + } + + lpass_mclk.enable = 1; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &lpass_mclk); + if (ret < 0) { + pr_err("%s afe_set_digital_codec_core_clock failed\n", + __func__); + return ret; + } + + return 0; +} + +static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return; + } + } + + lpass_mclk.enable = 0; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &lpass_mclk); + if (ret < 0) + pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n", + __func__, ret); +} + +static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk2 = + to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + } + + lpass_default.enable = 1; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default); + if (ret < 0) { + pr_err("%s: failed to set clock, ret = %d\n", __func__, ret); + return -EINVAL; + } + + return 0; +} + +static void audio_ext_lpass_mclk2_unprepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk2 = + to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) + pr_err("%s: sleep state select failed with %d\n", + __func__, ret); + } + + lpass_default.enable = 0; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default); + if (ret < 0) + pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret); +} + +static struct clk_ops audio_ext_ap_clk_ops = { + .prepare = audio_ext_clk_prepare, + .unprepare = audio_ext_clk_unprepare, +}; + +static struct clk_ops audio_ext_ap_clk2_ops = { + .prepare = audio_ext_clk2_prepare, + .unprepare = audio_ext_clk2_unprepare, +}; + +static struct clk_ops audio_ext_lpass_mclk_ops = { + .prepare = audio_ext_lpass_mclk_prepare, + .unprepare = audio_ext_lpass_mclk_unprepare, +}; + +static struct clk_ops audio_ext_lpass_mclk2_ops = { + .prepare = audio_ext_lpass_mclk2_prepare, + .unprepare = audio_ext_lpass_mclk2_unprepare, +}; + +static struct audio_ext_pmi_clk audio_pmi_clk = { + .gpio = -EINVAL, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ext_pmi_clk", + .ops = &clk_dummy_ops, + }, + }, +}; + +static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = { + .gpio = -EINVAL, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ext_pmi_lnbb_clk", + .ops = &clk_dummy_ops, + }, + }, +}; + +static struct audio_ext_ap_clk audio_ap_clk = { + .gpio = -EINVAL, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ap_clk", + .ops = &audio_ext_ap_clk_ops, + }, + }, +}; + +static struct audio_ext_ap_clk2 audio_ap_clk2 = { + .enabled = false, + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ap_clk2", + .ops = &audio_ext_ap_clk2_ops, + }, + }, +}; + +static struct audio_ext_lpass_mclk audio_lpass_mclk = { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk", + .ops = &audio_ext_lpass_mclk_ops, + }, + }, +}; + +static struct audio_ext_lpass_mclk audio_lpass_mclk2 = { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk2", + .ops = &audio_ext_lpass_mclk2_ops, + }, + }, +}; + +static struct clk_hw *audio_msm_hws[] = { + &audio_pmi_clk.fact.hw, + &audio_pmi_lnbb_clk.fact.hw, + &audio_ap_clk.fact.hw, + &audio_ap_clk2.fact.hw, + &audio_lpass_mclk.fact.hw, + &audio_lpass_mclk2.fact.hw, +}; + +static int audio_get_pinctrl(struct platform_device *pdev, + enum audio_clk_mux mux) +{ + struct pinctrl_info *pnctrl_info; + struct pinctrl *pinctrl; + int ret; + + switch (mux) { + case AP_CLK2: + pnctrl_info = &audio_ap_clk2.pnctrl_info; + break; + case LPASS_MCLK: + pnctrl_info = &audio_lpass_mclk.pnctrl_info; + break; + case LPASS_MCLK2: + pnctrl_info = &audio_lpass_mclk2.pnctrl_info; + break; + default: + dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n", + __func__, mux); + return -EINVAL; + } + pnctrl_info = &audio_ap_clk2.pnctrl_info; + + if (pnctrl_info->pinctrl) { + dev_dbg(&pdev->dev, "%s: already requested before\n", + __func__); + return -EINVAL; + } + + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n", + __func__); + return -EINVAL; + } + pnctrl_info->pinctrl = pinctrl; + /* get all state handles from Device Tree */ + pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep"); + if (IS_ERR(pnctrl_info->sleep)) { + dev_err(&pdev->dev, "%s: could not get sleep pinstate\n", + __func__); + goto err; + } + pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active"); + if (IS_ERR(pnctrl_info->active)) { + dev_err(&pdev->dev, "%s: could not get active pinstate\n", + __func__); + goto err; + } + /* Reset the TLMM pins to a default state */ + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n", + __func__, ret); + goto err; + } + return 0; + +err: + devm_pinctrl_put(pnctrl_info->pinctrl); + return -EINVAL; +} + +static int audio_ref_clk_probe(struct platform_device *pdev) +{ + int clk_gpio; + int ret; + u32 mclk_freq; + struct clk *audio_clk; + struct device *dev = &pdev->dev; + int i; + struct clk_onecell_data *clk_data; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,codec-mclk-clk-freq", + &mclk_freq); + if (!ret) { + lpass_mclk.clk_freq_in_hz = mclk_freq; + + ret = audio_get_pinctrl(pdev, LPASS_MCLK); + if (ret) + dev_err(&pdev->dev, "%s: Parsing pinctrl %s failed\n", + __func__, "LPASS_MCLK"); + ret = audio_get_pinctrl(pdev, LPASS_MCLK2); + if (ret) + dev_dbg(&pdev->dev, "%s: Parsing pinctrl %s failed\n", + __func__, "LPASS_MCLK2"); + } + + clk_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,audio-ref-clk-gpio", 0); + if (clk_gpio > 0) { + ret = gpio_request(clk_gpio, "EXT_CLK"); + if (ret) { + dev_err(&pdev->dev, + "Request ext clk gpio failed %d, err:%d\n", + clk_gpio, ret); + goto err; + } + if (of_property_read_bool(pdev->dev.of_node, + "qcom,node_has_rpm_clock")) { + audio_pmi_clk.gpio = clk_gpio; + } else + audio_ap_clk.gpio = clk_gpio; + + } + + ret = audio_get_pinctrl(pdev, AP_CLK2); + if (ret) + dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n", + __func__); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + goto err_gpio; + + clk_data->clk_num = ARRAY_SIZE(audio_msm_hws); + clk_data->clks = devm_kzalloc(&pdev->dev, + clk_data->clk_num * sizeof(struct clk *), + GFP_KERNEL); + if (!clk_data->clks) + goto err_clk; + + for (i = 0; i < ARRAY_SIZE(audio_msm_hws); i++) { + audio_clk = devm_clk_register(dev, audio_msm_hws[i]); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, + "%s: audio ref clock i = %d register failed\n", + __func__, i); + return PTR_ERR(audio_clk); + } + clk_data->clks[i] = audio_clk; + } + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (ret) { + dev_err(&pdev->dev, "%s: audio ref clock register failed\n", + __func__); + goto err_gpio; + } + + return 0; + +err_clk: + if (clk_data) + devm_kfree(&pdev->dev, clk_data->clks); + devm_kfree(&pdev->dev, clk_data); +err_gpio: + gpio_free(clk_gpio); + +err: + return ret; +} + +static int audio_ref_clk_remove(struct platform_device *pdev) +{ + struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info; + + if (audio_pmi_clk.gpio > 0) + gpio_free(audio_pmi_clk.gpio); + else if (audio_ap_clk.gpio > 0) + gpio_free(audio_ap_clk.gpio); + + if (pnctrl_info->pinctrl) { + devm_pinctrl_put(pnctrl_info->pinctrl); + pnctrl_info->pinctrl = NULL; + } + + return 0; +} + +static const struct of_device_id audio_ref_clk_match[] = { + {.compatible = "qcom,audio-ref-clk"}, + {} +}; +MODULE_DEVICE_TABLE(of, audio_ref_clk_match); + +static struct platform_driver audio_ref_clk_driver = { + .driver = { + .name = "audio-ref-clk", + .owner = THIS_MODULE, + .of_match_table = audio_ref_clk_match, + }, + .probe = audio_ref_clk_probe, + .remove = audio_ref_clk_remove, +}; + +static int __init audio_ref_clk_platform_init(void) +{ + return platform_driver_register(&audio_ref_clk_driver); +} +module_init(audio_ref_clk_platform_init); + +static void __exit audio_ref_clk_platform_exit(void) +{ + platform_driver_unregister(&audio_ref_clk_driver); +} +module_exit(audio_ref_clk_platform_exit); + +MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 06e00fdfe6a1..71858e268232 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -13681,6 +13681,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) snd_soc_dapm_ignore_suspend(dapm, "AIF Mix Playback"); snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX"); snd_soc_dapm_ignore_suspend(dapm, "VIfeed"); + snd_soc_dapm_ignore_suspend(dapm, "AIF5 CPE TX"); } snd_soc_dapm_sync(dapm); diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index b0bb89c8d9c2..1fdf81a3a45f 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -1879,6 +1879,7 @@ static void tavil_codec_override(struct snd_soc_codec *codec, int mode, { if (mode == CLS_AB || mode == CLS_AB_HIFI) { switch (event) { + case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_POST_PMU: if (!(snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) && @@ -2088,6 +2089,9 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, } switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_override(codec, CLS_AB, event); + break; case SND_SOC_DAPM_POST_PMU: /* * 5ms sleep is required after PA is enabled as per @@ -2102,6 +2106,13 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, lineout_mix_vol_reg, 0x10, 0x00); break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + tavil_codec_override(codec, CLS_AB, event); default: break; }; @@ -7039,10 +7050,12 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0, tavil_codec_enable_lineout_pa, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0, tavil_codec_enable_lineout_pa, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), @@ -8156,6 +8169,8 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { {WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, @@ -8189,6 +8204,8 @@ static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = { {WCD934X_CDC_COMPANDER2_CTL7, 0x1E, 0x06}, {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xFF, 0x84}, {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84}, + {WCD934X_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD934X_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4}, }; static const struct tavil_cpr_reg_defaults cpr_defaults[] = { diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index aa036d352f40..9c720acf8ef8 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -2449,6 +2449,63 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .name = "VoiceMMode2", .probe = fe_dai_probe, }, + { + .capture = { + .stream_name = "MultiMedia17 Capture", + .aif_name = "MM_UL17", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia17", + .probe = fe_dai_probe, + }, + { + .capture = { + .stream_name = "MultiMedia18 Capture", + .aif_name = "MM_UL18", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia18", + .probe = fe_dai_probe, + }, + { + .capture = { + .stream_name = "MultiMedia19 Capture", + .aif_name = "MM_UL19", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia19", + .probe = fe_dai_probe, + }, }; static int msm_fe_dai_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index a2cd6c6f98db..d3c0850d8de2 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -55,6 +55,10 @@ #define DSP_NUM_OUTPUT_FRAME_BUFFERED 2 #define FLAC_BLK_SIZE_LIMIT 65535 +/* Timestamp mode payload offsets */ +#define TS_LSW_OFFSET 6 +#define TS_MSW_OFFSET 7 + /* decoder parameter length */ #define DDP_DEC_MAX_NUM_PARAM 18 @@ -127,6 +131,13 @@ struct msm_compr_audio { uint64_t bytes_received; /* from userspace */ uint64_t bytes_sent; /* to DSP */ + uint64_t received_total; /* bytes received from DSP */ + uint64_t bytes_copied; /* to userspace */ + uint64_t bytes_read; /* from DSP */ + uint32_t bytes_read_offset; /* bytes read offset */ + + uint32_t ts_header_offset; /* holds the timestamp header offset */ + int32_t first_buffer; int32_t last_buffer; int32_t partial_drain_delay; @@ -362,6 +373,53 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd) return 0; } +static int msm_compr_read_buffer(struct msm_compr_audio *prtd) +{ + int buffer_length; + uint64_t bytes_available; + uint64_t buffer_sent; + struct audio_aio_read_param param; + int ret; + + if (!atomic_read(&prtd->start)) { + pr_err("%s: stream is not in started state\n", __func__); + return -EINVAL; + } + + buffer_length = prtd->codec_param.buffer.fragment_size - + prtd->ts_header_offset; + bytes_available = prtd->received_total - prtd->bytes_copied; + buffer_sent = prtd->bytes_read - prtd->bytes_copied; + if (buffer_sent + buffer_length + prtd->ts_header_offset + > prtd->buffer_size) { + pr_debug(" %s : Buffer is Full bytes_available: %llu\n", + __func__, bytes_available); + return 0; + } + + memset(¶m, 0x0, sizeof(struct audio_aio_read_param)); + param.paddr = prtd->buffer_paddr + prtd->bytes_read_offset + + prtd->ts_header_offset; + param.len = buffer_length; + param.uid = buffer_length; + param.flags = prtd->codec_param.codec.flags; + + pr_debug("%s: reading %d bytes from DSP byte_offset = %llu\n", + __func__, buffer_length, prtd->bytes_read); + ret = q6asm_async_read(prtd->audio_client, ¶m); + if (ret < 0) { + pr_err("%s: q6asm_async_read failed - %d\n", + __func__, ret); + return ret; + } + prtd->bytes_read += buffer_length; + prtd->bytes_read_offset += buffer_length; + if (prtd->bytes_read_offset >= prtd->buffer_size) + prtd->bytes_read_offset -= prtd->buffer_size; + + return 0; +} + static void compr_event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { @@ -374,6 +432,8 @@ static void compr_event_handler(uint32_t opcode, int stream_id; uint32_t stream_index; unsigned long flags; + uint64_t read_size; + uint32_t *buff_addr; if (!prtd) { pr_err("%s: prtd is NULL\n", __func__); @@ -459,6 +519,49 @@ static void compr_event_handler(uint32_t opcode, spin_unlock_irqrestore(&prtd->lock, flags); break; + + case ASM_DATA_EVENT_READ_DONE_V2: + spin_lock_irqsave(&prtd->lock, flags); + + pr_debug("ASM_DATA_EVENT_READ_DONE_V2 offset %d, length %d\n", + prtd->byte_offset, payload[4]); + + if (prtd->ts_header_offset) { + /* Update the header for received buffer */ + buff_addr = prtd->buffer + prtd->byte_offset; + /* Write the length of the buffer */ + *buff_addr = prtd->codec_param.buffer.fragment_size + - prtd->ts_header_offset; + buff_addr++; + /* Write the offset */ + *buff_addr = prtd->ts_header_offset; + buff_addr++; + /* Write the TS LSW */ + *buff_addr = payload[TS_LSW_OFFSET]; + buff_addr++; + /* Write the TS MSW */ + *buff_addr = payload[TS_MSW_OFFSET]; + } + /* Always assume read_size is same as fragment_size */ + read_size = prtd->codec_param.buffer.fragment_size; + prtd->byte_offset += read_size; + prtd->received_total += read_size; + if (prtd->byte_offset >= prtd->buffer_size) + prtd->byte_offset -= prtd->buffer_size; + + snd_compr_fragment_elapsed(cstream); + + if (!atomic_read(&prtd->start)) { + pr_debug("read_done received while not started, treat as xrun"); + atomic_set(&prtd->xrun, 1); + spin_unlock_irqrestore(&prtd->lock, flags); + break; + } + msm_compr_read_buffer(prtd); + + spin_unlock_irqrestore(&prtd->lock, flags); + break; + case ASM_DATA_EVENT_RENDERED_EOS: spin_lock_irqsave(&prtd->lock, flags); pr_debug("%s: ASM_DATA_CMDRSP_EOS token 0x%x,stream id %d\n", @@ -511,6 +614,14 @@ static void compr_event_handler(uint32_t opcode, /* FIXME: A state is a better way, dealing with this*/ spin_lock_irqsave(&prtd->lock, flags); + + if (cstream->direction == SND_COMPRESS_CAPTURE) { + atomic_set(&prtd->start, 1); + msm_compr_read_buffer(prtd); + spin_unlock_irqrestore(&prtd->lock, flags); + break; + } + if (!prtd->bytes_sent) { bytes_available = prtd->bytes_received - prtd->copied_total; if (bytes_available < cstream->runtime->fragment_size) { @@ -958,7 +1069,8 @@ static int msm_compr_init_pp_params(struct snd_compr_stream *cstream, return ret; } -static int msm_compr_configure_dsp(struct snd_compr_stream *cstream) +static int msm_compr_configure_dsp_for_playback + (struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime = cstream->runtime; struct msm_compr_audio *prtd = runtime->private_data; @@ -1096,7 +1208,108 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream) return ret; } -static int msm_compr_open(struct snd_compr_stream *cstream) +static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_compr_audio *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data; + uint16_t bits_per_sample; + uint16_t sample_word_size; + int dir = OUT, ret = 0; + struct audio_client *ac = prtd->audio_client; + uint32_t stream_index; + + switch (prtd->codec_param.codec.format) { + case SNDRV_PCM_FORMAT_S24_LE: + bits_per_sample = 24; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + bits_per_sample = 24; + sample_word_size = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits_per_sample = 32; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bits_per_sample = 16; + sample_word_size = 16; + break; + } + + 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 (ret < 0) { + pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret); + return ret; + } + + ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id, + ac->perf_mode, + prtd->session_id, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) { + pr_err("%s: stream reg failed:%d\n", __func__, ret); + return ret; + } + + ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE)); + if (ret < 0) { + pr_err("%s: Set IO mode failed\n", __func__); + return -EINVAL; + } + + stream_index = STREAM_ARRAY_INDEX(ac->stream_id); + if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) { + pr_err("%s: Invalid stream index:%d", __func__, stream_index); + return -EINVAL; + } + + runtime->fragments = prtd->codec_param.buffer.fragments; + runtime->fragment_size = prtd->codec_param.buffer.fragment_size; + pr_debug("%s: allocate %d buffers each of size %d\n", + __func__, runtime->fragments, + runtime->fragment_size); + ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac, + runtime->fragment_size, + runtime->fragments); + if (ret < 0) { + pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret); + return -ENOMEM; + } + + prtd->byte_offset = 0; + prtd->received_total = 0; + prtd->app_pointer = 0; + prtd->bytes_copied = 0; + prtd->bytes_read = 0; + prtd->bytes_read_offset = 0; + prtd->buffer = ac->port[dir].buf[0].data; + prtd->buffer_paddr = ac->port[dir].buf[0].phys; + prtd->buffer_size = runtime->fragments * runtime->fragment_size; + + /* Bit-0 of flags represent timestamp mode */ + if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) + prtd->ts_header_offset = sizeof(struct snd_codec_metadata); + else + prtd->ts_header_offset = 0; + + pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n", + __func__, prtd->sample_rate, prtd->num_channels, + bits_per_sample, sample_word_size); + ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client, + prtd->sample_rate, prtd->num_channels, + bits_per_sample, sample_word_size); + + return ret; +} + +static int msm_compr_playback_open(struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime = cstream->runtime; struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -1181,15 +1394,80 @@ static int msm_compr_open(struct snd_compr_stream *cstream) kfree(prtd); return -ENOMEM; } + pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); + prtd->audio_client->perf_mode = false; + prtd->session_id = prtd->audio_client->session; + return 0; +} + +static int msm_compr_capture_open(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct msm_compr_audio *prtd; + struct msm_compr_pdata *pdata = + snd_soc_platform_get_drvdata(rtd->platform); + + pr_debug("%s\n", __func__); + prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL); + if (prtd == NULL) { + pr_err("Failed to allocate memory for msm_compr_audio\n"); + return -ENOMEM; + } + + runtime->private_data = NULL; + prtd->cstream = cstream; + pdata->cstream[rtd->dai_link->be_id] = cstream; + + prtd->audio_client = q6asm_audio_client_alloc( + (app_cb)compr_event_handler, prtd); + if (!prtd->audio_client) { + pr_err("%s: Could not allocate memory for client\n", __func__); + pdata->cstream[rtd->dai_link->be_id] = NULL; + kfree(prtd); + return -ENOMEM; + } pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); prtd->audio_client->perf_mode = false; prtd->session_id = prtd->audio_client->session; + prtd->codec = FORMAT_LINEAR_PCM; + prtd->bytes_copied = 0; + prtd->bytes_read = 0; + prtd->bytes_read_offset = 0; + prtd->received_total = 0; + prtd->byte_offset = 0; + prtd->sample_rate = 48000; + prtd->num_channels = 2; + prtd->first_buffer = 0; + + spin_lock_init(&prtd->lock); + + atomic_set(&prtd->eos, 0); + atomic_set(&prtd->start, 0); + atomic_set(&prtd->drain, 0); + atomic_set(&prtd->xrun, 0); + atomic_set(&prtd->close, 0); + atomic_set(&prtd->wait_on_close, 0); + atomic_set(&prtd->error, 0); + + runtime->private_data = prtd; return 0; } -static int msm_compr_free(struct snd_compr_stream *cstream) +static int msm_compr_open(struct snd_compr_stream *cstream) +{ + int ret = 0; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_playback_open(cstream); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_capture_open(cstream); + return ret; +} + +static int msm_compr_playback_free(struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime; struct msm_compr_audio *prtd; @@ -1284,6 +1562,76 @@ static int msm_compr_free(struct snd_compr_stream *cstream) return 0; } +static int msm_compr_capture_free(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime; + struct msm_compr_audio *prtd; + struct snd_soc_pcm_runtime *soc_prtd; + struct msm_compr_pdata *pdata; + struct audio_client *ac; + int dir = OUT, stream_id; + unsigned long flags; + uint32_t stream_index; + + if (!cstream) { + pr_err("%s cstream is null\n", __func__); + return 0; + } + runtime = cstream->runtime; + soc_prtd = cstream->private_data; + if (!runtime || !soc_prtd || !(soc_prtd->platform)) { + pr_err("%s runtime or soc_prtd or platform is null\n", + __func__); + return 0; + } + prtd = runtime->private_data; + if (!prtd) { + pr_err("%s prtd is null\n", __func__); + return 0; + } + pdata = snd_soc_platform_get_drvdata(soc_prtd->platform); + ac = prtd->audio_client; + if (!pdata || !ac) { + pr_err("%s pdata or ac is null\n", __func__); + return 0; + } + + spin_lock_irqsave(&prtd->lock, flags); + stream_id = ac->stream_id; + + stream_index = STREAM_ARRAY_INDEX(stream_id); + if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0)) { + spin_unlock_irqrestore(&prtd->lock, flags); + pr_debug("close stream %d", stream_id); + q6asm_stream_cmd(ac, CMD_CLOSE, stream_id); + spin_lock_irqsave(&prtd->lock, flags); + } + spin_unlock_irqrestore(&prtd->lock, flags); + + pdata->cstream[soc_prtd->dai_link->be_id] = NULL; + msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, + SNDRV_PCM_STREAM_CAPTURE); + + q6asm_audio_client_buf_free_contiguous(dir, ac); + + q6asm_audio_client_free(ac); + + kfree(prtd); + + return 0; +} + +static int msm_compr_free(struct snd_compr_stream *cstream) +{ + int ret = 0; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_playback_free(cstream); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_capture_free(cstream); + return ret; +} + static bool msm_compr_validate_codec_compr(__u32 codec_id) { int32_t i; @@ -1449,7 +1797,10 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream, prtd->partial_drain_delay = msm_compr_get_partial_drain_delay(frame_sz, prtd->sample_rate); - ret = msm_compr_configure_dsp(cstream); + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_configure_dsp_for_playback(cstream); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_configure_dsp_for_capture(cstream); return ret; } @@ -1539,11 +1890,6 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) uint32_t stream_index; uint16_t bits_per_sample = 16; - if (cstream->direction != SND_COMPRESS_PLAYBACK) { - pr_err("%s: Unsupported stream type\n", __func__); - return -EINVAL; - } - spin_lock_irqsave(&prtd->lock, flags); if (atomic_read(&prtd->error)) { pr_err("%s Got RESET EVENTS notification, return immediately", @@ -1566,7 +1912,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) * compress passthrough volume is controlled in * ADM by adm_send_compressed_device_mute() */ - if (prtd->compr_passthr == LEGACY_PCM) { + if (prtd->compr_passthr == LEGACY_PCM && + cstream->direction == SND_COMPRESS_PLAYBACK) { /* set volume for the stream before RUN */ rc = msm_compr_set_volume(cstream, volume[0], volume[1]); @@ -1578,8 +1925,9 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) if (rc) pr_err("%s : init PP params failed : %d\n", __func__, rc); + } else { + msm_compr_read_buffer(prtd); } - /* issue RUN command for the stream */ q6asm_run_nowait(prtd->audio_client, 0, 0, 0); break; @@ -1589,6 +1937,18 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) prtd->gapless_state.gapless_transition); stream_id = ac->stream_id; atomic_set(&prtd->start, 0); + if (cstream->direction == SND_COMPRESS_CAPTURE) { + q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); + atomic_set(&prtd->xrun, 0); + prtd->received_total = 0; + prtd->bytes_copied = 0; + prtd->bytes_read = 0; + prtd->bytes_read_offset = 0; + prtd->byte_offset = 0; + prtd->app_pointer = 0; + spin_unlock_irqrestore(&prtd->lock, flags); + break; + } if (prtd->next_stream) { pr_debug("%s: interrupt next track wait queues\n", __func__); @@ -1979,7 +2339,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) } static int msm_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *arg) + struct snd_compr_tstamp *arg) { struct snd_compr_runtime *runtime = cstream->runtime; struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -1998,7 +2358,10 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, spin_lock_irqsave(&prtd->lock, flags); tstamp.sampling_rate = prtd->sample_rate; tstamp.byte_offset = prtd->byte_offset; - tstamp.copied_total = prtd->copied_total; + if (cstream->direction == SND_COMPRESS_PLAYBACK) + tstamp.copied_total = prtd->copied_total; + else if (cstream->direction == SND_COMPRESS_CAPTURE) + tstamp.copied_total = prtd->received_total; first_buffer = prtd->first_buffer; if (atomic_read(&prtd->error)) { pr_err("%s Got RESET EVENTS notification, return error\n", @@ -2012,37 +2375,39 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, spin_unlock_irqrestore(&prtd->lock, flags); return -ENETRESET; } + if (cstream->direction == SND_COMPRESS_PLAYBACK) { - gapless_transition = prtd->gapless_state.gapless_transition; - spin_unlock_irqrestore(&prtd->lock, flags); - - if (gapless_transition) - pr_debug("%s session time in gapless transition", - __func__); - - /* - - Do not query if no buffer has been given. - - Do not query on a gapless transition. - Playback for the 2nd stream can start (thus returning time - starting from 0) before the driver knows about EOS of first stream. - */ - - if (!first_buffer && !gapless_transition) { - if (pdata->use_legacy_api) - rc = q6asm_get_session_time_legacy(prtd->audio_client, - &prtd->marker_timestamp); - else - rc = q6asm_get_session_time(prtd->audio_client, - &prtd->marker_timestamp); + gapless_transition = prtd->gapless_state.gapless_transition; + spin_unlock_irqrestore(&prtd->lock, flags); + if (gapless_transition) + pr_debug("%s session time in gapless transition", + __func__); + /* + *- Do not query if no buffer has been given. + *- Do not query on a gapless transition. + * Playback for the 2nd stream can start (thus returning time + * starting from 0) before the driver knows about EOS of first + * stream. + */ + if (!first_buffer || gapless_transition) { - if (rc < 0) { - pr_err("%s: Get Session Time return value =%lld\n", - __func__, timestamp); - if (atomic_read(&prtd->error)) - return -ENETRESET; + if (pdata->use_legacy_api) + rc = q6asm_get_session_time_legacy( + prtd->audio_client, &prtd->marker_timestamp); else - return -EAGAIN; + rc = q6asm_get_session_time( + prtd->audio_client, &prtd->marker_timestamp); + if (rc < 0) { + pr_err("%s: Get Session Time return =%lld\n", + __func__, timestamp); + if (atomic_read(&prtd->error)) + return -ENETRESET; + else + return -EAGAIN; + } } + } else { + spin_unlock_irqrestore(&prtd->lock, flags); } timestamp = prtd->marker_timestamp; @@ -2103,8 +2468,8 @@ static int msm_compr_ack(struct snd_compr_stream *cstream, return 0; } -static int msm_compr_copy(struct snd_compr_stream *cstream, - char __user *buf, size_t count) +static int msm_compr_playback_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) { struct snd_compr_runtime *runtime = cstream->runtime; struct msm_compr_audio *prtd = runtime->private_data; @@ -2166,6 +2531,60 @@ static int msm_compr_copy(struct snd_compr_stream *cstream, return count; } +static int msm_compr_capture_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_compr_audio *prtd = runtime->private_data; + void *source; + unsigned long flags; + + pr_debug("%s: count = %zd\n", __func__, count); + if (!prtd->buffer) { + pr_err("%s: Buffer is not allocated yet ??", __func__); + return 0; + } + + spin_lock_irqsave(&prtd->lock, flags); + if (atomic_read(&prtd->error)) { + pr_err("%s Got RESET EVENTS notification", __func__); + spin_unlock_irqrestore(&prtd->lock, flags); + return -ENETRESET; + } + + source = prtd->buffer + prtd->app_pointer; + /* check if we have requested amount of data to copy to user*/ + if (count <= prtd->received_total - prtd->bytes_copied) { + spin_unlock_irqrestore(&prtd->lock, flags); + if (copy_to_user(buf, source, count)) { + pr_err("copy_to_user failed"); + return -EFAULT; + } + spin_lock_irqsave(&prtd->lock, flags); + prtd->app_pointer += count; + if (prtd->app_pointer >= prtd->buffer_size) + prtd->app_pointer -= prtd->buffer_size; + prtd->bytes_copied += count; + } + msm_compr_read_buffer(prtd); + + spin_unlock_irqrestore(&prtd->lock, flags); + return count; +} + +static int msm_compr_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + int ret = 0; + + pr_debug(" In %s\n", __func__); + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_playback_copy(cstream, buf, count); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_capture_copy(cstream, buf, count); + return ret; +} + static int msm_compr_get_caps(struct snd_compr_stream *cstream, struct snd_compr_caps *arg) { @@ -2760,7 +3179,7 @@ static int msm_compr_dec_params_get(struct snd_kcontrol *kcontrol, return 0; } -static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol, +static int msm_compr_playback_app_type_cfg_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { u64 fe_id = kcontrol->private_value; @@ -2787,7 +3206,7 @@ static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol, return 0; } -static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol, +static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { u64 fe_id = kcontrol->private_value; @@ -2822,6 +3241,68 @@ done: return ret; } +static int msm_compr_capture_app_type_cfg_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int app_type; + int acdb_dev_id; + int sample_rate = 48000; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %llu\n", + __func__, fe_id); + return -EINVAL; + } + + app_type = ucontrol->value.integer.value[0]; + acdb_dev_id = ucontrol->value.integer.value[1]; + if (ucontrol->value.integer.value[2] != 0) + sample_rate = ucontrol->value.integer.value[2]; + pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n", + __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX); + msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type, + acdb_dev_id, sample_rate, SESSION_TYPE_TX); + + return 0; +} + +static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %llu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX, + &app_type, &acdb_dev_id, &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, SESSION_TYPE_TX, + app_type, acdb_dev_id, sample_rate); +done: + return ret; +} + static int msm_compr_channel_map_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3209,7 +3690,8 @@ static int msm_compr_add_dec_runtime_params_control( static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) { - const char *mixer_ctl_name = "Audio Stream"; + const char *playback_mixer_ctl_name = "Audio Stream"; + const char *capture_mixer_ctl_name = "Audio Stream Capture"; const char *deviceNo = "NN"; const char *suffix = "App Type Cfg"; char *mixer_str = NULL; @@ -3220,8 +3702,8 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_compr_app_type_cfg_info, - .put = msm_compr_app_type_cfg_put, - .get = msm_compr_app_type_cfg_get, + .put = msm_compr_playback_app_type_cfg_put, + .get = msm_compr_playback_app_type_cfg_get, .private_value = 0, } }; @@ -3232,11 +3714,15 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) } pr_debug("%s: added new compr FE ctl with name %s, id %d, cpu dai %s, device no %d\n", - __func__, rtd->dai_link->name, rtd->dai_link->be_id, - rtd->dai_link->cpu_dai_name, rtd->pcm->device); + __func__, rtd->dai_link->name, rtd->dai_link->be_id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) + ctl_len = strlen(playback_mixer_ctl_name) + 1 + strlen(deviceNo) + + 1 + strlen(suffix) + 1; + else + ctl_len = strlen(capture_mixer_ctl_name) + 1 + strlen(deviceNo) + + 1 + strlen(suffix) + 1; - ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + - strlen(suffix) + 1; mixer_str = kzalloc(ctl_len, GFP_KERNEL); if (!mixer_str) { @@ -3244,14 +3730,31 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) return 0; } - snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name, - rtd->pcm->device, suffix); + if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) + snprintf(mixer_str, ctl_len, "%s %d %s", + playback_mixer_ctl_name, rtd->pcm->device, suffix); + else + snprintf(mixer_str, ctl_len, "%s %d %s", + capture_mixer_ctl_name, rtd->pcm->device, suffix); + fe_app_type_cfg_control[0].name = mixer_str; fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id; + + if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) { + fe_app_type_cfg_control[0].put = + msm_compr_playback_app_type_cfg_put; + fe_app_type_cfg_control[0].get = + msm_compr_playback_app_type_cfg_get; + } else { + fe_app_type_cfg_control[0].put = + msm_compr_capture_app_type_cfg_put; + fe_app_type_cfg_control[0].get = + msm_compr_capture_app_type_cfg_get; + } pr_debug("Registering new mixer ctl %s", mixer_str); snd_soc_add_platform_controls(rtd->platform, - fe_app_type_cfg_control, - ARRAY_SIZE(fe_app_type_cfg_control)); + fe_app_type_cfg_control, + ARRAY_SIZE(fe_app_type_cfg_control)); kfree(mixer_str); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 718f7017342b..f1f2fd908eca 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -2645,8 +2645,10 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_rx_dai = { .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_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000, + 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, @@ -2667,8 +2669,10 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_tx_dai = { .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_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000, + 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, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 9164475386ff..a456cc2ab857 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -548,6 +548,15 @@ static struct msm_pcm_routing_fdai_data /* MULTIMEDIA16 */ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA17 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA18 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA19 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, }; static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2] @@ -2288,6 +2297,21 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 = msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); +static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + +static const struct snd_kcontrol_new ext_ec_ref_mux_ul18 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL18 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + +static const struct snd_kcontrol_new ext_ec_ref_mux_ul19 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL19 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2417,6 +2441,15 @@ static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { @@ -2468,6 +2501,15 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { @@ -2519,6 +2561,16 @@ static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + }; static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { @@ -2621,6 +2673,15 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { @@ -2672,6 +2733,15 @@ static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { @@ -2723,6 +2793,15 @@ static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { @@ -2774,6 +2853,15 @@ static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { @@ -2825,6 +2913,15 @@ static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { @@ -2870,6 +2967,15 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = { @@ -2927,6 +3033,15 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { @@ -2978,6 +3093,15 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { @@ -3131,6 +3255,15 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new display_port_mixer_controls[] = { @@ -3432,6 +3565,15 @@ static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { @@ -3534,6 +3676,15 @@ static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { @@ -3585,6 +3736,15 @@ static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { @@ -3636,6 +3796,15 @@ static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { @@ -3687,6 +3856,15 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { @@ -5018,6 +5196,77 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new mmul17_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul18_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul19_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, @@ -8098,6 +8347,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0), @@ -8796,6 +9048,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0, mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0, + mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0, + mmul18_mixer_controls, ARRAY_SIZE(mmul18_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia19 Mixer", SND_SOC_NOPM, 0, 0, + mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)), SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)), SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -9060,6 +9318,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul8), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul9), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul17), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul18), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL19 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul19), }; static const struct snd_soc_dapm_route intercon[] = { @@ -9287,9 +9551,15 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia8 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"}, {"MultiMedia8 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, {"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia17 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, @@ -9884,10 +10154,16 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, @@ -9895,6 +10171,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MM_UL1", NULL, "MultiMedia1 Mixer"}, @@ -9905,6 +10184,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL5", NULL, "MultiMedia5 Mixer"}, {"MM_UL6", NULL, "MultiMedia6 Mixer"}, {"MM_UL8", NULL, "MultiMedia8 Mixer"}, + {"MM_UL17", NULL, "MultiMedia17 Mixer"}, + {"MM_UL18", NULL, "MultiMedia18 Mixer"}, + {"MM_UL19", NULL, "MultiMedia19 Mixer"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, @@ -10284,6 +10566,21 @@ static const struct snd_soc_dapm_route intercon[] = { {"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, {"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + + {"AUDIO_REF_EC_UL18 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL18 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL18 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL18 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + + {"AUDIO_REF_EC_UL19 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL19 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL19 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL19 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"}, {"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"}, {"MM_UL3", NULL, "AUDIO_REF_EC_UL3 MUX"}, @@ -10292,6 +10589,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"}, {"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"}, {"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"}, + {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"}, + {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"}, + {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"}, {"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"}, {"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"}, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 4fdfd6bb936d..d64fd640618e 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -182,6 +182,9 @@ enum { MSM_FRONTEND_DAI_MULTIMEDIA14, MSM_FRONTEND_DAI_MULTIMEDIA15, MSM_FRONTEND_DAI_MULTIMEDIA16, + MSM_FRONTEND_DAI_MULTIMEDIA17, + MSM_FRONTEND_DAI_MULTIMEDIA18, + MSM_FRONTEND_DAI_MULTIMEDIA19, MSM_FRONTEND_DAI_CS_VOICE, MSM_FRONTEND_DAI_VOIP, MSM_FRONTEND_DAI_AFE_RX, @@ -207,8 +210,8 @@ enum { MSM_FRONTEND_DAI_MAX, }; -#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA16 + 1) -#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA16 +#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA19 + 1) +#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA19 enum { MSM_BACKEND_DAI_PRI_I2S_RX = 0, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index e3545405f61d..38c51eb32f4d 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1639,7 +1639,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) asm_token.token = data->token; if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) { pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n", - __func__, data->opcode, payload[0]); + __func__, data->opcode, payload ? payload[0] : 0); wakeup_flag = 0; } @@ -1673,9 +1673,14 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->dest_port); if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) && (data->opcode != ASM_DATA_EVENT_EOS) && - (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) + (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) { + if (payload == NULL) { + pr_err("%s: payload is null\n", __func__); + return -EINVAL; + } dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", __func__, payload[0], payload[1], data->opcode); + } if (data->opcode == APR_BASIC_RSP_RESULT) { switch (payload[0]) { case ASM_STREAM_CMD_SET_PP_PARAMS_V2: @@ -2285,7 +2290,8 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr, static int __q6asm_open_read(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, - uint32_t pcm_format_block_ver) + uint32_t pcm_format_block_ver, + bool ts_mode) { int rc = 0x00; struct asm_stream_cmd_open_read_v3 open; @@ -2329,11 +2335,21 @@ static int __q6asm_open_read(struct audio_client *ac, case FORMAT_LINEAR_PCM: open.mode_flags |= 0x00; open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver); + if (ts_mode) + open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE; break; case FORMAT_MPEG4_AAC: open.mode_flags |= BUFFER_META_ENABLE; open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2; break; + case FORMAT_G711_ALAW_FS: + open.mode_flags |= BUFFER_META_ENABLE; + open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS; + break; + case FORMAT_G711_MLAW_FS: + open.mode_flags |= BUFFER_META_ENABLE; + open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS; + break; case FORMAT_V13K: open.mode_flags |= BUFFER_META_ENABLE; open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS; @@ -2391,14 +2407,16 @@ int q6asm_open_read(struct audio_client *ac, uint32_t format) { return __q6asm_open_read(ac, format, 16, - PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, + false/*ts_mode*/); } int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, + false/*ts_mode*/); } /* @@ -2412,7 +2430,8 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - PCM_MEDIA_FORMAT_V3/*media fmt block ver*/); + PCM_MEDIA_FORMAT_V3/*media fmt block ver*/, + false/*ts_mode*/); } EXPORT_SYMBOL(q6asm_open_read_v3); @@ -2427,7 +2446,8 @@ int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/); + PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/, + true/*ts_mode*/); } EXPORT_SYMBOL(q6asm_open_read_v4); @@ -2857,6 +2877,11 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, break; case FORMAT_DSD: open.dec_fmt_id = ASM_MEDIA_FMT_DSD; + case FORMAT_G711_ALAW_FS: + open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS; + break; + case FORMAT_G711_MLAW_FS: + open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS; break; default: pr_err("%s: Invalid format 0x%x\n", @@ -2873,6 +2898,12 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, case FORMAT_MPEG4_AAC: open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2; break; + case FORMAT_G711_ALAW_FS: + open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS; + break; + case FORMAT_G711_MLAW_FS: + open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS; + break; case FORMAT_V13K: open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS; break; @@ -3540,6 +3571,57 @@ fail_cmd: return rc; } +int q6asm_enc_cfg_blk_g711(struct audio_client *ac, + uint32_t frames_per_buf, + uint32_t sample_rate) +{ + struct asm_g711_enc_cfg_v2 enc_cfg; + int rc = 0; + + pr_debug("%s: session[%d]frames[%d]SR[%d]\n", + __func__, ac->session, frames_per_buf, + sample_rate); + + q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE); + atomic_set(&ac->cmd_state, -1); + + enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; + enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) - + sizeof(struct asm_stream_cmd_set_encdec_param); + enc_cfg.encblk.frames_per_buf = frames_per_buf; + enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size - + sizeof(struct asm_enc_cfg_blk_param_v2); + enc_cfg.sample_rate = sample_rate; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg); + if (rc < 0) { + pr_err("%s: Comamnd %d failed %d\n", + __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, 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. 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; + } + return 0; +fail_cmd: + return rc; +} + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels) { @@ -5424,6 +5506,75 @@ fail_cmd: return rc; } +/* + * q6asm_media_format_block_g711 - sends g711 decoder configuration + * parameters + * @ac: Client session handle + * @cfg: Audio stream manager configuration parameters + * @stream_id: Stream id + */ +int q6asm_media_format_block_g711(struct audio_client *ac, + struct asm_g711_dec_cfg *cfg, int stream_id) +{ + struct asm_g711_dec_fmt_blk_v2 fmt; + int rc = 0; + + if (!ac) { + pr_err("%s: audio client is null\n", __func__); + return -EINVAL; + } + if (!cfg) { + pr_err("%s: Invalid ASM config\n", __func__); + return -EINVAL; + } + + if (stream_id <= 0) { + pr_err("%s: Invalid stream id\n", __func__); + return -EINVAL; + } + + pr_debug("%s :session[%d]rate[%d]\n", __func__, + ac->session, cfg->sample_rate); + + memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2)); + + q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id); + atomic_set(&ac->cmd_state, -1); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmtblk); + + fmt.sample_rate = cfg->sample_rate; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s :Command 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; + } + return 0; +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_media_format_block_g711); + int q6asm_stream_media_format_block_vorbis(struct audio_client *ac, struct asm_vorbis_cfg *cfg, int stream_id) { @@ -7150,7 +7301,11 @@ int q6asm_async_read(struct audio_client *ac, lbuf_phys_addr = (param->paddr - 64); dir = OUT; } else { - lbuf_phys_addr = param->paddr; + if (param->flags & COMPRESSED_TIMESTAMP_FLAG) + lbuf_phys_addr = param->paddr - + sizeof(struct snd_codec_metadata); + else + lbuf_phys_addr = param->paddr; dir = OUT; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4c66eeaeeb03..b1980df07dce 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2623,8 +2623,7 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, dapm_mark_dirty(widgets[dir], "Route added"); } - if (dapm->card->instantiated && path->connect) - dapm_path_invalidate(path); + dapm_path_invalidate(path); return 0; err: |
