diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-07-12 11:28:31 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-07-12 11:28:32 -0600 |
| commit | 819b6079c0897725fd8a9dd0fd4402f5c69cb433 (patch) | |
| tree | baaa024b549b3d70c59177973302a416c785fed6 | |
| parent | a36d8398690233636488ffbebbc5bae5349e784d (diff) | |
| parent | 400520a6e2f06cc7c45e386e769a85d4aded565b (diff) | |
Promotion of kernel.lnx.4.4-160711.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1024170 Ie0cfab09192ca6b09ec4fe171aaf544e3fb5f08f ARM: dts: msm: return unused pIMEM Vault memory for msmc
1037857 I95544aaf607887ae34eace8a9b1f18a1375c5c6d ARM: dts: msm: add proxy vote for DSI supplies for msmco
1036737 Ie9bb609f9681580d90e5ec35b89e587758c272d4 ARM: dts: msm: enable audio over HDMI for msmcobalt
1028725 I6cdb366499f9589dff9a42491c7ff357e98d65c5 clk: msm: clock-mmss-cobalt: Add display port clock supp
1026885 1037945 I08d85ef462f09003aaa17f6ebc5d27de7083796f msm: vidc: update the check to ignore extradata plane in
964855 I17fa4f28cc151e3a3ad89d284995a3fa770bec68 leds: qpnp-flash-v2: add callback for max current query
999299 I3e961f4fe1728a32314a3acf7af719374c90d01f qseecom: make change for unload TA
1032294 Ie8a19341831d4ffaea36898a80c71ab25f5daf3c msm: sde: Updating linear format definition for v4l2 rot
1037982 I4f8ec495ae02908d1d8cd7e86148a6d4bd38b198 ARM: dts: msm: Add dts entry mpm2-sleep-counter for MSMC
1024370 Ifb303d7266c98eb94c5eb6f806b7c5e1d95236d3 driver: thermal: Configure ARM threshold instead of low
1039863 I980e39b8c072fc2ec35d84b8698c40c770f7f041 ARM: dts: msm: Add initial device tree files for falcon
1024204 I7d999382dcb6223d84424173a1726c250520ad04 ARM: dts: msm: configure default CMA region for msmcobal
1039560 I20bd718c8cb70029c4dd46c52dbece326b90ef80 msm: ipa3: fix the double ipa3_pre_init issue
1038150 I96010edabd04fef0eeb3cbb0b8f1a11d178d99b5 ASoC: msmcobalt: Fix slimbus tx channel configuration
1036737 Ieef8a2658f9730a9268041ac93ea3958489f2eae msmcobalt: enable audio over HDMI
1032455 I60c60470a649eecd5bacf0b39b20dff58c910897 ARM: dts: msm: Update MPM interrupt mappings for cobalt
1037449 Ie4dd908657573e5110bce65931d5507125da4c40 iommu/iommu-debug:: initialize variables before use
1035411 I597b58b478a35e9c3e3afb1a2ddd20ad87961c1a msm: sde: Correct rotator irq enable mismatch
1024187 Ic4ec03e4fd545d44118c2225a3f8e26901ca1d81 ARM: dts: msm: Add regulator node to flash-led for pmico
1037797 I52b909dd226494987c79ed106ffdf9892d966ef1 mfd: qcom-i2c-pmic: add option to skip irq control
1034091 I7e127d97cdd22409d4e70788a7cf2013593d3bfe msmcobalt: Add delay to check ADSP state during SSR
1018761 Idc368aff7090bcb52ae598faae9f95c1ffe1d4cf arm64: defconfig: msm: enable MODULE_SIG for msm chipset
1026286 Ib975c99b3b87998c357251a37f4862cbbf68697d wil6210: fix chan check in wil_p2p_listen
1036660 I8ccbbc9ef0795397614ad0644fd1f2b5e31e3780 ARM: dts: msm: create a separate dtsi file for msmcobalt
1037449 I9d173756e277c9006220c02c209309167f179609 iommu/io-pgtable-fast: validate data before use
1024187 I1515fba2fb04c0b4d21828af3cea6d322262ab14 leds: qpnp-flash-v2: add regulator support
950797 I2c9b0ba0837f8fec5c320e3117aa3b2f553db6b2 sound: usb: Add support for usb audio qmi service
982931 Ie1cd3ccf777e84665075bc3b6d9fffa7d897de49 wil6210: add module parameter for alternate interface na
1021009 I31a49465545e4b9a562b66bff7353d91817205f2 ARM: dts: msm: Change camera mount angle for msmcobalt
1026885 1037945 Ifd18d8689351c4a6a22c988d359fb413be19e142 msm: vidc: add ion_handle checking before mapping buffer
1039456 I37d91c4f7e5d98333cf6be3c75168e134ae78060 media: videobuf2: Increase max buffers
1034091 I8863185651fde8d29b5b8d8f183544bf0f215dbe ASoC: qdsp6v2: Fix apr registration failure in q6core
1023504 1039037 I053587ae85b36ce0b08fdb5918c0f6b9d678dd24 msm: vidc: Remove forced-setting of layer-wise bitrate f
950797 I1abc80652a167cefa667b914b3a80a87326c3d44 sound: usb: Add support to share iova with remote proces
1024187 Ief6a610c82b7f645966c596f543a1d30f7a40dcc leds: qpnp-flash-v2: add support for strobe configuratio
1035969 I6bab3370caf776de25316da58ca48fcd9fbc4b5e defconfig: arm64: msm: Disable qtaguid and net activity
1018826 I0ba4d62e3723841c3dfccdca210c80cd220f78f7 ASoC: msm: qdsp6v2: Fix FE id check in routing driver
1034091 I53a219b1ebed5bc3593d500d80d580aac6431ab5 drivers: soc: set apr handle to NULL on glink_open error
Change-Id: I2513c5f512828858c5dd28d56050967f4d788746
CRs-Fixed: 950797, 1035411, 1037857, 1024370, 964855, 1039456, 982931, 1023504, 1026885, 1028725, 1036660, 1035969, 1036737, 1037982, 1021009, 1037449, 1024204, 1038150, 1024187, 1039863, 1034091, 1039560, 1032455, 1018826, 1024170, 1032294, 999299, 1037945, 1026286, 1037797, 1039037, 1018761
55 files changed, 2896 insertions, 237 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 1c0dfa43952c..a35a8f0d6622 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -255,6 +255,7 @@ compatible = "qcom,msmhamster-rumi" compatible = "qcom,msmhamster-cdp" compatible = "qcom,msmhamster-mtp" compatible = "qcom,msmfalcon-sim" +compatible = "qcom,msmfalcon-rumi" compatible = "qcom,msm8952-rumi" compatible = "qcom,msm8952-sim" compatible = "qcom,msm8952-qrd" diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index f1a8c77c8387..1372e424927f 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -6,6 +6,8 @@ camera sensor when background light is dim to capture good picture. It can also be used for flashlight/torch application. It is part of PMIC on Qualcomm Technologies Inc. reference platforms. +Main node: + Required properties: - compatible : Should be "qcom,qpnp-flash-led-v2" - reg : Base address and size for flash LED modules @@ -14,10 +16,17 @@ Optional properties: - qcom,hdrm-auto-mode : Boolean type to select headroom auto mode enabled or not - qcom,isc-delay : Integer type to specify short circuit delay. Valid values are 32, 64, 128, 192. Unit is us. +- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified + value, additional GPIO configuration may be required to provide strobing + support. Supported values are: + 0: Flash strobe is used for LED1, LED2, LED3 + 1: Flash strobe is used for LED1, LED2 and GPIO10 is used for LED3 + 2: Flash strobe is used for LED1; GPIO9 is used for LED2; GPIO10 is used for LED3 + +Child node: Contains settings for each individual LED. Each LED channel needs a flash node and +torch node for itself, and an individual switch node to serve as an overall switch. -Required properties inside child node. Child node contains settings for each individual LED. -Each LED channel needs a flash node and torch node for itself, and an individual switch node to -serve as an overall switch. +Required Properties: - label : Type of led that will be used, either "flash", "torch", or "switch. - qcom,led-name : Name of the LED. - qcom,default-led-trigger : Trigger for the camera flash and torch. Accepted values are @@ -35,7 +44,7 @@ serve as an overall switch. type specifying flash duration. Values are from 10ms to 1280ms with 10ms resolution. This is not required for switch node. -Optional properties inside child node: +Optional properties: - qcom,current-ma : operational current intensity for LED in mA. Accepted values are a positive integer in the range of 0 to qcom,max-current inclusive. - qcom,ires-ua : Integer type to specify current resolution. Accepted values should be @@ -44,15 +53,35 @@ Optional properties inside child node: with 25mV resolution. Default setting is 325mV - qcom,hdrm-vol-hi-lo-win-mv : Integer type to specify headroom voltage swing range. Values are from 0mV to 375mV with 25mV resolution. Default setting is 100mV. -- pinctrl-names : This should be defined if a target uses pinctrl framework and there is GPIO - requirement for flash LEDs. See "pinctrl" in - Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt. It should specify - the names of the configs that pinctrl can install in driver. - Following are the pinctrl configs that can be installed: - "led_enable" : Enablement configuration of pins. This should specify active - config defined in each pin or pin group. - "led_disable" : Disablement configuration of pins. This should specify inactive - config defined in each pin or pin groups. +- pinctrl-names : Name of the pinctrl configuration that will be used when external GPIOs + are used for enabling/disabling, HW strobing of flash LEDs. For more + information on using pinctrl, please refer + Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt + Following are the pinctrl configs that can be specified: + "led_enable" : pinctrl config to enable led. This should specify the active + configuration defined for each pin or pin group. + "led_disable" : pinctrl config to disable led. This should specify the sleep + configuration defined for each pin or pin group. + "strobe_enable" : pinctrl config to enable hw-strobe. This should specify the + active configuration defined for each pin or pin group. + "strobe_disable" : pinctrl config to disable hw-strobe. This should specify the + sleep configuration defined for each pin or pin group. +- qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no + pinctrl support or PMIC GPIOs are used. +- qcom,hw-strobe-sel : Boolean property to enable hardware strobe. If not defined, software strobe + will be used. +- qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to + be edge triggered. Otherwise, it is level triggered. +- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe + signal polarity is set to active-low, else it is active-high. +- reg<n> : reg<n> (<n> represents number. e.g. 0,1,2,..) subnode is to add support for + multiple power sources. This subnode should only be specified for switch nodes. + Required property inside regulator node: + - regulator-name : Name of the regulator which has to be used for this + switch node. + Optional property inside regulator node: + - max-voltage-uv : This specifies max voltage of regulator. Some switch + or boost regulator does not need this property. Example: qcom,leds@d300 { @@ -156,6 +185,10 @@ Example: qcom,led-name = "led:switch"; qcom,default-led-trigger = "switch_trigger"; + reg0 { + regulator-name = "pmicobalt_bob"; + max-voltage-uv = <3600000>; + }; }; }; diff --git a/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt index 9c7c856ea42b..7e9aee1a96b3 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt +++ b/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt @@ -32,29 +32,29 @@ Platform independent properties: Definition: 7-bit I2C address of the device. - interrupt-parent - Usage: required + Usage: optional Value type: <phandle> Definition: phandle of the interrupt controller which services the summary interrupt. - interrupts - Usage: required + Usage: optional Value type: <prop-encoded-array> Definition: Summary interrupt specifier. - interrupt-controller - Usage: required + Usage: optional Value type: <empty> Definition: Boolean flag which indicates this device node is an interrupt controller. - #interrupt-cells - Usage: required + Usage: optional Value type: <u32> Definition: Number of cells to encode an interrupt source. - qcom,periph-map - Usage: required + Usage: optional Value type: <prop-encoded-array> Definition: A list of u32 arrays. This provides a mapping between the summary status register bits and peripheral addresses. diff --git a/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt b/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt new file mode 100644 index 000000000000..9d3fb78f96a7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt @@ -0,0 +1,26 @@ +QTI USB Audio QMI Device + +USB Audio QMI device is used to attach to remote processor IOMMU and +map USB Audio driver specific memory to iova to share with remote +processor. + +Required Properties: + +- compatible : "qcom,usb-audio-qmi-dev" + +- iommus : A list of phandle and IOMMU specifier pairs that describe the + IOMMU master interfaces of the device. + +- qcom,usb-audio-stream-id : Stream id is prepended to iova before passing + iova to remote processor. This allows remote processor to access iova. + +- qcom,usb-audio-intr-num : Interrupter number for external sub system + destination. + +Example: + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&lpass_q6_smmu 12>; + qcom,usb-audio-stream-id = <12>; + qcom,usb-audio-intr-num = <1>; + }; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index dd955be6c908..a42019b58897 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -116,7 +116,8 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb -dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb +dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb \ + msmfalcon-rumi.dtb ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index f5b59e6de558..c43ac0320c7a 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -686,8 +686,11 @@ pmicobalt_switch: qcom,led_switch { label = "switch"; qcom,led-name = "led:switch"; - qcom,default-led-trigger = - "switch_trigger"; + qcom,default-led-trigger = "switch_trigger"; + reg0 { + regulator-name = "pmicobalt_bob"; + max-voltage-uv = <3600000>; + }; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi index ae878c7f5bac..b414a215cbaa 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi @@ -30,6 +30,7 @@ sound-9335 { compatible = "qcom,msmcobalt-asoc-snd-tasha"; qcom,model = "msmcobalt-tasha-snd-card"; + qcom,hdmi-audio-rx; qcom,audio-routing = "AIF4 VI", "MCLK", @@ -98,8 +99,9 @@ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673"; - asoc-codec = <&stub_codec>; - asoc-codec-names = "msm-stub-codec.1"; + asoc-codec = <&stub_codec>, <&hdmi_audio>; + asoc-codec-names = "msm-stub-codec.1", + "msm-hdmi-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, <&wsa881x_213>, <&wsa881x_214>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi index 83b55da92fa2..92be85073351 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi @@ -198,7 +198,7 @@ reg = <0x0>; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi index 73f612516f84..b5d3a85f9b15 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi @@ -382,7 +382,13 @@ <0xff 324>, /* lpass_qca_slimbus_bam_ee1_irq */ <0xff 432>, /* smmu_Cirpt[8] */ <0xff 433>, /* smmu_Cirpt[9] */ - <0xff 461>; /* o_ocimem_nonsec_irq */ + <0xff 461>, /* o_ocimem_nonsec_irq */ + <0xff 69>, /* o_pwr_dcvsh_interrupt */ + <0xff 70>, /* o_perf_dcvsh_interrupt */ + <0xff 166>, /* o_lm_int_2qgic */ + <0xff 238>, /* crypto_bam_irq[0] */ + <0xff 132>; /* qup_irq */ + qcom,gpio-parent = <&tlmm>; qcom,gpio-map = <3 1>, diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts index 9848d6da33a5..d95507b505c2 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "msmcobalt.dtsi" -#include "msmcobalt-mtp.dtsi" +#include "msmcobalt-qrd.dtsi" / { model = "Qualcomm Technologies, Inc. MSM COBALT QRD"; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi new file mode 100644 index 000000000000..1720aca3b298 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi @@ -0,0 +1,13 @@ +/* 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 "msmcobalt-mtp.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 1d43d694eee5..74de62546c3b 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -149,6 +149,9 @@ pmcobalt_l1: regulator-l1 { regulator-min-microvolt = <880000>; regulator-max-microvolt = <880000>; + proxy-supply = <&pmcobalt_l1>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <73400>; status = "okay"; }; }; @@ -158,6 +161,9 @@ pmcobalt_l2: regulator-l2 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; + proxy-supply = <&pmcobalt_l2>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <12560>; status = "okay"; }; }; @@ -298,6 +304,9 @@ pmcobalt_l14: regulator-l14 { regulator-min-microvolt = <1880000>; regulator-max-microvolt = <1880000>; + proxy-supply = <&pmcobalt_l14>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <32000>; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 8d778ac3f104..90d1ecd8f29c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -258,7 +258,7 @@ removed_regions: removed_regions@85800000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x85800000 0 0x5300000>; + reg = <0 0x85800000 0 0x3700000>; }; peripheral_mem: peripheral_region@91900000 { @@ -310,6 +310,16 @@ alignment = <0 0x200000>; size = <0 0x5c00000>; }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x2000000>; + linux,cma-default; + }; }; }; @@ -2497,6 +2507,12 @@ qcom,rtb-size = <0x100000>; }; + qcom,mpm2-sleep-counter@10a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x010a3000 0x1000>; + clock-frequency = <32768>; + }; + qcom,msm-imem@146bf000 { compatible = "qcom,msm-imem"; reg = <0x146bf000 0x1000>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts new file mode 100644 index 000000000000..6631d31bac6d --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -0,0 +1,29 @@ +/* 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 "msmfalcon.dtsi" +#include "msmfalcon-pinctrl.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM FALCON RUMI"; + compatible = "qcom,msmfalcon-rumi", "qcom,msmfalcon", "qcom,rumi"; + qcom,board-id = <15 0>; +}; + +&uartblsp2dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index bf60b4047cb1..d41b23eeef67 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -36,6 +36,9 @@ 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_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y @@ -92,6 +95,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -140,7 +144,6 @@ 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 @@ -566,7 +569,6 @@ CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_DEBUG_RODATA=y CONFIG_DEBUG_ALIGN_RODATA=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y @@ -574,7 +576,6 @@ CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y -CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCRYPTO=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 6c37c8fdf0fc..3538ba14671f 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -33,6 +33,9 @@ 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_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y @@ -95,6 +98,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -143,7 +147,6 @@ 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 @@ -604,7 +607,6 @@ CONFIG_ARM64_PTDUMP=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_KERNEL_TEXT_RDONLY=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 706d01e147f5..67a134a02762 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -35,6 +35,9 @@ 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_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSMCOBALT=y @@ -95,6 +98,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -143,7 +147,6 @@ 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 @@ -540,7 +543,6 @@ CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_DEBUG_RODATA=y CONFIG_DEBUG_ALIGN_RODATA=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 0b275d433fc3..134c18c906ee 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -34,6 +34,9 @@ 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 @@ -96,6 +99,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -144,7 +148,6 @@ 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 @@ -625,7 +628,6 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/um/configs/x86_64_um_defconfig b/arch/um/configs/x86_64_um_defconfig index 078e6d981acd..487b68bad250 100644 --- a/arch/um/configs/x86_64_um_defconfig +++ b/arch/um/configs/x86_64_um_defconfig @@ -655,7 +655,7 @@ CONFIG_IPV6_MULTIPLE_TABLES=y # CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MROUTE is not set # CONFIG_ANDROID_PARANOID_NETWORK is not set -CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NET_ACTIVITY_STATS is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NET_PTP_CLASSIFY is not set # CONFIG_NETWORK_PHY_TIMESTAMPING is not set diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c index 47466ad04311..66807366d19d 100644 --- a/drivers/clk/msm/clock-mmss-cobalt.c +++ b/drivers/clk/msm/clock-mmss-cobalt.c @@ -46,7 +46,9 @@ static void __iomem *virt_base; #define mmpll10_pll_out_mm_source_val 4 #define dsi0phypll_mm_source_val 1 #define dsi1phypll_mm_source_val 2 -#define hdmiphypll_mm_source_val 1 +#define hdmiphypll_mm_source_val 1 +#define ext_dp_phy_pll_link_mm_source_val 1 +#define ext_dp_phy_pll_vco_mm_source_val 2 #define FIXDIV(div) (div ? (2 * (div) - 1) : (0)) @@ -61,9 +63,23 @@ static void __iomem *virt_base; | BVAL(10, 8, s##_mm_source_val), \ } +#define F_SLEW(f, s_f, s, div, m, n) \ + { \ + .freq_hz = (f), \ + .src_freq = (s_f), \ + .src_clk = &s.c, \ + .m_val = (m), \ + .n_val = ~((n)-(m)) * !!(n), \ + .d_val = ~(n),\ + .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \ + | BVAL(10, 8, s##_mm_source_val), \ + } + DEFINE_EXT_CLK(mmsscc_xo, NULL); DEFINE_EXT_CLK(mmsscc_gpll0, NULL); DEFINE_EXT_CLK(mmsscc_gpll0_div, NULL); +DEFINE_EXT_CLK(ext_dp_phy_pll_vco, NULL); +DEFINE_EXT_CLK(ext_dp_phy_pll_link, NULL); static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL); @@ -1091,6 +1107,57 @@ static struct rcg_clk dp_aux_clk_src = { }, }; +static struct clk_freq_tbl ftbl_dp_link_clk_src[] = { + F_SLEW( 162000000, 324000000, ext_dp_phy_pll_link, 2, 0, 0), + F_SLEW( 270000000, 540000000, ext_dp_phy_pll_link, 2, 0, 0), + F_SLEW( 540000000, 1080000000, ext_dp_phy_pll_link, 2, 0, 0), + F_END +}; + +static struct rcg_clk dp_link_clk_src = { + .cmd_rcgr_reg = MMSS_DP_LINK_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_dp_link_clk_src, + .current_freq = ftbl_dp_link_clk_src, + .base = &virt_base, + .c = { + .dbg_name = "dp_link_clk_src", + .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, + VDD_DIG_FMAX_MAP3(LOWER, 162000000, LOW, 270000000, + NOMINAL, 540000000), + CLK_INIT(dp_link_clk_src.c), + }, +}; + +/* + * Current understanding is that the DP PLL is going to be configured by using + * the set_rate ops for the dp_link_clk_src and dp_pixel_clk_src. When set_rate + * is called on this RCG, the rate call never makes it to the external DP + * clocks. + */ +static struct clk_freq_tbl ftbl_dp_crypto_clk_src[] = { + F_MM( 101250000, ext_dp_phy_pll_link, 1, 5, 16), + F_MM( 168750000, ext_dp_phy_pll_link, 1, 5, 16), + F_MM( 337500000, ext_dp_phy_pll_link, 1, 5, 16), + F_END +}; + +static struct rcg_clk dp_crypto_clk_src = { + .cmd_rcgr_reg = MMSS_DP_CRYPTO_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_dp_crypto_clk_src, + .current_freq = ftbl_dp_crypto_clk_src, + .base = &virt_base, + .c = { + .dbg_name = "dp_crypto_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOWER, 101250000, LOW, 168750000, + NOMINAL, 337500000), + CLK_INIT(dp_crypto_clk_src.c), + }, +}; + static struct branch_clk mmss_bimc_smmu_ahb_clk = { .cbcr_reg = MMSS_BIMC_SMMU_AHB_CBCR, .has_sibling = 1, @@ -1936,6 +2003,44 @@ static struct branch_clk mmss_mdss_dp_aux_clk = { }, }; +static struct branch_clk mmss_mdss_dp_link_clk = { + .cbcr_reg = MMSS_MDSS_DP_LINK_CBCR, + .has_sibling = 0, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_link_clk", + .parent = &dp_link_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_link_clk.c), + }, +}; + +/* Reset state of MMSS_MDSS_DP_LINK_INTF_DIV is 0x3 (div-4) */ +static struct branch_clk mmss_mdss_dp_link_intf_clk = { + .cbcr_reg = MMSS_MDSS_DP_LINK_INTF_CBCR, + .has_sibling = 1, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_link_intf_clk", + .parent = &dp_link_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_link_intf_clk.c), + }, +}; + +static struct branch_clk mmss_mdss_dp_crypto_clk = { + .cbcr_reg = MMSS_MDSS_DP_CRYPTO_CBCR, + .has_sibling = 0, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_crypto_clk", + .parent = &dp_crypto_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_crypto_clk.c), + }, +}; + static struct branch_clk mmss_mdss_dp_gtc_clk = { .cbcr_reg = MMSS_MDSS_DP_GTC_CBCR, .has_sibling = 0, @@ -2313,10 +2418,13 @@ static struct mux_clk mmss_debug_mux = { { &mmss_fd_core_clk.c, 0x0089 }, { &mmss_fd_core_uar_clk.c, 0x008a }, { &mmss_fd_ahb_clk.c, 0x008c }, - { &mmss_camss_cphy_csid0_clk.c, 0x008d}, - { &mmss_camss_cphy_csid1_clk.c, 0x008e}, - { &mmss_camss_cphy_csid2_clk.c, 0x008f}, - { &mmss_camss_cphy_csid3_clk.c, 0x0090}, + { &mmss_camss_cphy_csid0_clk.c, 0x008d }, + { &mmss_camss_cphy_csid1_clk.c, 0x008e }, + { &mmss_camss_cphy_csid2_clk.c, 0x008f }, + { &mmss_camss_cphy_csid3_clk.c, 0x0090 }, + { &mmss_mdss_dp_link_clk.c, 0x0098 }, + { &mmss_mdss_dp_link_intf_clk.c, 0x0099 }, + { &mmss_mdss_dp_crypto_clk.c, 0x009a }, { &mmss_mdss_dp_aux_clk.c, 0x009c }, { &mmss_mdss_dp_gtc_clk.c, 0x009d }, { &mmss_mdss_byte0_intf_clk.c, 0x00ad }, @@ -2384,6 +2492,10 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = { CLK_LIST(pclk1_clk_src), CLK_LIST(ext_extpclk_clk_src), CLK_LIST(extpclk_clk_src), + CLK_LIST(ext_dp_phy_pll_vco), + CLK_LIST(ext_dp_phy_pll_link), + CLK_LIST(dp_link_clk_src), + CLK_LIST(dp_crypto_clk_src), CLK_LIST(csi0phytimer_clk_src), CLK_LIST(csi1phytimer_clk_src), CLK_LIST(csi2phytimer_clk_src), @@ -2463,6 +2575,9 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = { CLK_LIST(mmss_mdss_byte0_intf_div_clk), CLK_LIST(mmss_mdss_byte1_intf_clk), CLK_LIST(mmss_mdss_dp_aux_clk), + CLK_LIST(mmss_mdss_dp_crypto_clk), + CLK_LIST(mmss_mdss_dp_link_clk), + CLK_LIST(mmss_mdss_dp_link_intf_clk), CLK_LIST(mmss_mdss_dp_gtc_clk), CLK_LIST(mmss_mdss_esc0_clk), CLK_LIST(mmss_mdss_esc1_clk), @@ -2646,6 +2761,11 @@ int msm_mmsscc_cobalt_probe(struct platform_device *pdev) ext_extpclk_clk_src.dev = &pdev->dev; ext_extpclk_clk_src.clk_id = "extpclk_src"; + ext_dp_phy_pll_link.dev = &pdev->dev; + ext_dp_phy_pll_link.clk_id = "dp_link_src"; + ext_dp_phy_pll_vco.dev = &pdev->dev; + ext_dp_phy_pll_vco.clk_id = "dp_vco_div"; + is_vq = of_device_is_compatible(pdev->dev.of_node, "qcom,mmsscc-hamster"); if (is_vq) diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index 44307f67fd22..9a25ebfdc778 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -420,6 +420,9 @@ av8l_fast_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) struct av8l_fast_io_pgtable *data = av8l_fast_alloc_pgtable_data(cfg); + if (!data) + return NULL; + /* restrict according to the fast map requirements */ cfg->ias = 32; cfg->pgsize_bitmap = SZ_4K; diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index a97c082d18d8..c78178c0e1a1 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1379,7 +1379,7 @@ static int __apply_to_new_mapping(struct seq_file *s, struct dma_iommu_mapping *mapping; struct iommu_debug_device *ddev = s->private; struct device *dev = ddev->dev; - int ret, fast = 1; + int ret = -EINVAL, fast = 1; phys_addr_t pt_phys; mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL); @@ -1688,7 +1688,7 @@ static const struct file_operations iommu_debug_atos_fops = { static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) { - ssize_t retval; + ssize_t retval = -EINVAL; int ret; char *comma1, *comma2, *comma3; char buf[100]; diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 6942a8a74ea9..068c62a2f27f 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -16,16 +16,20 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> #include <linux/regmap.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/leds-qpnp-flash-v2.h> #define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40) #define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43) #define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46) #define FLASH_LED_REG_IRES(base) (base + 0x47) +#define FLASH_LED_REG_STROBE_CFG(base) (base + 0x48) #define FLASH_LED_REG_STROBE_CTRL(base) (base + 0x49) -#define FLASH_LED_REG_CHANNEL_CTRL(base) (base + 0x4C) +#define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C) #define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D) #define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50) #define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52) @@ -33,10 +37,11 @@ #define FLASH_LED_HDRM_MODE_PRGM_MASK GENMASK(7, 0) #define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4) #define FLASH_LED_CURRENT_MASK GENMASK(6, 0) -#define FLASH_LED_STROBE_CTRL_MASK GENMASK(2, 0) +#define FLASH_LED_ENABLE_MASK GENMASK(2, 0) #define FLASH_LED_SAFETY_TMR_MASK GENMASK(7, 0) #define FLASH_LED_ISC_DELAY_MASK GENMASK(1, 0) #define FLASH_LED_MOD_CTRL_MASK BIT(7) +#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2) #define FLASH_LED_HEADROOM_AUTO_MODE_ENABLED true #define FLASH_LED_ISC_DELAY_SHIFT 6 @@ -54,7 +59,11 @@ #define FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV 0x04 #define FLASH_LED_HDRM_VOL_BASE_MV 125 #define FLASH_LED_HDRM_VOL_STEP_MV 25 -#define FLASH_LED_STROBE_ENABLE BIT(0) +#define FLASH_LED_STROBE_CFG_DEFAULT 0x00 +#define FLASH_LED_HW_STROBE_OPTION_1 0x00 +#define FLASH_LED_HW_STROBE_OPTION_2 0x01 +#define FLASH_LED_HW_STROBE_OPTION_3 0x02 +#define FLASH_LED_ENABLE BIT(0) #define FLASH_LED_MOD_ENABLE BIT(7) #define FLASH_LED_DISABLE 0x00 #define FLASH_LED_SAFETY_TMR_DISABLED 0x13 @@ -65,11 +74,18 @@ enum flash_led_type { FLASH_LED_TYPE_TORCH, }; +enum { + LED1 = 0, + LED2, + LED3, +}; + /* * Flash LED configuration read from device tree */ struct flash_led_platform_data { u8 isc_delay_us; + u8 hw_strobe_option; bool hdrm_auto_mode_en; }; @@ -143,6 +159,80 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) return 0; } +static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode, + int hw_strobe_option, bool on) +{ + int rc = 0; + + /* + * If the LED controlled by this fnode is not GPIO controlled + * for the given strobe_option, return. + */ + if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1) + return 0; + else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2 + && fnode->id != LED3) + return 0; + else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3 + && fnode->id == LED1) + return 0; + + if (gpio_is_valid(fnode->hw_strobe_gpio)) { + gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0); + } else if (fnode->hw_strobe_state_active && + fnode->hw_strobe_state_suspend) { + rc = pinctrl_select_state(fnode->pinctrl, + on ? fnode->hw_strobe_state_active : + fnode->hw_strobe_state_suspend); + if (rc) { + dev_err(&fnode->pdev->dev, + "failed to change hw strobe pin state\n"); + return rc; + } + } + + return rc; +} + +static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led, + struct flash_switch_data *snode, bool on) +{ + int i, rc = 0; + + if (snode->regulator_on == on) + return 0; + + if (on == false) { + i = snode->num_regulators; + goto out; + } + + for (i = 0; i < snode->num_regulators; i++) { + rc = regulator_enable(snode->reg_data[i].vreg); + if (rc < 0) { + dev_err(&led->pdev->dev, + "regulator enable failed, rc=%d\n", rc); + goto out; + } + } + snode->regulator_on = true; + + return rc; + +out: + while (i--) + regulator_disable(snode->reg_data[i].vreg); + + snode->regulator_on = false; + return rc; +} + +static int qpnp_flash_led_get_max_avail_current(struct flash_switch_data *snode, + struct qpnp_flash_led *led) +{ + return 3750; +} + static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value) { int prgm_current_ma = value; @@ -168,6 +258,10 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) if (!on) goto leds_turn_off; + rc = qpnp_flash_led_regulator_enable(led, snode, true); + if (rc) + return rc; + val = 0; for (i = 0; i < led->num_led_nodes; i++) val |= led->fnode[i].ires << (led->fnode[i].id * 2); @@ -176,6 +270,13 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) if (rc) return rc; + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_STROBE_CFG(led->base), + FLASH_LED_ENABLE_MASK, + led->pdata->hw_strobe_option); + if (rc) + return rc; + val = 0; for (i = 0; i < led->num_avail_leds; i++) { if (!led->fnode[i].led_on) @@ -184,7 +285,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) addr_offset = led->fnode[i].id; rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset), - FLASH_LED_STROBE_CTRL_MASK, FLASH_LED_STROBE_ENABLE); + FLASH_LED_ENABLE_MASK, led->fnode[i].trigger); if (rc) return rc; @@ -200,7 +301,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) if (rc) return rc; - val |= FLASH_LED_STROBE_ENABLE << led->fnode[i].id; + val |= FLASH_LED_ENABLE << led->fnode[i].id; if (led->fnode[i].pinctrl) { rc = pinctrl_select_state(led->fnode[i].pinctrl, @@ -211,6 +312,16 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) return rc; } } + + if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) { + rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], + led->pdata->hw_strobe_option, true); + if (rc) { + dev_err(&led->pdev->dev, + "Unable to enable hw strobe\n"); + return rc; + } + } } rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base), @@ -219,8 +330,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) return rc; rc = qpnp_flash_led_masked_write(led, - FLASH_LED_REG_CHANNEL_CTRL(led->base), - FLASH_LED_STROBE_CTRL_MASK, val); + FLASH_LED_EN_LED_CTRL(led->base), + FLASH_LED_ENABLE_MASK, val); if (rc) return rc; @@ -228,8 +339,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) leds_turn_off: rc = qpnp_flash_led_masked_write(led, - FLASH_LED_REG_CHANNEL_CTRL(led->base), - FLASH_LED_STROBE_CTRL_MASK, FLASH_LED_DISABLE); + FLASH_LED_EN_LED_CTRL(led->base), + FLASH_LED_ENABLE_MASK, FLASH_LED_DISABLE); if (rc) return rc; @@ -260,11 +371,56 @@ leds_turn_off: return rc; } } + + if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) { + rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], + led->pdata->hw_strobe_option, false); + if (rc) { + dev_err(&led->pdev->dev, + "Unable to disable hw strobe\n"); + return rc; + } + } } + qpnp_flash_led_regulator_enable(led, snode, false); + return 0; } +int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options) +{ + struct flash_switch_data *snode = + container_of(led_cdev, struct flash_switch_data, cdev); + struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev); + int rc, val = 0; + + if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) { + dev_err(&led->pdev->dev, "Invalid options %d\n", options); + return -EINVAL; + } + + if (options & ENABLE_REGULATOR) { + rc = qpnp_flash_led_regulator_enable(led, snode, true); + if (rc < 0) { + dev_err(&led->pdev->dev, + "enable regulator failed, rc=%d\n", rc); + return rc; + } + } + + if (options & QUERY_MAX_CURRENT) { + val = qpnp_flash_led_get_max_avail_current(snode, led); + if (val < 0) { + dev_err(&led->pdev->dev, + "query max current failed, rc=%d\n", val); + return val; + } + } + + return val; +} + static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { @@ -297,12 +453,111 @@ exit: spin_unlock(&led->lock); } +static int qpnp_flash_led_regulator_setup(struct qpnp_flash_led *led, + struct flash_switch_data *snode, bool on) +{ + int i, rc = 0; + + if (on == false) { + i = snode->num_regulators; + goto out; + } + + for (i = 0; i < snode->num_regulators; i++) { + snode->reg_data[i].vreg = regulator_get(snode->cdev.dev, + snode->reg_data[i].reg_name); + if (IS_ERR(snode->reg_data[i].vreg)) { + rc = PTR_ERR(snode->reg_data[i].vreg); + dev_err(&led->pdev->dev, + "Failed to get regulator, rc=%d\n", rc); + goto out; + } + + if (regulator_count_voltages(snode->reg_data[i].vreg) > 0) { + rc = regulator_set_voltage(snode->reg_data[i].vreg, + snode->reg_data[i].max_volt_uv, + snode->reg_data[i].max_volt_uv); + if (rc < 0) { + dev_err(&led->pdev->dev, + "regulator set voltage failed, rc=%d\n", + rc); + regulator_put(snode->reg_data[i].vreg); + goto out; + } + } + } + + return rc; + +out: + while (i--) { + if (regulator_count_voltages(snode->reg_data[i].vreg) > 0) + regulator_set_voltage(snode->reg_data[i].vreg, 0, + snode->reg_data[i].max_volt_uv); + + regulator_put(snode->reg_data[i].vreg); + } + + return rc; +} + +static int qpnp_flash_led_regulator_parse_dt(struct qpnp_flash_led *led, + struct flash_switch_data *snode, + struct device_node *node) { + + int i = 0, rc = 0, num_regs = 0; + struct device_node *temp = NULL; + const char *temp_string; + u32 val; + + while ((temp = of_get_next_available_child(node, temp))) { + if (of_find_property(temp, "regulator-name", NULL)) + num_regs++; + } + snode->num_regulators = num_regs; + + if (snode->num_regulators == 0) + return 0; + + snode->reg_data = devm_kcalloc(&led->pdev->dev, snode->num_regulators, + sizeof(*snode->reg_data), + GFP_KERNEL); + if (!snode->reg_data) + return -ENOMEM; + + for_each_available_child_of_node(node, temp) { + rc = of_property_read_string(temp, "regulator-name", + &temp_string); + if (!rc) + snode->reg_data[i].reg_name = temp_string; + else { + dev_err(&led->pdev->dev, + "Unable to read regulator name, rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(temp, "max-voltage-uv", &val); + if (!rc) { + snode->reg_data[i].max_volt_uv = val; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, + "Unable to read max voltage, rc=%d\n", rc); + return rc; + } + + i++; + } + + return 0; +} + static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, struct flash_node_data *fnode, struct device_node *node) { const char *temp_string; int rc; u32 val; + bool strobe_sel = 0, edge_trigger = 0, active_high = 0; fnode->pdev = led->pdev; fnode->cdev.brightness_set = qpnp_flash_led_brightness_set; @@ -429,6 +684,50 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return rc; } + strobe_sel = of_property_read_bool(node, "qcom,hw-strobe-sel"); + if (strobe_sel) { + edge_trigger = of_property_read_bool(node, + "qcom,hw-strobe-edge-trigger"); + active_high = !of_property_read_bool(node, + "qcom,hw-strobe-active-low"); + } + fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high; + + if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) { + if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) { + fnode->hw_strobe_gpio = of_get_named_gpio(node, + "qcom,hw-strobe-gpio", 0); + if (fnode->hw_strobe_gpio < 0) { + dev_err(&led->pdev->dev, + "Invalid gpio specified\n"); + return fnode->hw_strobe_gpio; + } + gpio_direction_output(fnode->hw_strobe_gpio, 0); + } else { + fnode->hw_strobe_gpio = -1; + fnode->hw_strobe_state_active = + pinctrl_lookup_state(fnode->pinctrl, + "strobe_enable"); + if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) { + dev_err(&led->pdev->dev, + "No active pin for hardware strobe, rc=%ld\n", + PTR_ERR(fnode->hw_strobe_state_active)); + fnode->hw_strobe_state_active = NULL; + } + + fnode->hw_strobe_state_suspend = + pinctrl_lookup_state(fnode->pinctrl, + "strobe_disable"); + if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) { + dev_err(&led->pdev->dev, + "No suspend pin for hardware strobe, rc=%ld\n", + PTR_ERR(fnode->hw_strobe_state_suspend) + ); + fnode->hw_strobe_state_suspend = NULL; + } + } + } + rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); if (rc) { dev_err(&led->pdev->dev, "Unable to register led node %d\n", @@ -469,7 +768,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, struct device_node *node) { - int rc; + int rc = 0; rc = of_property_read_string(node, "qcom,led-name", &led->snode->cdev.name); @@ -485,6 +784,21 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, return rc; } + rc = qpnp_flash_led_regulator_parse_dt(led, led->snode, node); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Unable to parse regulator data, rc=%d\n", rc); + return rc; + } + + if (led->snode->num_regulators) { + rc = qpnp_flash_led_regulator_setup(led, led->snode, true); + if (rc) { + dev_err(&led->pdev->dev, "Unable to setup regulator\n"); + return rc; + } + } + led->snode->pdev = led->pdev; led->snode->cdev.brightness_set = qpnp_flash_led_brightness_set; led->snode->cdev.brightness_get = qpnp_flash_led_brightness_get; @@ -517,6 +831,14 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, return rc; } + rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val); + if (!rc) { + led->pdata->hw_strobe_option = (u8)val; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to parse hw strobe option\n"); + return rc; + } + return 0; } @@ -632,6 +954,12 @@ static int qpnp_flash_led_remove(struct platform_device *pdev) struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev); int i = led->num_led_nodes; + if (led->snode->num_regulators) { + if (led->snode->regulator_on) + qpnp_flash_led_regulator_enable(led, led->snode, false); + qpnp_flash_led_regulator_setup(led, led->snode, false); + } + led_classdev_unregister(&led->snode->cdev); while (i > 0) led_classdev_unregister(&led->fnode[--i].cdev); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index a7ac094f6c1e..140d33582c87 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -90,10 +90,42 @@ static const struct v4l2_fmtdesc fmtdesc[] = { .pixelformat = SDE_PIX_FMT_BGRX_8888, }, { + .description = "SDE/XBGR_8888", + .pixelformat = SDE_PIX_FMT_XBGR_8888, + }, + { .description = "RGBA_5551", .pixelformat = SDE_PIX_FMT_RGBA_5551, }, { + .description = "ARGB_1555", + .pixelformat = SDE_PIX_FMT_ARGB_1555, + }, + { + .description = "ABGR_1555", + .pixelformat = SDE_PIX_FMT_ABGR_1555, + }, + { + .description = "BGRA_5551", + .pixelformat = SDE_PIX_FMT_BGRA_5551, + }, + { + .description = "BGRX_5551", + .pixelformat = SDE_PIX_FMT_BGRX_5551, + }, + { + .description = "RGBX_5551", + .pixelformat = SDE_PIX_FMT_RGBX_5551, + }, + { + .description = "XBGR_1555", + .pixelformat = SDE_PIX_FMT_XBGR_1555, + }, + { + .description = "XRGB_1555", + .pixelformat = SDE_PIX_FMT_XRGB_1555, + }, + { .description = "ARGB_4444", .pixelformat = SDE_PIX_FMT_ARGB_4444, }, @@ -102,6 +134,30 @@ static const struct v4l2_fmtdesc fmtdesc[] = { .pixelformat = SDE_PIX_FMT_RGBA_4444, }, { + .description = "BGRA_4444", + .pixelformat = SDE_PIX_FMT_BGRA_4444, + }, + { + .description = "ABGR_4444", + .pixelformat = SDE_PIX_FMT_ABGR_4444, + }, + { + .description = "RGBX_4444", + .pixelformat = SDE_PIX_FMT_RGBX_4444, + }, + { + .description = "XRGB_4444", + .pixelformat = SDE_PIX_FMT_XRGB_4444, + }, + { + .description = "BGRX_4444", + .pixelformat = SDE_PIX_FMT_BGRX_4444, + }, + { + .description = "XBGR_4444", + .pixelformat = SDE_PIX_FMT_XBGR_4444, + }, + { .description = "RGB_888", .pixelformat = SDE_PIX_FMT_RGB_888, }, diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c index 8e5793362875..5318c9da1277 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c @@ -318,6 +318,10 @@ static struct sde_mdp_format_params sde_mdp_format_map[] = { SDE_PIX_FMT_BGRX_8888, SDE_MDP_FMT_LINEAR, VALID_ROT_WB_ALL | VALID_MDP_WB_INTF_FORMAT, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_XBGR_8888, SDE_MDP_FMT_LINEAR, + VALID_ROT_WB_ALL | VALID_MDP_WB_INTF_FORMAT, + 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, SDE_MDP_COMPRESS_NONE), FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V1, SDE_MDP_FMT_LINEAR, SDE_MDP_CHROMA_H2V1, SDE_MDP_PIXEL_NORMAL, @@ -401,10 +405,36 @@ static struct sde_mdp_format_params sde_mdp_format_map[] = { }, FMT_RGB_1555(SDE_PIX_FMT_RGBA_5551, 1, VALID_ROT_WB_ALL, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_1555(SDE_PIX_FMT_ARGB_1555, 1, VALID_ROT_WB_ALL, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_ABGR_1555, 1, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_BGRA_5551, 1, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_1555(SDE_PIX_FMT_BGRX_5551, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_1555(SDE_PIX_FMT_RGBX_5551, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_1555(SDE_PIX_FMT_XBGR_1555, 0, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_XRGB_1555, 0, VALID_ROT_WB_ALL, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), FMT_RGB_4444(SDE_PIX_FMT_RGBA_4444, 1, VALID_ROT_WB_ALL, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), FMT_RGB_4444(SDE_PIX_FMT_ARGB_4444, 1, VALID_ROT_WB_ALL, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_BGRA_4444, 1, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_4444(SDE_PIX_FMT_ABGR_4444, 1, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_RGBX_4444, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_4444(SDE_PIX_FMT_XRGB_4444, 0, VALID_ROT_WB_ALL, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_BGRX_4444, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_4444(SDE_PIX_FMT_XBGR_4444, 0, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), FMT_RGB_1010102(SDE_PIX_FMT_RGBA_1010102, SDE_MDP_FMT_LINEAR, VALID_ROT_R3_WB_FORMAT | VALID_MDP_WB_INTF_FORMAT, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, SDE_MDP_COMPRESS_NONE), 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 d5388db4a9b1..c141797bcd3c 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -575,14 +575,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, if (rot->irq_num >= 0) reinit_completion(&ctx->regdma_comp); - /* enable IRQ for first regdma submission from idle */ - if (atomic_read(&rot->regdma_submit_count) == - atomic_read(&rot->regdma_done_count)) { - SDEROT_DBG("Enable IRQ! regdma submitcnt==donecnt -> %d\n", - atomic_read(&rot->regdma_submit_count)); - enable_irq(rot->irq_num); - } - /* * Last ROT command must be ROT_START before REGDMA start */ @@ -640,9 +632,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, enableInt | (ts_length << 14) | offset); } - /* Update REGDMA submit count */ - atomic_inc(&rot->regdma_submit_count); - /* Update command queue write ptr */ sde_hw_rotator_put_regdma_segment(ctx, wrptr); @@ -731,7 +720,6 @@ static u32 sde_hw_rotator_wait_done_regdma( u32 last_ts; u32 int_id; u32 sts = 0; - u32 d_count; unsigned long flags; if (rot->irq_num >= 0) { @@ -753,6 +741,8 @@ static u32 sde_hw_rotator_wait_done_regdma( SDEROT_ERR( "Timeout wait for regdma interrupt status, ts:%X\n", ctx->timestamp); + SDEROT_ERR("last_isr:0x%X, last_ts:0x%X, rc=%d\n", + last_isr, last_ts, rc); if (status & REGDMA_WATCHDOG_INT) SDEROT_ERR("REGDMA watchdog interrupt\n"); @@ -784,17 +774,6 @@ static u32 sde_hw_rotator_wait_done_regdma( status = 0; } - /* regardless success or timeout, update done count */ - d_count = atomic_inc_return(&rot->regdma_done_count); - - /* disable IRQ if no more regdma submission in queue */ - if (d_count == atomic_read(&rot->regdma_submit_count)) { - SDEROT_DBG( - "Disable IRQ!! regdma donecnt==submitcnt -> %d\n", - d_count); - disable_irq_nosync(rot->irq_num); - } - spin_unlock_irqrestore(&rot->rotisr_lock, flags); } else { int cnt = 200; @@ -1027,6 +1006,9 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext( sde_hw_rotator_swts_create(resinfo->rot); } + if (resinfo->rot->irq_num >= 0) + enable_irq(resinfo->rot->irq_num); + SDEROT_DBG("New rotator resource:%p, priority:%d\n", resinfo, wb_id); @@ -1053,6 +1035,9 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr, resinfo, hw->wb_id, atomic_read(&hw->num_active), hw->pending_count); + if (resinfo->rot->irq_num >= 0) + disable_irq(resinfo->rot->irq_num); + devm_kfree(&mgr->pdev->dev, resinfo); } @@ -1505,8 +1490,7 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) ctx->last_regdma_isr_status = isr; ctx->last_regdma_timestamp = ts; SDEROT_DBG( - "regdma complete: ctx:%p, ts:%X, dcount:%X\n", - ctx, ts, atomic_read(&rot->regdma_done_count)); + "regdma complete: ctx:%p, ts:%X\n", ctx, ts); complete_all(&ctx->regdma_comp); ts = (ts - 1) & SDE_REGDMA_SWTS_MASK; @@ -1854,8 +1838,6 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr) atomic_set(&rot->timestamp[0], 0); atomic_set(&rot->timestamp[1], 0); - atomic_set(&rot->regdma_submit_count, 0); - atomic_set(&rot->regdma_done_count, 0); ret = sde_rotator_hw_rev_init(rot); if (ret) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h index 5196b1351542..610caf16c764 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h @@ -263,9 +263,6 @@ struct sde_hw_rotator { struct completion rot_comp; struct completion regdma_comp; - atomic_t regdma_submit_count; - atomic_t regdma_done_count; - spinlock_t rotctx_lock; spinlock_t rotisr_lock; diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c index 009d8271563d..4ae13944362a 100644 --- a/drivers/media/platform/msm/vidc/msm_smem.c +++ b/drivers/media/platform/msm/vidc/msm_smem.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 @@ -462,6 +462,23 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, return mem; } +bool msm_smem_compare_buffers(void *clt, int fd, void *priv) +{ + struct smem_client *client = clt; + struct ion_handle *handle = NULL; + bool ret = false; + + if (!clt || !priv) { + dprintk(VIDC_ERR, "Invalid params: %p, %p\n", + clt, priv); + return false; + } + handle = ion_import_dma_buf(client->clnt, fd); + ret = handle == priv; + handle ? ion_free(client->clnt, handle) : 0; + return ret; +} + static int ion_cache_operations(struct smem_client *client, struct msm_smem *mem, enum smem_cache_ops cache_op) { diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 14b62984eae9..5c9dc6a53223 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1552,52 +1552,6 @@ static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers) return rc; } -static int set_bitrate_for_each_layer(struct msm_vidc_inst *inst, - u32 num_enh_layers, u32 total_bitrate) -{ - u32 property_id = 0; - int i = 0, rc = 0; - struct hfi_device *hdev = NULL; - struct hal_bitrate bitrate; - struct hal_enable enable; - int bitrate_table[3][4] = { - {50, 50, 0, 0}, - {34, 33, 33, 0}, - {25, 25, 25, 25} - }; - - if (!inst || !inst->core || !inst->core->device) { - dprintk(VIDC_ERR, "%s - invalid input\n", __func__); - return -EINVAL; - } - - if (!num_enh_layers || num_enh_layers > ARRAY_SIZE(bitrate_table)) { - dprintk(VIDC_ERR, "%s - invalid number of enh layers: %d\n", - __func__, num_enh_layers); - return -EINVAL; - } - hdev = inst->core->device; - - property_id = HAL_PARAM_VENC_BITRATE_TYPE; - enable.enable = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE; - rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, property_id, &enable); - if (rc) { - dprintk(VIDC_ERR, "Failed to set layerwise bitrate\n"); - return false; - } - - for (i = 0; !rc && i <= num_enh_layers; i++) { - property_id = HAL_CONFIG_VENC_TARGET_BITRATE; - bitrate.bit_rate = (u32)((total_bitrate * - bitrate_table[num_enh_layers - 1][i]) / 100); - bitrate.layer_id = i; - rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, property_id, &bitrate); - } - return rc; -} - static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) { u32 rc = 0; @@ -2269,26 +2223,10 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDEO_BITRATE: { - struct v4l2_ctrl *hier_p = TRY_GET_CTRL( - V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS); - + property_id = HAL_CONFIG_VENC_TARGET_BITRATE; + bitrate.bit_rate = ctrl->val; bitrate.layer_id = 0; - if (hier_p->val && - inst->fmts[CAPTURE_PORT]->fourcc == - V4L2_PIX_FMT_H264) { - rc = set_bitrate_for_each_layer(inst, - hier_p->val, ctrl->val); - if (rc) { - dprintk(VIDC_ERR, - "failed to set bitrate for multiple layers\n"); - rc = -EINVAL; - } - } else { - property_id = HAL_CONFIG_VENC_TARGET_BITRATE; - bitrate.bit_rate = ctrl->val; - bitrate.layer_id = 0; - pdata = &bitrate; - } + pdata = &bitrate; break; } case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: @@ -3236,8 +3174,8 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, bitrate.bit_rate = control[i].value; property_id = HAL_CONFIG_VENC_TARGET_BITRATE; pdata = &bitrate; - dprintk(VIDC_DBG, "layerwise bitrate for %d\n", - i); + dprintk(VIDC_DBG, "bitrate for layer(%d)=%d\n", + i, bitrate.bit_rate); rc = call_hfi_op(hdev, session_set_property, (void *)inst->session, property_id, pdata); diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 51be8df7ff35..8a4d5eb561c6 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -213,7 +213,9 @@ struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst, *plane = 0; list_for_each_entry(temp, &inst->registeredbufs.list, list) { for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) { - bool fd_matches = fd == temp->fd[i]; + bool ion_hndl_matches = temp->handle[i] ? + msm_smem_compare_buffers(inst->mem_client, fd, + temp->handle[i]->smem_priv) : false; bool device_addr_matches = device_addr == temp->device_addr[i]; bool contains_within = CONTAINS(temp->buff_off[i], @@ -223,7 +225,7 @@ struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst, temp->buff_off[i], temp->size[i]); if (!temp->inactive && - (fd_matches || device_addr_matches) && + (ion_hndl_matches || device_addr_matches) && (contains_within || overlaps)) { dprintk(VIDC_DBG, "This memory region is already mapped\n"); @@ -907,8 +909,7 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) for (i = 0; i < b->length; i++) { if (EXTRADATA_IDX(b->length) && - (i == EXTRADATA_IDX(b->length)) && - !b->m.planes[i].m.userptr) { + i == EXTRADATA_IDX(b->length)) { continue; } buffer_info = device_to_uvaddr(&inst->registeredbufs, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index c127a17b6157..72c1ddcf3a70 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -373,6 +373,7 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, struct context_bank_info *msm_smem_get_context_bank(void *clt, bool is_secure, enum hal_buffer buffer_type); void msm_vidc_fw_unload_handler(struct work_struct *work); +bool msm_smem_compare_buffers(void *clt, int fd, void *priv); /* XXX: normally should be in msm_vidc.h, but that's meant for public APIs, * whereas this is private */ int msm_vidc_destroy(struct msm_vidc_inst *inst); diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index 4d0bdce755a6..9eb75d876577 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.c @@ -58,7 +58,6 @@ struct i2c_pmic_periph { struct i2c_pmic { struct device *dev; - struct i2c_client *client; struct regmap *regmap; struct irq_domain *domain; struct i2c_pmic_periph *periph; @@ -497,25 +496,28 @@ static struct regmap_config i2c_pmic_regmap_config = { static int i2c_pmic_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int rc; struct i2c_pmic *chip; + int rc = 0; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + chip->dev = &client->dev; chip->regmap = devm_regmap_init_i2c(client, &i2c_pmic_regmap_config); if (!chip->regmap) return -ENODEV; + i2c_set_clientdata(client, chip); + if (!of_property_read_bool(chip->dev->of_node, "interrupt-controller")) + goto probe_children; + chip->domain = irq_domain_add_tree(client->dev.of_node, &i2c_pmic_domain_ops, chip); - if (!chip->domain) - return -ENOMEM; - - chip->client = client; - chip->dev = &client->dev; - i2c_set_clientdata(client, chip); + if (!chip->domain) { + rc = -ENOMEM; + goto cleanup; + } rc = i2c_pmic_parse_dt(chip); if (rc < 0) { @@ -549,6 +551,8 @@ static int i2c_pmic_probe(struct i2c_client *client, } enable_irq_wake(client->irq); + +probe_children: of_platform_populate(chip->dev->of_node, NULL, NULL, chip->dev); pr_info("I2C PMIC probe successful\n"); return rc; @@ -565,7 +569,8 @@ static int i2c_pmic_remove(struct i2c_client *client) struct i2c_pmic *chip = i2c_get_clientdata(client); of_platform_depopulate(chip->dev); - irq_domain_remove(chip->domain); + if (chip->domain) + irq_domain_remove(chip->domain); i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 1aec5e559dd5..273728482227 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -433,7 +433,6 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, smc_id = TZ_OS_APP_SHUTDOWN_ID; desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID; desc.args[0] = req->app_id; - __qseecom_reentrancy_check_if_no_app_blocked(smc_id); ret = scm_call2(smc_id, &desc); break; } @@ -2104,6 +2103,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, return 0; } + __qseecom_cleanup_app(data); + __qseecom_reentrancy_check_if_no_app_blocked(TZ_OS_APP_SHUTDOWN_ID); + if (data->client.app_id > 0) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, @@ -2132,11 +2134,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, } } - if (found_dead_app) { + if (found_dead_app) pr_warn("cleanup app_id %d(%s)\n", data->client.app_id, (char *)data->client.app_name); - __qseecom_cleanup_app(data); - } if (unload) { struct qseecom_unload_app_ireq req; @@ -2165,7 +2165,6 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (resp.result == QSEOS_RESULT_SUCCESS) pr_debug("App (%d) is unloaded!!\n", data->client.app_id); - __qseecom_cleanup_app(data); if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 2a05031ba631..bd4c17ca2484 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -14,10 +14,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/moduleparam.h> #include <linux/etherdevice.h> #include "wil6210.h" #include "txrx.h" +static bool alt_ifname; /* = false; */ +module_param(alt_ifname, bool, S_IRUGO); +MODULE_PARM_DESC(alt_ifname, " use an alternate interface name wigigN instead of wlanN"); + static int wil_open(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); @@ -136,6 +141,7 @@ void *wil_if_alloc(struct device *dev) struct wil6210_priv *wil; struct ieee80211_channel *ch; int rc = 0; + const char *ifname = alt_ifname ? "wigig%d" : "wlan%d"; wdev = wil_cfg80211_init(dev); if (IS_ERR(wdev)) { @@ -160,7 +166,7 @@ void *wil_if_alloc(struct device *dev) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup); + ndev = alloc_netdev(0, ifname, NET_NAME_UNKNOWN, wil_dev_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index 1c9153894dca..213b8259638c 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -114,8 +114,10 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, u8 channel = P2P_DMG_SOCIAL_CHANNEL; int rc; - if (chan) - channel = chan->hw_value; + if (!chan) + return -EINVAL; + + channel = chan->hw_value; wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 747ae3d82b68..3f4fc3fe8793 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -5059,16 +5059,16 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p, return -EOPNOTSUPP; } } - } - if (!ipa3_bus_scale_table) - ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p); + if (!ipa3_bus_scale_table) + ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p); - /* Proceed to real initialization */ - result = ipa3_pre_init(&ipa3_res, dev); - if (result) { - IPAERR("ipa3_init failed\n"); - return result; + /* Proceed to real initialization */ + result = ipa3_pre_init(&ipa3_res, dev); + if (result) { + IPAERR("ipa3_init failed\n"); + return result; + } } return result; diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index 14e46b38c6df..7e5f1661932f 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -330,6 +330,7 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl, if (IS_ERR_OR_NULL(apr_ch->handle)) { pr_err("%s: glink_open failed %s\n", __func__, svc_names[dest][clnt]); + apr_ch->handle = NULL; goto unlock; } diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c index 3c37f0728481..cd45eeccbfe7 100644 --- a/drivers/thermal/msm_lmh_dcvs.c +++ b/drivers/thermal/msm_lmh_dcvs.c @@ -44,11 +44,13 @@ #define MSM_LIMITS_ALGO_MODE_ENABLE 0x454E424C #define MSM_LIMITS_HI_THRESHOLD 0x48494748 -#define MSM_LIMITS_LO_THRESHOLD 0x4C4F5700 +#define MSM_LIMITS_ARM_THRESHOLD 0x41524D00 #define MSM_LIMITS_CLUSTER_0 0x6370302D #define MSM_LIMITS_CLUSTER_1 0x6370312D +#define MSM_LIMITS_HIGH_THRESHOLD_VAL 95000 +#define MSM_LIMITS_ARM_THRESHOLD_VAL 65000 #define MSM_LIMITS_POLLING_DELAY_MS 10 #define MSM_LIMITS_CLUSTER_0_REQ 0x179C1B04 #define MSM_LIMITS_CLUSTER_1_REQ 0x179C3B04 @@ -203,7 +205,7 @@ static int lmh_activate_trip(struct thermal_zone_device *dev, hw->temp_limits[LIMITS_TRIP_HI]) return -EINVAL; - thresh = (trip == LIMITS_TRIP_LO) ? MSM_LIMITS_LO_THRESHOLD : + thresh = (trip == LIMITS_TRIP_LO) ? MSM_LIMITS_ARM_THRESHOLD : MSM_LIMITS_HI_THRESHOLD; temp = hw->temp_limits[trip]; @@ -306,11 +308,11 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) if (ret) return ret; - hw->default_lo.temp = 65000; + hw->default_lo.temp = MSM_LIMITS_ARM_THRESHOLD_VAL; hw->default_lo.trip = THERMAL_TRIP_CONFIGURABLE_LOW; hw->default_lo.notify = trip_notify; - hw->default_hi.temp = 95000; + hw->default_hi.temp = MSM_LIMITS_HIGH_THRESHOLD_VAL; hw->default_hi.trip = THERMAL_TRIP_CONFIGURABLE_HI; hw->default_hi.notify = trip_notify; diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h index d3cfc622b323..5cdeb01a173b 100644 --- a/include/dt-bindings/clock/msm-clocks-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-cobalt.h @@ -306,6 +306,11 @@ #define clk_csi2_clk_src 0x4113589f #define clk_csi3_clk_src 0xfd934012 #define clk_fd_core_clk_src 0xe4799ab7 +#define clk_ext_dp_phy_pll_vco 0x441b576b +#define clk_ext_dp_phy_pll_link 0xea12644c +#define clk_dp_link_clk_src 0x370d0626 +#define clk_dp_crypto_clk_src 0xf8faa811 +#define clk_dp_pixel_clk_src 0xf5dfbabf #define clk_ext_extpclk_clk_src 0xe5b273af #define clk_ext_pclk0_clk_src 0x087c1612 #define clk_ext_pclk1_clk_src 0x8067c5a3 @@ -405,6 +410,10 @@ #define clk_mmss_mdss_byte1_intf_clk 0xcf654d8e #define clk_mmss_mdss_byte1_intf_div_clk 0xcdf334c5 #define clk_mmss_mdss_dp_aux_clk 0x23125eb6 +#define clk_mmss_mdss_dp_crypto_clk 0x9a072d4e +#define clk_mmss_mdss_dp_link_clk 0x8dd302d1 +#define clk_mmss_mdss_dp_link_intf_clk 0x70e386e6 +#define clk_mmss_mdss_dp_pixel_clk 0xb707b765 #define clk_mmss_mdss_dp_gtc_clk 0xb59c151a #define clk_mmss_mdss_esc0_clk 0x5721ff83 #define clk_mmss_mdss_esc1_clk 0xc3d0376b diff --git a/include/linux/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h index ae36a163ed21..1ff8781d3837 100644 --- a/include/linux/leds-qpnp-flash-v2.h +++ b/include/linux/leds-qpnp-flash-v2.h @@ -16,6 +16,15 @@ #include <linux/leds.h> #include "leds.h" +#define ENABLE_REGULATOR BIT(0) +#define QUERY_MAX_CURRENT BIT(1) + +struct flash_regulator_data { + struct regulator *vreg; + const char *reg_name; + u32 max_volt_uv; +}; + /* * Configurations for each individual LED */ @@ -25,6 +34,9 @@ struct flash_node_data { struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; + struct pinctrl_state *hw_strobe_state_active; + struct pinctrl_state *hw_strobe_state_suspend; + int hw_strobe_gpio; int ires_ua; int max_current; int current_ma; @@ -34,12 +46,18 @@ struct flash_node_data { u8 ires; u8 hdrm_val; u8 current_reg_val; + u8 trigger; bool led_on; }; struct flash_switch_data { struct platform_device *pdev; struct led_classdev cdev; + struct flash_regulator_data *reg_data; + u8 num_regulators; + bool regulator_on; }; +int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options); + #endif diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 647ebfe5174f..4984d372b04b 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -17,7 +17,7 @@ #include <linux/poll.h> #include <linux/dma-buf.h> -#define VB2_MAX_FRAME (32) +#define VB2_MAX_FRAME (64) #define VB2_MAX_PLANES (8) enum vb2_memory { diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index c7bb78a0d57b..46b0402a730f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -70,7 +70,7 @@ * Common stuff for both V4L1 and V4L2 * Moved from videodev.h */ -#define VIDEO_MAX_FRAME 32 +#define VIDEO_MAX_FRAME 64 #define VIDEO_MAX_PLANES 8 /* diff --git a/include/uapi/media/msm_sde_rotator.h b/include/uapi/media/msm_sde_rotator.h index d771959f2e03..461a171a42c1 100644 --- a/include/uapi/media/msm_sde_rotator.h +++ b/include/uapi/media/msm_sde_rotator.h @@ -13,9 +13,23 @@ #define SDE_PIX_FMT_BGRA_8888 V4L2_PIX_FMT_ARGB32 #define SDE_PIX_FMT_RGBX_8888 v4l2_fourcc('X', 'B', '2', '4') #define SDE_PIX_FMT_BGRX_8888 V4L2_PIX_FMT_XRGB32 +#define SDE_PIX_FMT_XBGR_8888 v4l2_fourcc('R', 'X', '2', '4') #define SDE_PIX_FMT_RGBA_5551 v4l2_fourcc('R', 'A', '1', '5') +#define SDE_PIX_FMT_ARGB_1555 V4L2_PIX_FMT_ARGB555 +#define SDE_PIX_FMT_ABGR_1555 v4l2_fourcc('A', 'B', '1', '5') +#define SDE_PIX_FMT_BGRA_5551 v4l2_fourcc('B', 'A', '1', '5') +#define SDE_PIX_FMT_BGRX_5551 v4l2_fourcc('B', 'X', '1', '5') +#define SDE_PIX_FMT_RGBX_5551 v4l2_fourcc('R', 'X', '1', '5') +#define SDE_PIX_FMT_XBGR_1555 v4l2_fourcc('X', 'B', '1', '5') +#define SDE_PIX_FMT_XRGB_1555 V4L2_PIX_FMT_XRGB555 #define SDE_PIX_FMT_ARGB_4444 V4L2_PIX_FMT_ARGB444 #define SDE_PIX_FMT_RGBA_4444 v4l2_fourcc('R', 'A', '1', '2') +#define SDE_PIX_FMT_BGRA_4444 v4l2_fourcc('B', 'A', '1', '2') +#define SDE_PIX_FMT_ABGR_4444 v4l2_fourcc('A', 'B', '1', '2') +#define SDE_PIX_FMT_RGBX_4444 v4l2_fourcc('R', 'X', '1', '2') +#define SDE_PIX_FMT_XRGB_4444 V4L2_PIX_FMT_XRGB444 +#define SDE_PIX_FMT_BGRX_4444 v4l2_fourcc('B', 'X', '1', '2') +#define SDE_PIX_FMT_XBGR_4444 v4l2_fourcc('X', 'B', '1', '2') #define SDE_PIX_FMT_RGB_888 V4L2_PIX_FMT_RGB24 #define SDE_PIX_FMT_BGR_888 V4L2_PIX_FMT_BGR24 #define SDE_PIX_FMT_RGB_565 V4L2_PIX_FMT_RGB565 diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 913bc0e06098..2963d00ea6e5 100755 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -967,7 +967,7 @@ config SND_SOC_MSM_STUB config SND_SOC_MSM_HDMI_CODEC_RX bool "HDMI Audio Playback" - depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996) + depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSMCOBALT) help HDMI audio drivers should be built only if the platform supports hdmi panel. diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index e4ad523bacb7..955a886e3fdc 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -89,13 +89,7 @@ enum { SLIM_TX_MAX, }; -struct slim_ch_config { - u32 sample_rate; - u32 bit_format; - u32 channels; -}; - -struct usb_be_config { +struct dev_config { u32 sample_rate; u32 bit_format; u32 channels; @@ -122,7 +116,7 @@ struct msm_asoc_wcd93xx_codec { }; /* Default configuration of slimbus channels */ -static struct slim_ch_config slim_rx_cfg[] = { +static struct dev_config slim_rx_cfg[] = { [SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, @@ -133,7 +127,7 @@ static struct slim_ch_config slim_rx_cfg[] = { [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, }; -static struct slim_ch_config slim_tx_cfg[] = { +static struct dev_config slim_tx_cfg[] = { [SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, @@ -145,18 +139,24 @@ static struct slim_ch_config slim_tx_cfg[] = { [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; -static struct usb_be_config usb_rx_cfg = { +static struct dev_config usb_rx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, .channels = 2, }; -static struct usb_be_config usb_tx_cfg = { +static struct dev_config usb_tx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, .channels = 1, }; +static struct dev_config hdmi_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + static int msm_vi_feed_tx_ch = 2; static const char *const slim_rx_ch_text[] = {"One", "Two"}; static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", @@ -169,10 +169,14 @@ static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_96", "KHZ_192"}; static char const *bt_sco_sample_rate_text[] = {"KHZ_8", "KHZ_16"}; static const char *const usb_ch_text[] = {"One", "Two"}; +static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", + "Six", "Seven", "Eight"}; static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", "KHZ_22P05", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_96", "KHZ_192"}; +static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text); @@ -182,12 +186,14 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_chs, hdmi_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); @@ -195,6 +201,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sco_sample_rate, bt_sco_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_sample_rate, hdmi_rx_sample_rate_text); static struct platform_device *spdev; @@ -565,9 +572,9 @@ static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol, if (ch_num < 0) return ch_num; - slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; + slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__, - ch_num, slim_rx_cfg[ch_num].channels); + ch_num, slim_tx_cfg[ch_num].channels); return 1; } @@ -914,6 +921,130 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } +static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (hdmi_rx_cfg.bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: hdmi_rx_cfg = %d, ucontrol value = %ld\n", + __func__, hdmi_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int hdmi_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: hdmi_rx_cfg.bit_format = %d, ucontrol value = %ld\n", + __func__, hdmi_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, + hdmi_rx_cfg.channels); + ucontrol->value.integer.value[0] = hdmi_rx_cfg.channels - 2; + + return 0; +} + +static int hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + hdmi_rx_cfg.channels = ucontrol->value.integer.value[0] + 2; + if (hdmi_rx_cfg.channels > 8) { + pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n", + __func__, hdmi_rx_cfg.channels); + hdmi_rx_cfg.channels = 8; + } + pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, + hdmi_rx_cfg.channels); + + return 1; +} + +static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (hdmi_rx_cfg.sample_rate) { + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__, + hdmi_rx_cfg.sample_rate); + + return 0; +} + +static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 2: + hdmi_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + hdmi_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + hdmi_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + } + + pr_debug("%s: hdmi_rx_cfg.sample_rate = %d\n", __func__, + hdmi_rx_cfg.sample_rate); + + return 0; +} + static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs, msm_slim_rx_ch_get, msm_slim_rx_ch_put), @@ -931,6 +1062,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_ch_get, usb_audio_rx_ch_put), SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, usb_audio_tx_ch_get, usb_audio_tx_ch_put), + SOC_ENUM_EXT("HDMI_RX Channels", hdmi_rx_chs, + hdmi_rx_ch_get, hdmi_rx_ch_put), SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format, slim_rx_bit_format_get, slim_rx_bit_format_put), SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format, @@ -943,6 +1076,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_format_get, usb_audio_rx_format_put), SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, usb_audio_tx_format_get, usb_audio_tx_format_put), + SOC_ENUM_EXT("HDMI_RX Bit Format", hdmi_rx_format, + hdmi_rx_format_get, hdmi_rx_format_put), SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate, @@ -960,6 +1095,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, usb_audio_tx_sample_rate_get, usb_audio_tx_sample_rate_put), + SOC_ENUM_EXT("HDMI_RX SampleRate", hdmi_rx_sample_rate, + hdmi_rx_sample_rate_get, + hdmi_rx_sample_rate_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -1147,6 +1285,15 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = usb_tx_cfg.channels; break; + case MSM_BACKEND_DAI_HDMI_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + hdmi_rx_cfg.bit_format); + if (channels->max < 2) + channels->min = channels->max = 2; + rate->min = rate->max = hdmi_rx_cfg.sample_rate; + channels->min = channels->max = hdmi_rx_cfg.channels; + break; + default: rate->min = rate->max = SAMPLING_RATE_48KHZ; break; @@ -1246,6 +1393,13 @@ static int msm_adsp_power_up_config(struct snd_soc_codec *codec) pr_debug("%s: ADSP Audio is ready\n", __func__); adsp_ready = 1; break; + } else { + /* + * ADSP will be coming up after subsystem restart and + * it might not be fully up when the control reaches + * here. So, wait for 50msec before checking ADSP state + */ + msleep(50); } } while (time_after(timeout, jiffies)); @@ -2761,12 +2915,31 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { }, }; +static struct snd_soc_dai_link hdmi_be_dai_link[] = { + /* HDMI BACK END DAI Link */ + { + .name = LPASS_BE_HDMI, + .stream_name = "HDMI Playback", + .cpu_dai_name = "msm-dai-q6-hdmi.8", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-hdmi-audio-codec-rx", + .codec_dai_name = "msm_hdmi_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_HDMI_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_tasha_dai_links[ ARRAY_SIZE(msm_common_dai_links) + ARRAY_SIZE(msm_tasha_fe_dai_links) + ARRAY_SIZE(msm_common_be_dai_links) + ARRAY_SIZE(msm_tasha_be_dai_links) + - ARRAY_SIZE(msm_wcn_be_dai_links)]; + ARRAY_SIZE(msm_wcn_be_dai_links) + + ARRAY_SIZE(hdmi_be_dai_link)]; static int msm_snd_card_late_probe(struct snd_soc_card *card) { @@ -3083,10 +3256,9 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = NULL; struct snd_soc_dai_link *dailink; - int len_1, len_2, len_3, len_4; + int len_1, len_2, len_3; int total_links; const struct of_device_id *match; - bool use_wcn_btfm = false; match = of_match_node(msmcobalt_asoc_machine_of_match, dev->of_node); if (!match) { @@ -3095,26 +3267,12 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) return NULL; } - if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { - use_wcn_btfm = true; - dev_dbg(dev, "%s(): WCN BTFM support present\n", __func__); - } else { - dev_dbg(dev, "%s(): No WCN BTFM support\n", __func__); - } - if (!strcmp(match->data, "tasha_codec")) { card = &snd_soc_card_tasha_msm; len_1 = ARRAY_SIZE(msm_common_dai_links); len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links); len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links); - len_4 = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links); - if (use_wcn_btfm) { - total_links = len_4 + - ARRAY_SIZE(msm_wcn_be_dai_links); - } else { - total_links = len_4; - } - + total_links = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links); memcpy(msm_tasha_dai_links, msm_common_dai_links, sizeof(msm_common_dai_links)); @@ -3127,10 +3285,23 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) memcpy(msm_tasha_dai_links + len_3, msm_tasha_be_dai_links, sizeof(msm_tasha_be_dai_links)); - if (use_wcn_btfm) - memcpy(msm_tasha_dai_links + len_4, + + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(msm_tasha_dai_links + total_links, msm_wcn_be_dai_links, sizeof(msm_wcn_be_dai_links)); + total_links += ARRAY_SIZE(msm_wcn_be_dai_links); + } + + if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { + dev_dbg(dev, "%s(): HDMI support present\n", __func__); + memcpy(msm_tasha_dai_links + total_links, + hdmi_be_dai_link, + sizeof(hdmi_be_dai_link)); + total_links += ARRAY_SIZE(hdmi_be_dai_link); + } dailink = msm_tasha_dai_links; } else if (!strcmp(match->data, "stub_codec")) { diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 7d1dfa8f3a75..4fb61470f118 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -9928,7 +9928,7 @@ static struct platform_driver msm_routing_pcm_driver = { int msm_routing_check_backend_enabled(int fedai_id) { int i; - if (fedai_id >= MSM_FRONTEND_DAI_MM_MAX_ID) { + if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) { /* bad ID assigned in machine driver */ pr_err("%s: bad MM ID\n", __func__); return 0; diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c index cc26af528aba..cc7616f1d897 100644 --- a/sound/soc/msm/qdsp6v2/q6core.c +++ b/sound/soc/msm/qdsp6v2/q6core.c @@ -357,14 +357,14 @@ int core_dts_eagle_set(int size, char *data) } size_aligned4byte = (size+3) & 0xFFFFFFFC; + mutex_lock(&(q6core_lcl.cmd_lock)); ocm_core_open(); if (q6core_lcl.core_handle_q) { payload = kzalloc(sizeof(struct adsp_dts_eagle) + size_aligned4byte, GFP_KERNEL); if (!payload) { - pr_err("DTS_EAGLE_CORE - %s: out of memory (aligned size %i).\n", - __func__, size_aligned4byte); - return -ENOMEM; + rc = -ENOMEM; + goto exit; } payload->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT, APR_HDR_LEN(APR_HDR_SIZE), @@ -387,6 +387,9 @@ int core_dts_eagle_set(int size, char *data) } kfree(payload); } + +exit: + mutex_unlock(&(q6core_lcl.cmd_lock)); return rc; } @@ -401,6 +404,7 @@ int core_dts_eagle_get(int id, int size, char *data) __func__, size, data); return -EINVAL; } + mutex_lock(&(q6core_lcl.cmd_lock)); ocm_core_open(); if (q6core_lcl.core_handle_q) { ah.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT, @@ -415,9 +419,8 @@ int core_dts_eagle_get(int id, int size, char *data) generic_get_data = kzalloc(sizeof(struct generic_get_data_) + size, GFP_KERNEL); if (!generic_get_data) { - pr_err("DTS_EAGLE_CORE - %s: error allocating memory of size %i\n", - __func__, size); - return -ENOMEM; + rc = -ENOMEM; + goto exit; } rc = apr_send_pkt(q6core_lcl.core_handle_q, @@ -425,7 +428,7 @@ int core_dts_eagle_get(int id, int size, char *data) if (rc < 0) { pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n", __func__, ah.opcode, rc); - goto fail_cmd_2; + goto exit; } rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait, @@ -435,7 +438,7 @@ int core_dts_eagle_get(int id, int size, char *data) pr_err("DTS_EAGLE_CORE - %s: EAGLE get params timed out\n", __func__); rc = -EINVAL; - goto fail_cmd_2; + goto exit; } if (generic_get_data->valid) { rc = 0; @@ -447,9 +450,10 @@ int core_dts_eagle_get(int id, int size, char *data) } } -fail_cmd_2: +exit: kfree(generic_get_data); generic_get_data = NULL; + mutex_unlock(&(q6core_lcl.cmd_lock)); return rc; } @@ -496,6 +500,7 @@ bool q6core_is_adsp_ready(void) hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0); hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE; + mutex_lock(&(q6core_lcl.cmd_lock)); ocm_core_open(); q6core_lcl.bus_bw_resp_received = 0; rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr); @@ -515,6 +520,7 @@ bool q6core_is_adsp_ready(void) } bail: pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret); + mutex_unlock(&(q6core_lcl.cmd_lock)); return ret; } @@ -692,6 +698,11 @@ static int q6core_send_custom_topologies(void) struct cal_block_data *cal_block = NULL; struct avcs_cmd_register_topologies reg_top; + if (!q6core_is_adsp_ready()) { + pr_err("%s: ADSP is not ready!\n", __func__); + return -ENODEV; + } + memset(®_top, 0, sizeof(reg_top)); mutex_lock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock); mutex_lock(&q6core_lcl.cmd_lock); @@ -708,12 +719,6 @@ static int q6core_send_custom_topologies(void) goto unlock; } - if (!q6core_is_adsp_ready()) { - pr_err("%s: ADSP is not ready!\n", __func__); - ret = -ENODEV; - goto unlock; - } - q6core_dereg_all_custom_topologies(); ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0, diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index a452ad7cec40..f32cfa40c192 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -162,5 +162,13 @@ config SND_BCD2000 source "sound/usb/line6/Kconfig" +config SND_USB_AUDIO_QMI + tristate "USB Audio QMI Service driver" + depends on MSM_QMI_INTERFACE + help + Starts USB Audio QMI server to communicate with remote entity + to perform operations like enable or disable particular audio + stream on a connected USB device. + endif # SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 2d2d122b069f..d2ac0386d3da 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ obj-$(CONFIG_SND_USB_LINE6) += line6/ +obj-$(CONFIG_SND_USB_AUDIO_QMI) += usb_audio_qmi_v01.o usb_audio_qmi_svc.o diff --git a/sound/usb/card.c b/sound/usb/card.c index 0a189d3b5efa..e94f4d2f2620 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -387,6 +387,7 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip) list_for_each_entry_safe(ep, n, &chip->ep_list, list) snd_usb_endpoint_free(ep); + mutex_destroy(&chip->dev_lock); mutex_destroy(&chip->mutex); kfree(chip); return 0; @@ -442,6 +443,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, } mutex_init(&chip->mutex); + mutex_init(&chip->dev_lock); init_waitqueue_head(&chip->shutdown_wait); chip->index = idx; chip->dev = dev; diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 8ee14f2365e7..81172a395e55 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -69,9 +69,14 @@ static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) { struct snd_usb_stream *stream = pcm->private_data; + struct snd_usb_audio *chip; + if (stream) { + mutex_lock(&stream->chip->dev_lock); + chip = stream->chip; stream->pcm = NULL; snd_usb_audio_stream_free(stream); + mutex_unlock(&chip->dev_lock); } } diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c new file mode 100644 index 000000000000..9d2b75876bfe --- /dev/null +++ b/sound/usb/usb_audio_qmi_svc.c @@ -0,0 +1,1122 @@ +/* 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/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/usb/audio.h> +#include <linux/uaccess.h> +#include <sound/pcm.h> +#include <sound/core.h> +#include <sound/asound.h> +#include <linux/usb.h> +#include <linux/qmi_encdec.h> +#include <soc/qcom/msm_qmi_interface.h> +#include <linux/iommu.h> +#include <linux/qcom_iommu.h> +#include <linux/platform_device.h> + +#include "usbaudio.h" +#include "card.h" +#include "helper.h" +#include "pcm.h" +#include "usb_audio_qmi_v01.h" + +#define SND_PCM_CARD_NUM_MASK 0xffff0000 +#define SND_PCM_DEV_NUM_MASK 0xff00 +#define SND_PCM_STREAM_DIRECTION 0xff + +#define PREPEND_SID_TO_IOVA(iova, sid) (u64)(((u64)(iova)) | \ + (((u64)sid) << 32)) + +/* event ring iova base address */ +#define IOVA_BASE 0x1000 + +#define IOVA_DCBA_BASE 0x2000 +#define IOVA_XFER_RING_BASE (IOVA_DCBA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1)) +#define IOVA_XFER_BUF_BASE (IOVA_XFER_RING_BASE + PAGE_SIZE * SNDRV_CARDS * 32) +#define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE) +#define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE) + +#define MAX_XFER_BUFF_LEN (2 * PAGE_SIZE) + +struct iova_info { + struct list_head list; + unsigned long start_iova; + size_t size; + bool in_use; +}; + +struct intf_info { + unsigned long data_xfer_ring_va; + size_t data_xfer_ring_size; + unsigned long sync_xfer_ring_va; + size_t sync_xfer_ring_size; + unsigned long xfer_buf_va; + size_t xfer_buf_size; + phys_addr_t xfer_buf_pa; + u8 *xfer_buf; + bool in_use; +}; + +struct uaudio_dev { + struct usb_device *udev; + unsigned int card_num; + atomic_t in_use; + struct kref kref; + unsigned long dcba_iova; + size_t dcba_size; + wait_queue_head_t disconnect_wq; + + /* interface specific */ + int num_intf; + struct intf_info *info; +}; + +static struct uaudio_dev uadev[SNDRV_CARDS]; + +struct uaudio_qmi_dev { + struct device *dev; + u32 sid; + u32 intr_num; + struct iommu_domain *domain; + + /* list to keep track of available iova */ + struct list_head dcba_list; + size_t dcba_iova_size; + unsigned long curr_dcba_iova; + struct list_head xfer_ring_list; + size_t xfer_ring_iova_size; + unsigned long curr_xfer_ring_iova; + struct list_head xfer_buf_list; + size_t xfer_buf_iova_size; + unsigned long curr_xfer_buf_iova; + /* bit fields representing pcm card enabled */ + unsigned long card_slot; + /* cache event ring phys addr */ + u64 er_phys_addr; +}; + +static struct uaudio_qmi_dev *uaudio_qdev; + +struct uaudio_qmi_svc { + struct qmi_handle *uaudio_svc_hdl; + void *curr_conn; + struct work_struct recv_msg_work; + struct workqueue_struct *uaudio_wq; + ktime_t t_request_recvd; + ktime_t t_resp_sent; +}; + +static struct uaudio_qmi_svc *uaudio_svc; + +static struct msg_desc uaudio_stream_req_desc = { + .max_msg_len = QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN, + .msg_id = QMI_UAUDIO_STREAM_REQ_V01, + .ei_array = qmi_uaudio_stream_req_msg_v01_ei, +}; + +static struct msg_desc uaudio_stream_resp_desc = { + .max_msg_len = QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN, + .msg_id = QMI_UAUDIO_STREAM_RESP_V01, + .ei_array = qmi_uaudio_stream_resp_msg_v01_ei, +}; + +enum mem_type { + MEM_EVENT_RING, + MEM_DCBA, + MEM_XFER_RING, + MEM_XFER_BUF, +}; + +static unsigned long uaudio_get_iova(unsigned long *curr_iova, + size_t *curr_iova_size, struct list_head *head, size_t size) +{ + struct iova_info *info, *new_info = NULL; + struct list_head *curr_head; + unsigned long va = 0; + size_t tmp_size = size; + bool found = false; + + if (size % PAGE_SIZE) { + pr_err("%s: size %zu is not page size multiple\n", __func__, + size); + goto done; + } + + if (size > *curr_iova_size) { + pr_err("%s: size %zu > curr size %zu\n", __func__, size, + *curr_iova_size); + goto done; + } + if (*curr_iova_size == 0) { + pr_err("%s: iova mapping is full\n", __func__); + goto done; + } + + list_for_each_entry(info, head, list) { + /* exact size iova_info */ + if (!info->in_use && info->size == size) { + info->in_use = true; + va = info->start_iova; + *curr_iova_size -= size; + found = true; + pr_debug("%s: exact size :%zu found\n", __func__, size); + goto done; + } else if (!info->in_use && tmp_size >= info->size) { + if (!new_info) + new_info = info; + pr_debug("%s: partial size: %zu found\n", __func__, + info->size); + tmp_size -= info->size; + if (tmp_size) + continue; + + va = new_info->start_iova; + for (curr_head = &new_info->list; curr_head != + &info->list; curr_head = curr_head->next) { + new_info = list_entry(curr_head, struct + iova_info, list); + new_info->in_use = true; + } + info->in_use = true; + *curr_iova_size -= size; + found = true; + goto done; + } else { + /* iova region in use */ + new_info = NULL; + tmp_size = size; + } + } + + info = kzalloc(sizeof(struct iova_info), GFP_KERNEL); + if (!info) { + va = 0; + goto done; + } + + va = info->start_iova = *curr_iova; + info->size = size; + info->in_use = true; + *curr_iova += size; + *curr_iova_size -= size; + found = true; + list_add_tail(&info->list, head); + +done: + if (!found) + pr_err("%s: unable to find %zu size iova\n", __func__, size); + else + pr_debug("%s: va:%lu curr_iova:%lu curr_iova_size:%zu\n", + __func__, va, *curr_iova, *curr_iova_size); + + return va; +} + +static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa, + size_t size) +{ + unsigned long va = 0; + bool map = true; + int ret; + + switch (mtype) { + case MEM_EVENT_RING: + va = IOVA_BASE; + /* er already mapped */ + if (uaudio_qdev->er_phys_addr == pa) + map = false; + break; + case MEM_DCBA: + va = uaudio_get_iova(&uaudio_qdev->curr_dcba_iova, + &uaudio_qdev->dcba_iova_size, &uaudio_qdev->dcba_list, size); + break; + case MEM_XFER_RING: + va = uaudio_get_iova(&uaudio_qdev->curr_xfer_ring_iova, + &uaudio_qdev->xfer_ring_iova_size, &uaudio_qdev->xfer_ring_list, + size); + break; + case MEM_XFER_BUF: + va = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, + &uaudio_qdev->xfer_buf_iova_size, &uaudio_qdev->xfer_buf_list, + size); + break; + default: + pr_err("%s: unknown mem type %d\n", __func__, mtype); + } + + if (!va) + map = false; + + if (!map) + goto done; + + pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa, + va, mtype); + ret = iommu_map(uaudio_qdev->domain, va, pa, size, + IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE); + if (ret) + pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n", + __func__, &pa, va, mtype, ret); +done: + return va; +} + +static void uaudio_put_iova(unsigned long va, size_t size, struct list_head + *head, size_t *curr_iova_size) +{ + struct iova_info *info; + size_t tmp_size = size; + bool found = false; + + list_for_each_entry(info, head, list) { + if (info->start_iova == va) { + if (!info->in_use) { + pr_err("%s: va %lu is not in use\n", __func__, + va); + return; + } + found = true; + info->in_use = false; + if (info->size == size) + goto done; + } + + if (found && tmp_size >= info->size) { + info->in_use = false; + tmp_size -= info->size; + if (!tmp_size) + goto done; + } + } + + if (!found) { + pr_err("%s: unable to find the va %lu\n", __func__, va); + return; + } +done: + *curr_iova_size += size; + pr_debug("%s: curr_iova_size %zu\n", __func__, *curr_iova_size); +} + +static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, + size_t size) +{ + size_t umap_size; + bool unmap = true; + + if (!va || !size) + return; + + switch (mtype) { + case MEM_EVENT_RING: + if (uaudio_qdev->er_phys_addr) + uaudio_qdev->er_phys_addr = 0; + else + unmap = false; + break; + case MEM_DCBA: + uaudio_put_iova(va, size, &uaudio_qdev->dcba_list, + &uaudio_qdev->dcba_iova_size); + break; + case MEM_XFER_RING: + uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list, + &uaudio_qdev->xfer_ring_iova_size); + break; + case MEM_XFER_BUF: + uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list, + &uaudio_qdev->xfer_buf_iova_size); + break; + default: + pr_err("%s: unknown mem type %d\n", __func__, mtype); + unmap = false; + } + + if (!unmap) + return; + + pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype); + + umap_size = iommu_unmap(uaudio_qdev->domain, va, size); + if (umap_size != size) + pr_err("%s: unmapped size %zu for iova %lu\n", __func__, + umap_size, va); +} + +static int prepare_qmi_response(struct snd_usb_substream *subs, + struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len, + int card_num) +{ + int ret = -ENODEV; + struct usb_interface *iface; + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; + struct usb_host_endpoint *ep; + struct uac_format_type_i_continuous_descriptor *fmt; + struct uac_format_type_i_discrete_descriptor *fmt_v1; + struct uac_format_type_i_ext_descriptor *fmt_v2; + struct uac1_as_header_descriptor *as; + struct uac1_ac_header_descriptor *ac; + int protocol; + u8 *xfer_buf; + u32 len, mult, remainder; + unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0, + xfer_buf_va = 0; + phys_addr_t xhci_pa, xfer_buf_pa; + + iface = usb_ifnum_to_if(subs->dev, subs->interface); + if (!iface) { + pr_err("%s: interface # %d does not exist\n", __func__, + subs->interface); + goto err; + } + + alts = &iface->altsetting[subs->altset_idx]; + altsd = get_iface_desc(alts); + protocol = altsd->bInterfaceProtocol; + + /* get format type */ + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, + UAC_FORMAT_TYPE); + if (!fmt) { + pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", __func__, + subs->interface, subs->altset_idx); + goto err; + } + + if (protocol == UAC_VERSION_1) { + as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, + UAC_AS_GENERAL); + if (!as) { + pr_err("%s: %u:%d : no UAC_AS_GENERAL desc\n", __func__, + subs->interface, subs->altset_idx); + goto err; + } + resp->bDelay = as->bDelay; + fmt_v1 = (struct uac_format_type_i_discrete_descriptor *)fmt; + resp->bSubslotSize = fmt_v1->bSubframeSize; + } else if (protocol == UAC_VERSION_2) { + fmt_v2 = (struct uac_format_type_i_ext_descriptor *)fmt; + resp->bSubslotSize = fmt_v2->bSubslotSize; + } else { + pr_err("%s: unknown protocol version %x\n", __func__, protocol); + goto err; + } + + ac = snd_usb_find_csint_desc(alts->extra, + alts->extralen, + NULL, UAC_HEADER); + if (!ac) { + pr_err("%s: %u:%d : no UAC_HEADER desc\n", __func__, + subs->interface, subs->altset_idx); + goto err; + } + resp->bcdADC = ac->bcdADC; + + resp->slot_id = subs->dev->slot_id; + + memcpy(&resp->std_as_opr_intf_desc, &alts->desc, sizeof(alts->desc)); + + ep = usb_pipe_endpoint(subs->dev, subs->data_endpoint->pipe); + if (!ep) { + pr_err("%s: data ep # %d context is null\n", __func__, + subs->data_endpoint->ep_num); + goto err; + } + memcpy(&resp->std_as_data_ep_desc, &ep->desc, sizeof(ep->desc)); + + xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep); + if (!xhci_pa) { + pr_err("%s:failed to get data ep ring dma address\n", __func__); + goto err; + } + + resp->xhci_mem_info.tr_data.pa = xhci_pa; + + if (subs->sync_endpoint) { + ep = usb_pipe_endpoint(subs->dev, subs->sync_endpoint->pipe); + if (!ep) { + pr_err("%s: sync ep # %d context is null\n", __func__, + subs->sync_endpoint->ep_num); + goto err; + } + memcpy(&resp->std_as_sync_ep_desc, &ep->desc, sizeof(ep->desc)); + xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep); + if (!xhci_pa) { + pr_err("%s:failed to get sync ep ring dma address\n", + __func__); + goto err; + } + resp->xhci_mem_info.tr_sync.pa = xhci_pa; + } + + resp->interrupter_num = uaudio_qdev->intr_num; + + /* map xhci data structures PA memory to iova */ + + /* event ring */ + ret = usb_sec_event_ring_setup(subs->dev, resp->interrupter_num); + if (ret) { + pr_err("%s: failed to setup sec event ring ret %d\n", __func__, + ret); + goto err; + } + xhci_pa = usb_get_sec_event_ring_dma_addr(subs->dev, + resp->interrupter_num); + if (!xhci_pa) { + pr_err("%s: failed to get sec event ring dma address\n", + __func__); + goto err; + } + + va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE); + if (!va) + goto err; + + resp->xhci_mem_info.evt_ring.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + resp->xhci_mem_info.evt_ring.pa = xhci_pa; + resp->xhci_mem_info.evt_ring.size = PAGE_SIZE; + uaudio_qdev->er_phys_addr = xhci_pa; + + /* dcba */ + xhci_pa = usb_get_dcba_dma_addr(subs->dev); + if (!xhci_pa) { + pr_err("%s:failed to get dcba dma address\n", __func__); + goto unmap_er; + } + + if (!uadev[card_num].dcba_iova) { /* mappped per usb device */ + va = uaudio_iommu_map(MEM_DCBA, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_er; + + uadev[card_num].dcba_iova = va; + uadev[card_num].dcba_size = PAGE_SIZE; + } + + dcba_va = uadev[card_num].dcba_iova; + resp->xhci_mem_info.dcba.va = PREPEND_SID_TO_IOVA(dcba_va, + uaudio_qdev->sid); + resp->xhci_mem_info.dcba.pa = xhci_pa; + resp->xhci_mem_info.dcba.size = PAGE_SIZE; + + /* data transfer ring */ + xhci_pa = resp->xhci_mem_info.tr_data.pa; + va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_dcba; + + tr_data_va = va; + resp->xhci_mem_info.tr_data.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + resp->xhci_mem_info.tr_data.size = PAGE_SIZE; + + /* sync transfer ring */ + if (!resp->xhci_mem_info.tr_sync.pa) + goto skip_sync; + + xhci_pa = resp->xhci_mem_info.tr_sync.pa; + va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_data; + + tr_sync_va = va; + resp->xhci_mem_info.tr_sync.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + resp->xhci_mem_info.tr_sync.size = PAGE_SIZE; + +skip_sync: + /* xfer buffer, multiple of 4K only */ + if (!xfer_buf_len) + xfer_buf_len = PAGE_SIZE; + + mult = xfer_buf_len / PAGE_SIZE; + remainder = xfer_buf_len % PAGE_SIZE; + len = mult * PAGE_SIZE; + len += remainder ? PAGE_SIZE : 0; + + if (len > MAX_XFER_BUFF_LEN) { + pr_err("%s: req buf len %d > max buf len %lu, setting %lu\n", + __func__, len, MAX_XFER_BUFF_LEN, MAX_XFER_BUFF_LEN); + len = MAX_XFER_BUFF_LEN; + } + + xfer_buf = usb_alloc_coherent(subs->dev, len, GFP_KERNEL, &xfer_buf_pa); + if (!xfer_buf) + goto unmap_sync; + + resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa; + resp->xhci_mem_info.xfer_buff.size = len; + + va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len); + if (!va) + goto unmap_sync; + + xfer_buf_va = va; + resp->xhci_mem_info.xfer_buff.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + + if (!atomic_read(&uadev[card_num].in_use)) { + kref_init(&uadev[card_num].kref); + init_waitqueue_head(&uadev[card_num].disconnect_wq); + uadev[card_num].num_intf = + subs->dev->config->desc.bNumInterfaces; + uadev[card_num].info = + kzalloc(sizeof(struct intf_info) * + uadev[card_num].num_intf, GFP_KERNEL); + if (!uadev[card_num].info) { + ret = -ENOMEM; + goto unmap_xfer_buf; + } + uadev[card_num].udev = subs->dev; + atomic_set(&uadev[card_num].in_use, 1); + } else { + kref_get(&uadev[card_num].kref); + } + + if (uadev[card_num].info[subs->interface].in_use) { + pr_err("%s interface# %d already in use card# %d\n", __func__, + subs->interface, card_num); + goto unmap_xfer_buf; + } + + uadev[card_num].card_num = card_num; + + /* cache intf specific info to use it for unmap and free xfer buf */ + uadev[card_num].info[subs->interface].data_xfer_ring_va = tr_data_va; + uadev[card_num].info[subs->interface].data_xfer_ring_size = PAGE_SIZE; + uadev[card_num].info[subs->interface].sync_xfer_ring_va = tr_sync_va; + uadev[card_num].info[subs->interface].sync_xfer_ring_size = PAGE_SIZE; + uadev[card_num].info[subs->interface].xfer_buf_va = xfer_buf_va; + uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa; + uadev[card_num].info[subs->interface].xfer_buf_size = len; + uadev[card_num].info[subs->interface].xfer_buf = xfer_buf; + uadev[card_num].info[subs->interface].in_use = true; + + set_bit(card_num, &uaudio_qdev->card_slot); + + return 0; + +unmap_xfer_buf: + uaudio_iommu_unmap(MEM_XFER_BUF, xfer_buf_va, len); +unmap_sync: + usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa); + uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE); +unmap_data: + uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE); +unmap_dcba: + uaudio_iommu_unmap(MEM_DCBA, dcba_va, PAGE_SIZE); +unmap_er: + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); +err: + return ret; +} + +void uaudio_disconnect_cb(struct snd_usb_audio *chip) +{ + int ret, if_idx; + struct uaudio_dev *dev; + int card_num = chip->card_num; + + pr_debug("%s: for card# %d\n", __func__, card_num); + + mutex_lock(&chip->dev_lock); + if (card_num >= SNDRV_CARDS) { + pr_err("%s: invalid card number\n", __func__); + goto done; + } + + dev = &uadev[card_num]; + if (atomic_read(&dev->in_use)) { + ret = wait_event_interruptible(dev->disconnect_wq, + !atomic_read(&dev->in_use)); + if (ret < 0) { + pr_debug("%s: failed with ret %d\n", __func__, ret); + goto done; + } + } + + /* clean up */ + if (!dev->udev) { + pr_debug("%s: no clean up required\n", __func__); + goto done; + } + + /* free xfer buffer and unmap xfer ring and buf per interface */ + for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { + if (!dev->info[if_idx].in_use) + continue; + usb_free_coherent(dev->udev, + dev->info[if_idx].xfer_buf_size, + dev->info[if_idx].xfer_buf, + dev->info[if_idx].xfer_buf_pa); + + uaudio_iommu_unmap(MEM_XFER_RING, + dev->info[if_idx].data_xfer_ring_va, + dev->info[if_idx].data_xfer_ring_size); + dev->info[if_idx].data_xfer_ring_va = 0; + dev->info[if_idx].data_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_RING, + dev->info[if_idx].sync_xfer_ring_va, + dev->info[if_idx].sync_xfer_ring_size); + dev->info[if_idx].sync_xfer_ring_va = 0; + dev->info[if_idx].sync_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_BUF, + dev->info[if_idx].xfer_buf_va, + dev->info[if_idx].xfer_buf_size); + dev->info[if_idx].xfer_buf_va = 0; + dev->info[if_idx].xfer_buf_size = 0; + pr_debug("%s: release resources: intf# %d card# %d\n", __func__, + if_idx, card_num); + } + + /* iommu_unmap dcba iova for a usb device */ + uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size); + + dev->dcba_iova = 0; + dev->dcba_size = 0; + dev->num_intf = 0; + + /* free interface info */ + kfree(dev->info); + dev->info = NULL; + + clear_bit(card_num, &uaudio_qdev->card_slot); + + /* all audio devices are disconnected */ + if (!uaudio_qdev->card_slot) { + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); + usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); + pr_debug("%s: all audio devices disconnected\n", __func__); + } + + dev->udev = NULL; +done: + mutex_unlock(&chip->dev_lock); +} + +static void uaudio_dev_release(struct kref *kref) +{ + struct uaudio_dev *dev = container_of(kref, struct uaudio_dev, kref); + + pr_debug("%s for dev %p\n", __func__, dev); + + atomic_set(&dev->in_use, 0); + + clear_bit(dev->card_num, &uaudio_qdev->card_slot); + + /* all audio devices are disconnected */ + if (!uaudio_qdev->card_slot) { + usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); + pr_debug("%s: all audio devices disconnected\n", __func__); + } + + wake_up(&dev->disconnect_wq); +} + +static int handle_uaudio_stream_req(void *req_h, void *req) +{ + struct qmi_uaudio_stream_req_msg_v01 *req_msg; + struct qmi_uaudio_stream_resp_msg_v01 resp = {0}; + struct snd_usb_substream *subs; + struct snd_usb_audio *chip = NULL; + struct uaudio_qmi_svc *svc = uaudio_svc; + struct intf_info *info; + u8 pcm_card_num, pcm_dev_num, direction; + int intf_num = -1, ret = 0; + + req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req; + + direction = req_msg->usb_token & SND_PCM_STREAM_DIRECTION; + pcm_dev_num = (req_msg->usb_token & SND_PCM_DEV_NUM_MASK) >> 8; + pcm_card_num = (req_msg->usb_token & SND_PCM_CARD_NUM_MASK) >> 16; + + pr_debug("%s:card#:%d dev#:%d dir:%d en:%d fmt:%d rate:%d #ch:%d\n", + __func__, pcm_card_num, pcm_dev_num, direction, req_msg->enable, + req_msg->audio_format, req_msg->bit_rate, + req_msg->number_of_ch); + + if (pcm_card_num >= SNDRV_CARDS) { + pr_err("%s: invalid card # %u", __func__, pcm_card_num); + ret = -EINVAL; + goto response; + } + + subs = find_snd_usb_substream(pcm_card_num, pcm_dev_num, direction, + &chip, uaudio_disconnect_cb); + if (!subs || !chip || atomic_read(&chip->shutdown)) { + pr_err("%s: can't find substream for card# %u, dev# %u dir%u\n", + __func__, pcm_card_num, pcm_dev_num, direction); + ret = -ENODEV; + goto response; + } + + mutex_lock(&chip->dev_lock); + intf_num = subs->interface; + if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm + || !subs->stream->chip) { + ret = -ENODEV; + mutex_unlock(&chip->dev_lock); + goto response; + } + + subs->pcm_format = req_msg->audio_format; + subs->channels = req_msg->number_of_ch; + subs->cur_rate = req_msg->bit_rate; + + ret = snd_usb_enable_audio_stream(subs, req_msg->enable); + + if (!ret && req_msg->enable) + ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size, + pcm_card_num); + + mutex_unlock(&chip->dev_lock); + +response: + if (!req_msg->enable && ret != -EINVAL) { + if (intf_num >= 0) { + mutex_lock(&chip->dev_lock); + info = &uadev[pcm_card_num].info[intf_num]; + uaudio_iommu_unmap(MEM_XFER_RING, + info->data_xfer_ring_va, + info->data_xfer_ring_size); + info->data_xfer_ring_va = 0; + info->data_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_RING, + info->sync_xfer_ring_va, + info->sync_xfer_ring_size); + info->sync_xfer_ring_va = 0; + info->sync_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_BUF, + info->xfer_buf_va, + info->xfer_buf_size); + info->xfer_buf_va = 0; + + usb_free_coherent(uadev[pcm_card_num].udev, + info->xfer_buf_size, + info->xfer_buf, + info->xfer_buf_pa); + info->xfer_buf_size = 0; + info->xfer_buf = NULL; + info->xfer_buf_pa = 0; + info->in_use = false; + pr_debug("%s:release resources: intf# %d card# %d\n", + __func__, intf_num, pcm_card_num); + mutex_unlock(&chip->dev_lock); + } + if (atomic_read(&uadev[pcm_card_num].in_use)) + kref_put(&uadev[pcm_card_num].kref, + uaudio_dev_release); + } + + resp.status = ret; + ret = qmi_send_resp_from_cb(svc->uaudio_svc_hdl, svc->curr_conn, req_h, + &uaudio_stream_resp_desc, &resp, sizeof(resp)); + + svc->t_resp_sent = ktime_get(); + + pr_debug("%s: t_resp sent - t_req recvd (in ms) %lld\n", __func__, + ktime_to_ms(ktime_sub(svc->t_resp_sent, svc->t_request_recvd))); + + return ret; +} + +static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle, + void *conn_h) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle || !conn_h) { + pr_err("%s: handle mismatch\n", __func__); + return -EINVAL; + } + if (svc->curr_conn) { + pr_err("%s: Service is busy\n", __func__); + return -ECONNREFUSED; + } + svc->curr_conn = conn_h; + return 0; +} + +static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, + void *conn_h) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) { + pr_err("%s: handle mismatch\n", __func__); + return -EINVAL; + } + + svc->curr_conn = NULL; + return 0; +} + +static int uaudio_qmi_svc_req_cb(struct qmi_handle *handle, void *conn_h, + void *req_h, unsigned int msg_id, void *req) +{ + int ret; + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) { + pr_err("%s: handle mismatch\n", __func__); + return -EINVAL; + } + + switch (msg_id) { + case QMI_UAUDIO_STREAM_REQ_V01: + ret = handle_uaudio_stream_req(req_h, req); + break; + + default: + ret = -ENOTSUPP; + break; + } + return ret; +} + +static int uaudio_qmi_svc_req_desc_cb(unsigned int msg_id, + struct msg_desc **req_desc) +{ + int ret; + + pr_debug("%s: msg_id %d\n", __func__, msg_id); + + switch (msg_id) { + case QMI_UAUDIO_STREAM_REQ_V01: + *req_desc = &uaudio_stream_req_desc; + ret = sizeof(struct qmi_uaudio_stream_req_msg_v01); + break; + + default: + ret = -ENOTSUPP; + break; + } + return ret; +} + +static void uaudio_qmi_svc_recv_msg(struct work_struct *w) +{ + int ret; + struct uaudio_qmi_svc *svc = container_of(w, struct uaudio_qmi_svc, + recv_msg_work); + + do { + pr_debug("%s: Notified about a Receive Event", __func__); + } while ((ret = qmi_recv_msg(svc->uaudio_svc_hdl)) == 0); + + if (ret != -ENOMSG) + pr_err("%s: Error receiving message\n", __func__); +} + +static void uaudio_qmi_svc_ntfy(struct qmi_handle *handle, + enum qmi_event_type event, void *priv) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + pr_debug("%s: event %d", __func__, event); + + svc->t_request_recvd = ktime_get(); + + switch (event) { + case QMI_RECV_MSG: + queue_work(svc->uaudio_wq, &svc->recv_msg_work); + break; + default: + break; + } +} + +static struct qmi_svc_ops_options uaudio_svc_ops_options = { + .version = 1, + .service_id = UAUDIO_STREAM_SERVICE_ID_V01, + .service_vers = UAUDIO_STREAM_SERVICE_VERS_V01, + .connect_cb = uaudio_qmi_svc_connect_cb, + .disconnect_cb = uaudio_qmi_svc_disconnect_cb, + .req_desc_cb = uaudio_qmi_svc_req_desc_cb, + .req_cb = uaudio_qmi_svc_req_cb, +}; + +static int uaudio_qmi_plat_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *node = pdev->dev.of_node; + + uaudio_qdev = devm_kzalloc(&pdev->dev, sizeof(struct uaudio_qmi_dev), + GFP_KERNEL); + if (!uaudio_qdev) + return -ENOMEM; + + uaudio_qdev->dev = &pdev->dev; + + ret = of_property_read_u32(node, "qcom,usb-audio-stream-id", + &uaudio_qdev->sid); + if (ret) { + dev_err(&pdev->dev, "failed to read sid.\n"); + return -ENODEV; + } + + ret = of_property_read_u32(node, "qcom,usb-audio-intr-num", + &uaudio_qdev->intr_num); + if (ret) { + dev_err(&pdev->dev, "failed to read intr num.\n"); + return -ENODEV; + } + + uaudio_qdev->domain = iommu_domain_alloc(msm_iommu_get_bus(&pdev->dev)); + if (!uaudio_qdev) { + dev_err(&pdev->dev, "failed to callocate iommu domin\n"); + return -ENODEV; + } + + /* attach to external processor iommu */ + ret = iommu_attach_device(uaudio_qdev->domain, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to attach device ret = %d\n", ret); + goto free_domain; + } + + /* initialize dcba, xfer ring and xfer buf iova list */ + INIT_LIST_HEAD(&uaudio_qdev->dcba_list); + uaudio_qdev->curr_dcba_iova = IOVA_DCBA_BASE; + uaudio_qdev->dcba_iova_size = SNDRV_CARDS * PAGE_SIZE; + + INIT_LIST_HEAD(&uaudio_qdev->xfer_ring_list); + uaudio_qdev->curr_xfer_ring_iova = IOVA_XFER_RING_BASE; + uaudio_qdev->xfer_ring_iova_size = + IOVA_XFER_RING_MAX - IOVA_XFER_RING_BASE; + + INIT_LIST_HEAD(&uaudio_qdev->xfer_buf_list); + uaudio_qdev->curr_xfer_buf_iova = IOVA_XFER_BUF_BASE; + uaudio_qdev->xfer_buf_iova_size = + IOVA_XFER_BUF_MAX - IOVA_XFER_BUF_BASE; + + return 0; + +free_domain: + iommu_domain_free(uaudio_qdev->domain); + return ret; +} + +static int uaudio_qmi_plat_remove(struct platform_device *pdev) +{ + iommu_detach_device(uaudio_qdev->domain, &pdev->dev); + iommu_domain_free(uaudio_qdev->domain); + uaudio_qdev->domain = NULL; + + return 0; +} + +static const struct of_device_id of_uaudio_matach[] = { + { + .compatible = "qcom,usb-audio-qmi-dev", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_uaudio_matach); + +static struct platform_driver uaudio_qmi_driver = { + .probe = uaudio_qmi_plat_probe, + .remove = uaudio_qmi_plat_remove, + .driver = { + .name = "uaudio-qmi", + .of_match_table = of_uaudio_matach, + }, +}; + +static int uaudio_qmi_svc_init(void) +{ + int ret; + struct uaudio_qmi_svc *svc; + + svc = kzalloc(sizeof(struct uaudio_qmi_svc), GFP_KERNEL); + if (!svc) + return -ENOMEM; + + svc->uaudio_wq = create_singlethread_workqueue("uaudio_svc"); + if (!svc->uaudio_wq) { + ret = -ENOMEM; + goto free_svc; + } + + svc->uaudio_svc_hdl = qmi_handle_create(uaudio_qmi_svc_ntfy, NULL); + if (!svc->uaudio_svc_hdl) { + pr_err("%s: Error creating svc_hdl\n", __func__); + ret = -EFAULT; + goto destroy_uaudio_wq; + } + + ret = qmi_svc_register(svc->uaudio_svc_hdl, &uaudio_svc_ops_options); + if (ret < 0) { + pr_err("%s:Error registering uaudio svc %d\n", __func__, ret); + goto destroy_svc_handle; + } + + INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg); + + uaudio_svc = svc; + + return 0; + +destroy_svc_handle: + qmi_handle_destroy(svc->uaudio_svc_hdl); +destroy_uaudio_wq: + destroy_workqueue(svc->uaudio_wq); +free_svc: + kfree(svc); + return ret; +} + +static void uaudio_qmi_svc_exit(void) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + qmi_svc_unregister(svc->uaudio_svc_hdl); + flush_workqueue(svc->uaudio_wq); + qmi_handle_destroy(svc->uaudio_svc_hdl); + destroy_workqueue(svc->uaudio_wq); + kfree(svc); + uaudio_svc = NULL; +} + +static int __init uaudio_qmi_plat_init(void) +{ + int ret; + + ret = platform_driver_register(&uaudio_qmi_driver); + if (ret) + return ret; + + return uaudio_qmi_svc_init(); +} + +static void __exit uaudio_qmi_plat_exit(void) +{ + uaudio_qmi_svc_exit(); + platform_driver_unregister(&uaudio_qmi_driver); +} + +module_init(uaudio_qmi_plat_init); +module_exit(uaudio_qmi_plat_exit); + +MODULE_DESCRIPTION("USB AUDIO QMI Service Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/usb/usb_audio_qmi_v01.c b/sound/usb/usb_audio_qmi_v01.c new file mode 100644 index 000000000000..31b1ba74d5c7 --- /dev/null +++ b/sound/usb/usb_audio_qmi_v01.c @@ -0,0 +1,565 @@ + /* 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/qmi_encdec.h> + +#include <soc/qcom/msm_qmi_interface.h> + +#include "usb_audio_qmi_v01.h" + +static struct elem_info mem_info_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, + va), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, + pa), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, + size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info apps_mem_info_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + evt_ring), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + tr_data), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + tr_sync), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + xfer_buff), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + dcba), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info usb_endpoint_descriptor_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bLength), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bDescriptorType), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bEndpointAddress), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bmAttributes), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + wMaxPacketSize), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bInterval), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bRefresh), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bSynchAddress), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info usb_interface_descriptor_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bLength), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bDescriptorType), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceNumber), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bAlternateSetting), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bNumEndpoints), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceClass), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceSubClass), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceProtocol), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + iInterface), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info qmi_uaudio_stream_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + priv_data), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + enable), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + usb_token), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + audio_format), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + number_of_ch), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + bit_rate), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + xfer_buff_size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + priv_data), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + status), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + slot_id), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + bSubslotSize), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_interface_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + std_as_opr_intf_desc), + .ei_array = usb_interface_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + std_as_data_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + std_as_sync_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x08, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + bDelay), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x09, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + bcdADC), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct apps_mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x0A, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + xhci_mem_info), + .ei_array = apps_mem_info_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x0B, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + interrupter_num), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_token), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + priv_data), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + status), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + slot_id), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + bSubslotSize), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_interface_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_opr_intf_desc), + .ei_array = usb_interface_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_data_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x08, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_sync_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct apps_mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x09, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + xhci_mem_info), + .ei_array = apps_mem_info_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; diff --git a/sound/usb/usb_audio_qmi_v01.h b/sound/usb/usb_audio_qmi_v01.h new file mode 100644 index 000000000000..7ad1ab8a61a9 --- /dev/null +++ b/sound/usb/usb_audio_qmi_v01.h @@ -0,0 +1,103 @@ + /* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef USB_QMI_V01_H +#define USB_QMI_V01_H + +#define UAUDIO_STREAM_SERVICE_ID_V01 0x41C +#define UAUDIO_STREAM_SERVICE_VERS_V01 0x01 + +#define QMI_UAUDIO_STREAM_RESP_V01 0x0001 +#define QMI_UAUDIO_STREAM_REQ_V01 0x0001 +#define QMI_UADUIO_STREAM_IND_V01 0x0001 + + +struct mem_info_v01 { + uint64_t va; + uint64_t pa; + uint32_t size; +}; + +struct apps_mem_info_v01 { + struct mem_info_v01 evt_ring; + struct mem_info_v01 tr_data; + struct mem_info_v01 tr_sync; + struct mem_info_v01 xfer_buff; + struct mem_info_v01 dcba; +}; + +struct usb_endpoint_descriptor_v01 { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + uint8_t bRefresh; + uint8_t bSynchAddress; +}; + +struct usb_interface_descriptor_v01 { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +}; + +struct qmi_uaudio_stream_req_msg_v01 { + uint32_t priv_data; + uint8_t enable; + uint32_t usb_token; + uint32_t audio_format; + uint32_t number_of_ch; + uint32_t bit_rate; + uint32_t xfer_buff_size; +}; +#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 46 +extern struct elem_info qmi_uaudio_stream_req_msg_v01_ei[]; + +struct qmi_uaudio_stream_resp_msg_v01 { + uint32_t priv_data; + uint32_t status; + uint32_t slot_id; + uint8_t bSubslotSize; + struct usb_interface_descriptor_v01 std_as_opr_intf_desc; + struct usb_endpoint_descriptor_v01 std_as_data_ep_desc; + struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc; + uint8_t bDelay; + uint16_t bcdADC; + struct apps_mem_info_v01 xhci_mem_info; + uint8_t interrupter_num; +}; +#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 177 +extern struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[]; + +struct qmi_uaudio_stream_ind_msg_v01 { + uint32_t usb_token; + uint32_t priv_data; + uint32_t status; + uint32_t slot_id; + uint8_t bSubslotSize; + struct usb_interface_descriptor_v01 std_as_opr_intf_desc; + struct usb_endpoint_descriptor_v01 std_as_data_ep_desc; + struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc; + struct apps_mem_info_v01 xhci_mem_info; +}; +#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 171 +extern struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[]; + +#endif diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 207ddb26f4ed..b776122d0ca9 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -60,6 +60,8 @@ struct snd_usb_audio { bool autoclock; /* from the 'autoclock' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ + + struct mutex dev_lock; /* to protect any race with disconnect */ int card_num; /* cache pcm card number to use upon disconnect */ void (*disconnect_cb)(struct snd_usb_audio *chip); }; |
