diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-04-08 15:15:20 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-04-08 15:15:21 -0600 |
| commit | f2bc8a14186b7468d444792d1077e3efb16ef880 (patch) | |
| tree | 9c9f5f46883be5d81ba593d5da6379c4c89a3bc5 | |
| parent | d31ca55280c228f9e8833b7ebdfad1247e3ac7de (diff) | |
| parent | 3f901317b1835e7b26d6c72b6c8f2c79539866fc (diff) | |
Promotion of kernel.lnx.4.4-160407.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
969563 If9ec89ab2f2ea341f38d8952c1688d277a5082ed edac: cortex: Support L2 error reporting on Kryo2xx Gold
990478 I520b7943b85cd61065703c7bf9a5d8efb6302a56 msm: ipa: support WDI 2.0 suspend
998162 I74539e626c641c78c4b1ed759e0b9da1b82e89cf ASoC: msmcobalt: Machine driver changes for kernel 4.4
987415 I20921a97b02dce0507f58c4951ce539a2aae5597 wil6210: switch to generated wmi.h
982882 I7eac78d7beb90436d24468547aeb789f7c8ec878 wil6210: protect synchronous wmi commands handling
994255 Ic0934d795c2c7c20332358a3da603e093f94d980 ARM: dts: msm: Move SMD packet node to GLINK packet for
1000118 I95fbcd5a1b70816cb3b03b7e3652243b1c3e527e msm: defconfig: Enable CONFIG_QCOM_KGSL in msmcortex_def
998162 I625a8970e800487746d458c8f51f63c1b371f08c soc: qcom: Add avtimer device tree documentation
1000722 I2187343430efea1dc20523d6e8a5965f360864e6 soc: qcom: spm: Add SAW v4.1 support
982882 I11fa67f7040c4a728f0cd7633f4fbb829ac165d0 wil6210: prevent access to vring_tx_data lock during its
989126 I5ad87614edb1307cffaa798f9b393d816dce012a soc: qcom: msm_glink_pkt: remove the wakeup source durin
1000176 995213 Id347f540f866be6b8442d5f166c6cf7b0ae4c000 iommu/arm-smmu: Fix DOMAIN_ATTR_S1_BYPASS check
998162 Ie176b5e67263e56b296ae144e1a414b4bfa51e80 ASoC: msmcobalt: Add machine driver support for msmcobal
994871 I907adfb5f5d24c06dd038b07a17b31d42b91dfad soc: qcom: ipc_router_mhi_xprt: Code Refactor to handle
988580 I8205df6ecbeed8eca7ff9a81534edadf51309fe1 msm: camera: Change API to populate regulator name
982882 I66a6a23239710c85b9cdb5824c205692c4b53866 wil6210: wait for disconnect completion
982882 I0e438d437154b1b47c572218072a736da5013c80 wil6210: AP: prevent connecting to already connected sta
999684 I469e8609bf23bee97b3f9c612401aaf92bc72a30 dwc3: gadget: Resume controller when udc_stop is called
1000176 I6653b3b6ceb071283fb5a8e07257c496e99dd1f3 iommu/arm-smmu: Support DOMAIN_ATTR_S1_BYPASS
979349 I5633baa3d687972a2038336c78555747fc489c84 soc: qcom: Add SSR support in generic interrupt handler
1000767 I12b0341148f05a3129e8b1aed3ba322277276360 arm64: Check for parity errors on synchronous aborts
999679 Id44c91481d4c184a1991768baf13adad2fae9fb3 usb: phy: qusb: Update QUSB PHY power up functionality f
998028 I5f80603633464e7eea322fde57110e377b72d84c soc: qcom: smem: Renaming smem item SMEM_SMEM_STATIC_LOG
978953 I7a9a61c8aa11bd5c0f5f2effc487a2225e27011d icnss: Add support of skiping QMI
987962 999619 Ib64384d4cc18577c4f33f140ed35311b998f4dda ARM: dts: msm: Add camera isp and ispif soc node for msm
999935 I1b24c4e13daaae3e63c5cacefcbda12b8cfbeeb8 msm: ipa3: remove odu_bridge functions from ipa.h
ARM: dts: msm: Add RTC device for msmcobalt
998951 I806ed575427b90ee82c08ac1a7f8c8692c03b6d1 defconfig: msmcortex: Enable TSENS
982882 Ia78ddf6f5243a8d28c3bfdfc29e0eb512658d0a7 wil6210: TX vring optimization
994721 I18f52fa873b332fb6ad644afc565a84bfed154cc ARM: dts: msm: Rename low power names to be same between
998740 Id59f17528ead86a7c0ac787811b716a209df1eaf icnss: Init spin lock in icnss_probe
1000759 I67181840c8e889ff31111f4fd419edbf5d8d0810 defconfig: msmcortex-perf: Enable POWER_RESET_QCOM
994255 I4a0022954d34d52899d5dd357813c4da90717e2e soc: qcom: msm_glink_pkt: Add GLINK_OPT_INITIAL_XPORT fl
447740 Ieded4bfe038ca936247fa4b638070e979b02eaa1 android/lowmemorykiller: Wait for memory to be freed
994871 I798d27248acaf7aa2ab15e8739c638a96a49b2b7 ARM: dts: msm: Add external modem to ipcrouter dtsi
987584 Ifea6c2de94071719ffede0f641f8a47526bc9e03 icnss: Allocate msa memory in icnss_probe
999679 I68ae8d863a6e438a8d11061db2c75072f4a4e012 ARM: dts: msm: Add QUSB PHY major revision for msm8996
995686 Ide2c4500cfdd0a9c684329ab5f7ac0603e4fc199 regulator: cpr3-regulator: wait for SPM availability for
993907 I55e895be945a690a707f6015c09578e31c1de693 msm: ipa: fix hdr log print
1000634 I539dc604b150f9f23fda09f343cc5e1d25a6ca47 pinctrl: qcom: Add target value for gpio interrupt on ms
995505 Iefe2d6b370f6ec303286afc139fa9913fa9a4099 cpufreq_stats: Disable cpu hotplug during stats table cr
1001094 I965a463ec4808d72ac8fc9d7aa98011ab45c984e ARM: dts: msm: Limit msmcobalt cluster frequencies to 30
954082 Ic7baf2a3da4ed8f8a9023617059e22fd81c3ba45 PM / devfreq: bw_hwmon: Fix race condition in polling in
980185 I55618784befc61e37e68d3b8d8c7c5c30f45e4fc msm: rmnet_ipa3: fix the crash issue
987593 I635d710759a94e2bb29fd3c7811816d09243de50 ARM: dts: msm: Support AVS_CTL register write for msmcob
999887 I4ef85fc64f465aa0d4901493b80dd676596affcb msm: ipa3: add ipc logging support for ipahal
999988 I59681cf42274f70d5f46b869257a838014d8bf61 pwm: Add snapshot of device tree documentation for pwm-q
987415 I5018f40be6a71b4b8c7c3ee94c8e70cfa1fb373a wil6210: Set permanent MAC address to wiphy
1000176 If2ae2021ae9ce10bd22f424967cfcd9c3f94534e arm64: dma_mapping: Support DOMAIN_ATTR_S1_BYPASS
982882 I7d6e3cf5e8abab45da5febc0129fb67830d9e6cb wil6210: remove BACK RX and TX workers
990478 I73447c5557d42817ac2214532273e0de638e13d9 msm: ipa: header change for wlan VA mapping
986484 I5921dc3978bf96221b50148bb2f86b0ffed3b5fb icnss: Update WLAN mode in wlan_firmware_service
998951 I22b8c5834a278d6ebb943e73c70966f37a7b3dcd arm: enable configurable thermal trips for ARCH_QCOM tar
1001094 I6224ecb800bcbca821f42abec43bc57ee701ce80 clk: msm: clock-osm: support OPP table with single frequ
982931 I05b99ec66b0da41697f41c547aab0b0497dd9be6 wil6210: add support for discovery mode during scan
994871 I23d391546a191eb104fb4c50e19aef8a8b566adb defconfig: msm: Enable IPC Router MHI transport
999530 Ia5d76ea4de29dbafe309a831f8a2418c058cba94 soc: qcom: Service locator for kernel clients
1000176 I2f78d5c798d0d2575d52b341aaf29b35294c93f1 ion: Fix typo in ion system secure heap
987415 Ie6684664743694f004289da9ec041f685ec0c05e wil6210: replay attack detection
1000636 I5a77c08532bb5e841f8c1e8e494857e1361dfc40 ARM: dts: msm: Modem PIL clock change for MSMCOBALT
999988 I96761cd2bf18bce6ef7795b6686c5da72fe11a89 defconfig: arm64: msmcortex: enable PWM support for msmc
999935 Ib5109681c62137d1310539daa816d5229bc08098 msm: ipa3: add odu_bridge to ipa_clients folder
Id72e67e31fb52e07f01fb6e234b102f63b400aa5 arm64: process management: Add TIF_MM_RELEASED
995744 Ie763455df2cffcb4fc9447a1bbcc8d9c7d577c6c msm: camera: isp: Add camif raw path output format suppo
952834 I5fe327ea61eb2d16591861b1246fdca2ecce2b1c soc: qcom: glink_smd_xprt: Fix handling subsystem restar
986135 I796b06fae4376cda792d7f26a430ad4580899846 wil6210: add support for platform specific notification
979349 I14504819e04c3e952fcdbceba5a20f876b92ae88 ARM: dts: msm: Add SPSS SSR support for MSMCOBALT.
990478 Ib0cdd0c7614916e53f2731f61d0399959d4b739d msm: ipa: header file change for WDI2.0
982931 I9f26a8ff8433268240eb9443befadc0d279a0293 cfg80211: basic support for PBSS network type
998162 Icc1ddddfdce35ab1ca70dc68fb4878f7c0c36dc7 ARM: msm: dts: Add support for audio on msmcobalt
991098 I45809876336633a496d03e507403944c12f0abb9 ARM: dts: msm: Add bluetooth DT for msm8998
1000770 I26cc21856e9a26be71af6aa91d50e5af2f9fefc6 ARM: dts: msm: Add RTC device for msmcobalt
999530 I37cb319638ce5b6285b2f2ff4386fd92cbda83fd soc: qcom: Add infrastructure to test service locator
990478 I4ac096336f5aeb01fbba8241cda987f56edc1232 msm: ipa: change for WDI2.0
I7d8a8fd39ca5625e6448ed2efebfb621f6e93845 android/lowmemorykiller: Check all tasks for death pendi
982082 I77753fd25d5a4256a4a4cdd74518facd63becf25 msm: camera: sensor: Update actuator specific I2C struct
996222 I18f1ce72dfe93da2fdb80725ed66218eb0af2f49 msm: camera: Add support to enable eLDOs through GPIOs
999935 Ic6da089ebd7878f0d7ceebde7cd8e8549c30182e msm: ipa3: include ipa.h from ipa_odu_bridge.h
998870 I53113d6454de577d4e68f226975a078889d6b2c3 wil6210: disable PCIe relaxed ordering
998162 Ia06b7877b35c599fdb7a38c09e1cc003d88ec46b defconfig: Add support for audio drivers on msmcobalt
990478 I910ed12f79f58dd1a0b0a58fb1cceb7d79ceaaa4 ARM: dts: msm: Add IPA WDI2.0 support for MSMcobalt
999935 Iadfcf4a88472c54fbfe066fa6304146140b76201 msm: ipa3: add ipc logging for odu_bridge driver
991098 Ibf0e4a0ebd55adaadb6d26b335c3d0a9edbe8845 bluetooth: Add WCN3990 power control
Change-Id: I43cbfc16fb8ce9039622425df3a0377fb12b950b
CRs-Fixed: 1000634, 986484, 986135, 979349, 999684, 998028, 1000759, 994871, 1000770, 998951, 994721, 995744, 987962, 1001094, 987584, 980185, 999887, 993907, 982882, 999530, 987415, 998870, 999988, 988580, 998740, 995686, 998162, 982931, 994255, 999679, 996222, 989126, 969563, 1000722, 447740, 987593, 1000767, 999935, 999619, 952834, 991098, 1000118, 990478, 978953, 995213, 954082, 1000176, 995505, 1000636, 982082
122 files changed, 8624 insertions, 3230 deletions
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt index f07a2beafbb3..08fab81f3393 100644 --- a/Documentation/devicetree/bindings/cnss/icnss.txt +++ b/Documentation/devicetree/bindings/cnss/icnss.txt @@ -14,6 +14,7 @@ Required properties: - qcom,wlan-msa-memory: MSA memory size Optional properties: + - qcom,skip-qmi: Boolean property to decide whether to use QMI or not Example: @@ -35,4 +36,5 @@ Example: <0 140 0 /* CE10 */ >, <0 141 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x200000>; + qcom,skip-qmi; }; diff --git a/Documentation/devicetree/bindings/media/video/msm-ispif.txt b/Documentation/devicetree/bindings/media/video/msm-ispif.txt new file mode 100644 index 000000000000..c4086df2b283 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-ispif.txt @@ -0,0 +1,159 @@ +* Qualcomm MSM ISPIF + +Required properties: +- cell-index: ispif hardware core index +- compatible : + - "qcom,ispif" + - "qcom,ispif-v3.0" +- reg : offset and length of the register set for the device + for the ispif operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should contain the ispif interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- camss-vdd-supply: phandle to GDSC regulator. +- mmagic-vdd-supply: phandle to mmagic regulator. +- vfe0-vdd-supply: phandle to vfe0 regulator. +- vfe1-vdd-supply: phandle to vfe1 regulator. +- clocks: list of phandles to the clock controller device and coresponding + clock names. +- clock-names: name of the clocks required for the device used by the consumer. +- qcom,clock-rates: clock rate in Hz. +- qcom,clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property qcom,clock-rates. + +Optional properties: +- qcom,num-isps: The number of ISPs the ISPIF module is connected to. If not set + the default value used is 1 + +Example: + + qcom,ispif@fda0a000 { + cell-index = <0>; + compatible = "qcom,ispif"; + reg = <0xfda0a000 0x300>; + reg-names = "ispif"; + interrupts = <0 55 0>; + interrupt-names = "ispif"; + camss-vdd-supply = <&gdsc_camss_top>; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + vfe0-vdd-supply = <&gdsc_vfe0>; + vfe1-vdd-supply = <&gdsc_vfe1>; + clocks = <&clock_mmss clk_camss_ispif_ahb_clk>, + <&clock_mmss clk_csi0_clk_src>, + <&clock_mmss clk_camss_csi0_clk>, + <&clock_mmss clk_camss_csi0rdi_clk>, + <&clock_mmss clk_camss_csi0pix_clk>, + <&clock_mmss clk_csi1_clk_src>, + <&clock_mmss clk_camss_csi1_clk>, + <&clock_mmss clk_camss_csi1rdi_clk>, + <&clock_mmss clk_camss_csi1pix_clk>, + <&clock_mmss clk_csi2_clk_src>, + <&clock_mmss clk_camss_csi2_clk>, + <&clock_mmss clk_camss_csi2rdi_clk>, + <&clock_mmss clk_camss_csi2pix_clk>, + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_camss_csi3_clk>, + <&clock_mmss clk_camss_csi3rdi_clk>, + <&clock_mmss clk_camss_csi3pix_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_camss_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe1_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>; + clock-names = "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_pix_clk", "csi0_rdi_clk", + "csi1_src_clk", "csi1_clk", + "csi1_pix_clk", "csi1_rdi_clk", + "csi2_src_clk", "csi2_clk", + "csi2_pix_clk", "csi2_rdi_clk", + "csi3_src_clk", "csi3_clk", + "csi3_pix_clk", "csi3_rdi_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk"; + qcom,clock-rates = <0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE"; + + }; + +or + + qcom,ispif@fda0a000 { + cell-index = <0>; + compatible = "qcom,ispif-v3.0", "qcom,ispif"; + reg = <0xfda0a000 0x300>; + reg-names = "ispif"; + interrupts = <0 55 0>; + interrupt-names = "ispif"; + qcom,num-isps = <2> + vdd-supply = <&gdsc_camss_top>; + clocks = <&clock_mmss clk_camss_ispif_ahb_clk>, + <&clock_mmss clk_csi0_clk_src>, + <&clock_mmss clk_camss_csi0_clk>, + <&clock_mmss clk_camss_csi0rdi_clk>, + <&clock_mmss clk_camss_csi0pix_clk>, + <&clock_mmss clk_csi1_clk_src>, + <&clock_mmss clk_camss_csi1_clk>, + <&clock_mmss clk_camss_csi1rdi_clk>, + <&clock_mmss clk_camss_csi1pix_clk>, + <&clock_mmss clk_csi2_clk_src>, + <&clock_mmss clk_camss_csi2_clk>, + <&clock_mmss clk_camss_csi2rdi_clk>, + <&clock_mmss clk_camss_csi2pix_clk>, + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_camss_csi3_clk>, + <&clock_mmss clk_camss_csi3rdi_clk>, + <&clock_mmss clk_camss_csi3pix_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_camss_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe1_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>; + clock-names = "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_pix_clk", "csi0_rdi_clk", + "csi1_src_clk", "csi1_clk", + "csi1_pix_clk", "csi1_rdi_clk", + "csi2_src_clk", "csi2_clk", + "csi2_pix_clk", "csi2_rdi_clk", + "csi3_src_clk", "csi3_clk", + "csi3_pix_clk", "csi3_rdi_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk"; + qcom,clock-rates = <0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE"; + + }; + diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt new file mode 100644 index 000000000000..39a4bd1601e6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt @@ -0,0 +1,205 @@ +* Qualcomm MSM VFE + +Required properties for parent node: +- compatible : + - "qcom,vfe" +- #address-cells : Number of address related values in the reg field +- #size-cells : Number of size related values in the reg field +- ranges: How the register offsets for child translate to parent. + +Required properties for child node: +- cell-index: vfe hardware core index +- compatible : + - "qcom,vfe32" + - "qcom,vfe40" + - "qcom,vfe44" + - "qcom,vfe46" + - "qcom,vfe47" + - "qcom,vfe48" +- reg : offset and length of the register set for the device + for the vfe operating in compatible mode. For parent node, add union of + all registers for both vfe. +- reg-names : should specify relevant names to each reg property defined. + Only needed for child node. + - "vfe" - Required. + - "vfe_vbif" - Optional for "vfe32". Required for "vfe40". +- interrupts : should contain the vfe interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. + - "vfe" - Required. +- vdd-supply: phandle to GDSC regulator controlling VFE core. +- qos-entries: number of QoS registers to program +- qos-regs: relative address offsets of QoS registers +- qos-settings: QoS values to be written to QoS registers +- vbif-entries - number of VBIF registers to program (optional) +- vbif-regs: relative address offsets of VBIF registers (optional) +- vbif-settings: VBIF values to be written to VBIF registers (optional) +- ds-entries: number danger/safe registers to program (optional) +- ds-regs: relative address offsets of danger/safe registers (optional) +- ds-settings: danger/safe values to be written to registers (optional) + NOTE: For all qos*, vbif*, ds* parameters, same SoC can have different + hardware versions with different entries/registers/settings. They can be + specified by adding version to the string e.g. qos-v2-settings. Also + different SoC can have same hardware version and still different QOS, VBIF, + and DS parameters. In this case they are exported if separate SoC version + specific dts files. +- max-svs-clk: svs rate of the VFE clock in Hertz. +- max-nominal-clk: nominal rate of the VFE clock in Hertz. +- max-turbo-clk: turbo/high rate of the VFE clock in Hertz. + +Example: + +vfe0: qcom,vfe0@fda10000 { + cell-index = <0>; + compatible = "qcom,vfe44"; + reg = <0xfda10000 0x1000>; + <0xfda40000 0x200>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 57 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + qos-entries = <8>; + qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8 + 0x2dc 0x2e0>; + qos-settings = <0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0x0002aaaa>; + qos-v2-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + qos-v3-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + vbif-entries = <17>; + vbif-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xdc 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-settings = <0x1 0x01010101 0x01010101 0x10010110 + 0x10101010 0x10101010 0x10101010 0x00001010 + 0x00001010 0x00000707 0x00000707 0x00000030 + 0x00000fff 0x0fff0fff 0x00000001 0x22222222 + 0x00002222>; + vbif-v2-entries = <16>; + vbif-v2-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-v2-settings = <0x1 0x10101010 0x10101010 0x10101010 + 0x10101010 0x10101010 0x10101010 0x00000010 + 0x00000010 0x00000707 0x00000010 0x00000fff + 0x0fff0fff 0x00000003 0x22222222 0x00002222>; + ds-entries = <17>; + ds-regs = <0x988 0x98c 0x990 0x994 0x998 + 0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0 + 0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>; + ds-settings = <0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x00000103>; + max-clk-svs = <300000000>; + max-clk-nominal = <465000000>; + max-clk-turbo = <600000000>; +}; + +vfe1: qcom,vfe1@fda14000 { + cell-index = <1>; + compatible = "qcom,vfe44"; + reg = <0xfda14000 0x1000>; + <0xfda40000 0x200>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 58 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + qos-entries = <8>; + qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8 + 0x2dc 0x2e0>; + qos-settings = <0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0x0002aaaa>; + qos-v2-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + qos-v3-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + vbif-entries = <17>; + vbif-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xdc 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-settings = <0x1 0x01010101 0x01010101 0x10010110 + 0x10101010 0x10101010 0x10101010 0x00001010 + 0x00001010 0x00000707 0x00000707 0x00000030 + 0x00000fff 0x0fff0fff 0x00000001 0x22222222 + 0x00002222>; + vbif-v2-entries = <16>; + vbif-v2-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-v2-settings = <0x1 0x10101010 0x10101010 0x10101010 + 0x10101010 0x10101010 0x10101010 0x00000010 + 0x00000010 0x00000707 0x00000010 0x00000fff + 0x0fff0fff 0x00000003 0x22222222 0x00002222>; + ds-entries = <17>; + ds-regs = <0x988 0x98c 0x990 0x994 0x998 + 0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0 + 0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>; + ds-settings = <0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x00000103>; + max-clk-svs = <300000000>; + max-clk-nominal = <465000000>; + max-clk-turbo = <600000000>; +}; + +qcom,vfe { + compatible = "qcom,vfe"; + num_child = <2>; +}; + +In version specific file one needs to move only entries that differ between +SoC versions with same VFE HW version: + + &vfe0 { + qos-entries = <8>; + qos-regs = <0x378 0x37C 0x380 0x384 0x388 0x38C + 0x390 0x394>; + qos-settings = <0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0x0001AAA9>; + vbif-entries = <1>; + vbif-regs = <0x124>; + vbif-settings = <0x3>; + ds-entries = <17>; + ds-regs = <0xBD8 0xBDC 0xBE0 0xBE4 0xBE8 + 0xBEC 0xBF0 0xBF4 0xBF8 0xBFC 0xC00 + 0xC04 0xC08 0xC0C 0xC10 0xC14 0xC18>; + ds-settings = <0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x00000103>; + max-clk-svs = <300000000>; + max-clk-nominal = <465000000>; + max-clk-turbo = <600000000>; + }; diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index b4b74e98092b..c8f7c6c4391e 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -53,6 +53,8 @@ memory allocation over a PCIe bridge configures embedded pipe filtering rules - qcom,skip-uc-pipe-reset: Boolean context flag to indicate whether a pipe reset via the IPA uC is required +- qcom,ipa-wdi2: Boolean context flag to indicate whether + using wdi-2.0 or not - qcom,use-dma-zone: Boolean context flag to indicate whether memory allocations controlled by IPA driver that do not specify a struct device * should use GFP_DMA to diff --git a/Documentation/devicetree/bindings/pwm/pwm-qpnp.txt b/Documentation/devicetree/bindings/pwm/pwm-qpnp.txt new file mode 100644 index 000000000000..52a4bc81b4c1 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-qpnp.txt @@ -0,0 +1,211 @@ +Qualcomm Technologies, Inc. QPNP PWM/LPG controller + +qpnp-pwm driver supports Pulse Width Module (PWM) functionality. PWM feature is +used in range of applications such as varying Display brightness, LED dimming, +etc. QTI PMICs have a physical device called Light Pulse Generator (LPG). In +addition to support PWM functionality, the LPG module provides a rich set of +user defined PWM pattern configurations, such as sawtooth, linear up, linear +down, triangular patterns etc. The PWM patterns are used in applications such as +charger driver where the driver uses these patterns to indicate various states +of charging. + +Required device bindings: +- compatible: should be "qcom,qpnp-pwm" +- reg: Offset and length of the controller's LPG channel register. +- reg-names: Name for the above register. + "qpnp-lpg-channel-base" = physical base address of the + controller's LPG channel register. +- qcom,channel-id: channel Id for the PWM. +- qcom,supported-sizes: Supported PWM sizes. + Following three pwm sizes lists are supported by PWM/LPG controllers. + <6>, <9>; + <7>, <8>; + <6>, <7>, <9>; +- qcom,ramp-index: Ramp index in LUT ramp control register. + Each LPG has an index in the LUT ramp control register. + One exception is that, if LPG does not support LUT mode + and supports only PWM mode then there is no need to + provide the ramp-index. + +Optional device bindings: +- qcom,force-pwm-size: For certain LPG channels, PWM size can be forced. + Possible values 6, 7, 8 and 9. +- qcom,channel-owner: A string value to supply owner information. +- qcom,mode-select: 0 = PWM mode + 1 = LPG mode +- qcom,lpg-dtest-line: indicates which DTEST line to be configured for LPG + output. Possible values are 1, 2, 3 and 4. +- qcom,dtest-output: indicates the output configuration for DTEST line. + 0 = Disabled + 1 = LPG output low + 2 = LPG output high + 3,4,5 = DTEST line specific configuration + 6,7 = Not used +If this binding is specified along with the required bindings of PWM/LPG then +in addition to configure PWM/LPG the qpnp-pwm driver also enables the feature +at the probe time. In the case where the binding is not specified the qpnp-pwm +driver does not enable the feature. Also, it is considered an error to specify +a particular mode using this binding but not the respective feature subnode. + +All PWM devices support both PWM and LPG features within the same device. +To support each feature, there are some required and optional bindings passed +through device tree. + +The PWM device can enable one feature (either PWM or LPG) at any given time. +Therefore, the qpnp-pwm driver applies the last PWM or LPG feature configuration +and enables that feature. + +Required bindings to support PWM feature: +- qcom,period: PWM period time in microseconds. +- qcom,duty: PWM duty time in microseconds. +- label: "pwm" + +Required bindings to support LPG feature: +The following bindings are needed to configure LPG mode, where a list of +duty cycle percentages is populated. The size of the list cannot exceed +the size of the LPG look-up table. + +- reg: Offset and length of LPG look-up table (LUT). The LPG look-up table is a + contiguous address space that is populated with PWM values. + The size of PWM value is 9 bit and the size of each + entry of the table is 8 bit. Thus, two entries are used + to fill each PWM value. The lower entry is used for PWM + LSB byte and higher entry is used for PWM MSB bit. +- reg-names: Name for the above register. + "qpnp-lpg-lut-base" = physical base address of LPG LUT. +- qcom,period: PWM period time in microseconds. +- qcom,duty-percents: List of entries for look-up table +- cell-index: Index of look-up table that should be used to start + filling up the duty-pct list. start-idx + size of list + cannot exceed the size of look-up table. +- label: "lpg" + + +Optional bindings to support LPG feature: +- qcom,ramp-step-duration: Time (in ms) to wait before loading next entry of LUT +- qcom,lpg-lut-pause-hi: Time (in ms) to wait once pattern reaches to hi + index. +- qcom,lpg-lut-pause-lo: Time (in ms) to wait once pattern reaches to lo + index. +- qcom,lpg-lut-ramp-direction: 1 = Start the pattern from lo index to hi index. + 0 = Start the pattern from hi index to lo index. +- qcom,lpg-lut-pattern-repeat: 1 = Repeat the pattern after the pause once it + reaches to last duty cycle. + 0 = Do not repeat the pattern. +- qcom,lpg-lut-ramp-toggle: 1 = Toggle the direction of the pattern. + 0 = Do not toggle the direction. +- qcom,lpg-lut-enable-pause-hi: 1 = Enable pause time at hi index. + 0 = Disable pause time at hi index. +- qcom,lpg-lut-enable-pause-lo: 1 = Enable pause time at lo index. + 0 = Disable pause time at lo index. + + +Example: + qcom,spmi@fc4c0000 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm8941@1 { + spmi-slave-container; + reg = <0x1>; + #address-cells = <1>; + #size-cells = <1>; + + pwm@b100 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,qpnp-pwm"; + reg = <0xb100 0x100>, <0xb040 0x80>; + reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <7>, <9>; + qcom,ramp-index = <0>; + status = "okay"; + }; + + pwm@b200 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,qpnp-pwm"; + reg = <0xb200 0x100>, <0xb040 0x80>; + reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base"; + qcom,channel-id = <1>; + qcom,supported-sizes = <6>, <7>, <9>; + qcom,ramp-index = <1>; + qcom,force-pwm-size = <9>; + qcom,period = <6000000>; + status = "okay"; + + qcom,pwm { + qcom,duty = <4000000>; + label = "pwm"; + }; + }; + + pwm@b500 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,qpnp-pwm" + reg = <0xb500 0x100>, <0xb040 0x80>; + reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base"; + qcom,channel-id = <4>; + qcom,supported-sizes = <6>, <7>, <9>; + qcom,ramp-index = <4>; + qcom,period = <6000000>; + qcom,mode-select = <0>; + qcom,channel-owner = "RGB-led"; + status = "okay"; + + qcom,pwm { + qcom,duty = <4000000>; + label = "pwm"; + }; + + qcom,lpg { + qcom,duty-percents = <1 14 28 42 56 84 100 + 100 84 56 42 28 14 1>; + cell-index = <0>; + qcom,ramp-step-duration = <20>; + label = "lpg"; + }; + }; + + pwm@b300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,qpnp-pwm"; + reg = <0xb200 0x100>, <0xb040 0x80>; + reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base"; + qcom,channel-id = <2>; + qcom,supported-sizes = <6>, <7>, <9>; + qcom,ramp-index = <1>; + qcom,force-pwm-size = <9>; + qcom,period = <6000000>; + qcom,lpg-dtest-line = <3>; + qcom,dtest-output = <1>; + status = "okay"; + + qcom,pwm { + qcom,duty = <4000000>; + label = "pwm"; + }; + }; + }; + }; + +There are couple of ways to configure PWM device channels as shown in above +example, +1. The PWM device channel #0 is configured with only required device bindings. +In this case, the qpnp-pwm driver does not configure any mode by default. + +2. The qpnp-pwm driver configures PWM device channel #1 with PWM feature +configuration, but does not enable the channel since "qcom,mode-select" binding +is not specified in the devicetree. + +3. Both the PWM and LPG configurations are provided for PWM device channel #4. +The qpnp-pwm driver configures both the modes, but enables PWM mode at the probe +time. It also sets the channel owner information for the channel. + +4. This configuration is pretty similar to #2 above except in this case channel +#3 is configured for PWM mode. Also it's DTEST3 line is configured to output +LPG OUT low. diff --git a/Documentation/devicetree/bindings/soc/qcom/avtimer.txt b/Documentation/devicetree/bindings/soc/qcom/avtimer.txt new file mode 100644 index 000000000000..157f79b2b07a --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/avtimer.txt @@ -0,0 +1,26 @@ +* avtimer + +Avtimer provides an interface for clients to enable avtimer block +on qdsp6. 64 bit AVtimer exposed by qdsp6 is used for audio and video +stream synchronization during capture and playback usecases. + +Required properties: +- reg : physical address and length of avtimer register +- reg-names : AVtimer register name + Required register resource entries are: + "avtimer_lsb_addr" : AVtimer lsb physical address + "avtimer_msb_addr" : AVtimer msb physical address +- compatible : Must be "qcom,avtimer" + +Optional properties: +- clk-div : The clk is at 27MHz and hence ticks are to be + divided by 27 to achive the msec value. + +Example: + qcom,avtimer@90f7000 { + compatible = "qcom,avtimer"; + reg = <0x90f700c 0x4>, + <0x90f7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <27>; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index d34bc841863d..cb92feb9a613 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -87,6 +87,14 @@ Required properties: - compatible : "qcom,msm-stub-codec" +* msm-hdmi-dba-codec-rx + +Required properties: + + - compatible : "qcom,msm-hdmi-dba-codec-rx" + - qcom,dba-bridge-chip: String info to indicate which bridge-chip + is used for HDMI using DBA. + * msm-dai-fe Required properties: @@ -1935,3 +1943,115 @@ Example: asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; }; + +* MSMCOBALT ASoC Machine driver + +Required properties: +- compatible : "qcom,msmcobalt-asoc-snd-tasha" +- qcom,model : The user-visible name of this sound card. +- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,mbhc-audio-jack-type : String to indicate the jack type on the hardware. + Possible Values: + 4-pole-jack : Jack on the hardware is 4-pole. + 5-pole-jack : Jack on the hardware is 5-pole. + 6-pole-jack : Jack on the hardware is 6-pole. +- clock-names : clock name defined for external clock. +- clocks : external clock defined for codec clock. +- qcom,hph-en1-gpio : GPIO to enable HiFi amplifiers. +- qcom,hph-en0-gpio : GPIO to enable HiFi audio route to headset. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device + +Example: + + sound-9335 { + compatible = "qcom,msmcobalt-asoc-snd"; + qcom,model = "msmcobalt-tasha-snd-card"; + + qcom,audio-routing = + "RX_BIAS", "MCLK", + "LDO_H", "MCLK", + "AIF4 MAD", "MCLK", + "ultrasound amp", "LINEOUT1", + "ultrasound amp", "LINEOUT3", + "AMIC1", "MIC BIAS1 Internal1", + "MIC BIAS1 Internal1", "Handset Mic", + "AMIC2", "MIC BIAS2 External", + "MIC BIAS2 External", "Headset Mic", + "AMIC3", "MIC BIAS2 External", + "MIC BIAS2 External", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2 External", + "MIC BIAS2 External", "ANCLeft Headset Mic", + "DMIC1", "MIC BIAS1 External", + "MIC BIAS1 External", "Digital Mic1", + "DMIC2", "MIC BIAS1 External", + "MIC BIAS1 External", "Digital Mic2", + "DMIC3", "MIC BIAS3 External", + "MIC BIAS3 External", "Digital Mic3", + "DMIC4", "MIC BIAS3 External", + "MIC BIAS3 External", "Digital Mic4", + "DMIC5", "MIC BIAS4 External", + "MIC BIAS4 External", "Digital Mic5", + "DMIC6", "MIC BIAS4 External", + "MIC BIAS4 External", "Digital Mic6"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,tasha-mclk-clk-freq = <9600000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp"; + asoc-cpu = <&dai_hdmi>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft", + "SpkrRight", "SpkrLeft"; + }; diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index 048d00057ea9..cccdb281a31d 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -175,6 +175,7 @@ Optional properties: - qcom,emulation: Indicates that we are running on emulation platform. - qcom,hold-reset: Indicates that hold QUSB PHY into reset state. - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided. + - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0 Example: qusb_phy: qusb@f9b39000 { diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi new file mode 100644 index 000000000000..82302c735cbb --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + compr: qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "regular"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + qcom,vote-bms; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + dai_hdmi: qcom,msm-dai-q6-hdmi { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <8>; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + dai_mi2s0: qcom,msm-dai-q6-mi2s-prim { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s1: qcom,msm-dai-q6-mi2s-sec { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <1>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s2: qcom,msm-dai-q6-mi2s-tert { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <2>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_mi2s3: qcom,msm-dai-q6-mi2s-quat { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <3>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s4: qcom,msm-dai-q6-mi2s-quin { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <5>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s5: qcom,msm-dai-q6-mi2s-senary { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <6>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + sb_0_rx: qcom,msm-dai-q6-sb-0-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16384>; + }; + + sb_0_tx: qcom,msm-dai-q6-sb-0-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16385>; + }; + + sb_1_rx: qcom,msm-dai-q6-sb-1-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16386>; + }; + + sb_1_tx: qcom,msm-dai-q6-sb-1-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16387>; + }; + + sb_2_rx: qcom,msm-dai-q6-sb-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16388>; + }; + + sb_2_tx: qcom,msm-dai-q6-sb-2-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16389>; + }; + + + sb_3_rx: qcom,msm-dai-q6-sb-3-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16390>; + }; + + sb_3_tx: qcom,msm-dai-q6-sb-3-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16391>; + }; + + sb_4_rx: qcom,msm-dai-q6-sb-4-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16392>; + }; + + sb_4_tx: qcom,msm-dai-q6-sb-4-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16393>; + }; + + sb_5_tx: qcom,msm-dai-q6-sb-5-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16395>; + }; + + sb_5_rx: qcom,msm-dai-q6-sb-5-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16394>; + }; + + bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12288>; + }; + + bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12289>; + }; + + int_fm_rx: qcom,msm-dai-q6-int-fm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12292>; + }; + + int_fm_tx: qcom,msm-dai-q6-int-fm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12293>; + }; + + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + + dai_pri_auxpcm: qcom,msm-pri-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + }; + + hdmi_dba: qcom,msm-hdmi-dba-codec-rx { + compatible = "qcom,msm-hdmi-dba-codec-rx"; + qcom,dba-bridge-chip = "adv7533"; + }; + + msm_audio_ion: qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <1>; + qcom,smmu-enabled; + iommus = <&adsp_io 1>; + }; + + qcom,msm-adsp-loader { + status = "ok"; + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-pmcobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmcobalt.dtsi index 318197221357..40ae5fc03472 100644 --- a/arch/arm/boot/dts/qcom/msm-pmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmcobalt.dtsi @@ -234,6 +234,22 @@ compatible = "qcom,qpnp-coincell"; reg = <0x2800 0x100>; }; + + pmcobalt_rtc: qcom,pmcobalt_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pmcobalt_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + qcom,pmcobalt_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; }; qcom,pmcobalt@1 { diff --git a/arch/arm/boot/dts/qcom/msm8996-ipcrouter.dtsi b/arch/arm/boot/dts/qcom/msm8996-ipcrouter.dtsi index a443f90e4cb8..a034754f8719 100644 --- a/arch/arm/boot/dts/qcom/msm8996-ipcrouter.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-ipcrouter.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -45,4 +45,14 @@ qcom,xprt-version = <1>; qcom,fragmented-data; }; + + qcom,ipc_router_external_modem_xprt2 { + compatible = "qcom,ipc_router_mhi_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,out-chan-id = <34>; + qcom,in-chan-id = <35>; + qcom,xprt-remote = "external-modem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <3>; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 3672d6f313cd..3a5b55848d53 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -2086,6 +2086,7 @@ 0x00 0x18>; phy_type= "utmi"; qcom,phy-clk-scheme = "cmos"; + qcom,major-rev = <1>; clocks = <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, <&clock_gcc clk_gcc_qusb2phy_prim_reset>, @@ -2122,6 +2123,7 @@ 0x00 0x18>; phy_type = "utmi"; qcom,phy-clk-scheme = "cmos"; + qcom,major-rev = <1>; qcom,hold-reset; clocks = <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi new file mode 100644 index 000000000000..0f8b0908816b --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi @@ -0,0 +1,177 @@ +/* + * 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-wsa881x.dtsi" + +&msm_audio_ion { + qcom,smmu-version = <2>; + iommus = <&lpass_q6_smmu 1>; +}; + +&soc { + qcom,avtimer@170f7000 { + compatible = "qcom,avtimer"; + reg = <0x170f700c 0x4>, + <0x170f7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <27>; + }; + + sound-9335 { + compatible = "qcom,msmcobalt-asoc-snd-tasha"; + qcom,model = "msmcobalt-tasha-snd-card"; + + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "AMIC6", "MIC BIAS4", + "MIC BIAS4", "Analog Mic6", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,tasha-mclk-clk-freq = <9600000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp"; + asoc-cpu = <&dai_hdmi>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; + + cpe: qcom,msm-cpe-lsm { + compatible = "qcom,msm-cpe-lsm"; + }; + + wcd9xxx_intc: wcd9xxx-irq { + status = "ok"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-names = "cdc-int"; + }; + + clock_audio: audio_ext_clk { + status = "ok"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; +}; + +&slim_msm { + msm_dai_slim { + compatible = "qcom,msm-dai-slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; + + tasha_codec { + compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 A0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30>; + + qcom,cdc-reset-gpio = <&tlmm 64 0>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + + cdc-vdd-buck-supply = <&pmcobalt_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmcobalt_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmcobalt_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmcobalt_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmcobalt_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 01 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi index c6d6666f66a0..ada4500d432e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi @@ -164,4 +164,236 @@ qcom,dup-frame-indicator-off = <70>; }; }; + + qcom,ispif@ca31000 { + cell-index = <0>; + compatible = "qcom,ispif-v3.0", "qcom,ispif"; + reg = <0xca31000 0xc00>, + <0xca00020 0x4>; + reg-names = "ispif", "csi_clk_mux"; + interrupts = <0 309 0>; + interrupt-names = "ispif"; + qcom,num-isps = <0x2>; + camss-vdd-supply = <&gdsc_camss_top>; + vfe0-vdd-supply = <&gdsc_vfe0>; + vfe1-vdd-supply = <&gdsc_vfe1>; + qcom,vdd-names = "camss-vdd", "vfe0-vdd", + "vfe1-vdd"; + clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_mmss_camss_ispif_ahb_clk>, + <&clock_mmss clk_csi0_clk_src>, + <&clock_mmss clk_mmss_camss_csi0_clk>, + <&clock_mmss clk_mmss_camss_csi0rdi_clk>, + <&clock_mmss clk_mmss_camss_csi0pix_clk>, + <&clock_mmss clk_csi1_clk_src>, + <&clock_mmss clk_mmss_camss_csi1_clk>, + <&clock_mmss clk_mmss_camss_csi1rdi_clk>, + <&clock_mmss clk_mmss_camss_csi1pix_clk>, + <&clock_mmss clk_csi2_clk_src>, + <&clock_mmss clk_mmss_camss_csi2_clk>, + <&clock_mmss clk_mmss_camss_csi2rdi_clk>, + <&clock_mmss clk_mmss_camss_csi2pix_clk>, + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_mmss_camss_csi3_clk>, + <&clock_mmss clk_mmss_camss_csi3rdi_clk>, + <&clock_mmss clk_mmss_camss_csi3pix_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_mmss_camss_vfe0_clk>, + <&clock_mmss clk_mmss_camss_csi_vfe0_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_mmss_camss_vfe1_clk>, + <&clock_mmss clk_mmss_camss_csi_vfe1_clk>; + clock-names = "camss_top_ahb_clk", + "camss_ahb_clk", "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_pix_clk", "csi0_rdi_clk", + "csi1_src_clk", "csi1_clk", + "csi1_pix_clk", "csi1_rdi_clk", + "csi2_src_clk", "csi2_clk", + "csi2_pix_clk", "csi2_rdi_clk", + "csi3_src_clk", "csi3_clk", + "csi3_pix_clk", "csi3_rdi_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", + "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", + "camss_csi_vfe1_clk"; + qcom,clock-rates = <0 0 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE"; + status = "disabled"; + }; + + vfe0: qcom,vfe0@ca10000 { + cell-index = <0>; + compatible = "qcom,vfe48"; + reg = <0xca10000 0x4000>, + <0xca40000 0x3000>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 314 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe0>; + camss-vdd-supply = <&gdsc_camss_top>; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + qcom,vdd-names = "vdd", "camss-vdd", "smmu-vdd"; + clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_mmss_camss_vfe0_clk>, + <&clock_mmss clk_mmss_camss_csi_vfe0_clk>, + <&clock_mmss clk_mmss_camss_vfe0_ahb_clk>, + <&clock_mmss clk_mmss_camss_vfe_vbif_ahb_clk>, + <&clock_mmss clk_mmss_camss_vfe0_stream_clk>, + <&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>; + clock-names = "camss_top_ahb_clk" , "camss_ahb_clk", + "vfe_clk_src", "camss_vfe_clk", + "camss_csi_vfe_clk", + "vfe_ahb_clk", "vfe_vbif_ahb_clk", + "vfe_stream_clk", "vfe_vbif_axi_clk", + "mmss_smmu_axi_clk"; + qcom,clock-rates = <0 0 384000000 0 0 0 0 0 0 0 + 0 0 576000000 0 0 0 0 0 0 0 + 0 0 600000000 0 0 0 0 0 0 0>; + status = "disabled"; + qos-entries = <8>; + qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 + 0x41c 0x420>; + qos-settings = <0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9>; + vbif-entries = <3>; + vbif-regs = <0x124 0xac 0xd0>; + vbif-settings = <0x3 0x40 0x1010>; + ds-entries = <17>; + ds-regs = <0x424 0x428 0x42c 0x430 0x434 + 0x438 0x43c 0x440 0x444 0x448 0x44c + 0x450 0x454 0x458 0x45c 0x460 0x464>; + ds-settings = <0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0x40000103>; + qcom,msm-bus,name = "msm_camera_vfe"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <29 512 0 0>, + <29 512 100000000 100000000>; + qcom,msm-bus-vector-dyn-vote; + }; + + vfe1: qcom,vfe1@ca14000 { + cell-index = <1>; + compatible = "qcom,vfe48"; + reg = <0xca14000 0x4000>, + <0xca40000 0x3000>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 315 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe1>; + camss-vdd-supply = <&gdsc_camss_top>; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + qcom,vdd-names = "vdd", "camss-vdd", "smmu-vdd"; + clocks = <&clock_mmss clk_mmss_camss_top_ahb_clk>, + <&clock_mmss clk_mmss_camss_ahb_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_mmss_camss_vfe1_clk>, + <&clock_mmss clk_mmss_camss_csi_vfe1_clk>, + <&clock_mmss clk_mmss_camss_vfe1_ahb_clk>, + <&clock_mmss clk_mmss_camss_vfe_vbif_ahb_clk>, + <&clock_mmss clk_mmss_camss_vfe1_stream_clk>, + <&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>, + <&clock_mmss clk_mmss_bimc_smmu_axi_clk>; + clock-names = "camss_top_ahb_clk" , "camss_ahb_clk", + "vfe_clk_src", "camss_vfe_clk", + "camss_csi_vfe_clk", + "vfe_ahb_clk", "vfe_vbif_ahb_clk", + "vfe_stream_clk", "vfe_vbif_axi_clk", + "mmss_smmu_axi_clk"; + qcom,clock-rates = <0 0 384000000 0 0 0 0 0 0 0 + 0 0 576000000 0 0 0 0 0 0 0 + 0 0 600000000 0 0 0 0 0 0 0>; + status = "disabled"; + qos-entries = <8>; + qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 + 0x41c 0x420>; + qos-settings = <0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9 + 0xaaa9aaa9>; + vbif-entries = <3>; + vbif-regs = <0x124 0xac 0xd0>; + vbif-settings = <0x3 0x40 0x1010>; + ds-entries = <17>; + ds-regs = <0x424 0x428 0x42c 0x430 0x434 + 0x438 0x43c 0x440 0x444 0x448 0x44c + 0x450 0x454 0x458 0x45c 0x460 0x464>; + ds-settings = <0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0xcccc0011 + 0x40000103>; + qcom,msm-bus,name = "msm_camera_vfe"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <29 512 0 0>, + <29 512 100000000 100000000>; + qcom,msm-bus-vector-dyn-vote; + }; + + qcom,vfe { + compatible = "qcom,vfe"; + num_child = <2>; + }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi index 14791077a5bc..bada543c9a2f 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi @@ -11,3 +11,27 @@ */ #include "msmcobalt-pinctrl.dtsi" +/ { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pmcobalt_s3>; + qca,bt-vdd-xtal-supply = <&pmcobalt_s5>; + qca,bt-vdd-core-supply = <&pmcobalt_l7_pin_ctrl>; + qca,bt-vdd-ldo-supply = <&pmcobalt_l17_pin_ctrl>; + qca,bt-vdd-pa-supply = <&pmcobalt_l25_pin_ctrl>; + qca,bt-chip-pwd-supply = <&pmicobalt_bob_pin1>; + + qca,bt-vdd-io-voltage-level = <1350000 1350000>; + qca,bt-vdd-xtal-voltage-level = <2050000 2050000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-ldo-voltage-level = <1300000 1300000>; + qca,bt-vdd-pa-voltage-level = <3300000 3300000>; + qca,bt-chip-pwd-voltage-level = <3600000 3600000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <0>; /* LPM/PFM */ + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index 14791077a5bc..139ca5c8fec8 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -11,3 +11,27 @@ */ #include "msmcobalt-pinctrl.dtsi" +/ { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pmcobalt_s3>; + qca,bt-vdd-xtal-supply = <&pmcobalt_s5>; + qca,bt-vdd-core-supply = <&pmcobalt_l7_pin_ctrl>; + qca,bt-vdd-ldo-supply = <&pmcobalt_l17_pin_ctrl>; + qca,bt-vdd-pa-supply = <&pmcobalt_l25_pin_ctrl>; + qca,bt-chip-pwd-supply = <&pmicobalt_bob_pin1>; + + qca,bt-vdd-io-voltage-level = <1350000 1350000>; + qca,bt-vdd-xtal-voltage-level = <2050000 2050000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-ldo-voltage-level = <1300000 1300000>; + qca,bt-vdd-pa-voltage-level = <3300000 3300000>; + qca,bt-chip-pwd-voltage-level = <3600000 3600000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <0>; /* LPM/PFM */ + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index 28e459c03b3a..0185570a96bd 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,5 +32,103 @@ bias-disable; }; }; + + wcd9xxx_intr { + wcd_intr_default: wcd_intr_default{ + mux { + pins = "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio54"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-enable; + }; + }; + }; + + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + drive-strength = <16>; + bias-pull-down; + output-high; + }; + }; + }; + + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio66"; + function = "gpio"; + }; + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio66"; + function = "gpio"; + }; + config { + pins = "gpio66"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi index d48efe70c34a..31b1c9486226 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi @@ -11,6 +11,38 @@ */ &soc { + qcom,spm@178120000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x17812000 0x1000>; + qcom,name = "gold-l2"; /* Gold L2 SAW */ + qcom,saw2-ver-reg = <0xfd0>; + qcom,cpu-vctl-list = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,vctl-timeout-us = <50>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,saw2-avs-ctl = <0x1010031>; + qcom,saw2-avs-limit = <0x4000208>; + qcom,pfm-port = <0x2>; + }; + + qcom,spm@179120000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x17912000 0x1000>; + qcom,name = "silver-l2"; /* Silver L2 SAW */ + qcom,saw2-ver-reg = <0xfd0>; + qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,vctl-timeout-us = <50>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,saw2-avs-ctl = <0x1010031>; + qcom,saw2-avs-limit = <0x4000208>; + qcom,pfm-port = <0x2>; + }; + qcom,lpm-levels { compatible = "qcom,lpm-levels"; qcom,use-psci; @@ -161,7 +193,7 @@ qcom,pm-cluster-level@1{ /* D2D */ reg = <1>; - label = "perf-l2-ret"; + label = "perf-l2-dynret"; qcom,psci-mode = <2>; qcom,latency-us = <60>; qcom,ss-power = <700>; @@ -172,7 +204,7 @@ qcom,pm-cluster-level@2{ /* D2E */ reg = <2>; - label = "perf-l2-memret"; + label = "perf-l2-ret"; qcom,psci-mode = <3>; qcom,latency-us = <100>; qcom,ss-power = <640>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi new file mode 100644 index 000000000000..6417564b8533 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi @@ -0,0 +1,57 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&slim_msm { + tasha_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170211>; + qcom,spkr-sd-n-gpio = <&tlmm 65 0>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa881x_212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170212>; + qcom,spkr-sd-n-gpio = <&tlmm 66 0>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + wsa881x_213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170213>; + qcom,spkr-sd-n-gpio = <&tlmm 65 0>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa881x_214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170214>; + qcom,spkr-sd-n-gpio = <&tlmm 66 0>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index c157f544e5ba..e9b60a996f83 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -521,55 +521,10 @@ qcom,governor-per-policy; qcom,cpufreq-table-0 = - < 300000 >, - < 345600 >, - < 422400 >, - < 499200 >, - < 576000 >, - < 633600 >, - < 710400 >, - < 806400 >, - < 883200 >, - < 960000 >, - < 1036800 >, - < 1113600 >, - < 1190400 >, - < 1248000 >, - < 1324800 >, - < 1401600 >, - < 1478400 >, - < 1574400 >, - < 1651200 >, - < 1728000 >, - < 1804800 >, - < 1881600 >; + < 300000 >; qcom,cpufreq-table-4 = - < 300000 >, - < 345600 >, - < 422400 >, - < 480000 >, - < 556800 >, - < 633600 >, - < 710400 >, - < 787200 >, - < 844800 >, - < 902400 >, - < 979200 >, - < 1056000 >, - < 1171200 >, - < 1248000 >, - < 1324800 >, - < 1401600 >, - < 1478400 >, - < 1536000 >, - < 1632000 >, - < 1708800 >, - < 1785600 >, - < 1862400 >, - < 1939200 >, - < 2016000 >, - < 2092800 >; + < 300000 >; }; arm64-cpu-erp { @@ -653,55 +608,10 @@ interrupt-names = "pwrcl-irq", "perfcl-irq"; qcom,pwrcl-speedbin0-v0 = - < 300000000 0x0004000f 0x031e001e 0x1>, - < 345600000 0x05040012 0x04200020 0x1>, - < 422400000 0x05040016 0x04200020 0x1>, - < 499200000 0x0504001a 0x05200020 0x1>, - < 576000000 0x0504001e 0x06200020 0x1>, - < 633600000 0x04040021 0x07200020 0x1>, - < 710400000 0x04040025 0x07200020 0x1>, - < 806400000 0x0404002a 0x08220022 0x2>, - < 883200000 0x0404002e 0x09250025 0x2>, - < 960000000 0x04040032 0x0a280028 0x2>, - < 1036800000 0x04040036 0x0b2b002b 0x3>, - < 1113600000 0x0404003a 0x0c2e002e 0x3>, - < 1190400000 0x0404003e 0x0c320032 0x3>, - < 1248000000 0x04040041 0x0d340034 0x3>, - < 1324800000 0x04040045 0x0e370037 0x3>, - < 1401600000 0x04040049 0x0f3a003a 0x3>, - < 1478400000 0x0404004d 0x103e003e 0x3>, - < 1574400000 0x04040052 0x10420042 0x4>, - < 1651200000 0x04040056 0x11450045 0x4>, - < 1728000000 0x0404005a 0x12480048 0x4>, - < 1804800000 0x0404005e 0x134b004b 0x4>, - < 1881600000 0x04040062 0x144e004e 0x4>; + < 300000000 0x0004000f 0x031e001e 0x1>; qcom,perfcl-speedbin0-v0 = - < 300000000 0x0004000f 0x03200020 0x1>, - < 345600000 0x05040012 0x04200020 0x1>, - < 422400000 0x05040016 0x04200020 0x1>, - < 480000000 0x05040019 0x05200020 0x1>, - < 556800000 0x0504001d 0x06200020 0x1>, - < 633600000 0x04040021 0x07200020 0x1>, - < 710400000 0x04040025 0x07200020 0x1>, - < 787200000 0x04040029 0x08210021 0x1>, - < 844800000 0x0404002c 0x09240024 0x2>, - < 902400000 0x0404002f 0x09260026 0x2>, - < 979200000 0x04040033 0x0a290029 0x2>, - < 1056000000 0x04040037 0x0b2c002c 0x2>, - < 1171200000 0x0404003d 0x0c300030 0x3>, - < 1248000000 0x04040041 0x0d340034 0x3>, - < 1324800000 0x04040045 0x0e370037 0x3>, - < 1401600000 0x04040049 0x0f3b003b 0x3>, - < 1478400000 0x0404004d 0x0f3e003e 0x3>, - < 1536000000 0x04040050 0x10400040 0x3>, - < 1632000000 0x04040055 0x11440044 0x4>, - < 1708800000 0x04040059 0x12480048 0x4>, - < 1785600000 0x0404005d 0x134a004a 0x4>, - < 1862400000 0x04040061 0x134e004e 0x4>, - < 1939200000 0x04040065 0x14510051 0x4>, - < 2016000000 0x04040069 0x15540054 0x4>, - < 2092800000 0x0404006d 0x16570057 0x4>; + < 300000000 0x0004000f 0x03200020 0x1>; qcom,osm-pll-setup; @@ -813,6 +723,7 @@ qcom,use-gsi; qcom,use-ipa-tethering-bridge; qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; clock-names = "core_clk"; clocks = <&clock_gcc clk_ipa_clk>; qcom,msm-bus,name = "ipa"; @@ -901,22 +812,6 @@ rpm-channel-name = "rpm_requests"; }; - qcom,smdpkt { - compatible = "qcom,smdpkt"; - - qcom,smdpkt-apr-apps2 { - qcom,smdpkt-remote = "adsp"; - qcom,smdpkt-port-name = "apr_apps2"; - qcom,smdpkt-dev-name = "apr_apps2"; - }; - - qcom,smdpkt-loopback { - qcom,smdpkt-remote = "modem"; - qcom,smdpkt-port-name = "LOOPBACK"; - qcom,smdpkt-dev-name = "smd_pkt_loopback"; - }; - }; - glink_mpss: qcom,glink-ssr-modem { compatible = "qcom,glink_ssr"; label = "modem"; @@ -1021,7 +916,7 @@ compatible = "qcom,glinkpkt"; qcom,glinkpkt-at-mdm0 { - qcom,glinkpkt-transport = "smd_trans"; + qcom,glinkpkt-transport = "smem"; qcom,glinkpkt-edge = "mpss"; qcom,glinkpkt-ch-name = "DS"; qcom,glinkpkt-dev-name = "at_mdm0"; @@ -1040,6 +935,20 @@ qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT"; qcom,glinkpkt-dev-name = "glink_pkt_loopback"; }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; }; qcom,ipc_router { @@ -1549,7 +1458,7 @@ clocks = <&clock_gcc clk_cxo_clk_src>, <&clock_gcc clk_gcc_mss_cfg_ahb_clk>, <&clock_gcc clk_pnoc_clk>, - <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>, + <&clock_gcc clk_gcc_bimc_mss_q6_axi_clk>, <&clock_gcc clk_gcc_boot_rom_ahb_clk>, <&clock_gcc clk_gpll0_out_msscc>, <&clock_gcc clk_gcc_mss_snoc_axi_clk>, @@ -1591,6 +1500,18 @@ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; }; + slim_msm: slim@91c0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x91c0000 0x2C000>, + <0x9184000 0x32000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0>, <0 164 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x600000>; + qcom,ea-pc = <0x160>; + }; + tsens0: tsens@10aa000 { compatible = "qcom,msmcobalt-tsens"; reg = <0x10aa000 0x2000>, @@ -1898,9 +1819,10 @@ reg = <0x1d0101c 0x4>, <0x1d01024 0x4>, <0x1d01028 0x4>, - <0x1d0103c 0x4>; + <0x1d0103c 0x4>, + <0x1d02030 0x4>; reg-names = "sp2soc_irq_status", "sp2soc_irq_clr", - "sp2soc_irq_mask","rmb_err"; + "sp2soc_irq_mask", "rmb_err", "rmb_err_spare2"; interrupts = <0 352 1>; vdd_cx-supply = <&pmcobalt_s1_level>; @@ -1917,7 +1839,7 @@ qcom,proxy-timeout-ms = <10000>; qcom,firmware-name = "spss"; memory-region = <&peripheral_mem>; - qcom,spss-scsr-bits = <0 1 2 3 16 17 24 25>; + qcom,spss-scsr-bits = <24 25>; }; qcom,msm-rtb { @@ -2199,3 +2121,6 @@ #include "msmcobalt-gpu.dtsi" #include "msm-pmcobalt.dtsi" #include "msm-pmicobalt.dtsi" +#include "msmcobalt-pinctrl.dtsi" +#include "msm-audio-lpass.dtsi" +#include "msmcobalt-audio.dtsi" diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 8087882ac33f..559ac84dcaa2 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -55,6 +55,7 @@ config ARCH_QCOM select PM_OPP select SOC_BUS select MSM_IRQ + select THERMAL_WRITABLE_TRIPS help This enables support for the ARMv8 based Qualcomm chipsets. diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 95a96e34c4c4..5791959408bd 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -533,6 +533,7 @@ CONFIG_QCOM_BUSPM_DEV=m CONFIG_QCOM_BUS_TOPOLOGY_ADHOC=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SPM=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 5ca974ffac43..deffb3241e12 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -536,6 +536,7 @@ CONFIG_QCOM_BUSPM_DEV=m CONFIG_QCOM_BUS_TOPOLOGY_ADHOC=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SPM=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 3f44a31d4dc4..763e73dea5e1 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -277,6 +277,9 @@ CONFIG_VIRTIO_CONSOLE=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C=y CONFIG_I2C_QUP=y +CONFIG_SLIMBUS=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y CONFIG_SPMI=y CONFIG_PINCTRL_MSMCOBALT=y CONFIG_GPIOLIB=y @@ -285,11 +288,15 @@ CONFIG_GPIO_QPNP_PIN=y CONFIG_QPNP_SMBCHARGER=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_MSM_APM=y # CONFIG_HWMON is not set +CONFIG_THERMAL_TSENS8974=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_RPM_SMD=y @@ -307,6 +314,10 @@ CONFIG_FB_ARMCLCD=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_MSMCOBALT=y CONFIG_UHID=y CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y @@ -421,6 +432,8 @@ CONFIG_TRACER_PKT=y CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_EXTCON=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y CONFIG_PHY_XGENE=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index c358c2a1cc56..2fd4f2ebf418 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -290,6 +290,9 @@ CONFIG_VIRTIO_CONSOLE=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C=y CONFIG_I2C_QUP=y +CONFIG_SLIMBUS=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y CONFIG_SPMI=y CONFIG_PINCTRL_MSMCOBALT=y CONFIG_GPIOLIB=y @@ -304,7 +307,9 @@ CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_MSM_APM=y # CONFIG_HWMON is not set +CONFIG_THERMAL_TSENS8974=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_RPM_SMD=y @@ -317,12 +322,17 @@ CONFIG_REGULATOR_CPRH_KBSS=y CONFIG_REGULATOR_MEM_ACC=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_STUB=y +CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_ARMCLCD=y CONFIG_FB_VIRTUAL=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_MSMCOBALT=y CONFIG_UHID=y CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y @@ -448,6 +458,8 @@ CONFIG_TRACER_PKT=y CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_EXTCON=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y CONFIG_PHY_XGENE=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 90c7ff233735..bfef76e14e2d 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -113,6 +113,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_RESTORE_SIGMASK 20 #define TIF_SINGLESTEP 21 #define TIF_32BIT 22 /* 32bit process */ +#define TIF_MM_RELEASED 24 #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 1a665e04d139..e6777606a934 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -2112,14 +2112,19 @@ int arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping) { int err; + int s1_bypass = 0; err = iommu_attach_device(mapping->domain, dev); if (err) return err; + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + kref_get(&mapping->kref); dev->archdata.mapping = mapping; - set_dma_ops(dev, &iommu_ops); + if (!s1_bypass) + set_dma_ops(dev, &iommu_ops); pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); return 0; diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 92ddac1e8ca2..c2a5a018bd00 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -38,6 +38,7 @@ #include <asm/system_misc.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> +#include <asm/edac.h> static const char *fault_name(unsigned int esr); @@ -376,6 +377,7 @@ static int __kprobes do_translation_fault(unsigned long addr, */ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) { + arm64_check_cache_ecc(NULL); return 1; } diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 3ca376f9c2e3..00cb1064ea13 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -36,6 +36,7 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qca,ar3002" }, { .compatible = "qca,qca6174" }, + { .compatible = "qca,wcn3990" }, {} }; @@ -85,6 +86,16 @@ static int bt_vreg_enable(struct bt_power_vreg_data *vreg) } } + if (vreg->load_uA >= 0) { + rc = regulator_set_load(vreg->reg, + vreg->load_uA); + if (rc < 0) { + BT_PWR_ERR("vreg_set_mode(%s) failed rc=%d\n", + vreg->name, rc); + goto out; + } + } + rc = regulator_enable(vreg->reg); if (rc < 0) { BT_PWR_ERR("regulator_enable(%s) failed. rc=%d\n", @@ -117,14 +128,19 @@ static int bt_vreg_disable(struct bt_power_vreg_data *vreg) if (vreg->set_voltage_sup) { /* Set the min voltage to 0 */ - rc = regulator_set_voltage(vreg->reg, - 0, - vreg->high_vol_level); + rc = regulator_set_voltage(vreg->reg, 0, + vreg->high_vol_level); if (rc < 0) { BT_PWR_ERR("vreg_set_vol(%s) failed rc=%d\n", vreg->name, rc); goto out; - + } + } + if (vreg->load_uA >= 0) { + rc = regulator_set_load(vreg->reg, 0); + if (rc < 0) { + BT_PWR_ERR("vreg_set_mode(%s) failed rc=%d\n", + vreg->name, rc); } } } @@ -154,7 +170,7 @@ static int bt_configure_gpios(int on) int rc = 0; int bt_reset_gpio = bt_power_pdata->bt_gpio_sys_rst; - BT_PWR_DBG("%s bt_gpio= %d on: %d", __func__, bt_reset_gpio, on); + BT_PWR_DBG("bt_gpio= %d on: %d", bt_reset_gpio, on); if (on) { rc = gpio_request(bt_reset_gpio, "bt_sys_rst_n"); @@ -211,7 +227,6 @@ static int bluetooth_power(int on) goto vdd_core_fail; } } - if (bt_power_pdata->bt_vdd_pa) { rc = bt_configure_vreg(bt_power_pdata->bt_vdd_pa); if (rc < 0) { @@ -378,6 +393,7 @@ static int bt_dt_parse_vreg_info(struct device *dev, vreg->name = vreg_name; + /* Parse voltage-level from each node */ snprintf(prop_name, MAX_PROP_SIZE, "%s-voltage-level", vreg_name); prop = of_get_property(np, prop_name, &len); @@ -389,10 +405,21 @@ static int bt_dt_parse_vreg_info(struct device *dev, vreg->high_vol_level = be32_to_cpup(&prop[1]); } + /* Parse current-level from each node */ + snprintf(prop_name, MAX_PROP_SIZE, + "%s-current-level", vreg_name); + ret = of_property_read_u32(np, prop_name, &vreg->load_uA); + if (ret < 0) { + BT_PWR_DBG("%s property is not valid\n", prop_name); + vreg->load_uA = -1; + ret = 0; + } + *vreg_data = vreg; - BT_PWR_DBG("%s: vol=[%d %d]uV\n", + BT_PWR_DBG("%s: vol=[%d %d]uV, current=[%d]uA\n", vreg->name, vreg->low_vol_level, - vreg->high_vol_level); + vreg->high_vol_level, + vreg->load_uA); } else BT_PWR_INFO("%s: is not provided in device tree", vreg_name); diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index 173f9214d7f7..14b988c1e089 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -1681,13 +1681,14 @@ static u32 find_voltage(struct clk_osm *c, unsigned long rate) return -EINVAL; } -static int add_opp(struct clk_osm *c, struct device *dev, - unsigned long max_rate, unsigned long min_rate) +static int add_opp(struct clk_osm *c, struct device *dev) { unsigned long rate = 0; u32 uv; long rc; - int j = 1; + int j = 0; + unsigned long min_rate = c->c.fmax[0]; + unsigned long max_rate = c->c.fmax[c->c.num_fmax - 1]; while (1) { rate = c->c.fmax[j++]; @@ -1712,11 +1713,15 @@ static int add_opp(struct clk_osm *c, struct device *dev, if (rate == min_rate) pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", rate, uv, dev_name(dev)); - if (rate == max_rate) { + + if (rate == max_rate && max_rate != min_rate) { pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", rate, uv, dev_name(dev)); break; } + + if (min_rate == max_rate) + break; } return 0; @@ -1762,15 +1767,11 @@ static void populate_opp_table(struct platform_device *pdev) for_each_possible_cpu(cpu) { if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) { - WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu), - pwrcl_clk.c.fmax[pwrcl_clk.c.num_fmax - 1], - pwrcl_clk.c.fmax[1]), + WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)), "Failed to add OPP levels for power cluster\n"); } if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) { - WARN(add_opp(&perfcl_clk, get_cpu_device(cpu), - perfcl_clk.c.fmax[perfcl_clk.c.num_fmax - 1], - perfcl_clk.c.fmax[1]), + WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)), "Failed to add OPP levels for perf cluster\n"); } } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 5e370a30a964..1be58ffd3bce 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -322,16 +322,20 @@ static int __init cpufreq_stats_init(void) if (ret) return ret; + get_online_cpus(); for_each_online_cpu(cpu) cpufreq_stats_create_table(cpu); + put_online_cpus(); ret = cpufreq_register_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); if (ret) { cpufreq_unregister_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); + get_online_cpus(); for_each_online_cpu(cpu) cpufreq_stats_free_table(cpu); + put_online_cpus(); return ret; } diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index 05198a17ad5f..e0f75b0022fc 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -764,6 +764,8 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, { int ret; unsigned int sample_ms; + struct hwmon_node *node; + struct bw_hwmon *hw; switch (event) { case DEVFREQ_GOV_START: @@ -790,7 +792,22 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, sample_ms = *(unsigned int *)data; sample_ms = max(MIN_MS, sample_ms); sample_ms = min(MAX_MS, sample_ms); + /* + * Suspend/resume the HW monitor around the interval update + * to prevent the HW monitor IRQ from trying to change + * stop/start the delayed workqueue while the interval update + * is happening. + */ + node = df->data; + hw = node->hw; + hw->suspend_hwmon(hw); devfreq_interval_update(df, &sample_ms); + ret = hw->resume_hwmon(hw); + if (ret) { + dev_err(df->dev.parent, + "Unable to resume HW monitor (%d)\n", ret); + return ret; + } break; case DEVFREQ_GOV_SUSPEND: diff --git a/drivers/edac/cortex_arm64_edac.c b/drivers/edac/cortex_arm64_edac.c index d134e8822c9d..2268bd3fa8f0 100644 --- a/drivers/edac/cortex_arm64_edac.c +++ b/drivers/edac/cortex_arm64_edac.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -63,6 +63,14 @@ #define A57_L2MERRSR_CPUID(a) (((a) >> 18) & 0x0f) #define A57_L2MERRSR_INDEX(a) ((a) & 0x1ffff) +#define KRYO2XX_GOLD_L2MERRSR_FATAL(a) ((a) & (1LL << 63)) +#define KRYO2XX_GOLD_L2MERRSR_OTHER(a) (((a) >> 40) & 0x3f) +#define KRYO2XX_GOLD_L2MERRSR_REPT(a) (((a) >> 32) & 0x3f) +#define KRYO2XX_GOLD_L2MERRSR_VALID(a) ((a) & (1 << 31)) +#define KRYO2XX_GOLD_L2MERRSR_RAMID(a) ((a) & (1 << 24)) +#define KRYO2XX_GOLD_L2MERRSR_WAY(a) (((a) >> 18) & 0x0f) +#define KRYO2XX_GOLD_L2MERRSR_INDEX(a) (((a) >> 3) & 0x3fff) + #define L2ECTLR_INT_ERR (1 << 30) #define L2ECTLR_EXT_ERR (1 << 29) @@ -220,6 +228,32 @@ static void ca53_ca57_print_error_state_regs(void) "Double bit error on dirty L2 cacheline\n"); } +static void kryo2xx_gold_print_error_state_regs(void) +{ + u64 l2merrsr; + u32 esr_el1; + u32 l2ectlr; + + l2merrsr = read_l2merrsr_el1; + esr_el1 = read_esr_el1; + l2ectlr = read_l2ectlr_el1; + + uncached_logk_pc(LOGK_READL, __builtin_return_address(0), + (void *)l2merrsr); + uncached_logk_pc(LOGK_READL, __builtin_return_address(0), + (void *)((u64)esr_el1)); + uncached_logk_pc(LOGK_READL, __builtin_return_address(0), + (void *)((u64)l2ectlr)); + + edac_printk(KERN_CRIT, EDAC_CPU, "L2MERRSR value = %#llx\n", l2merrsr); + + edac_printk(KERN_CRIT, EDAC_CPU, "ESR value = %#x\n", esr_el1); + edac_printk(KERN_CRIT, EDAC_CPU, "L2ECTLR value = %#x\n", l2ectlr); + if (ESR_L2_DBE(esr_el1)) + edac_printk(KERN_CRIT, EDAC_CPU, + "Double bit error on dirty L2 cacheline\n"); +} + static void ca53_parse_cpumerrsr(struct erp_local_data *ed) { u64 cpumerrsr; @@ -480,6 +514,50 @@ static void ca57_parse_l2merrsr(struct erp_local_data *ed) write_l2merrsr_el1(0); } + +static void kryo2xx_gold_parse_l2merrsr(struct erp_local_data *ed) +{ + u64 l2merrsr; + int ramid, way; + + l2merrsr = read_l2merrsr_el1; + + if (!KRYO2XX_GOLD_L2MERRSR_VALID(l2merrsr)) + return; + + if (KRYO2XX_GOLD_L2MERRSR_FATAL(l2merrsr)) + ed->err = DBE; + + edac_printk(KERN_CRIT, EDAC_CPU, "Gold L2 %s Error detected\n", + err_name[ed->err]); + kryo2xx_gold_print_error_state_regs(); + if (ed->err == DBE) + edac_printk(KERN_CRIT, EDAC_CPU, "Fatal error\n"); + + way = KRYO2XX_GOLD_L2MERRSR_WAY(l2merrsr); + ramid = KRYO2XX_GOLD_L2MERRSR_RAMID(l2merrsr); + + edac_printk(KERN_CRIT, EDAC_CPU, + "L2 %s RAM error in way 0x%02x, index 0x%04x\n", + ramid ? "data" : "tag", + (int) KRYO2XX_GOLD_L2MERRSR_WAY(l2merrsr), + (int) KRYO2XX_GOLD_L2MERRSR_INDEX(l2merrsr)); + + edac_printk(KERN_CRIT, EDAC_CPU, "Repeated error count: %d\n", + (int) KRYO2XX_GOLD_L2MERRSR_REPT(l2merrsr)); + edac_printk(KERN_CRIT, EDAC_CPU, "Other error count: %d\n", + (int) KRYO2XX_GOLD_L2MERRSR_OTHER(l2merrsr)); + + if (ed->err == SBE) { + errors[A57_L2_CE].func(ed->drv->edev_ctl, smp_processor_id(), + L2_CACHE, errors[A57_L2_CE].msg); + } else if (ed->err == DBE) { + errors[A57_L2_UE].func(ed->drv->edev_ctl, smp_processor_id(), + L2_CACHE, errors[A57_L2_UE].msg); + } + write_l2merrsr_el1(0); +} + static DEFINE_SPINLOCK(local_handler_lock); static DEFINE_SPINLOCK(l2ectlr_lock); @@ -508,6 +586,10 @@ static void arm64_erp_local_handler(void *info) ca57_parse_l2merrsr(errdata); break; + case ARM_CPU_PART_KRYO2XX_GOLD: + kryo2xx_gold_parse_l2merrsr(errdata); + break; + default: edac_printk(KERN_CRIT, EDAC_CPU, "Unknown CPU Part Number in MIDR: %#04x (%#08x)\n", partnum, cpuid); @@ -675,6 +757,10 @@ static void check_sbe_event(struct erp_drvdata *drv) ca57_parse_cpumerrsr(&errdata); ca57_parse_l2merrsr(&errdata); break; + + case ARM_CPU_PART_KRYO2XX_GOLD: + kryo2xx_gold_parse_l2merrsr(&errdata); + break; }; spin_unlock_irqrestore(&local_handler_lock, flags); } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index b2c53de88b03..a9b6b24725b4 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1453,7 +1453,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, } /* SCTLR */ - reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP; + reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_EAE_SBOP; + + if (!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) || + !stage1) + reg |= SCTLR_M; if (stage1) reg |= SCTLR_S1_ASIDPNE; #ifdef __BIG_ENDIAN @@ -2898,6 +2902,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, & (1 << DOMAIN_ATTR_NON_FATAL_FAULTS)); ret = 0; break; + case DOMAIN_ATTR_S1_BYPASS: + *((int *)data) = !!(smmu_domain->attributes + & (1 << DOMAIN_ATTR_S1_BYPASS)); + ret = 0; + break; default: ret = -ENODEV; break; @@ -3009,6 +3018,18 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, smmu_domain->non_fatal_faults = *((int *)data); ret = 0; break; + case DOMAIN_ATTR_S1_BYPASS: { + int bypass = *((int *)data); + + if (bypass) + smmu_domain->attributes |= 1 << DOMAIN_ATTR_S1_BYPASS; + else + smmu_domain->attributes &= + ~(1 << DOMAIN_ATTR_S1_BYPASS); + + ret = 0; + break; + } default: ret = -ENODEV; break; diff --git a/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h b/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h index 015c2099603c..97aadc8446c7 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h +++ b/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h @@ -9,6 +9,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#ifndef _CAM_HW_OPS_H_ +#define _CAM_HW_OPS_H_ enum cam_ahb_clk_vote { /* need to update the voting requests @@ -37,3 +39,4 @@ enum cam_ahb_clk_client { int cam_config_ahb_clk(struct device *dev, unsigned long freq, enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote); int cam_ahb_clk_init(struct platform_device *pdev); +#endif /* _CAM_HW_OPS_H_ */ diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c index d699d091e3c7..33e1299cd027 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c @@ -473,16 +473,16 @@ EXPORT_SYMBOL(msm_camera_put_clk_info_and_rates); /* Get regulators from DT */ int msm_camera_get_regulator_info(struct platform_device *pdev, - struct regulator ***vdd, + struct msm_cam_regulator **vdd_info, int *num_reg) { uint32_t cnt; int i, rc; struct device_node *of_node; - const char *name; char prop_name[32]; + struct msm_cam_regulator *tmp_reg; - if (!pdev || !vdd || !num_reg) + if (!pdev || !vdd_info || !num_reg) return -EINVAL; of_node = pdev->dev.of_node; @@ -499,82 +499,95 @@ int msm_camera_get_regulator_info(struct platform_device *pdev, return -EINVAL; } - *num_reg = cnt; - (*vdd) = devm_kcalloc(&pdev->dev, cnt, sizeof(struct regulator *), - GFP_KERNEL); - if (!*vdd) + tmp_reg = devm_kcalloc(&pdev->dev, cnt, + sizeof(struct msm_cam_regulator), GFP_KERNEL); + if (!tmp_reg) return -ENOMEM; for (i = 0; i < cnt; i++) { rc = of_property_read_string_index(of_node, - "qcom,vdd-names", i, &name); + "qcom,vdd-names", i, &tmp_reg[i].name); if (rc < 0) { pr_err("Fail to fetch regulators: %d\n", i); rc = -EINVAL; goto err1; } - CDBG("regulator-names[%d] = %s\n", i, name); + CDBG("regulator-names[%d] = %s\n", i, tmp_reg[i].name); - snprintf(prop_name, 32, "%s-supply", name); + snprintf(prop_name, 32, "%s-supply", tmp_reg[i].name); if (of_get_property(of_node, prop_name, NULL)) { - (*vdd)[i] = devm_regulator_get(&pdev->dev, name); - if (IS_ERR((*vdd)[i])) { + tmp_reg[i].vdd = + devm_regulator_get(&pdev->dev, tmp_reg[i].name); + if (IS_ERR(tmp_reg[i].vdd)) { rc = -EINVAL; pr_err("Fail to get regulator :%d\n", i); goto err1; } } else { - pr_err("Regulator phandle not found :%s\n", name); + pr_err("Regulator phandle not found :%s\n", + tmp_reg[i].name); + rc = -EINVAL; goto err1; } - CDBG("vdd ptr[%d] :%p\n", i, (*vdd)[i]); + CDBG("vdd ptr[%d] :%p\n", i, tmp_reg[i].vdd); } + *num_reg = cnt; + *vdd_info = tmp_reg; + return 0; err1: for (--i; i >= 0; i--) - devm_regulator_put((*vdd)[i]); - devm_kfree(&pdev->dev, *vdd); + devm_regulator_put(tmp_reg[i].vdd); + devm_kfree(&pdev->dev, tmp_reg); return rc; } EXPORT_SYMBOL(msm_camera_get_regulator_info); /* Enable/Disable regulators */ -int msm_camera_regulator_enable(struct regulator **vdd, +int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info, int cnt, int enable) { int i; int rc; + struct msm_cam_regulator *tmp = vdd_info; - CDBG("cnt : %d, enable : %d\n", cnt, enable); - if (!vdd) { + if (!tmp) { pr_err("Invalid params"); return -EINVAL; } + CDBG("cnt : %d\n", cnt); for (i = 0; i < cnt; i++) { - if (enable) { - rc = regulator_enable(vdd[i]); - if (rc < 0) { - pr_err("regulator enable failed %d\n", i); - goto error; + if (tmp && !IS_ERR_OR_NULL(tmp->vdd)) { + CDBG("name : %s, enable : %d\n", tmp->name, enable); + if (enable) { + rc = regulator_enable(tmp->vdd); + if (rc < 0) { + pr_err("regulator enable failed %d\n", + i); + goto error; + } + } else { + rc = regulator_disable(tmp->vdd); + if (rc < 0) + pr_err("regulator disable failed %d\n", + i); } - } else { - rc = regulator_disable(vdd[i]); - if (rc < 0) - pr_err("regulator disable failed %d\n", i); } + tmp++; } return 0; error: for (--i; i > 0; i--) { - if (!IS_ERR_OR_NULL(vdd[i])) - regulator_disable(vdd[i]); + --tmp; + if (!IS_ERR_OR_NULL(tmp->vdd)) + regulator_disable(tmp->vdd); } return rc; } @@ -582,24 +595,23 @@ EXPORT_SYMBOL(msm_camera_regulator_enable); /* Put regulators regulators */ void msm_camera_put_regulators(struct platform_device *pdev, - struct regulator ***vdd, - int cnt) + struct msm_cam_regulator **vdd_info, int cnt) { int i; - if (!*vdd) { + if (!vdd_info || !*vdd_info) { pr_err("Invalid params\n"); return; } for (i = cnt - 1; i >= 0; i--) { - if (!IS_ERR_OR_NULL((*vdd)[i])) - devm_regulator_put((*vdd)[i]); - CDBG("vdd ptr[%d] :%p\n", i, (*vdd)[i]); + if (vdd_info[i] && !IS_ERR_OR_NULL(vdd_info[i]->vdd)) + devm_regulator_put(vdd_info[i]->vdd); + CDBG("vdd ptr[%d] :%p\n", i, vdd_info[i]->vdd); } - devm_kfree(&pdev->dev, *vdd); - *vdd = NULL; + devm_kfree(&pdev->dev, *vdd_info); + *vdd_info = NULL; } EXPORT_SYMBOL(msm_camera_put_regulators); @@ -643,12 +655,11 @@ EXPORT_SYMBOL(msm_camera_register_irq); int msm_camera_register_threaded_irq(struct platform_device *pdev, struct resource *irq, irq_handler_t handler_fn, irq_handler_t thread_fn, unsigned long irqflags, - char *irq_name, void *dev_id) + const char *irq_name, void *dev_id) { int rc = 0; - if (!pdev || !irq || !handler_fn || !thread_fn || - !irq_name || !dev_id) { + if (!pdev || !irq || !irq_name || !dev_id) { pr_err("Invalid params\n"); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h index 0b60d4137354..9724d5951862 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h +++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h @@ -34,6 +34,11 @@ enum cam_bus_client { CAM_BUS_CLIENT_MAX }; +struct msm_cam_regulator { + const char *name; + struct regulator *vdd; +}; + /** * @brief : Gets clock information from dtsi * @@ -154,28 +159,28 @@ long msm_camera_clk_set_rate(struct device *dev, * platform device * * @param pdev : platform device to get regulator information - * @param vdd: Pointer to populate the regulator names + * @param vdd_info: Pointer to populate the regulator names * @param num_reg: Pointer to populate the number of regulators * extracted from dtsi * * @return Status of operation. Negative in case of error. Zero otherwise. */ int msm_camera_get_regulator_info(struct platform_device *pdev, - struct regulator ***vddd, int *num_reg); + struct msm_cam_regulator **vdd_info, int *num_reg); /** * @brief : Enable/Disable the regultors * * This function enables/disables the regulators for a specific * platform device * - * @param vdd: Pointer to list of regulators + * @param vdd_info: Pointer to list of regulators * @param cnt: Number of regulators to enable/disable * @param enable: Flags specifies either enable/disable * * @return Status of operation. Negative in case of error. Zero otherwise. */ -int msm_camera_regulator_enable(struct regulator **vdd, +int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info, int cnt, int enable); /** @@ -184,13 +189,12 @@ int msm_camera_regulator_enable(struct regulator **vdd, * This function releases the regulator resources. * * @param pdev: Pointer to platform device - * @param vdd: Pointer to list of regulators + * @param vdd_info: Pointer to list of regulators * @param cnt: Number of regulators to release */ void msm_camera_put_regulators(struct platform_device *pdev, - struct regulator ***vdd, - int cnt); + struct msm_cam_regulator **vdd_info, int cnt); /** * @brief : Get the IRQ resource * @@ -248,7 +252,7 @@ int msm_camera_register_threaded_irq(struct platform_device *pdev, irq_handler_t handler_fn, irq_handler_t thread_fn, unsigned long irqflags, - char *irq_name, + const char *irq_name, void *dev); /** diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index bc6d8b439292..98afe4cd3074 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -1224,7 +1224,7 @@ static int fd_probe(struct platform_device *pdev) goto error_mem_resources; } - ret = msm_camera_get_regulator_info(pdev, &fd->vdd, + ret = msm_camera_get_regulator_info(pdev, &fd->vdd_info, &fd->num_reg); if (ret < 0) { dev_err(&pdev->dev, "Fail to get regulators\n"); @@ -1298,7 +1298,7 @@ error_get_bus: msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info, &fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num); error_get_clocks: - msm_camera_put_regulators(pdev, &fd->vdd, fd->num_reg); + msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg); error_get_regulator: msm_fd_hw_release_mem_resources(fd); error_mem_resources: @@ -1325,7 +1325,7 @@ static int fd_device_remove(struct platform_device *pdev) msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD); msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info, &fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num); - msm_camera_put_regulators(pdev, &fd->vdd, fd->num_reg); + msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg); msm_fd_hw_release_mem_resources(fd); kfree(fd); diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h index e86a9abf7126..b96c33b3fd07 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h @@ -225,7 +225,7 @@ struct msm_fd_device { int irq_num; void __iomem *iomem_base[MSM_FD_IOMEM_LAST]; struct msm_cam_clk_info *clk_info; - struct regulator **vdd; + struct msm_cam_regulator *vdd_info; int num_reg; struct resource *irq; diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c index b8ee18da44cd..1e6398e54d68 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c @@ -838,7 +838,8 @@ int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx) if (fd->ref_count == 0) { ret = - msm_camera_regulator_enable(fd->vdd, fd->num_reg, true); + msm_camera_regulator_enable(fd->vdd_info, + fd->num_reg, true); if (ret < 0) { dev_err(fd->dev, "Fail to enable vdd\n"); goto error; @@ -881,7 +882,7 @@ error_set_dt: fd->clk, fd->clk_num, false); error_clocks: error_bus_request: - msm_camera_regulator_enable(fd->vdd, fd->num_reg, false); + msm_camera_regulator_enable(fd->vdd_info, fd->num_reg, false); error: mutex_unlock(&fd->lock); return ret; @@ -909,7 +910,7 @@ void msm_fd_hw_put(struct msm_fd_device *fd) msm_fd_hw_bus_request(fd, 0); msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info, fd->clk, fd->clk_num, false); - msm_camera_regulator_enable(fd->vdd, fd->num_reg, false); + msm_camera_regulator_enable(fd->vdd_info, fd->num_reg, false); } mutex_unlock(&fd->lock); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 8a9a4f2a1c30..bc22a3987f85 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -721,7 +721,6 @@ struct vfe_device { uint32_t isp_raw0_debug; uint32_t isp_raw1_debug; uint32_t isp_raw2_debug; - uint8_t is_camif_raw_crop_supported; /* irq info */ uint32_t irq0_mask; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 337ae59f88e8..850cffaef3a4 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -433,8 +433,6 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) break; case VFE40_8937_VERSION: case VFE40_8953_VERSION: - vfe_dev->is_camif_raw_crop_supported = 1; - break; default: ISP_DBG("%s: No special QOS\n", __func__); } @@ -1400,44 +1398,44 @@ static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, msm_camera_io_w((subsample_cfg->line_skip << 16) | subsample_cfg->pixel_skip, vfe_dev->vfe_base + 0x30C); - if (vfe_dev->is_camif_raw_crop_supported) { - /* Pdaf output will be sent in PLAIN16 format*/ - val = msm_camera_io_r(vfe_dev->vfe_base + 0x54); - switch (subsample_cfg->output_format) { - case CAMIF_PLAIN_8: - val |= 4 << 9; - break; - case CAMIF_PLAIN_16: - val |= 5 << 9; - break; - case CAMIF_MIPI_RAW: - val |= 1 << 9; - break; - case CAMIF_QCOM_RAW: - default: - break; - } - msm_camera_io_w(val, vfe_dev->vfe_base + 0x54); - if (subsample_cfg->first_pixel || - subsample_cfg->last_pixel || - subsample_cfg->first_line || - subsample_cfg->last_line) { - msm_camera_io_w( - subsample_cfg->first_pixel << 16 | - subsample_cfg->last_pixel, - vfe_dev->vfe_base + 0x8A4); - msm_camera_io_w( - subsample_cfg->first_line << 16 | - subsample_cfg->last_line, - vfe_dev->vfe_base + 0x8A8); - val = msm_camera_io_r( - vfe_dev->vfe_base + 0x2F8); - val |= 1 << 22; - msm_camera_io_w(val, - vfe_dev->vfe_base + 0x2F8); - } - } + if (subsample_cfg->first_pixel || + subsample_cfg->last_pixel || + subsample_cfg->first_line || + subsample_cfg->last_line) { + msm_camera_io_w( + subsample_cfg->first_pixel << 16 | + subsample_cfg->last_pixel, + vfe_dev->vfe_base + 0x8A4); + msm_camera_io_w( + subsample_cfg->first_line << 16 | + subsample_cfg->last_line, + vfe_dev->vfe_base + 0x8A8); + val = msm_camera_io_r( + vfe_dev->vfe_base + 0x2F8); + val |= 1 << 22; + msm_camera_io_w(val, + vfe_dev->vfe_base + 0x2F8); + } + ISP_DBG("%s:camif raw op fmt %d\n", + __func__, subsample_cfg->output_format); + /* Pdaf output will be sent in PLAIN16 format*/ + val = msm_camera_io_r(vfe_dev->vfe_base + 0x54); + switch (subsample_cfg->output_format) { + case CAMIF_PLAIN_8: + val |= 4 << 9; + break; + case CAMIF_PLAIN_16: + val |= 5 << 9; + break; + case CAMIF_MIPI_RAW: + val |= 1 << 9; + break; + case CAMIF_QCOM_RAW: + default: + break; + } + msm_camera_io_w(val, vfe_dev->vfe_base + 0x54); } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 054d736a2dc3..ea3c8f71912b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1317,6 +1317,48 @@ static void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev, msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x49C); } + if (subsample_cfg->first_pixel || + subsample_cfg->last_pixel || + subsample_cfg->first_line || + subsample_cfg->last_line) { + msm_camera_io_w( + subsample_cfg->first_pixel << 16 | + subsample_cfg->last_pixel, + vfe_dev->vfe_base + 0xCE4); + msm_camera_io_w( + subsample_cfg->first_line << 16 | + subsample_cfg->last_line, + vfe_dev->vfe_base + 0xCE4); + val = msm_camera_io_r( + vfe_dev->vfe_base + 0x47C); + ISP_DBG("%s: camif raw crop enabled\n", __func__); + val |= 1 << 22; + msm_camera_io_w(val, + vfe_dev->vfe_base + 0x47C); + } + + ISP_DBG("%s: camif raw op fmt %d\n", + __func__, subsample_cfg->output_format); + /* Pdaf output can be sent in below formats */ + val = msm_camera_io_r(vfe_dev->vfe_base + 0x88); + switch (subsample_cfg->output_format) { + case CAMIF_PLAIN_8: + val |= PLAIN8 << 9; + break; + case CAMIF_PLAIN_16: + val |= PLAIN16 << 9; + break; + case CAMIF_MIPI_RAW: + val |= MIPI << 9; + break; + case CAMIF_QCOM_RAW: + val |= QCOM << 9; + break; + default: + break; + } + msm_camera_io_w(val, vfe_dev->vfe_base + 0x88); + val = msm_camera_io_r(vfe_dev->vfe_base + 0x46C); val |= camif_cfg->camif_input; msm_camera_io_w(val, vfe_dev->vfe_base + 0x46C); diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h index 6ceaa4130a78..30a91d32be87 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h @@ -67,7 +67,7 @@ struct msm_jpeg_device { struct msm_cam_clk_info *jpeg_clk_info; size_t num_clk; int num_reg; - struct regulator **jpeg_vdd; + struct msm_cam_regulator *jpeg_vdd; uint32_t hw_version; struct device *device; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index d3e65bd2ee36..034789880a1f 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -1206,7 +1206,7 @@ static int jpegdma_probe(struct platform_device *pdev) goto error_mem_resources; /* get all the regulators */ - ret = msm_camera_get_regulator_info(pdev, &jpegdma->vdd, + ret = msm_camera_get_regulator_info(pdev, &jpegdma->dma_vdd, &jpegdma->num_reg); if (ret < 0) goto error_get_regulators; @@ -1313,7 +1313,7 @@ error_qos_get: msm_camera_put_clk_info(pdev, &jpegdma->jpeg_clk_info, &jpegdma->clk, jpegdma->num_clk); error_get_clocks: - msm_camera_put_regulators(pdev, &jpegdma->vdd, + msm_camera_put_regulators(pdev, &jpegdma->dma_vdd, jpegdma->num_reg); error_get_regulators: msm_jpegdma_hw_release_mem_resources(jpegdma); @@ -1341,7 +1341,7 @@ static int jpegdma_device_remove(struct platform_device *pdev) /* unregister bus client */ msm_camera_unregister_bus_client(dma->bus_client); /* release all the regulators */ - msm_camera_put_regulators(dma->pdev, &dma->vdd, + msm_camera_put_regulators(dma->pdev, &dma->dma_vdd, dma->num_reg); /* release all the clocks */ msm_camera_put_clk_info(dma->pdev, &dma->jpeg_clk_info, diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h index 48d0aaca2cd9..adb8b94f098c 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h @@ -334,7 +334,7 @@ struct msm_jpegdma_device { void __iomem *iomem_base[MSM_JPEGDMA_IOMEM_LAST]; struct resource *irq; - struct regulator **vdd; + struct msm_cam_regulator *dma_vdd; int num_reg; struct clk **clk; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c index 46970a3e73b5..41086936a0b1 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c @@ -1524,7 +1524,7 @@ int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma) mutex_lock(&dma->lock); /* enable all the regulators */ - ret = msm_camera_regulator_enable(dma->vdd, + ret = msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, true); if (ret < 0) { dev_err(dma->dev, "Fail to enable regulators\n"); @@ -1547,14 +1547,14 @@ int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma) dma->jpeg_clk_info, dma->clk, dma->num_clk, false); /* disable all the regulators */ - msm_camera_regulator_enable(dma->vdd, dma->num_reg, false); + msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); mutex_unlock(&dma->lock); return 0; error_clocks: - msm_camera_regulator_enable(dma->vdd, dma->num_reg, false); + msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); error_regulators_get: mutex_unlock(&dma->lock); return ret; @@ -1577,7 +1577,7 @@ int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "msm_jpegdma_hw_get E\n"); /* enable all the regulators */ - ret = msm_camera_regulator_enable(dma->vdd, + ret = msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, true); if (ret < 0) { dev_err(dma->dev, "Fail to enable regulators\n"); @@ -1620,7 +1620,7 @@ error_hw_reset: msm_camera_clk_enable(&dma->pdev->dev, dma->jpeg_clk_info, dma->clk, dma->num_clk, false); error_clocks: - msm_camera_regulator_enable(dma->vdd, dma->num_reg, false); + msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); error_regulators_get: mutex_unlock(&dma->lock); return ret; @@ -1650,7 +1650,7 @@ void msm_jpegdma_hw_put(struct msm_jpegdma_device *dma) msm_camera_clk_enable(&dma->pdev->dev, dma->jpeg_clk_info, dma->clk, dma->num_clk, false); /* disable all the regulators */ - msm_camera_regulator_enable(dma->vdd, dma->num_reg, false); + msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); } /* Reset clock rate, need to be updated on next processing */ dma->active_clock_rate = -1; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index 203314b182a7..b11e37ffef30 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -210,7 +210,7 @@ struct cpp_device { struct clk **cpp_clk; struct msm_cam_clk_info *clk_info; size_t num_clks; - struct regulator **cpp_vdd; + struct msm_cam_regulator *cpp_vdd; int num_reg; struct mutex mutex; enum cpp_state state; diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 7653b1b07cb8..0ad3d9a51f20 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1022,7 +1022,7 @@ static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl, if (!cnt) return 0; - if (cnt >= MSM_ACTUATOT_MAX_VREGS) { + if (cnt >= MSM_ACTUATOR_MAX_VREGS) { pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt); return -EINVAL; } @@ -1048,6 +1048,8 @@ static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl, static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) { int32_t rc = 0; + enum msm_sensor_power_seq_gpio_t gpio; + CDBG("Enter\n"); if (a_ctrl->actuator_state != ACT_DISABLE_STATE) { @@ -1064,6 +1066,41 @@ static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) return rc; } + for (gpio = SENSOR_GPIO_AF_PWDM; + gpio < SENSOR_GPIO_MAX; gpio++) { + if (a_ctrl->gconf && + a_ctrl->gconf->gpio_num_info && + a_ctrl->gconf->gpio_num_info-> + valid[gpio] == 1) { + + gpio_set_value_cansleep( + a_ctrl->gconf->gpio_num_info-> + gpio_num[gpio], + GPIOF_OUT_INIT_LOW); + + if (a_ctrl->cam_pinctrl_status) { + rc = pinctrl_select_state( + a_ctrl->pinctrl_info.pinctrl, + a_ctrl->pinctrl_info. + gpio_state_suspend); + if (rc < 0) + pr_err("ERR:%s:%d cannot set pin to suspend state: %d", + __func__, __LINE__, rc); + + devm_pinctrl_put( + a_ctrl->pinctrl_info.pinctrl); + } + a_ctrl->cam_pinctrl_status = 0; + rc = msm_camera_request_gpio_table( + a_ctrl->gconf->cam_gpio_req_tbl, + a_ctrl->gconf->cam_gpio_req_tbl_size, + 0); + if (rc < 0) + pr_err("ERR:%s:Failed in selecting state in actuator power down: %d\n", + __func__, rc); + } + } + kfree(a_ctrl->step_position_table); a_ctrl->step_position_table = NULL; kfree(a_ctrl->i2c_reg_tbl); @@ -1657,6 +1694,8 @@ static long msm_actuator_subdev_fops_ioctl(struct file *file, unsigned int cmd, static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl) { int rc = 0; + enum msm_sensor_power_seq_gpio_t gpio; + CDBG("%s called\n", __func__); rc = msm_actuator_vreg_control(a_ctrl, 1); @@ -1665,6 +1704,33 @@ static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl) return rc; } + for (gpio = SENSOR_GPIO_AF_PWDM; gpio < SENSOR_GPIO_MAX; gpio++) { + if (a_ctrl->gconf && + a_ctrl->gconf->gpio_num_info && + a_ctrl->gconf->gpio_num_info->valid[gpio] == 1) { + rc = msm_camera_request_gpio_table( + a_ctrl->gconf->cam_gpio_req_tbl, + a_ctrl->gconf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("ERR:%s:Failed in selecting state for actuator: %d\n", + __func__, rc); + return rc; + } + if (a_ctrl->cam_pinctrl_status) { + rc = pinctrl_select_state( + a_ctrl->pinctrl_info.pinctrl, + a_ctrl->pinctrl_info.gpio_state_active); + if (rc < 0) + pr_err("ERR:%s:%d cannot set pin to active state: %d", + __func__, __LINE__, rc); + } + + gpio_set_value_cansleep( + a_ctrl->gconf->gpio_num_info->gpio_num[gpio], + 1); + } + } + /* VREG needs some delay to power up */ usleep_range(2000, 3000); a_ctrl->actuator_state = ACT_ENABLE_STATE; @@ -1825,6 +1891,20 @@ static int32_t msm_actuator_platform_probe(struct platform_device *pdev) return rc; } } + rc = msm_sensor_driver_get_gpio_data(&(msm_actuator_t->gconf), + (&pdev->dev)->of_node); + if (rc < 0) { + pr_err("%s: No/Error Actuator GPIOs\n", __func__); + } else { + msm_actuator_t->cam_pinctrl_status = 1; + rc = msm_camera_pinctrl_init( + &(msm_actuator_t->pinctrl_info), &(pdev->dev)); + if (rc < 0) { + pr_err("ERR:%s: Error in reading actuator pinctrl\n", + __func__); + msm_actuator_t->cam_pinctrl_status = 0; + } + } msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; msm_actuator_t->actuator_mutex = &msm_actuator_mutex; diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h index fb819a7935cb..3b61ee0acabb 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,7 +25,7 @@ #define DEFINE_MSM_MUTEX(mutexname) \ static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) -#define MSM_ACTUATOT_MAX_VREGS (10) +#define MSM_ACTUATOR_MAX_VREGS (10) #define ACTUATOR_MAX_POLL_COUNT 10 struct msm_actuator_ctrl_t; @@ -68,7 +68,7 @@ struct msm_actuator { struct msm_actuator_vreg { struct camera_vreg_t *cam_vreg; - void *data[MSM_ACTUATOT_MAX_VREGS]; + void *data[MSM_ACTUATOR_MAX_VREGS]; int num_vreg; }; @@ -82,7 +82,7 @@ struct msm_actuator_ctrl_t { enum af_camera_name cam_name; struct mutex *actuator_mutex; struct msm_actuator_func_tbl *func_tbl; - enum msm_actuator_data_type i2c_data_type; + enum msm_camera_i2c_data_type i2c_data_type; struct v4l2_subdev sdev; struct v4l2_subdev_ops *act_v4l2_subdev_ops; @@ -105,6 +105,9 @@ struct msm_actuator_ctrl_t { struct msm_actuator_vreg vreg_cfg; struct park_lens_data_t park_lens; uint32_t max_code_size; + struct msm_camera_gpio_conf *gconf; + struct msm_pinctrl_info pinctrl_info; + uint8_t cam_pinctrl_status; }; #endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index 97df0d690153..86d61e7a8185 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -681,77 +681,6 @@ static struct v4l2_subdev_ops msm_flash_subdev_ops = { static const struct v4l2_subdev_internal_ops msm_flash_internal_ops; -static int32_t msm_flash_get_gpio_dt_data(struct device_node *of_node, - struct msm_flash_ctrl_t *fctrl) -{ - int32_t rc = 0, i = 0; - uint16_t *gpio_array = NULL; - int16_t gpio_array_size = 0; - struct msm_camera_gpio_conf *gconf = NULL; - - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size > 0) { - fctrl->power_info.gpio_conf = - kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!fctrl->power_info.gpio_conf) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - gconf = fctrl->power_info.gpio_conf; - - gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, - GFP_KERNEL); - if (!gpio_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto free_gpio_conf; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - if (((int16_t)gpio_array[i]) < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -EINVAL; - goto free_gpio_array; - } - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto free_gpio_array; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto free_cam_gpio_req_tbl; - } - - if (fctrl->flash_driver_type == FLASH_DRIVER_DEFAULT) - fctrl->flash_driver_type = FLASH_DRIVER_GPIO; - CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__, - fctrl->flash_driver_type); - } - - return 0; - -free_cam_gpio_req_tbl: - kfree(gconf->cam_gpio_req_tbl); -free_gpio_array: - kfree(gpio_array); -free_gpio_conf: - kfree(fctrl->power_info.gpio_conf); - return rc; -} - static int32_t msm_flash_get_pmic_source_info( struct device_node *of_node, struct msm_flash_ctrl_t *fctrl) @@ -977,13 +906,19 @@ static int32_t msm_flash_get_dt_data(struct device_node *of_node, } /* Read the gpio information from device tree */ - rc = msm_flash_get_gpio_dt_data(of_node, fctrl); + rc = msm_sensor_driver_get_gpio_data( + &(fctrl->power_info.gpio_conf), of_node); if (rc < 0) { - pr_err("%s:%d msm_flash_get_gpio_dt_data failed rc %d\n", + pr_err("%s:%d msm_sensor_driver_get_gpio_data failed rc %d\n", __func__, __LINE__, rc); return rc; } + if (fctrl->flash_driver_type == FLASH_DRIVER_DEFAULT) + fctrl->flash_driver_type = FLASH_DRIVER_GPIO; + CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__, + fctrl->flash_driver_type); + /* Read the flash and torch source info from device tree node */ rc = msm_flash_get_pmic_source_info(of_node, fctrl); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c index 6ad68151d867..af4723520045 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c @@ -67,8 +67,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; break; case CAM_VIO: @@ -88,8 +86,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; break; case CAM_VANA: @@ -109,8 +105,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; break; case CAM_VAF: @@ -130,8 +124,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; break; case CAM_V_CUSTOM1: @@ -152,9 +144,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; case CAM_V_CUSTOM2: for (j = 0; j < num_vreg; j++) { @@ -174,8 +163,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; break; default: @@ -184,7 +171,6 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, break; } } - return 0; } @@ -762,7 +748,6 @@ int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, rc = -ENOMEM; return rc; } - rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val); if (rc != -EINVAL) { if (rc < 0) { @@ -1036,6 +1021,7 @@ int msm_camera_get_dt_vreg_data(struct device_node *of_node, if (!count || (count == -EINVAL)) { pr_err("%s:%d number of entries is 0 or not present in dts\n", __func__, __LINE__); + *num_vreg = 0; return 0; } @@ -1190,12 +1176,10 @@ static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) return 0; } -static int msm_camera_pinctrl_init(struct msm_camera_power_ctrl_t *ctrl) -{ - struct msm_pinctrl_info *sensor_pctrl = NULL; +int msm_camera_pinctrl_init( + struct msm_pinctrl_info *sensor_pctrl, struct device *dev) { - sensor_pctrl = &ctrl->pinctrl_info; - sensor_pctrl->pinctrl = devm_pinctrl_get(ctrl->dev); + sensor_pctrl->pinctrl = devm_pinctrl_get(dev); if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { pr_err("%s:%d Getting pinctrl handle failed\n", __func__, __LINE__); @@ -1220,6 +1204,120 @@ static int msm_camera_pinctrl_init(struct msm_camera_power_ctrl_t *ctrl) return 0; } +int msm_cam_sensor_handle_reg_gpio(int seq_val, + struct msm_camera_gpio_conf *gconf, int val) { + + int gpio_offset = -1; + + if (!gconf) { + pr_err("ERR:%s: Input Parameters are not proper\n", __func__); + return -EINVAL; + } + CDBG("%s: %d Seq val: %d, config: %d", __func__, __LINE__, + seq_val, val); + + switch (seq_val) { + case CAM_VDIG: + gpio_offset = SENSOR_GPIO_VDIG; + break; + + case CAM_VIO: + gpio_offset = SENSOR_GPIO_VIO; + break; + + case CAM_VANA: + gpio_offset = SENSOR_GPIO_VANA; + break; + + case CAM_VAF: + gpio_offset = SENSOR_GPIO_VAF; + break; + + case CAM_V_CUSTOM1: + gpio_offset = SENSOR_GPIO_CUSTOM1; + break; + + case CAM_V_CUSTOM2: + gpio_offset = SENSOR_GPIO_CUSTOM2; + break; + + default: + pr_err("%s:%d Invalid VREG seq val %d\n", __func__, + __LINE__, seq_val); + return -EINVAL; + } + + CDBG("%s: %d GPIO offset: %d, seq_val: %d\n", __func__, __LINE__, + gpio_offset, seq_val); + + if ((gconf->gpio_num_info->valid[gpio_offset] == 1)) { + gpio_set_value_cansleep( + gconf->gpio_num_info->gpio_num + [gpio_offset], val); + } + return 0; +} + +int32_t msm_sensor_driver_get_gpio_data( + struct msm_camera_gpio_conf **gpio_conf, + struct device_node *of_node) +{ + int32_t rc = 0, i = 0; + uint16_t *gpio_array = NULL; + int16_t gpio_array_size = 0; + struct msm_camera_gpio_conf *gconf = NULL; + + /* Validate input parameters */ + if (!of_node) { + pr_err("failed: invalid param of_node %pK", of_node); + return -EINVAL; + } + + gpio_array_size = of_gpio_count(of_node); + CDBG("gpio count %d\n", gpio_array_size); + if (gpio_array_size <= 0) + return 0; + + gconf = kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!gconf) + return -ENOMEM; + + *gpio_conf = gconf; + + gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL); + if (!gpio_array) + goto FREE_GPIO_CONF; + + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("gpio_array[%d] = %d", i, gpio_array[i]); + } + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc < 0) { + pr_err("failed in msm_camera_get_dt_gpio_req_tbl\n"); + goto FREE_GPIO_CONF; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc < 0) { + pr_err("failed in msm_camera_init_gpio_pin_tbl\n"); + goto FREE_GPIO_REQ_TBL; + } + kfree(gpio_array); + return rc; + +FREE_GPIO_REQ_TBL: + kfree(gconf->cam_gpio_req_tbl); +FREE_GPIO_CONF: + kfree(gconf); + kfree(gpio_array); + *gpio_conf = NULL; + return rc; +} + int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, enum msm_camera_device_type_t device_type, struct msm_camera_i2c_client *sensor_i2c_client) @@ -1236,7 +1334,7 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL) pr_err("%s:%d mux install\n", __func__, __LINE__); - ret = msm_camera_pinctrl_init(ctrl); + ret = msm_camera_pinctrl_init(&(ctrl->pinctrl_info), ctrl->dev); if (ret < 0) { pr_err("%s:%d Initialization of pinctrl failed\n", __func__, __LINE__); @@ -1303,8 +1401,6 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, (int) power_setting->config_val); break; case SENSOR_VREG: - if (power_setting->seq_val == INVALID_VREG) - break; if (power_setting->seq_val >= CAM_VREG_MAX) { pr_err("%s vreg index %d >= max %d\n", __func__, power_setting->seq_val, @@ -1319,9 +1415,18 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, &power_setting->data[0], 1); else - pr_err("ERR:%s: %d usr_idx:%d dts_idx:%d\n", + pr_err("%s: %d usr_idx:%d dts_idx:%d\n", __func__, __LINE__, power_setting->seq_val, ctrl->num_vreg); + + rc = msm_cam_sensor_handle_reg_gpio( + power_setting->seq_val, + ctrl->gpio_conf, 1); + if (rc < 0) { + pr_err("ERR:%s Error in handling VREG GPIO\n", + __func__); + goto power_up_failed; + } break; case SENSOR_I2C_MUX: if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) @@ -1348,7 +1453,6 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, goto power_up_failed; } } - CDBG("%s exit\n", __func__); return 0; power_up_failed: @@ -1380,6 +1484,9 @@ power_up_failed: pr_err("%s:%d:seq_val: %d > num_vreg: %d\n", __func__, __LINE__, power_setting->seq_val, ctrl->num_vreg); + + msm_cam_sensor_handle_reg_gpio(power_setting->seq_val, + ctrl->gpio_conf, GPIOF_OUT_INIT_LOW); break; case SENSOR_I2C_MUX: if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) @@ -1505,6 +1612,11 @@ int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, } else pr_err("%s error in power up/down seq data\n", __func__); + ret = msm_cam_sensor_handle_reg_gpio(pd->seq_val, + ctrl->gpio_conf, GPIOF_OUT_INIT_LOW); + if (ret < 0) + pr_err("ERR:%s Error while disabling VREG GPIO\n", + __func__); break; case SENSOR_I2C_MUX: if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h index baf883fcfc36..220915511cce 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h @@ -15,6 +15,7 @@ #include <soc/qcom/camera2.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/of.h> #include "msm_camera_i2c.h" #include "cam_soc_api.h" @@ -58,4 +59,10 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, int num_vreg, struct msm_sensor_power_setting *power_setting, uint16_t power_setting_size); +int msm_camera_pinctrl_init + (struct msm_pinctrl_info *sensor_pctrl, struct device *dev); + +int32_t msm_sensor_driver_get_gpio_data( + struct msm_camera_gpio_conf **gpio_conf, + struct device_node *of_node); #endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 24b2631d1bd5..addefb4e5a58 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -982,70 +982,6 @@ free_slave_info: return rc; } -static int32_t msm_sensor_driver_get_gpio_data( - struct msm_camera_sensor_board_info *sensordata, - struct device_node *of_node) -{ - int32_t rc = 0, i = 0; - struct msm_camera_gpio_conf *gconf = NULL; - uint16_t *gpio_array = NULL; - uint16_t gpio_array_size = 0; - - /* Validate input paramters */ - if (!sensordata || !of_node) { - pr_err("failed: invalid params sensordata %p of_node %p", - sensordata, of_node); - return -EINVAL; - } - - sensordata->power_info.gpio_conf = kzalloc( - sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); - if (!sensordata->power_info.gpio_conf) { - pr_err("failed"); - return -ENOMEM; - } - gconf = sensordata->power_info.gpio_conf; - - gpio_array_size = of_gpio_count(of_node); - CDBG("gpio count %d", gpio_array_size); - if (!gpio_array_size) - return 0; - - gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, GFP_KERNEL); - if (!gpio_array) { - pr_err("failed"); - goto FREE_GPIO_CONF; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("gpio_array[%d] = %d", i, gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, - gpio_array_size); - if (rc < 0) { - pr_err("failed"); - goto FREE_GPIO_CONF; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array, - gpio_array_size); - if (rc < 0) { - pr_err("failed"); - goto FREE_GPIO_REQ_TBL; - } - - kfree(gpio_array); - return rc; - -FREE_GPIO_REQ_TBL: - kfree(sensordata->power_info.gpio_conf->cam_gpio_req_tbl); -FREE_GPIO_CONF: - kfree(sensordata->power_info.gpio_conf); - kfree(gpio_array); - return rc; -} - static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl) { int32_t rc = 0; @@ -1113,7 +1049,8 @@ static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl) } /* Read gpio information */ - rc = msm_sensor_driver_get_gpio_data(sensordata, of_node); + rc = msm_sensor_driver_get_gpio_data + (&(sensordata->power_info.gpio_conf), of_node); if (rc < 0) { pr_err("failed: msm_sensor_driver_get_gpio_data rc %d", rc); goto FREE_VREG_DATA; diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index fc2c6b6e95b1..947eeafc480c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -153,6 +153,8 @@ static int32_t msm_ois_vreg_control(struct msm_ois_ctrl_t *o_ctrl, static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl) { int32_t rc = 0; + enum msm_sensor_power_seq_gpio_t gpio; + CDBG("Enter\n"); if (o_ctrl->ois_state != OIS_DISABLE_STATE) { @@ -162,6 +164,39 @@ static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl) return rc; } + for (gpio = SENSOR_GPIO_AF_PWDM; gpio < SENSOR_GPIO_MAX; + gpio++) { + if (o_ctrl->gconf && + o_ctrl->gconf->gpio_num_info && + o_ctrl->gconf-> + gpio_num_info->valid[gpio] == 1) { + gpio_set_value_cansleep( + o_ctrl->gconf->gpio_num_info + ->gpio_num[gpio], + GPIOF_OUT_INIT_LOW); + + if (o_ctrl->cam_pinctrl_status) { + rc = pinctrl_select_state( + o_ctrl->pinctrl_info.pinctrl, + o_ctrl->pinctrl_info. + gpio_state_suspend); + if (rc < 0) + pr_err("ERR:%s:%d cannot set pin to suspend state: %d", + __func__, __LINE__, rc); + devm_pinctrl_put( + o_ctrl->pinctrl_info.pinctrl); + } + o_ctrl->cam_pinctrl_status = 0; + rc = msm_camera_request_gpio_table( + o_ctrl->gconf->cam_gpio_req_tbl, + o_ctrl->gconf->cam_gpio_req_tbl_size, + 0); + if (rc < 0) + pr_err("ERR:%s:Failed in selecting state in ois power down: %d\n", + __func__, rc); + } + } + o_ctrl->i2c_tbl_index = 0; o_ctrl->ois_state = OIS_OPS_INACTIVE; } @@ -438,6 +473,8 @@ static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd, static int32_t msm_ois_power_up(struct msm_ois_ctrl_t *o_ctrl) { int rc = 0; + enum msm_sensor_power_seq_gpio_t gpio; + CDBG("%s called\n", __func__); rc = msm_ois_vreg_control(o_ctrl, 1); @@ -446,6 +483,33 @@ static int32_t msm_ois_power_up(struct msm_ois_ctrl_t *o_ctrl) return rc; } + for (gpio = SENSOR_GPIO_AF_PWDM; + gpio < SENSOR_GPIO_MAX; gpio++) { + if (o_ctrl->gconf && o_ctrl->gconf->gpio_num_info && + o_ctrl->gconf->gpio_num_info->valid[gpio] == 1) { + rc = msm_camera_request_gpio_table( + o_ctrl->gconf->cam_gpio_req_tbl, + o_ctrl->gconf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("ERR:%s:Failed in selecting state for ois: %d\n", + __func__, rc); + return rc; + } + if (o_ctrl->cam_pinctrl_status) { + rc = pinctrl_select_state( + o_ctrl->pinctrl_info.pinctrl, + o_ctrl->pinctrl_info.gpio_state_active); + if (rc < 0) + pr_err("ERR:%s:%d cannot set pin to active state: %d", + __func__, __LINE__, rc); + } + + gpio_set_value_cansleep( + o_ctrl->gconf->gpio_num_info->gpio_num[gpio], + 1); + } + } + o_ctrl->ois_state = OIS_ENABLE_STATE; CDBG("Exit\n"); return rc; @@ -662,6 +726,21 @@ static int32_t msm_ois_platform_probe(struct platform_device *pdev) } } + rc = msm_sensor_driver_get_gpio_data(&(msm_ois_t->gconf), + (&pdev->dev)->of_node); + if (rc < 0) { + pr_err("%s: No/Error OIS GPIO\n", __func__); + } else { + msm_ois_t->cam_pinctrl_status = 1; + rc = msm_camera_pinctrl_init( + &(msm_ois_t->pinctrl_info), &(pdev->dev)); + if (rc < 0) { + pr_err("ERR:%s: Error in reading OIS pinctrl\n", + __func__); + msm_ois_t->cam_pinctrl_status = 0; + } + } + msm_ois_t->ois_v4l2_subdev_ops = &msm_ois_subdev_ops; msm_ois_t->ois_mutex = &msm_ois_mutex; diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h index e6db9ad4ffa0..b9f8d4a0c3c8 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -58,6 +58,9 @@ struct msm_ois_ctrl_t { uint32_t subdev_id; enum msm_ois_state_t ois_state; struct msm_ois_vreg vreg_cfg; + struct msm_camera_gpio_conf *gconf; + struct msm_pinctrl_info pinctrl_info; + uint8_t cam_pinctrl_status; }; #endif diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 774352f9e256..0c25e8beec3c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -82,6 +82,12 @@ static const u32 wil_cipher_suites[] = { WLAN_CIPHER_SUITE_GCMP, }; +static const char * const key_usage_str[] = { + [WMI_KEY_USE_PAIRWISE] = "PTK", + [WMI_KEY_USE_RX_GROUP] = "RX_GTK", + [WMI_KEY_USE_TX_GROUP] = "TX_GTK", +}; + int wil_iftype_nl2wmi(enum nl80211_iftype type) { static const struct { @@ -113,7 +119,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, .interval_usec = 0, }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_notify_req_done_event evt; } __packed reply; struct wil_net_stats *stats = &wil->sta[cid].stats; @@ -313,6 +319,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); memset(&cmd, 0, sizeof(cmd)); + cmd.cmd.scan_type = WMI_ACTIVE_SCAN; cmd.cmd.num_channels = 0; n = min(request->n_channels, 4U); for (i = 0; i < n; i++) { @@ -340,6 +347,11 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, if (rc) goto out; + if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) { + cmd.cmd.discovery_mode = 1; + wil_dbg_misc(wil, "active scan with discovery_mode=1\n"); + } + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); @@ -422,6 +434,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, if (sme->privacy && !rsn_eid) wil_info(wil, "WSC connection\n"); + if (sme->pbss) { + wil_err(wil, "connect - PBSS not yet supported\n"); + return -EOPNOTSUPP; + } + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); @@ -535,7 +552,18 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code); - rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); + if (!(test_bit(wil_status_fwconnecting, wil->status) || + test_bit(wil_status_fwconnected, wil->status))) { + wil_err(wil, "%s: Disconnect was called while disconnected\n", + __func__); + return 0; + } + + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + WMI_DISCONNECT_EVENTID, NULL, 0, + WIL6210_DISCONNECT_TO_MS); + if (rc) + wil_err(wil, "%s: disconnect error %d\n", __func__, rc); return rc; } @@ -552,7 +580,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_mgmt *mgmt_frame = (void *)buf; struct wmi_sw_tx_req_cmd *cmd; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_sw_tx_complete_event evt; } __packed evt; @@ -594,11 +622,6 @@ static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil, { struct wireless_dev *wdev = wil->wdev; enum wmi_key_usage rc; - static const char * const key_usage_str[] = { - [WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE", - [WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP", - [WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP", - }; if (pairwise) { rc = WMI_KEY_USE_PAIRWISE; @@ -622,20 +645,86 @@ static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil, return rc; } +static struct wil_tid_crypto_rx_single * +wil_find_crypto_ctx(struct wil6210_priv *wil, u8 key_index, + enum wmi_key_usage key_usage, const u8 *mac_addr) +{ + int cid = -EINVAL; + int tid = 0; + struct wil_sta_info *s; + struct wil_tid_crypto_rx *c; + + if (key_usage == WMI_KEY_USE_TX_GROUP) + return NULL; /* not needed */ + + /* supplicant provides Rx group key in STA mode with NULL MAC address */ + if (mac_addr) + cid = wil_find_cid(wil, mac_addr); + else if (key_usage == WMI_KEY_USE_RX_GROUP) + cid = wil_find_cid_by_idx(wil, 0); + if (cid < 0) { + wil_err(wil, "No CID for %pM %s[%d]\n", mac_addr, + key_usage_str[key_usage], key_index); + return ERR_PTR(cid); + } + + s = &wil->sta[cid]; + if (key_usage == WMI_KEY_USE_PAIRWISE) + c = &s->tid_crypto_rx[tid]; + else + c = &s->group_crypto_rx; + + return &c->key_id[key_index]; +} + static int wil_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) { + int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); + struct wil_tid_crypto_rx_single *cc = wil_find_crypto_ctx(wil, + key_index, + key_usage, + mac_addr); + + wil_dbg_misc(wil, "%s(%pM %s[%d] PN %*phN)\n", __func__, + mac_addr, key_usage_str[key_usage], key_index, + params->seq_len, params->seq); + + if (IS_ERR(cc)) { + wil_err(wil, "Not connected, %s(%pM %s[%d] PN %*phN)\n", + __func__, mac_addr, key_usage_str[key_usage], key_index, + params->seq_len, params->seq); + return -EINVAL; + } - wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index, - pairwise ? "PTK" : "GTK"); + if (cc) + cc->key_set = false; - return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, - params->key, key_usage); + if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) { + wil_err(wil, + "Wrong PN len %d, %s(%pM %s[%d] PN %*phN)\n", + params->seq_len, __func__, mac_addr, + key_usage_str[key_usage], key_index, + params->seq_len, params->seq); + return -EINVAL; + } + + rc = wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, + params->key, key_usage); + if ((rc == 0) && cc) { + if (params->seq) + memcpy(cc->pn, params->seq, IEEE80211_GCMP_PN_LEN); + else + memset(cc->pn, 0, IEEE80211_GCMP_PN_LEN); + cc->key_set = true; + } + + return rc; } static int wil_cfg80211_del_key(struct wiphy *wiphy, @@ -645,9 +734,20 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); + struct wil_tid_crypto_rx_single *cc = wil_find_crypto_ctx(wil, + key_index, + key_usage, + mac_addr); + + wil_dbg_misc(wil, "%s(%pM %s[%d])\n", __func__, mac_addr, + key_usage_str[key_usage], key_index); - wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index, - pairwise ? "PTK" : "GTK"); + if (IS_ERR(cc)) + wil_info(wil, "Not connected, %s(%pM %s[%d])\n", __func__, + mac_addr, key_usage_str[key_usage], key_index); + + if (!IS_ERR_OR_NULL(cc)) + cc->key_set = false; return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage); } @@ -938,6 +1038,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } + if (info->pbss) { + wil_err(wil, "AP: PBSS not yet supported\n"); + return -EOPNOTSUPP; + } + switch (info->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: hidden_ssid = WMI_HIDDEN_SSID_DISABLED; diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 97bc186f9728..96169cb0dfd0 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,6 +37,7 @@ enum dbg_off_type { doff_x32 = 1, doff_ulong = 2, doff_io32 = 3, + doff_u8 = 4 }; /* offset to "wil" */ @@ -68,13 +69,13 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, seq_puts(s, "???\n"); } - if (vring->va && (vring->size < 1025)) { + if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { uint i; for (i = 0; i < vring->size; i++) { volatile struct vring_tx_desc *d = &vring->va[i].tx; - if ((i % 64) == 0 && (i != 0)) + if ((i % 128) == 0 && (i != 0)) seq_puts(s, "\n"); seq_printf(s, "%c", (d->dma.status & BIT(0)) ? _s : (vring->ctx[i].skb ? _h : 'h')); @@ -346,6 +347,10 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, tbl[i].mode, dbg, base + tbl[i].off); break; + case doff_u8: + f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, + base + tbl[i].off); + break; default: f = ERR_PTR(-EINVAL); } @@ -827,9 +832,9 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; - struct wil6210_mbox_hdr_wmi *wmi; + struct wmi_cmd_hdr *wmi; void *cmd; - int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi); + int cmdlen = len - sizeof(struct wmi_cmd_hdr); u16 cmdid; int rc, rc1; @@ -847,7 +852,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, } cmd = &wmi[1]; - cmdid = le16_to_cpu(wmi->id); + cmdid = le16_to_cpu(wmi->command_id); rc1 = wmi_send(wil, cmdid, cmd, cmdlen); kfree(wmi); @@ -991,7 +996,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) .interval_usec = 0, }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_notify_req_done_event evt; } __packed reply; @@ -1339,6 +1344,34 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) r->ssn_last_drop); } +static void wil_print_rxtid_crypto(struct seq_file *s, int tid, + struct wil_tid_crypto_rx *c) +{ + int i; + + for (i = 0; i < 4; i++) { + struct wil_tid_crypto_rx_single *cc = &c->key_id[i]; + + if (cc->key_set) + goto has_keys; + } + return; + +has_keys: + if (tid < WIL_STA_TID_NUM) + seq_printf(s, " [%2d] PN", tid); + else + seq_puts(s, " [GR] PN"); + + for (i = 0; i < 4; i++) { + struct wil_tid_crypto_rx_single *cc = &c->key_id[i]; + + seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-", + cc->pn); + } + seq_puts(s, "\n"); +} + static int wil_sta_debugfs_show(struct seq_file *s, void *data) __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) { @@ -1366,18 +1399,25 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) spin_lock_bh(&p->tid_rx_lock); for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; + struct wil_tid_crypto_rx *c = + &p->tid_crypto_rx[tid]; if (r) { - seq_printf(s, "[%2d] ", tid); + seq_printf(s, " [%2d] ", tid); wil_print_rxtid(s, r); } + + wil_print_rxtid_crypto(s, tid, c); } + wil_print_rxtid_crypto(s, WIL_STA_TID_NUM, + &p->group_crypto_rx); spin_unlock_bh(&p->tid_rx_lock); seq_printf(s, - "Rx invalid frame: non-data %lu, short %lu, large %lu\n", + "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n", p->stats.rx_non_data_frame, p->stats.rx_short_frame, - p->stats.rx_large_frame); + p->stats.rx_large_frame, + p->stats.rx_replay); seq_puts(s, "Rx/MCS:"); for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); @@ -1493,6 +1533,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), WIL_FIELD(ap_isolate, S_IRUGO, doff_u32), + WIL_FIELD(discovery_mode, S_IRUGO | S_IWUSR, doff_u8), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 4f2ffa5c6e17..ae902958bf55 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -394,9 +394,10 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) wil_fw_core_dump(wil); wil_notify_fw_error(wil); isr &= ~ISR_MISC_FW_ERROR; - if (wil->platform_ops.notify_crash) { + if (wil->platform_ops.notify) { wil_err(wil, "notify platform driver about FW crash"); - wil->platform_ops.notify_crash(wil->platform_handle); + wil->platform_ops.notify(wil->platform_handle, + WIL_PLATFORM_EVT_FW_CRASH); } else { wil_fw_error_recovery(wil); } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 26606ef49d61..f1bdcf4c783b 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -23,9 +23,6 @@ #include "wmi.h" #include "boot_loader.h" -#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 -#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 - bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug"); @@ -152,7 +149,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) might_sleep(); wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, sta->status); - + /* inform upper/lower layers */ if (sta->status != wil_sta_unused) { if (!from_event) wmi_disconnect_sta(wil, sta->addr, reason_code, true); @@ -168,7 +165,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } sta->status = wil_sta_unused; } - + /* reorder buffers */ for (i = 0; i < WIL_STA_TID_NUM; i++) { struct wil_tid_ampdu_rx *r; @@ -180,10 +177,15 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) spin_unlock_bh(&sta->tid_rx_lock); } + /* crypto context */ + memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx)); + memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx)); + /* release vrings */ for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { if (wil->vring2cid_tid[i][0] == cid) wil_vring_fini_tx(wil, i); } + /* statistics */ memset(&sta->stats, 0, sizeof(sta->stats)); } @@ -438,10 +440,11 @@ int wil_priv_init(struct wil6210_priv *wil) for (i = 0; i < WIL6210_MAX_CID; i++) spin_lock_init(&wil->sta[i].tid_rx_lock); + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) + spin_lock_init(&wil->vring_tx_data[i].lock); + mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); - mutex_init(&wil->back_rx_mutex); - mutex_init(&wil->back_tx_mutex); mutex_init(&wil->probe_client_mutex); init_completion(&wil->wmi_ready); @@ -454,13 +457,9 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); - INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); - INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); - INIT_LIST_HEAD(&wil->back_rx_pending); - INIT_LIST_HEAD(&wil->back_tx_pending); INIT_LIST_HEAD(&wil->probe_client_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); @@ -520,10 +519,6 @@ void wil_priv_deinit(struct wil6210_priv *wil) wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); mutex_unlock(&wil->mutex); wmi_event_flush(wil); - wil_back_rx_flush(wil); - cancel_work_sync(&wil->back_rx_worker); - wil_back_tx_flush(wil); - cancel_work_sync(&wil->back_tx_worker); wil_probe_client_flush(wil); cancel_work_sync(&wil->probe_client_worker); destroy_workqueue(wil->wq_service); @@ -622,8 +617,7 @@ static int wil_target_reset(struct wil6210_priv *wil) BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); /* Enable fix for PCIe HW bug, set "No snoop" for RX transactions */ - wil_s(wil, RGF_DMA_PEDI_DIF, BIT_DMA_WR_CMD_ATTR_NO_SNOOP | - BIT_DMA_WR_CMD_ATTR_RELAXED_ORDERING); + wil_s(wil, RGF_DMA_PEDI_DIF, BIT_DMA_WR_CMD_ATTR_NO_SNOOP); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; @@ -641,6 +635,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) static int wil_get_bl_info(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); + struct wiphy *wiphy = wil_to_wiphy(wil); union { struct bl_dedicated_registers_v0 bl0; struct bl_dedicated_registers_v1 bl1; @@ -685,6 +680,7 @@ static int wil_get_bl_info(struct wil6210_priv *wil) } ether_addr_copy(ndev->perm_addr, mac); + ether_addr_copy(wiphy->perm_addr, mac); if (!is_valid_ether_addr(ndev->dev_addr)) ether_addr_copy(ndev->dev_addr, mac); @@ -771,6 +767,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (wil->hw_version == HW_VER_UNKNOWN) return -ENODEV; + if (wil->platform_ops.notify) { + rc = wil->platform_ops.notify(wil->platform_handle, + WIL_PLATFORM_EVT_PRE_RESET); + if (rc) + wil_err(wil, + "%s: PRE_RESET platform notify failed, rc %d\n", + __func__, rc); + } + set_bit(wil_status_resetting, wil->status); cancel_work_sync(&wil->disconnect_worker); @@ -850,8 +855,27 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* we just started MAC, wait for FW ready */ rc = wil_wait_for_fw_ready(wil); - if (rc == 0) /* check FW is responsive */ - rc = wmi_echo(wil); + if (rc) + return rc; + + /* check FW is responsive */ + rc = wmi_echo(wil); + if (rc) { + wil_err(wil, "%s: wmi_echo failed, rc %d\n", + __func__, rc); + return rc; + } + + if (wil->platform_ops.notify) { + rc = wil->platform_ops.notify(wil->platform_handle, + WIL_PLATFORM_EVT_FW_RDY); + if (rc) { + wil_err(wil, + "%s: FW_RDY notify failed, rc %d\n", + __func__, rc); + rc = 0; + } + } } return rc; @@ -943,8 +967,7 @@ int wil_up(struct wil6210_priv *wil) int __wil_down(struct wil6210_priv *wil) { - int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS / - WAIT_FOR_DISCONNECT_INTERVAL_MS; + int rc; WARN_ON(!mutex_is_locked(&wil->mutex)); @@ -968,22 +991,16 @@ int __wil_down(struct wil6210_priv *wil) } if (test_bit(wil_status_fwconnected, wil->status) || - test_bit(wil_status_fwconnecting, wil->status)) - wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); + test_bit(wil_status_fwconnecting, wil->status)) { - /* make sure wil is idle (not connected) */ - mutex_unlock(&wil->mutex); - while (iter--) { - int idle = !test_bit(wil_status_fwconnected, wil->status) && - !test_bit(wil_status_fwconnecting, wil->status); - if (idle) - break; - msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS); + mutex_unlock(&wil->mutex); + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + WMI_DISCONNECT_EVENTID, NULL, 0, + WIL6210_DISCONNECT_TO_MS); + mutex_lock(&wil->mutex); + if (rc) + wil_err(wil, "timeout waiting for disconnect\n"); } - mutex_lock(&wil->mutex); - - if (iter < 0) - wil_err(wil, "timeout waiting for idle FW/HW\n"); wil_reset(wil, false); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 32031e7a11d5..19ed127d4d05 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -291,35 +291,15 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize) return min(max_agg_size, req_agg_wsize); } -/* Block Ack - Rx side (recipient */ +/* Block Ack - Rx side (recipient) */ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl) -{ - struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL); - - if (!req) - return -ENOMEM; - - req->cidxtid = cidxtid; - req->dialog_token = dialog_token; - req->ba_param_set = le16_to_cpu(ba_param_set); - req->ba_timeout = le16_to_cpu(ba_timeout); - req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl); - - mutex_lock(&wil->back_rx_mutex); - list_add_tail(&req->list, &wil->back_rx_pending); - mutex_unlock(&wil->back_rx_mutex); - - queue_work(wil->wq_service, &wil->back_rx_worker); - - return 0; -} - -static void wil_back_rx_handle(struct wil6210_priv *wil, - struct wil_back_rx *req) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { + u16 param_set = le16_to_cpu(ba_param_set); + u16 agg_timeout = le16_to_cpu(ba_timeout); + u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl); struct wil_sta_info *sta; u8 cid, tid; u16 agg_wsize = 0; @@ -328,34 +308,35 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) * bits 2..5: TID * bits 6..15: buffer size */ - u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15); - bool agg_amsdu = !!(req->ba_param_set & BIT(0)); - int ba_policy = req->ba_param_set & BIT(1); - u16 agg_timeout = req->ba_timeout; + u16 req_agg_wsize = WIL_GET_BITS(param_set, 6, 15); + bool agg_amsdu = !!(param_set & BIT(0)); + int ba_policy = param_set & BIT(1); u16 status = WLAN_STATUS_SUCCESS; - u16 ssn = req->ba_seq_ctrl >> 4; + u16 ssn = seq_ctrl >> 4; struct wil_tid_ampdu_rx *r; - int rc; + int rc = 0; might_sleep(); - parse_cidxtid(req->cidxtid, &cid, &tid); + parse_cidxtid(cidxtid, &cid, &tid); /* sanity checks */ if (cid >= WIL6210_MAX_CID) { wil_err(wil, "BACK: invalid CID %d\n", cid); - return; + rc = -EINVAL; + goto out; } sta = &wil->sta[cid]; if (sta->status != wil_sta_connected) { wil_err(wil, "BACK: CID %d not connected\n", cid); - return; + rc = -EINVAL; + goto out; } wil_dbg_wmi(wil, "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n", - cid, sta->addr, tid, req_agg_wsize, req->ba_timeout, - agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn); + cid, sta->addr, tid, req_agg_wsize, agg_timeout, + agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn); /* apply policies */ if (ba_policy) { @@ -365,10 +346,13 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) if (status == WLAN_STATUS_SUCCESS) agg_wsize = wil_agg_size(wil, req_agg_wsize); - rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status, + rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status, agg_amsdu, agg_wsize, agg_timeout); - if (rc || (status != WLAN_STATUS_SUCCESS)) - return; + if (rc || (status != WLAN_STATUS_SUCCESS)) { + wil_err(wil, "%s: do not apply ba, rc(%d), status(%d)\n", + __func__, rc, status); + goto out; + } /* apply */ r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); @@ -376,143 +360,37 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); sta->tid_rx[tid] = r; spin_unlock_bh(&sta->tid_rx_lock); -} - -void wil_back_rx_flush(struct wil6210_priv *wil) -{ - struct wil_back_rx *evt, *t; - wil_dbg_misc(wil, "%s()\n", __func__); - - mutex_lock(&wil->back_rx_mutex); - - list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) { - list_del(&evt->list); - kfree(evt); - } - - mutex_unlock(&wil->back_rx_mutex); -} - -/* Retrieve next ADDBA request from the pending list */ -static struct list_head *next_back_rx(struct wil6210_priv *wil) -{ - struct list_head *ret = NULL; - - mutex_lock(&wil->back_rx_mutex); - - if (!list_empty(&wil->back_rx_pending)) { - ret = wil->back_rx_pending.next; - list_del(ret); - } - - mutex_unlock(&wil->back_rx_mutex); - - return ret; -} - -void wil_back_rx_worker(struct work_struct *work) -{ - struct wil6210_priv *wil = container_of(work, struct wil6210_priv, - back_rx_worker); - struct wil_back_rx *evt; - struct list_head *lh; - - while ((lh = next_back_rx(wil)) != NULL) { - evt = list_entry(lh, struct wil_back_rx, list); - - wil_back_rx_handle(wil, evt); - kfree(evt); - } +out: + return rc; } -/* BACK - Tx (originator) side */ -static void wil_back_tx_handle(struct wil6210_priv *wil, - struct wil_back_tx *req) +/* BACK - Tx side (originator) */ +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) { - struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid]; - int rc; + u8 agg_wsize = wil_agg_size(wil, wsize); + u16 agg_timeout = 0; + struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; + int rc = 0; if (txdata->addba_in_progress) { wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n", - req->ringid); - return; + ringid); + goto out; } if (txdata->agg_wsize) { wil_dbg_misc(wil, - "ADDBA for vring[%d] already established wsize %d\n", - req->ringid, txdata->agg_wsize); - return; + "ADDBA for vring[%d] already done for wsize %d\n", + ringid, txdata->agg_wsize); + goto out; } txdata->addba_in_progress = true; - rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout); - if (rc) + rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout); + if (rc) { + wil_err(wil, "%s: wmi_addba failed, rc (%d)", __func__, rc); txdata->addba_in_progress = false; -} - -static struct list_head *next_back_tx(struct wil6210_priv *wil) -{ - struct list_head *ret = NULL; - - mutex_lock(&wil->back_tx_mutex); - - if (!list_empty(&wil->back_tx_pending)) { - ret = wil->back_tx_pending.next; - list_del(ret); - } - - mutex_unlock(&wil->back_tx_mutex); - - return ret; -} - -void wil_back_tx_worker(struct work_struct *work) -{ - struct wil6210_priv *wil = container_of(work, struct wil6210_priv, - back_tx_worker); - struct wil_back_tx *evt; - struct list_head *lh; - - while ((lh = next_back_tx(wil)) != NULL) { - evt = list_entry(lh, struct wil_back_tx, list); - - wil_back_tx_handle(wil, evt); - kfree(evt); } -} - -void wil_back_tx_flush(struct wil6210_priv *wil) -{ - struct wil_back_tx *evt, *t; - - wil_dbg_misc(wil, "%s()\n", __func__); - - mutex_lock(&wil->back_tx_mutex); - - list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) { - list_del(&evt->list); - kfree(evt); - } - - mutex_unlock(&wil->back_tx_mutex); -} - -int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) -{ - struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL); - - if (!req) - return -ENOMEM; - req->ringid = ringid; - req->agg_wsize = wil_agg_size(wil, wsize); - req->agg_timeout = 0; - - mutex_lock(&wil->back_tx_mutex); - list_add_tail(&req->list, &wil->back_tx_pending); - mutex_unlock(&wil->back_tx_mutex); - - queue_work(wil->wq_service, &wil->back_tx_worker); - - return 0; +out: + return rc; } diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h index e59239d22b94..c4db2a9d9f7f 100644 --- a/drivers/net/wireless/ath/wil6210/trace.h +++ b/drivers/net/wireless/ath/wil6210/trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Qualcomm Atheros, Inc. + * Copyright (c) 2013-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,39 +37,40 @@ static inline void trace_ ## name(proto) {} #endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */ DECLARE_EVENT_CLASS(wil6210_wmi, - TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len), + TP_PROTO(struct wmi_cmd_hdr *wmi, void *buf, u16 buf_len), TP_ARGS(wmi, buf, buf_len), TP_STRUCT__entry( __field(u8, mid) - __field(u16, id) - __field(u32, timestamp) + __field(u16, command_id) + __field(u32, fw_timestamp) __field(u16, buf_len) __dynamic_array(u8, buf, buf_len) ), TP_fast_assign( __entry->mid = wmi->mid; - __entry->id = le16_to_cpu(wmi->id); - __entry->timestamp = le32_to_cpu(wmi->timestamp); + __entry->command_id = le16_to_cpu(wmi->command_id); + __entry->fw_timestamp = le32_to_cpu(wmi->fw_timestamp); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), TP_printk( "MID %d id 0x%04x len %d timestamp %d", - __entry->mid, __entry->id, __entry->buf_len, __entry->timestamp + __entry->mid, __entry->command_id, __entry->buf_len, + __entry->fw_timestamp ) ); DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd, - TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len), + TP_PROTO(struct wmi_cmd_hdr *wmi, void *buf, u16 buf_len), TP_ARGS(wmi, buf, buf_len) ); DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event, - TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len), + TP_PROTO(struct wmi_cmd_hdr *wmi, void *buf, u16 buf_len), TP_ARGS(wmi, buf, buf_len) ); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 9680b970b863..f260b232fd57 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -549,6 +549,60 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) return rc; } +/** + * reverse_memcmp - Compare two areas of memory, in reverse order + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + * + * Cut'n'paste from original memcmp (see lib/string.c) + * with minimal modifications + */ +static int reverse_memcmp(const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for (su1 = cs + count - 1, su2 = ct + count - 1; count > 0; + --su1, --su2, count--) { + res = *su1 - *su2; + if (res) + break; + } + return res; +} + +static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb) +{ + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int cid = wil_rxdesc_cid(d); + int tid = wil_rxdesc_tid(d); + int key_id = wil_rxdesc_key_id(d); + int mc = wil_rxdesc_mcast(d); + struct wil_sta_info *s = &wil->sta[cid]; + struct wil_tid_crypto_rx *c = mc ? &s->group_crypto_rx : + &s->tid_crypto_rx[tid]; + struct wil_tid_crypto_rx_single *cc = &c->key_id[key_id]; + const u8 *pn = (u8 *)&d->mac.pn_15_0; + + if (!cc->key_set) { + wil_err_ratelimited(wil, + "Key missing. CID %d TID %d MCast %d KEY_ID %d\n", + cid, tid, mc, key_id); + return -EINVAL; + } + + if (reverse_memcmp(pn, cc->pn, IEEE80211_GCMP_PN_LEN) <= 0) { + wil_err_ratelimited(wil, + "Replay attack. CID %d TID %d MCast %d KEY_ID %d PN %6phN last %6phN\n", + cid, tid, mc, key_id, pn, cc->pn); + return -EINVAL; + } + memcpy(cc->pn, pn, IEEE80211_GCMP_PN_LEN); + + return 0; +} + /* * Pass Rx packet to the netif. Update statistics. * Called in softirq context (NAPI poll). @@ -561,6 +615,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) unsigned int len = skb->len; struct vring_rx_desc *d = wil_skb_rxdesc(skb); int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ + int security = wil_rxdesc_security(d); struct ethhdr *eth = (void *)skb->data; /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication * is not suitable, need to look at data @@ -586,6 +641,13 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) skb_orphan(skb); + if (security && (wil_rx_crypto_check(wil, skb) != 0)) { + rc = GRO_DROP; + dev_kfree_skb(skb); + stats->rx_replay++; + goto stats; + } + if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { if (mcast) { /* send multicast frames both to higher layers in @@ -627,6 +689,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", len, gro_res_str[rc]); } +stats: /* statistics. rc set to GRO_NORMAL for AP bridging */ if (unlikely(rc == GRO_DROP)) { ndev->stats.rx_dropped++; @@ -717,6 +780,21 @@ void wil_rx_fini(struct wil6210_priv *wil) wil_vring_free(wil, vring, 0); } +static inline void wil_tx_data_init(struct vring_tx_data *txdata) +{ + spin_lock_bh(&txdata->lock); + txdata->dot1x_open = 0; + txdata->enabled = 0; + txdata->idle = 0; + txdata->last_idle = 0; + txdata->begin = 0; + txdata->agg_wsize = 0; + txdata->agg_timeout = 0; + txdata->agg_amsdu = 0; + txdata->addba_in_progress = false; + spin_unlock_bh(&txdata->lock); +} + int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, int cid, int tid) { @@ -742,7 +820,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, }, }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_vring_cfg_done_event cmd; } __packed reply; struct vring *vring = &wil->vring_tx[id]; @@ -758,8 +836,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, goto out; } - memset(txdata, 0, sizeof(*txdata)); - spin_lock_init(&txdata->lock); + wil_tx_data_init(txdata); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -791,8 +868,10 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, return 0; out_free: + spin_lock_bh(&txdata->lock); txdata->dot1x_open = false; txdata->enabled = 0; + spin_unlock_bh(&txdata->lock); wil_vring_free(wil, vring, 1); wil->vring2cid_tid[id][0] = WIL6210_MAX_CID; wil->vring2cid_tid[id][1] = 0; @@ -818,7 +897,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) }, }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_vring_cfg_done_event cmd; } __packed reply; struct vring *vring = &wil->vring_tx[id]; @@ -834,8 +913,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) goto out; } - memset(txdata, 0, sizeof(*txdata)); - spin_lock_init(&txdata->lock); + wil_tx_data_init(txdata); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -865,8 +943,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) return 0; out_free: + spin_lock_bh(&txdata->lock); txdata->enabled = 0; txdata->dot1x_open = false; + spin_unlock_bh(&txdata->lock); wil_vring_free(wil, vring, 1); out: @@ -894,7 +974,6 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) napi_synchronize(&wil->napi_tx); wil_vring_free(wil, vring, 1); - memset(txdata, 0, sizeof(*txdata)); } static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index ee7c7b4b9a17..fcdffaa8251b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -480,6 +480,16 @@ static inline int wil_rxdesc_ext_subtype(struct vring_rx_desc *d) return WIL_GET_BITS(d->mac.d0, 28, 31); } +static inline int wil_rxdesc_key_id(struct vring_rx_desc *d) +{ + return WIL_GET_BITS(d->mac.d1, 4, 5); +} + +static inline int wil_rxdesc_security(struct vring_rx_desc *d) +{ + return WIL_GET_BITS(d->mac.d1, 7, 7); +} + static inline int wil_rxdesc_ds_bits(struct vring_rx_desc *d) { return WIL_GET_BITS(d->mac.d1, 8, 9); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e07ce3832c27..fa0df00c1c11 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -22,6 +22,7 @@ #include <net/cfg80211.h> #include <linux/timex.h> #include <linux/types.h> +#include "wmi.h" #include "wil_platform.h" extern bool no_fw_recovery; @@ -51,7 +52,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) -#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_RING_SIZE_ORDER_DEFAULT (12) #define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7) #define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */ /* limit ring size in range [32..32k] */ @@ -92,6 +93,7 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ #define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000) #define WIL6210_SCAN_TO msecs_to_jiffies(10000) +#define WIL6210_DISCONNECT_TO_MS (2000) #define WIL6210_RX_HIGH_TRSH_INIT (0) #define WIL6210_RX_HIGH_TRSH_DEFAULT \ (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3)) @@ -336,29 +338,11 @@ struct wil6210_mbox_hdr { /* max. value for wil6210_mbox_hdr.len */ #define MAX_MBOXITEM_SIZE (240) -/** - * struct wil6210_mbox_hdr_wmi - WMI header - * - * @mid: MAC ID - * 00 - default, created by FW - * 01..0f - WiFi ports, driver to create - * 10..fe - debug - * ff - broadcast - * @id: command/event ID - * @timestamp: FW fills for events, free-running msec timer - */ -struct wil6210_mbox_hdr_wmi { - u8 mid; - u8 reserved; - __le16 id; - __le32 timestamp; -} __packed; - struct pending_wmi_event { struct list_head list; struct { struct wil6210_mbox_hdr hdr; - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; u8 data[0]; } __packed event; }; @@ -457,6 +441,21 @@ struct wil_tid_ampdu_rx { bool first_time; /* is it 1-st time this buffer used? */ }; +/** + * struct wil_tid_crypto_rx_single - TID crypto information (Rx). + * + * @pn: GCMP PN for the session + * @key_set: valid key present + */ +struct wil_tid_crypto_rx_single { + u8 pn[IEEE80211_GCMP_PN_LEN]; + bool key_set; +}; + +struct wil_tid_crypto_rx { + struct wil_tid_crypto_rx_single key_id[4]; +}; + enum wil_sta_status { wil_sta_unused = 0, wil_sta_conn_pending = 1, @@ -476,6 +475,7 @@ struct wil_net_stats { unsigned long rx_non_data_frame; unsigned long rx_short_frame; unsigned long rx_large_frame; + unsigned long rx_replay; u16 last_mcs_rx; u64 rx_per_mcs[WIL_MCS_MAX + 1]; }; @@ -497,6 +497,8 @@ struct wil_sta_info { spinlock_t tid_rx_lock; /* guarding tid_rx array */ unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; + struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM]; + struct wil_tid_crypto_rx group_crypto_rx; }; enum { @@ -509,24 +511,6 @@ enum { hw_capability_last }; -struct wil_back_rx { - struct list_head list; - /* request params, converted to CPU byte order - what we asked for */ - u8 cidxtid; - u8 dialog_token; - u16 ba_param_set; - u16 ba_timeout; - u16 ba_seq_ctrl; -}; - -struct wil_back_tx { - struct list_head list; - /* request params, converted to CPU byte order - what we asked for */ - u8 ringid; - u8 agg_wsize; - u16 agg_timeout; -}; - struct wil_probe_client_req { struct list_head list; u64 cookie; @@ -597,13 +581,6 @@ struct wil6210_priv { spinlock_t wmi_ev_lock; struct napi_struct napi_rx; struct napi_struct napi_tx; - /* BACK */ - struct list_head back_rx_pending; - struct mutex back_rx_mutex; /* protect @back_rx_pending */ - struct work_struct back_rx_worker; - struct list_head back_tx_pending; - struct mutex back_tx_mutex; /* protect @back_tx_pending */ - struct work_struct back_tx_worker; /* keep alive */ struct list_head probe_client_pending; struct mutex probe_client_mutex; /* protect @probe_client_pending */ @@ -624,6 +601,7 @@ struct wil6210_priv { /* debugfs */ struct dentry *debug; struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; + u8 discovery_mode; void *platform_handle; struct wil_platform_ops platform_ops; @@ -767,11 +745,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl); -void wil_back_rx_worker(struct work_struct *work); -void wil_back_rx_flush(struct wil6210_priv *wil); int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize); -void wil_back_tx_worker(struct work_struct *work); -void wil_back_tx_flush(struct wil6210_priv *wil); void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index 9a949d910343..33d4a34b3b1c 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -19,6 +19,12 @@ struct device; +enum wil_platform_event { + WIL_PLATFORM_EVT_FW_CRASH = 0, + WIL_PLATFORM_EVT_PRE_RESET = 1, + WIL_PLATFORM_EVT_FW_RDY = 2, +}; + /** * struct wil_platform_ops - wil platform module calls from this * driver to platform driver @@ -28,7 +34,7 @@ struct wil_platform_ops { int (*suspend)(void *handle); int (*resume)(void *handle); void (*uninit)(void *handle); - int (*notify_crash)(void *handle); + int (*notify)(void *handle, enum wil_platform_event evt); }; /** diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index e1a6cb8840ed..db7d2b602d1a 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -176,7 +176,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) { struct { struct wil6210_mbox_hdr hdr; - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; } __packed cmd = { .hdr = { .type = WIL_MBOX_HDR_TYPE_WMI, @@ -185,7 +185,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) }, .wmi = { .mid = 0, - .id = cpu_to_le16(cmdid), + .command_id = cpu_to_le16(cmdid), }, }; struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx; @@ -487,6 +487,14 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) return; } del_timer_sync(&wil->connect_timer); + } else if ((wdev->iftype == NL80211_IFTYPE_AP) || + (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { + if (wil->sta[evt->cid].status != wil_sta_unused) { + wil_err(wil, "%s: AP: Invalid status %d for CID %d\n", + __func__, wil->sta[evt->cid].status, evt->cid); + mutex_unlock(&wil->mutex); + return; + } } /* FIXME FW can transmit only ucast frames to peer */ @@ -648,7 +656,7 @@ static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len) static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { - struct wmi_vring_ba_status_event *evt = d; + struct wmi_ba_status_event *evt = d; struct vring_tx_data *txdata; wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n", @@ -834,10 +842,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) offsetof(struct wil6210_mbox_ring_desc, sync), 0); /* indicate */ if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && - (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { - struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; - u16 id = le16_to_cpu(wmi->id); - u32 tstamp = le32_to_cpu(wmi->timestamp); + (len >= sizeof(struct wmi_cmd_hdr))) { + struct wmi_cmd_hdr *wmi = &evt->event.wmi; + u16 id = le16_to_cpu(wmi->command_id); + u32 tstamp = le32_to_cpu(wmi->fw_timestamp); + spin_lock_irqsave(&wil->wmi_ev_lock, flags); if (wil->reply_id && wil->reply_id == id) { if (wil->reply_buf) { memcpy(wil->reply_buf, wmi, @@ -845,6 +854,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) immed_reply = true; } } + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n", id, wmi->mid, tstamp); @@ -888,13 +898,16 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, mutex_lock(&wil->wmi_mutex); + spin_lock(&wil->wmi_ev_lock); + wil->reply_id = reply_id; + wil->reply_buf = reply; + wil->reply_size = reply_size; + spin_unlock(&wil->wmi_ev_lock); + rc = __wmi_send(wil, cmdid, buf, len); if (rc) goto out; - wil->reply_id = reply_id; - wil->reply_buf = reply; - wil->reply_size = reply_size; remain = wait_for_completion_timeout(&wil->wmi_call, msecs_to_jiffies(to_msec)); if (0 == remain) { @@ -907,10 +920,14 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, cmdid, reply_id, to_msec - jiffies_to_msecs(remain)); } + +out: + spin_lock(&wil->wmi_ev_lock); wil->reply_id = 0; wil->reply_buf = NULL; wil->reply_size = 0; - out: + spin_unlock(&wil->wmi_ev_lock); + mutex_unlock(&wil->wmi_mutex); return rc; @@ -951,7 +968,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, .hidden_ssid = hidden_ssid, }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_pcp_started_event evt; } __packed reply; @@ -1005,7 +1022,7 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) { int rc; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_set_ssid_cmd cmd; } __packed reply; int len; /* reply.cmd.ssid_len in CPU order */ @@ -1038,7 +1055,7 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel) { int rc; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_set_pcp_channel_cmd cmd; } __packed reply; @@ -1146,7 +1163,7 @@ int wmi_rxon(struct wil6210_priv *wil, bool on) { int rc; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_listen_started_event evt; } __packed reply; @@ -1183,7 +1200,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh), }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_cfg_rx_chain_done_event evt; } __packed evt; int rc; @@ -1237,7 +1254,7 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW), }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_temp_sense_done_event evt; } __packed reply; @@ -1263,7 +1280,7 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason, .disconnect_reason = cpu_to_le16(reason), }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_disconnect_event evt; } __packed reply; @@ -1355,7 +1372,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, .ba_timeout = cpu_to_le16(timeout), }; struct { - struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cmd_hdr wmi; struct wmi_rcp_addba_resp_sent_event evt; } __packed reply; @@ -1411,10 +1428,10 @@ static void wmi_event_handle(struct wil6210_priv *wil, u16 len = le16_to_cpu(hdr->len); if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) && - (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { - struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]); + (len >= sizeof(struct wmi_cmd_hdr))) { + struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]); void *evt_data = (void *)(&wmi[1]); - u16 id = le16_to_cpu(wmi->id); + u16 id = le16_to_cpu(wmi->command_id); wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n", id, wil->reply_id); diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 6e90e78f1554..29865e0b5203 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. - * Copyright (c) 2006-2012 Wilocity . + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2006-2012 Wilocity * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,187 +17,197 @@ /* * This file contains the definitions of the WMI protocol specified in the - * Wireless Module Interface (WMI) for the Wilocity - * MARLON 60 Gigabit wireless solution. + * Wireless Module Interface (WMI) for the Qualcomm + * 60 GHz wireless solution. * It includes definitions of all the commands and events. * Commands are messages from the host to the WM. * Events are messages from the WM to the host. + * + * This is an automatically generated file. */ #ifndef __WILOCITY_WMI_H__ #define __WILOCITY_WMI_H__ /* General */ -#define WILOCITY_MAX_ASSOC_STA (8) -#define WILOCITY_DEFAULT_ASSOC_STA (1) -#define WMI_MAC_LEN (6) -#define WMI_PROX_RANGE_NUM (3) -#define WMI_MAX_LOSS_DMG_BEACONS (32) +#define WMI_MAX_ASSOC_STA (8) +#define WMI_DEFAULT_ASSOC_STA (1) +#define WMI_MAC_LEN (6) +#define WMI_PROX_RANGE_NUM (3) +#define WMI_MAX_LOSS_DMG_BEACONS (20) + +/* Mailbox interface + * used for commands and events + */ +enum wmi_mid { + MID_DEFAULT = 0x00, + FIRST_DBG_MID_ID = 0x10, + LAST_DBG_MID_ID = 0xFE, + MID_BROADCAST = 0xFF, +}; + +/* WMI_CMD_HDR */ +struct wmi_cmd_hdr { + u8 mid; + u8 reserved; + __le16 command_id; + __le32 fw_timestamp; +} __packed; /* List of Commands */ enum wmi_command_id { - WMI_CONNECT_CMDID = 0x0001, - WMI_DISCONNECT_CMDID = 0x0003, - WMI_DISCONNECT_STA_CMDID = 0x0004, - WMI_START_SCAN_CMDID = 0x0007, - WMI_SET_BSS_FILTER_CMDID = 0x0009, - WMI_SET_PROBED_SSID_CMDID = 0x000a, - WMI_SET_LISTEN_INT_CMDID = 0x000b, - WMI_BCON_CTRL_CMDID = 0x000f, - WMI_ADD_CIPHER_KEY_CMDID = 0x0016, - WMI_DELETE_CIPHER_KEY_CMDID = 0x0017, - WMI_SET_APPIE_CMDID = 0x003f, - WMI_SET_WSC_STATUS_CMDID = 0x0041, - WMI_PXMT_RANGE_CFG_CMDID = 0x0042, - WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, -/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */ - WMI_MEM_READ_CMDID = 0x0800, - WMI_MEM_WR_CMDID = 0x0801, - WMI_ECHO_CMDID = 0x0803, - WMI_DEEP_ECHO_CMDID = 0x0804, - WMI_CONFIG_MAC_CMDID = 0x0805, - WMI_CONFIG_PHY_DEBUG_CMDID = 0x0806, - WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x0808, - WMI_PHY_GET_STATISTICS_CMDID = 0x0809, - WMI_FS_TUNE_CMDID = 0x080a, - WMI_CORR_MEASURE_CMDID = 0x080b, - WMI_READ_RSSI_CMDID = 0x080c, - WMI_TEMP_SENSE_CMDID = 0x080e, - WMI_DC_CALIB_CMDID = 0x080f, - WMI_SEND_TONE_CMDID = 0x0810, - WMI_IQ_TX_CALIB_CMDID = 0x0811, - WMI_IQ_RX_CALIB_CMDID = 0x0812, - WMI_SET_UCODE_IDLE_CMDID = 0x0813, - WMI_SET_WORK_MODE_CMDID = 0x0815, - WMI_LO_LEAKAGE_CALIB_CMDID = 0x0816, - WMI_MARLON_R_READ_CMDID = 0x0818, - WMI_MARLON_R_WRITE_CMDID = 0x0819, - WMI_MARLON_R_TXRX_SEL_CMDID = 0x081a, - MAC_IO_STATIC_PARAMS_CMDID = 0x081b, - MAC_IO_DYNAMIC_PARAMS_CMDID = 0x081c, - WMI_SILENT_RSSI_CALIB_CMDID = 0x081d, - WMI_RF_RX_TEST_CMDID = 0x081e, - WMI_CFG_RX_CHAIN_CMDID = 0x0820, - WMI_VRING_CFG_CMDID = 0x0821, - WMI_BCAST_VRING_CFG_CMDID = 0x0822, - WMI_VRING_BA_EN_CMDID = 0x0823, - WMI_VRING_BA_DIS_CMDID = 0x0824, - WMI_RCP_ADDBA_RESP_CMDID = 0x0825, - WMI_RCP_DELBA_CMDID = 0x0826, - WMI_SET_SSID_CMDID = 0x0827, - WMI_GET_SSID_CMDID = 0x0828, - WMI_SET_PCP_CHANNEL_CMDID = 0x0829, - WMI_GET_PCP_CHANNEL_CMDID = 0x082a, - WMI_SW_TX_REQ_CMDID = 0x082b, - WMI_READ_MAC_RXQ_CMDID = 0x0830, - WMI_READ_MAC_TXQ_CMDID = 0x0831, - WMI_WRITE_MAC_RXQ_CMDID = 0x0832, - WMI_WRITE_MAC_TXQ_CMDID = 0x0833, - WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x0834, - WMI_MLME_PUSH_CMDID = 0x0835, - WMI_BEAMFORMING_MGMT_CMDID = 0x0836, - WMI_BF_TXSS_MGMT_CMDID = 0x0837, - WMI_BF_SM_MGMT_CMDID = 0x0838, - WMI_BF_RXSS_MGMT_CMDID = 0x0839, - WMI_BF_TRIG_CMDID = 0x083A, - WMI_SET_SECTORS_CMDID = 0x0849, - WMI_MAINTAIN_PAUSE_CMDID = 0x0850, - WMI_MAINTAIN_RESUME_CMDID = 0x0851, - WMI_RS_MGMT_CMDID = 0x0852, - WMI_RF_MGMT_CMDID = 0x0853, - WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854, - WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855, + WMI_CONNECT_CMDID = 0x01, + WMI_DISCONNECT_CMDID = 0x03, + WMI_DISCONNECT_STA_CMDID = 0x04, + WMI_START_SCAN_CMDID = 0x07, + WMI_SET_BSS_FILTER_CMDID = 0x09, + WMI_SET_PROBED_SSID_CMDID = 0x0A, + WMI_SET_LISTEN_INT_CMDID = 0x0B, + WMI_BCON_CTRL_CMDID = 0x0F, + WMI_ADD_CIPHER_KEY_CMDID = 0x16, + WMI_DELETE_CIPHER_KEY_CMDID = 0x17, + WMI_PCP_CONF_CMDID = 0x18, + WMI_SET_APPIE_CMDID = 0x3F, + WMI_SET_WSC_STATUS_CMDID = 0x41, + WMI_PXMT_RANGE_CFG_CMDID = 0x42, + WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43, + WMI_MEM_READ_CMDID = 0x800, + WMI_MEM_WR_CMDID = 0x801, + WMI_ECHO_CMDID = 0x803, + WMI_DEEP_ECHO_CMDID = 0x804, + WMI_CONFIG_MAC_CMDID = 0x805, + WMI_CONFIG_PHY_DEBUG_CMDID = 0x806, + WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808, + WMI_PHY_GET_STATISTICS_CMDID = 0x809, + WMI_FS_TUNE_CMDID = 0x80A, + WMI_CORR_MEASURE_CMDID = 0x80B, + WMI_READ_RSSI_CMDID = 0x80C, + WMI_TEMP_SENSE_CMDID = 0x80E, + WMI_DC_CALIB_CMDID = 0x80F, + WMI_SEND_TONE_CMDID = 0x810, + WMI_IQ_TX_CALIB_CMDID = 0x811, + WMI_IQ_RX_CALIB_CMDID = 0x812, + WMI_SET_UCODE_IDLE_CMDID = 0x813, + WMI_SET_WORK_MODE_CMDID = 0x815, + WMI_LO_LEAKAGE_CALIB_CMDID = 0x816, + WMI_MARLON_R_READ_CMDID = 0x818, + WMI_MARLON_R_WRITE_CMDID = 0x819, + WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A, + MAC_IO_STATIC_PARAMS_CMDID = 0x81B, + MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C, + WMI_SILENT_RSSI_CALIB_CMDID = 0x81D, + WMI_RF_RX_TEST_CMDID = 0x81E, + WMI_CFG_RX_CHAIN_CMDID = 0x820, + WMI_VRING_CFG_CMDID = 0x821, + WMI_BCAST_VRING_CFG_CMDID = 0x822, + WMI_VRING_BA_EN_CMDID = 0x823, + WMI_VRING_BA_DIS_CMDID = 0x824, + WMI_RCP_ADDBA_RESP_CMDID = 0x825, + WMI_RCP_DELBA_CMDID = 0x826, + WMI_SET_SSID_CMDID = 0x827, + WMI_GET_SSID_CMDID = 0x828, + WMI_SET_PCP_CHANNEL_CMDID = 0x829, + WMI_GET_PCP_CHANNEL_CMDID = 0x82A, + WMI_SW_TX_REQ_CMDID = 0x82B, + WMI_READ_MAC_RXQ_CMDID = 0x830, + WMI_READ_MAC_TXQ_CMDID = 0x831, + WMI_WRITE_MAC_RXQ_CMDID = 0x832, + WMI_WRITE_MAC_TXQ_CMDID = 0x833, + WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834, + WMI_MLME_PUSH_CMDID = 0x835, + WMI_BEAMFORMING_MGMT_CMDID = 0x836, + WMI_BF_TXSS_MGMT_CMDID = 0x837, + WMI_BF_SM_MGMT_CMDID = 0x838, + WMI_BF_RXSS_MGMT_CMDID = 0x839, + WMI_BF_TRIG_CMDID = 0x83A, + WMI_SET_SECTORS_CMDID = 0x849, + WMI_MAINTAIN_PAUSE_CMDID = 0x850, + WMI_MAINTAIN_RESUME_CMDID = 0x851, + WMI_RS_MGMT_CMDID = 0x852, + WMI_RF_MGMT_CMDID = 0x853, + WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854, + WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855, + WMI_OTP_READ_CMDID = 0x856, + WMI_OTP_WRITE_CMDID = 0x857, /* Performance monitoring commands */ - WMI_BF_CTRL_CMDID = 0x0862, - WMI_NOTIFY_REQ_CMDID = 0x0863, - WMI_GET_STATUS_CMDID = 0x0864, - WMI_UNIT_TEST_CMDID = 0x0900, - WMI_HICCUP_CMDID = 0x0901, - WMI_FLASH_READ_CMDID = 0x0902, - WMI_FLASH_WRITE_CMDID = 0x0903, - WMI_SECURITY_UNIT_TEST_CMDID = 0x0904, - /*P2P*/ - WMI_P2P_CFG_CMDID = 0x0910, - WMI_PORT_ALLOCATE_CMDID = 0x0911, - WMI_PORT_DELETE_CMDID = 0x0912, - WMI_POWER_MGMT_CFG_CMDID = 0x0913, - WMI_START_LISTEN_CMDID = 0x0914, - WMI_START_SEARCH_CMDID = 0x0915, - WMI_DISCOVERY_START_CMDID = 0x0916, - WMI_DISCOVERY_STOP_CMDID = 0x0917, - WMI_PCP_START_CMDID = 0x0918, - WMI_PCP_STOP_CMDID = 0x0919, - WMI_GET_PCP_FACTOR_CMDID = 0x091b, - - WMI_SET_MAC_ADDRESS_CMDID = 0xf003, - WMI_ABORT_SCAN_CMDID = 0xf007, - WMI_SET_PMK_CMDID = 0xf028, - - WMI_SET_PROMISCUOUS_MODE_CMDID = 0xf041, - WMI_GET_PMK_CMDID = 0xf048, - WMI_SET_PASSPHRASE_CMDID = 0xf049, - WMI_SEND_ASSOC_RES_CMDID = 0xf04a, - WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xf04b, - WMI_EAPOL_TX_CMDID = 0xf04c, - WMI_MAC_ADDR_REQ_CMDID = 0xf04d, - WMI_FW_VER_CMDID = 0xf04e, - WMI_PMC_CMDID = 0xf04f, + WMI_BF_CTRL_CMDID = 0x862, + WMI_NOTIFY_REQ_CMDID = 0x863, + WMI_GET_STATUS_CMDID = 0x864, + WMI_UNIT_TEST_CMDID = 0x900, + WMI_HICCUP_CMDID = 0x901, + WMI_FLASH_READ_CMDID = 0x902, + WMI_FLASH_WRITE_CMDID = 0x903, + /* P2P */ + WMI_P2P_CFG_CMDID = 0x910, + WMI_PORT_ALLOCATE_CMDID = 0x911, + WMI_PORT_DELETE_CMDID = 0x912, + WMI_POWER_MGMT_CFG_CMDID = 0x913, + WMI_START_LISTEN_CMDID = 0x914, + WMI_START_SEARCH_CMDID = 0x915, + WMI_DISCOVERY_START_CMDID = 0x916, + WMI_DISCOVERY_STOP_CMDID = 0x917, + WMI_PCP_START_CMDID = 0x918, + WMI_PCP_STOP_CMDID = 0x919, + WMI_GET_PCP_FACTOR_CMDID = 0x91B, + WMI_SET_MAC_ADDRESS_CMDID = 0xF003, + WMI_ABORT_SCAN_CMDID = 0xF007, + WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, + WMI_GET_PMK_CMDID = 0xF048, + WMI_SET_PASSPHRASE_CMDID = 0xF049, + WMI_SEND_ASSOC_RES_CMDID = 0xF04A, + WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B, + WMI_MAC_ADDR_REQ_CMDID = 0xF04D, + WMI_FW_VER_CMDID = 0xF04E, + WMI_PMC_CMDID = 0xF04F, }; -/* - * Commands data structures - */ - -/* - * WMI_CONNECT_CMDID - */ +/* WMI_CONNECT_CMDID */ enum wmi_network_type { WMI_NETTYPE_INFRA = 0x01, WMI_NETTYPE_ADHOC = 0x02, WMI_NETTYPE_ADHOC_CREATOR = 0x04, WMI_NETTYPE_AP = 0x10, WMI_NETTYPE_P2P = 0x20, - WMI_NETTYPE_WBE = 0x40, /* PCIE over 60g */ + /* PCIE over 60g */ + WMI_NETTYPE_WBE = 0x40, }; enum wmi_dot11_auth_mode { - WMI_AUTH11_OPEN = 0x01, - WMI_AUTH11_SHARED = 0x02, - WMI_AUTH11_LEAP = 0x04, - WMI_AUTH11_WSC = 0x08, + WMI_AUTH11_OPEN = 0x01, + WMI_AUTH11_SHARED = 0x02, + WMI_AUTH11_LEAP = 0x04, + WMI_AUTH11_WSC = 0x08, }; enum wmi_auth_mode { - WMI_AUTH_NONE = 0x01, - WMI_AUTH_WPA = 0x02, - WMI_AUTH_WPA2 = 0x04, - WMI_AUTH_WPA_PSK = 0x08, - WMI_AUTH_WPA2_PSK = 0x10, - WMI_AUTH_WPA_CCKM = 0x20, - WMI_AUTH_WPA2_CCKM = 0x40, + WMI_AUTH_NONE = 0x01, + WMI_AUTH_WPA = 0x02, + WMI_AUTH_WPA2 = 0x04, + WMI_AUTH_WPA_PSK = 0x08, + WMI_AUTH_WPA2_PSK = 0x10, + WMI_AUTH_WPA_CCKM = 0x20, + WMI_AUTH_WPA2_CCKM = 0x40, }; enum wmi_crypto_type { - WMI_CRYPT_NONE = 0x01, - WMI_CRYPT_WEP = 0x02, - WMI_CRYPT_TKIP = 0x04, - WMI_CRYPT_AES = 0x08, - WMI_CRYPT_AES_GCMP = 0x20, + WMI_CRYPT_NONE = 0x01, + WMI_CRYPT_AES_GCMP = 0x20, }; enum wmi_connect_ctrl_flag_bits { - WMI_CONNECT_ASSOC_POLICY_USER = 0x0001, - WMI_CONNECT_SEND_REASSOC = 0x0002, - WMI_CONNECT_IGNORE_WPA_GROUP_CIPHER = 0x0004, - WMI_CONNECT_PROFILE_MATCH_DONE = 0x0008, - WMI_CONNECT_IGNORE_AAC_BEACON = 0x0010, - WMI_CONNECT_CSA_FOLLOW_BSS = 0x0020, - WMI_CONNECT_DO_WPA_OFFLOAD = 0x0040, - WMI_CONNECT_DO_NOT_DEAUTH = 0x0080, + WMI_CONNECT_ASSOC_POLICY_USER = 0x01, + WMI_CONNECT_SEND_REASSOC = 0x02, + WMI_CONNECT_IGNORE_WPA_GROUP_CIPHER = 0x04, + WMI_CONNECT_PROFILE_MATCH_DONE = 0x08, + WMI_CONNECT_IGNORE_AAC_BEACON = 0x10, + WMI_CONNECT_CSA_FOLLOW_BSS = 0x20, + WMI_CONNECT_DO_WPA_OFFLOAD = 0x40, + WMI_CONNECT_DO_NOT_DEAUTH = 0x80, }; -#define WMI_MAX_SSID_LEN (32) +#define WMI_MAX_SSID_LEN (32) +/* WMI_CONNECT_CMDID */ struct wmi_connect_cmd { u8 network_type; u8 dot11_auth_mode; @@ -216,31 +226,17 @@ struct wmi_connect_cmd { u8 reserved1[2]; } __packed; -/* - * WMI_DISCONNECT_STA_CMDID - */ +/* WMI_DISCONNECT_STA_CMDID */ struct wmi_disconnect_sta_cmd { u8 dst_mac[WMI_MAC_LEN]; __le16 disconnect_reason; } __packed; -/* - * WMI_SET_PMK_CMDID - */ - -#define WMI_MIN_KEY_INDEX (0) #define WMI_MAX_KEY_INDEX (3) #define WMI_MAX_KEY_LEN (32) #define WMI_PASSPHRASE_LEN (64) -#define WMI_PMK_LEN (32) - -struct wmi_set_pmk_cmd { - u8 pmk[WMI_PMK_LEN]; -} __packed; -/* - * WMI_SET_PASSPHRASE_CMDID - */ +/* WMI_SET_PASSPHRASE_CMDID */ struct wmi_set_passphrase_cmd { u8 ssid[WMI_MAX_SSID_LEN]; u8 passphrase[WMI_PASSPHRASE_LEN]; @@ -248,36 +244,34 @@ struct wmi_set_passphrase_cmd { u8 passphrase_len; } __packed; -/* - * WMI_ADD_CIPHER_KEY_CMDID - */ +/* WMI_ADD_CIPHER_KEY_CMDID */ enum wmi_key_usage { - WMI_KEY_USE_PAIRWISE = 0, - WMI_KEY_USE_RX_GROUP = 1, - WMI_KEY_USE_TX_GROUP = 2, + WMI_KEY_USE_PAIRWISE = 0x00, + WMI_KEY_USE_RX_GROUP = 0x01, + WMI_KEY_USE_TX_GROUP = 0x02, }; struct wmi_add_cipher_key_cmd { u8 key_index; u8 key_type; - u8 key_usage; /* enum wmi_key_usage */ + /* enum wmi_key_usage */ + u8 key_usage; u8 key_len; - u8 key_rsc[8]; /* key replay sequence counter */ + /* key replay sequence counter */ + u8 key_rsc[8]; u8 key[WMI_MAX_KEY_LEN]; - u8 key_op_ctrl; /* Additional Key Control information */ + /* Additional Key Control information */ + u8 key_op_ctrl; u8 mac[WMI_MAC_LEN]; } __packed; -/* - * WMI_DELETE_CIPHER_KEY_CMDID - */ +/* WMI_DELETE_CIPHER_KEY_CMDID */ struct wmi_delete_cipher_key_cmd { u8 key_index; u8 mac[WMI_MAC_LEN]; } __packed; -/* - * WMI_START_SCAN_CMDID +/* WMI_START_SCAN_CMDID * * Start L1 scan operation * @@ -286,146 +280,142 @@ struct wmi_delete_cipher_key_cmd { * - WMI_SCAN_COMPLETE_EVENTID */ enum wmi_scan_type { - WMI_LONG_SCAN = 0, - WMI_SHORT_SCAN = 1, - WMI_PBC_SCAN = 2, - WMI_DIRECT_SCAN = 3, - WMI_ACTIVE_SCAN = 4, + WMI_ACTIVE_SCAN = 0x00, + WMI_SHORT_SCAN = 0x01, + WMI_PASSIVE_SCAN = 0x02, + WMI_DIRECT_SCAN = 0x03, + WMI_LONG_SCAN = 0x04, }; +/* WMI_START_SCAN_CMDID */ struct wmi_start_scan_cmd { - u8 direct_scan_mac_addr[6]; - u8 reserved[2]; - __le32 home_dwell_time; /* Max duration in the home channel(ms) */ - __le32 force_scan_interval; /* Time interval between scans (ms)*/ - u8 scan_type; /* wmi_scan_type */ - u8 num_channels; /* how many channels follow */ + u8 direct_scan_mac_addr[WMI_MAC_LEN]; + /* DMG Beacon frame is transmitted during active scanning */ + u8 discovery_mode; + /* reserved */ + u8 reserved; + /* Max duration in the home channel(ms) */ + __le32 dwell_time; + /* Time interval between scans (ms) */ + __le32 force_scan_interval; + /* enum wmi_scan_type */ + u8 scan_type; + /* how many channels follow */ + u8 num_channels; + /* channels ID's: + * 0 - 58320 MHz + * 1 - 60480 MHz + * 2 - 62640 MHz + */ struct { u8 channel; u8 reserved; - } channel_list[0]; /* channels ID's */ - /* 0 - 58320 MHz */ - /* 1 - 60480 MHz */ - /* 2 - 62640 MHz */ + } channel_list[0]; } __packed; -/* - * WMI_SET_PROBED_SSID_CMDID - */ +/* WMI_SET_PROBED_SSID_CMDID */ #define MAX_PROBED_SSID_INDEX (3) enum wmi_ssid_flag { - WMI_SSID_FLAG_DISABLE = 0, /* disables entry */ - WMI_SSID_FLAG_SPECIFIC = 1, /* probes specified ssid */ - WMI_SSID_FLAG_ANY = 2, /* probes for any ssid */ + /* disables entry */ + WMI_SSID_FLAG_DISABLE = 0x00, + /* probes specified ssid */ + WMI_SSID_FLAG_SPECIFIC = 0x01, + /* probes for any ssid */ + WMI_SSID_FLAG_ANY = 0x02, }; struct wmi_probed_ssid_cmd { - u8 entry_index; /* 0 to MAX_PROBED_SSID_INDEX */ - u8 flag; /* enum wmi_ssid_flag */ + /* 0 to MAX_PROBED_SSID_INDEX */ + u8 entry_index; + /* enum wmi_ssid_flag */ + u8 flag; u8 ssid_len; u8 ssid[WMI_MAX_SSID_LEN]; } __packed; -/* - * WMI_SET_APPIE_CMDID +/* WMI_SET_APPIE_CMDID * Add Application specified IE to a management frame */ -#define WMI_MAX_IE_LEN (1024) +#define WMI_MAX_IE_LEN (1024) -/* - * Frame Types - */ +/* Frame Types */ enum wmi_mgmt_frame_type { - WMI_FRAME_BEACON = 0, - WMI_FRAME_PROBE_REQ = 1, - WMI_FRAME_PROBE_RESP = 2, - WMI_FRAME_ASSOC_REQ = 3, - WMI_FRAME_ASSOC_RESP = 4, - WMI_NUM_MGMT_FRAME, + WMI_FRAME_BEACON = 0x00, + WMI_FRAME_PROBE_REQ = 0x01, + WMI_FRAME_PROBE_RESP = 0x02, + WMI_FRAME_ASSOC_REQ = 0x03, + WMI_FRAME_ASSOC_RESP = 0x04, + WMI_NUM_MGMT_FRAME = 0x05, }; struct wmi_set_appie_cmd { - u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ + /* enum wmi_mgmt_frame_type */ + u8 mgmt_frm_type; u8 reserved; - __le16 ie_len; /* Length of the IE to be added to MGMT frame */ + /* Length of the IE to be added to MGMT frame */ + __le16 ie_len; u8 ie_info[0]; } __packed; -/* - * WMI_PXMT_RANGE_CFG_CMDID - */ +/* WMI_PXMT_RANGE_CFG_CMDID */ struct wmi_pxmt_range_cfg_cmd { u8 dst_mac[WMI_MAC_LEN]; __le16 range; } __packed; -/* - * WMI_PXMT_SNR2_RANGE_CFG_CMDID - */ +/* WMI_PXMT_SNR2_RANGE_CFG_CMDID */ struct wmi_pxmt_snr2_range_cfg_cmd { - s8 snr2range_arr[WMI_PROX_RANGE_NUM-1]; + s8 snr2range_arr[2]; } __packed; -/* - * WMI_RF_MGMT_CMDID - */ +/* WMI_RF_MGMT_CMDID */ enum wmi_rf_mgmt_type { - WMI_RF_MGMT_W_DISABLE = 0, - WMI_RF_MGMT_W_ENABLE = 1, - WMI_RF_MGMT_GET_STATUS = 2, + WMI_RF_MGMT_W_DISABLE = 0x00, + WMI_RF_MGMT_W_ENABLE = 0x01, + WMI_RF_MGMT_GET_STATUS = 0x02, }; +/* WMI_RF_MGMT_CMDID */ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; -/* - * WMI_THERMAL_THROTTLING_CTRL_CMDID - */ +/* WMI_THERMAL_THROTTLING_CTRL_CMDID */ #define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) +/* WMI_THERMAL_THROTTLING_CTRL_CMDID */ struct wmi_thermal_throttling_ctrl_cmd { __le32 time_on_usec; __le32 time_off_usec; __le32 max_txop_length_usec; } __packed; -/* - * WMI_RF_RX_TEST_CMDID - */ +/* WMI_RF_RX_TEST_CMDID */ struct wmi_rf_rx_test_cmd { __le32 sector; } __packed; -/* - * WMI_CORR_MEASURE_CMDID - */ +/* WMI_CORR_MEASURE_CMDID */ struct wmi_corr_measure_cmd { - s32 freq_mhz; + __le32 freq_mhz; __le32 length_samples; __le32 iterations; } __packed; -/* - * WMI_SET_SSID_CMDID - */ +/* WMI_SET_SSID_CMDID */ struct wmi_set_ssid_cmd { __le32 ssid_len; u8 ssid[WMI_MAX_SSID_LEN]; } __packed; -/* - * WMI_SET_PCP_CHANNEL_CMDID - */ +/* WMI_SET_PCP_CHANNEL_CMDID */ struct wmi_set_pcp_channel_cmd { u8 channel; u8 reserved[3]; } __packed; -/* - * WMI_BCON_CTRL_CMDID - */ +/* WMI_BCON_CTRL_CMDID */ struct wmi_bcon_ctrl_cmd { __le16 bcon_interval; __le16 frag_num; @@ -434,214 +424,192 @@ struct wmi_bcon_ctrl_cmd { u8 pcp_max_assoc_sta; u8 disable_sec_offload; u8 disable_sec; + u8 hidden_ssid; + u8 is_go; + u8 reserved[2]; } __packed; -/******* P2P ***********/ - -/* - * WMI_PORT_ALLOCATE_CMDID - */ +/* WMI_PORT_ALLOCATE_CMDID */ enum wmi_port_role { - WMI_PORT_STA = 0, - WMI_PORT_PCP = 1, - WMI_PORT_AP = 2, - WMI_PORT_P2P_DEV = 3, - WMI_PORT_P2P_CLIENT = 4, - WMI_PORT_P2P_GO = 5, + WMI_PORT_STA = 0x00, + WMI_PORT_PCP = 0x01, + WMI_PORT_AP = 0x02, + WMI_PORT_P2P_DEV = 0x03, + WMI_PORT_P2P_CLIENT = 0x04, + WMI_PORT_P2P_GO = 0x05, }; +/* WMI_PORT_ALLOCATE_CMDID */ struct wmi_port_allocate_cmd { u8 mac[WMI_MAC_LEN]; u8 port_role; u8 mid; } __packed; -/* - * WMI_PORT_DELETE_CMDID - */ -struct wmi_delete_port_cmd { +/* WMI_PORT_DELETE_CMDID */ +struct wmi_port_delete_cmd { u8 mid; u8 reserved[3]; } __packed; -/* - * WMI_P2P_CFG_CMDID - */ +/* WMI_P2P_CFG_CMDID */ enum wmi_discovery_mode { - WMI_DISCOVERY_MODE_NON_OFFLOAD = 0, - WMI_DISCOVERY_MODE_OFFLOAD = 1, - WMI_DISCOVERY_MODE_PEER2PEER = 2, + WMI_DISCOVERY_MODE_NON_OFFLOAD = 0x00, + WMI_DISCOVERY_MODE_OFFLOAD = 0x01, + WMI_DISCOVERY_MODE_PEER2PEER = 0x02, }; struct wmi_p2p_cfg_cmd { - u8 discovery_mode; /* wmi_discovery_mode */ + /* enum wmi_discovery_mode */ + u8 discovery_mode; u8 channel; - __le16 bcon_interval; /* base to listen/search duration calculation */ + /* base to listen/search duration calculation */ + __le16 bcon_interval; } __packed; -/* - * WMI_POWER_MGMT_CFG_CMDID - */ +/* WMI_POWER_MGMT_CFG_CMDID */ enum wmi_power_source_type { - WMI_POWER_SOURCE_BATTERY = 0, - WMI_POWER_SOURCE_OTHER = 1, + WMI_POWER_SOURCE_BATTERY = 0x00, + WMI_POWER_SOURCE_OTHER = 0x01, }; struct wmi_power_mgmt_cfg_cmd { - u8 power_source; /* wmi_power_source_type */ + /* enum wmi_power_source_type */ + u8 power_source; u8 reserved[3]; } __packed; -/* - * WMI_PCP_START_CMDID - */ - -enum wmi_hidden_ssid { - WMI_HIDDEN_SSID_DISABLED = 0, - WMI_HIDDEN_SSID_SEND_EMPTY = 1, - WMI_HIDDEN_SSID_CLEAR = 2, -}; - +/* WMI_PCP_START_CMDID */ struct wmi_pcp_start_cmd { __le16 bcon_interval; u8 pcp_max_assoc_sta; u8 hidden_ssid; - u8 reserved0[8]; + u8 is_go; + u8 reserved0[7]; u8 network_type; u8 channel; u8 disable_sec_offload; u8 disable_sec; } __packed; -/* - * WMI_SW_TX_REQ_CMDID - */ +/* WMI_SW_TX_REQ_CMDID */ struct wmi_sw_tx_req_cmd { u8 dst_mac[WMI_MAC_LEN]; __le16 len; u8 payload[0]; } __packed; -/* - * WMI_VRING_CFG_CMDID - */ - struct wmi_sw_ring_cfg { __le64 ring_mem_base; __le16 ring_size; __le16 max_mpdu_size; } __packed; +/* wmi_vring_cfg_schd */ struct wmi_vring_cfg_schd { __le16 priority; __le16 timeslot_us; } __packed; enum wmi_vring_cfg_encap_trans_type { - WMI_VRING_ENC_TYPE_802_3 = 0, - WMI_VRING_ENC_TYPE_NATIVE_WIFI = 1, + WMI_VRING_ENC_TYPE_802_3 = 0x00, + WMI_VRING_ENC_TYPE_NATIVE_WIFI = 0x01, }; enum wmi_vring_cfg_ds_cfg { - WMI_VRING_DS_PBSS = 0, - WMI_VRING_DS_STATION = 1, - WMI_VRING_DS_AP = 2, - WMI_VRING_DS_ADDR4 = 3, + WMI_VRING_DS_PBSS = 0x00, + WMI_VRING_DS_STATION = 0x01, + WMI_VRING_DS_AP = 0x02, + WMI_VRING_DS_ADDR4 = 0x03, }; enum wmi_vring_cfg_nwifi_ds_trans_type { - WMI_NWIFI_TX_TRANS_MODE_NO = 0, - WMI_NWIFI_TX_TRANS_MODE_AP2PBSS = 1, - WMI_NWIFI_TX_TRANS_MODE_STA2PBSS = 2, + WMI_NWIFI_TX_TRANS_MODE_NO = 0x00, + WMI_NWIFI_TX_TRANS_MODE_AP2PBSS = 0x01, + WMI_NWIFI_TX_TRANS_MODE_STA2PBSS = 0x02, }; enum wmi_vring_cfg_schd_params_priority { - WMI_SCH_PRIO_REGULAR = 0, - WMI_SCH_PRIO_HIGH = 1, + WMI_SCH_PRIO_REGULAR = 0x00, + WMI_SCH_PRIO_HIGH = 0x01, }; -#define CIDXTID_CID_POS (0) -#define CIDXTID_CID_LEN (4) -#define CIDXTID_CID_MSK (0xF) -#define CIDXTID_TID_POS (4) -#define CIDXTID_TID_LEN (4) -#define CIDXTID_TID_MSK (0xF0) +#define CIDXTID_CID_POS (0) +#define CIDXTID_CID_LEN (4) +#define CIDXTID_CID_MSK (0xF) +#define CIDXTID_TID_POS (4) +#define CIDXTID_TID_LEN (4) +#define CIDXTID_TID_MSK (0xF0) +#define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0) +#define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1) +#define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1) +#define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1) +#define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1) +#define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2) +#define VRING_CFG_TO_RESOLUTION_VALUE_POS (0) +#define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6) +#define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F) struct wmi_vring_cfg { struct wmi_sw_ring_cfg tx_sw_ring; - u8 ringid; /* 0-23 vrings */ - + /* 0-23 vrings */ + u8 ringid; u8 cidxtid; - u8 encap_trans_type; - u8 ds_cfg; /* 802.3 DS cfg */ + /* 802.3 DS cfg */ + u8 ds_cfg; u8 nwifi_ds_trans_type; - - #define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0) - #define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1) - #define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1) - #define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1) - #define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1) - #define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2) u8 mac_ctrl; - - #define VRING_CFG_TO_RESOLUTION_VALUE_POS (0) - #define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6) - #define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F) u8 to_resolution; u8 agg_max_wsize; struct wmi_vring_cfg_schd schd_params; } __packed; enum wmi_vring_cfg_cmd_action { - WMI_VRING_CMD_ADD = 0, - WMI_VRING_CMD_MODIFY = 1, - WMI_VRING_CMD_DELETE = 2, + WMI_VRING_CMD_ADD = 0x00, + WMI_VRING_CMD_MODIFY = 0x01, + WMI_VRING_CMD_DELETE = 0x02, }; +/* WMI_VRING_CFG_CMDID */ struct wmi_vring_cfg_cmd { __le32 action; struct wmi_vring_cfg vring_cfg; } __packed; -/* - * WMI_BCAST_VRING_CFG_CMDID - */ struct wmi_bcast_vring_cfg { struct wmi_sw_ring_cfg tx_sw_ring; - u8 ringid; /* 0-23 vrings */ + /* 0-23 vrings */ + u8 ringid; u8 encap_trans_type; - u8 ds_cfg; /* 802.3 DS cfg */ + /* 802.3 DS cfg */ + u8 ds_cfg; u8 nwifi_ds_trans_type; } __packed; +/* WMI_BCAST_VRING_CFG_CMDID */ struct wmi_bcast_vring_cfg_cmd { __le32 action; struct wmi_bcast_vring_cfg vring_cfg; } __packed; -/* - * WMI_VRING_BA_EN_CMDID - */ +/* WMI_VRING_BA_EN_CMDID */ struct wmi_vring_ba_en_cmd { u8 ringid; u8 agg_max_wsize; __le16 ba_timeout; u8 amsdu; + u8 reserved[3]; } __packed; -/* - * WMI_VRING_BA_DIS_CMDID - */ +/* WMI_VRING_BA_DIS_CMDID */ struct wmi_vring_ba_dis_cmd { u8 ringid; u8 reserved; __le16 reason; } __packed; -/* - * WMI_NOTIFY_REQ_CMDID - */ +/* WMI_NOTIFY_REQ_CMDID */ struct wmi_notify_req_cmd { u8 cid; u8 year; @@ -654,102 +622,100 @@ struct wmi_notify_req_cmd { u8 miliseconds; } __packed; -/* - * WMI_CFG_RX_CHAIN_CMDID - */ +/* WMI_CFG_RX_CHAIN_CMDID */ enum wmi_sniffer_cfg_mode { - WMI_SNIFFER_OFF = 0, - WMI_SNIFFER_ON = 1, + WMI_SNIFFER_OFF = 0x00, + WMI_SNIFFER_ON = 0x01, }; enum wmi_sniffer_cfg_phy_info_mode { - WMI_SNIFFER_PHY_INFO_DISABLED = 0, - WMI_SNIFFER_PHY_INFO_ENABLED = 1, + WMI_SNIFFER_PHY_INFO_DISABLED = 0x00, + WMI_SNIFFER_PHY_INFO_ENABLED = 0x01, }; enum wmi_sniffer_cfg_phy_support { - WMI_SNIFFER_CP = 0, - WMI_SNIFFER_DP = 1, - WMI_SNIFFER_BOTH_PHYS = 2, + WMI_SNIFFER_CP = 0x00, + WMI_SNIFFER_DP = 0x01, + WMI_SNIFFER_BOTH_PHYS = 0x02, }; +/* wmi_sniffer_cfg */ struct wmi_sniffer_cfg { - __le32 mode; /* enum wmi_sniffer_cfg_mode */ - __le32 phy_info_mode; /* enum wmi_sniffer_cfg_phy_info_mode */ - __le32 phy_support; /* enum wmi_sniffer_cfg_phy_support */ + /* enum wmi_sniffer_cfg_mode */ + __le32 mode; + /* enum wmi_sniffer_cfg_phy_info_mode */ + __le32 phy_info_mode; + /* enum wmi_sniffer_cfg_phy_support */ + __le32 phy_support; u8 channel; u8 reserved[3]; } __packed; enum wmi_cfg_rx_chain_cmd_action { - WMI_RX_CHAIN_ADD = 0, - WMI_RX_CHAIN_DEL = 1, + WMI_RX_CHAIN_ADD = 0x00, + WMI_RX_CHAIN_DEL = 0x01, }; enum wmi_cfg_rx_chain_cmd_decap_trans_type { - WMI_DECAP_TYPE_802_3 = 0, - WMI_DECAP_TYPE_NATIVE_WIFI = 1, - WMI_DECAP_TYPE_NONE = 2, + WMI_DECAP_TYPE_802_3 = 0x00, + WMI_DECAP_TYPE_NATIVE_WIFI = 0x01, + WMI_DECAP_TYPE_NONE = 0x02, }; enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { - WMI_NWIFI_RX_TRANS_MODE_NO = 0, - WMI_NWIFI_RX_TRANS_MODE_PBSS2AP = 1, - WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 2, + WMI_NWIFI_RX_TRANS_MODE_NO = 0x00, + WMI_NWIFI_RX_TRANS_MODE_PBSS2AP = 0x01, + WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 0x02, }; enum wmi_cfg_rx_chain_cmd_reorder_type { - WMI_RX_HW_REORDER = 0, - WMI_RX_SW_REORDER = 1, + WMI_RX_HW_REORDER = 0x00, + WMI_RX_SW_REORDER = 0x01, }; +#define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0) +#define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1) +#define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1) +#define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_POS (1) +#define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_LEN (1) +#define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK (0x2) +#define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0) +#define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1) +#define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1) +#define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1) +#define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1) +#define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2) +#define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0) +#define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1) +#define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1) +#define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1) +#define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1) +#define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2) +#define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0) +#define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1) +#define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1) +#define RING_CTRL_OVERRIDE_WB_THRSH_POS (1) +#define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1) +#define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2) +#define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2) +#define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1) +#define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4) +#define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3) +#define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1) +#define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8) + +/* WMI_CFG_RX_CHAIN_CMDID */ struct wmi_cfg_rx_chain_cmd { __le32 action; struct wmi_sw_ring_cfg rx_sw_ring; u8 mid; u8 decap_trans_type; - - #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0) - #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1) - #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1) - #define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_POS (1) - #define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_LEN (1) - #define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK (0x2) u8 l2_802_3_offload_ctrl; - - #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0) - #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1) - #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1) - #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1) - #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1) - #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2) u8 l2_nwifi_offload_ctrl; - u8 vlan_id; u8 nwifi_ds_trans_type; - - #define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0) - #define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1) - #define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1) - #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1) - #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1) - #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2) u8 l3_l4_ctrl; - - #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0) - #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1) - #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1) - #define RING_CTRL_OVERRIDE_WB_THRSH_POS (1) - #define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1) - #define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2) - #define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2) - #define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1) - #define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4) - #define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3) - #define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1) - #define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8) u8 ring_ctrl; - __le16 prefetch_thrsh; __le16 wb_thrsh; __le32 itr_value; @@ -757,31 +723,27 @@ struct wmi_cfg_rx_chain_cmd { u8 reorder_type; u8 reserved; struct wmi_sniffer_cfg sniffer_cfg; + __le16 max_rx_pl_per_desc; } __packed; -/* - * WMI_RCP_ADDBA_RESP_CMDID - */ +/* WMI_RCP_ADDBA_RESP_CMDID */ struct wmi_rcp_addba_resp_cmd { u8 cidxtid; u8 dialog_token; __le16 status_code; - __le16 ba_param_set; /* ieee80211_ba_parameterset field to send */ + /* ieee80211_ba_parameterset field to send */ + __le16 ba_param_set; __le16 ba_timeout; } __packed; -/* - * WMI_RCP_DELBA_CMDID - */ +/* WMI_RCP_DELBA_CMDID */ struct wmi_rcp_delba_cmd { u8 cidxtid; u8 reserved; __le16 reason; } __packed; -/* - * WMI_RCP_ADDBA_REQ_CMDID - */ +/* WMI_RCP_ADDBA_REQ_CMDID */ struct wmi_rcp_addba_req_cmd { u8 cidxtid; u8 dialog_token; @@ -792,32 +754,16 @@ struct wmi_rcp_addba_req_cmd { __le16 ba_seq_ctrl; } __packed; -/* - * WMI_SET_MAC_ADDRESS_CMDID - */ +/* WMI_SET_MAC_ADDRESS_CMDID */ struct wmi_set_mac_address_cmd { u8 mac[WMI_MAC_LEN]; u8 reserved[2]; } __packed; -/* -* WMI_EAPOL_TX_CMDID -*/ -struct wmi_eapol_tx_cmd { - u8 dst_mac[WMI_MAC_LEN]; - __le16 eapol_len; - u8 eapol[0]; -} __packed; - -/* - * WMI_ECHO_CMDID - * +/* WMI_ECHO_CMDID * Check FW is alive - * * WMI_DEEP_ECHO_CMDID - * * Check FW and ucode are alive - * * Returned event: WMI_ECHO_RSP_EVENTID * same event for both commands */ @@ -825,70 +771,79 @@ struct wmi_echo_cmd { __le32 value; } __packed; -/* - * WMI_TEMP_SENSE_CMDID +/* WMI_OTP_READ_CMDID */ +struct wmi_otp_read_cmd { + __le32 addr; + __le32 size; + __le32 values; +} __packed; + +/* WMI_OTP_WRITE_CMDID */ +struct wmi_otp_write_cmd { + __le32 addr; + __le32 size; + __le32 values; +} __packed; + +/* WMI_TEMP_SENSE_CMDID * * Measure MAC and radio temperatures + * + * Possible modes for temperature measurement */ - -/* Possible modes for temperature measurement */ enum wmi_temperature_measure_mode { - TEMPERATURE_USE_OLD_VALUE = 0x1, - TEMPERATURE_MEASURE_NOW = 0x2, + TEMPERATURE_USE_OLD_VALUE = 0x01, + TEMPERATURE_MEASURE_NOW = 0x02, }; +/* WMI_TEMP_SENSE_CMDID */ struct wmi_temp_sense_cmd { __le32 measure_baseband_en; __le32 measure_rf_en; __le32 measure_mode; } __packed; -/* - * WMI_PMC_CMDID - */ -enum wmi_pmc_op_e { - WMI_PMC_ALLOCATE = 0, - WMI_PMC_RELEASE = 1, +enum wmi_pmc_op { + WMI_PMC_ALLOCATE = 0x00, + WMI_PMC_RELEASE = 0x01, }; +/* WMI_PMC_CMDID */ struct wmi_pmc_cmd { - u8 op; /* enum wmi_pmc_cmd_op_type */ + /* enum wmi_pmc_cmd_op_type */ + u8 op; u8 reserved; __le16 ring_size; __le64 mem_base; } __packed; -/* - * WMI Events - */ - -/* +/* WMI Events * List of Events (target to host) */ enum wmi_event_id { WMI_READY_EVENTID = 0x1001, WMI_CONNECT_EVENTID = 0x1002, WMI_DISCONNECT_EVENTID = 0x1003, - WMI_SCAN_COMPLETE_EVENTID = 0x100a, - WMI_REPORT_STATISTICS_EVENTID = 0x100b, + WMI_SCAN_COMPLETE_EVENTID = 0x100A, + WMI_REPORT_STATISTICS_EVENTID = 0x100B, WMI_RD_MEM_RSP_EVENTID = 0x1800, WMI_FW_READY_EVENTID = 0x1801, - WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x0200, + WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, WMI_ECHO_RSP_EVENTID = 0x1803, - WMI_FS_TUNE_DONE_EVENTID = 0x180a, - WMI_CORR_MEASURE_EVENTID = 0x180b, - WMI_READ_RSSI_EVENTID = 0x180c, - WMI_TEMP_SENSE_DONE_EVENTID = 0x180e, - WMI_DC_CALIB_DONE_EVENTID = 0x180f, + WMI_FS_TUNE_DONE_EVENTID = 0x180A, + WMI_CORR_MEASURE_EVENTID = 0x180B, + WMI_READ_RSSI_EVENTID = 0x180C, + WMI_TEMP_SENSE_DONE_EVENTID = 0x180E, + WMI_DC_CALIB_DONE_EVENTID = 0x180F, WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811, WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, - WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a, - WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181d, - WMI_RF_RX_TEST_DONE_EVENTID = 0x181e, + WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181A, + WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181D, + WMI_RF_RX_TEST_DONE_EVENTID = 0x181E, WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820, WMI_VRING_CFG_DONE_EVENTID = 0x1821, WMI_BA_STATUS_EVENTID = 0x1823, @@ -896,15 +851,13 @@ enum wmi_event_id { WMI_RCP_ADDBA_RESP_SENT_EVENTID = 0x1825, WMI_DELBA_EVENTID = 0x1826, WMI_GET_SSID_EVENTID = 0x1828, - WMI_GET_PCP_CHANNEL_EVENTID = 0x182a, - WMI_SW_TX_COMPLETE_EVENTID = 0x182b, - + WMI_GET_PCP_CHANNEL_EVENTID = 0x182A, + WMI_SW_TX_COMPLETE_EVENTID = 0x182B, WMI_READ_MAC_RXQ_EVENTID = 0x1830, WMI_READ_MAC_TXQ_EVENTID = 0x1831, WMI_WRITE_MAC_RXQ_EVENTID = 0x1832, WMI_WRITE_MAC_TXQ_EVENTID = 0x1833, WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834, - WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, @@ -914,20 +867,18 @@ enum wmi_event_id { WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, - + WMI_OTP_READ_RESULT_EVENTID = 0x1856, /* Performance monitoring events */ WMI_DATA_PORT_OPEN_EVENTID = 0x1860, WMI_WBE_LINK_DOWN_EVENTID = 0x1861, - WMI_BF_CTRL_DONE_EVENTID = 0x1862, WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863, WMI_GET_STATUS_DONE_EVENTID = 0x1864, WMI_VRING_EN_EVENTID = 0x1865, - WMI_UNIT_TEST_EVENTID = 0x1900, WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, - /*P2P*/ + /* P2P */ WMI_P2P_CFG_DONE_EVENTID = 0x1910, WMI_PORT_ALLOCATED_EVENTID = 0x1911, WMI_PORT_DELETED_EVENTID = 0x1912, @@ -937,49 +888,42 @@ enum wmi_event_id { WMI_DISCOVERY_STOPPED_EVENTID = 0x1917, WMI_PCP_STARTED_EVENTID = 0x1918, WMI_PCP_STOPPED_EVENTID = 0x1919, - WMI_PCP_FACTOR_EVENTID = 0x191a, + WMI_PCP_FACTOR_EVENTID = 0x191A, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, WMI_MAC_ADDR_RESP_EVENTID = 0x9003, WMI_FW_VER_EVENTID = 0x9004, + WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID = 0x9005, }; -/* - * Events data structures - */ - +/* Events data structures */ enum wmi_fw_status { - WMI_FW_STATUS_SUCCESS, - WMI_FW_STATUS_FAILURE, + WMI_FW_STATUS_SUCCESS = 0x00, + WMI_FW_STATUS_FAILURE = 0x01, }; -/* - * WMI_RF_MGMT_STATUS_EVENTID - */ +/* WMI_RF_MGMT_STATUS_EVENTID */ enum wmi_rf_status { - WMI_RF_ENABLED = 0, - WMI_RF_DISABLED_HW = 1, - WMI_RF_DISABLED_SW = 2, - WMI_RF_DISABLED_HW_SW = 3, + WMI_RF_ENABLED = 0x00, + WMI_RF_DISABLED_HW = 0x01, + WMI_RF_DISABLED_SW = 0x02, + WMI_RF_DISABLED_HW_SW = 0x03, }; +/* WMI_RF_MGMT_STATUS_EVENTID */ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; -/* - * WMI_THERMAL_THROTTLING_STATUS_EVENTID - */ +/* WMI_THERMAL_THROTTLING_STATUS_EVENTID */ struct wmi_thermal_throttling_status_event { __le32 time_on_usec; __le32 time_off_usec; __le32 max_txop_length_usec; } __packed; -/* - * WMI_GET_STATUS_DONE_EVENTID - */ +/* WMI_GET_STATUS_DONE_EVENTID */ struct wmi_get_status_done_event { __le32 is_associated; u8 cid; @@ -995,9 +939,7 @@ struct wmi_get_status_done_event { __le32 is_secured; } __packed; -/* - * WMI_FW_VER_EVENTID - */ +/* WMI_FW_VER_EVENTID */ struct wmi_fw_ver_event { u8 major; u8 minor; @@ -1005,9 +947,7 @@ struct wmi_fw_ver_event { __le16 build; } __packed; -/* -* WMI_MAC_ADDR_RESP_EVENTID -*/ +/* WMI_MAC_ADDR_RESP_EVENTID */ struct wmi_mac_addr_resp_event { u8 mac[WMI_MAC_LEN]; u8 auth_mode; @@ -1015,42 +955,38 @@ struct wmi_mac_addr_resp_event { __le32 offload_mode; } __packed; -/* -* WMI_EAPOL_RX_EVENTID -*/ +/* WMI_EAPOL_RX_EVENTID */ struct wmi_eapol_rx_event { u8 src_mac[WMI_MAC_LEN]; __le16 eapol_len; u8 eapol[0]; } __packed; -/* -* WMI_READY_EVENTID -*/ +/* WMI_READY_EVENTID */ enum wmi_phy_capability { - WMI_11A_CAPABILITY = 1, - WMI_11G_CAPABILITY = 2, - WMI_11AG_CAPABILITY = 3, - WMI_11NA_CAPABILITY = 4, - WMI_11NG_CAPABILITY = 5, - WMI_11NAG_CAPABILITY = 6, - WMI_11AD_CAPABILITY = 7, - WMI_11N_CAPABILITY_OFFSET = WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY, + WMI_11A_CAPABILITY = 0x01, + WMI_11G_CAPABILITY = 0x02, + WMI_11AG_CAPABILITY = 0x03, + WMI_11NA_CAPABILITY = 0x04, + WMI_11NG_CAPABILITY = 0x05, + WMI_11NAG_CAPABILITY = 0x06, + WMI_11AD_CAPABILITY = 0x07, + WMI_11N_CAPABILITY_OFFSET = 0x03, }; struct wmi_ready_event { __le32 sw_version; __le32 abi_version; u8 mac[WMI_MAC_LEN]; - u8 phy_capability; /* enum wmi_phy_capability */ + /* enum wmi_phy_capability */ + u8 phy_capability; u8 numof_additional_mids; } __packed; -/* - * WMI_NOTIFY_REQ_DONE_EVENTID - */ +/* WMI_NOTIFY_REQ_DONE_EVENTID */ struct wmi_notify_req_done_event { - __le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */ + /* beamforming status, 0: fail; 1: OK; 2: retrying */ + __le32 status; __le64 tsf; __le32 snr_val; __le32 tx_tpt; @@ -1066,9 +1002,7 @@ struct wmi_notify_req_done_event { u8 reserved[3]; } __packed; -/* - * WMI_CONNECT_EVENTID - */ +/* WMI_CONNECT_EVENTID */ struct wmi_connect_event { u8 channel; u8 reserved0; @@ -1082,68 +1016,103 @@ struct wmi_connect_event { u8 assoc_resp_len; u8 cid; u8 reserved2[3]; + /* not in use */ u8 assoc_info[0]; } __packed; -/* - * WMI_DISCONNECT_EVENTID - */ +/* WMI_DISCONNECT_EVENTID */ enum wmi_disconnect_reason { - WMI_DIS_REASON_NO_NETWORK_AVAIL = 1, - WMI_DIS_REASON_LOST_LINK = 2, /* bmiss */ - WMI_DIS_REASON_DISCONNECT_CMD = 3, - WMI_DIS_REASON_BSS_DISCONNECTED = 4, - WMI_DIS_REASON_AUTH_FAILED = 5, - WMI_DIS_REASON_ASSOC_FAILED = 6, - WMI_DIS_REASON_NO_RESOURCES_AVAIL = 7, - WMI_DIS_REASON_CSERV_DISCONNECT = 8, - WMI_DIS_REASON_INVALID_PROFILE = 10, - WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH = 11, - WMI_DIS_REASON_PROFILE_MISMATCH = 12, - WMI_DIS_REASON_CONNECTION_EVICTED = 13, - WMI_DIS_REASON_IBSS_MERGE = 14, + WMI_DIS_REASON_NO_NETWORK_AVAIL = 0x01, + /* bmiss */ + WMI_DIS_REASON_LOST_LINK = 0x02, + WMI_DIS_REASON_DISCONNECT_CMD = 0x03, + WMI_DIS_REASON_BSS_DISCONNECTED = 0x04, + WMI_DIS_REASON_AUTH_FAILED = 0x05, + WMI_DIS_REASON_ASSOC_FAILED = 0x06, + WMI_DIS_REASON_NO_RESOURCES_AVAIL = 0x07, + WMI_DIS_REASON_CSERV_DISCONNECT = 0x08, + WMI_DIS_REASON_INVALID_PROFILE = 0x0A, + WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH = 0x0B, + WMI_DIS_REASON_PROFILE_MISMATCH = 0x0C, + WMI_DIS_REASON_CONNECTION_EVICTED = 0x0D, + WMI_DIS_REASON_IBSS_MERGE = 0x0E, }; struct wmi_disconnect_event { - __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ - u8 bssid[WMI_MAC_LEN]; /* set if known */ - u8 disconnect_reason; /* see wmi_disconnect_reason */ - u8 assoc_resp_len; /* not used */ - u8 assoc_info[0]; /* not used */ + /* reason code, see 802.11 spec. */ + __le16 protocol_reason_status; + /* set if known */ + u8 bssid[WMI_MAC_LEN]; + /* see enum wmi_disconnect_reason */ + u8 disconnect_reason; + /* last assoc req may passed to host - not in used */ + u8 assoc_resp_len; + /* last assoc req may passed to host - not in used */ + u8 assoc_info[0]; } __packed; -/* - * WMI_SCAN_COMPLETE_EVENTID - */ +/* WMI_SCAN_COMPLETE_EVENTID */ enum scan_status { - WMI_SCAN_SUCCESS = 0, - WMI_SCAN_FAILED = 1, - WMI_SCAN_ABORTED = 2, - WMI_SCAN_REJECTED = 3, + WMI_SCAN_SUCCESS = 0x00, + WMI_SCAN_FAILED = 0x01, + WMI_SCAN_ABORTED = 0x02, + WMI_SCAN_REJECTED = 0x03, + WMI_SCAN_ABORT_REJECTED = 0x04, }; struct wmi_scan_complete_event { - __le32 status; /* scan_status */ + /* enum scan_status */ + __le32 status; } __packed; -/* - * WMI_BA_STATUS_EVENTID - */ +/* WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT */ +enum wmi_acs_info_bitmask { + WMI_ACS_INFO_BITMASK_BEACON_FOUND = 0x01, + WMI_ACS_INFO_BITMASK_BUSY_TIME = 0x02, + WMI_ACS_INFO_BITMASK_TX_TIME = 0x04, + WMI_ACS_INFO_BITMASK_RX_TIME = 0x08, + WMI_ACS_INFO_BITMASK_NOISE = 0x10, +}; + +struct scan_acs_info { + u8 channel; + u8 beacon_found; + /* msec */ + __le16 busy_time; + __le16 tx_time; + __le16 rx_time; + u8 noise; + u8 reserved[3]; +} __packed; + +struct wmi_acs_passive_scan_complete_event { + __le32 dwell_time; + /* valid fields within channel info according to + * their appearance in struct order + */ + __le16 filled; + u8 num_scanned_channels; + u8 reserved; + struct scan_acs_info scan_info_list[0]; +} __packed; + +/* WMI_BA_STATUS_EVENTID */ enum wmi_vring_ba_status { - WMI_BA_AGREED = 0, - WMI_BA_NON_AGREED = 1, + WMI_BA_AGREED = 0x00, + WMI_BA_NON_AGREED = 0x01, /* BA_EN in middle of teardown flow */ - WMI_BA_TD_WIP = 2, + WMI_BA_TD_WIP = 0x02, /* BA_DIS or BA_EN in middle of BA SETUP flow */ - WMI_BA_SETUP_WIP = 3, + WMI_BA_SETUP_WIP = 0x03, /* BA_EN when the BA session is already active */ - WMI_BA_SESSION_ACTIVE = 4, + WMI_BA_SESSION_ACTIVE = 0x04, /* BA_DIS when the BA session is not active */ - WMI_BA_SESSION_NOT_ACTIVE = 5, + WMI_BA_SESSION_NOT_ACTIVE = 0x05, }; -struct wmi_vring_ba_status_event { - __le16 status; /* enum wmi_vring_ba_status */ +struct wmi_ba_status_event { + /* enum wmi_vring_ba_status */ + __le16 status; u8 reserved[2]; u8 ringid; u8 agg_wsize; @@ -1151,18 +1120,14 @@ struct wmi_vring_ba_status_event { u8 amsdu; } __packed; -/* - * WMI_DELBA_EVENTID - */ +/* WMI_DELBA_EVENTID */ struct wmi_delba_event { u8 cidxtid; u8 from_initiator; __le16 reason; } __packed; -/* - * WMI_VRING_CFG_DONE_EVENTID - */ +/* WMI_VRING_CFG_DONE_EVENTID */ struct wmi_vring_cfg_done_event { u8 ringid; u8 status; @@ -1170,174 +1135,151 @@ struct wmi_vring_cfg_done_event { __le32 tx_vring_tail_ptr; } __packed; -/* - * WMI_RCP_ADDBA_RESP_SENT_EVENTID - */ +/* WMI_RCP_ADDBA_RESP_SENT_EVENTID */ struct wmi_rcp_addba_resp_sent_event { u8 cidxtid; u8 reserved; __le16 status; } __packed; -/* - * WMI_RCP_ADDBA_REQ_EVENTID - */ +/* WMI_RCP_ADDBA_REQ_EVENTID */ struct wmi_rcp_addba_req_event { u8 cidxtid; u8 dialog_token; - __le16 ba_param_set; /* ieee80211_ba_parameterset as it received */ + /* ieee80211_ba_parameterset as it received */ + __le16 ba_param_set; __le16 ba_timeout; - __le16 ba_seq_ctrl; /* ieee80211_ba_seqstrl field as it received */ + /* ieee80211_ba_seqstrl field as it received */ + __le16 ba_seq_ctrl; } __packed; -/* - * WMI_CFG_RX_CHAIN_DONE_EVENTID - */ +/* WMI_CFG_RX_CHAIN_DONE_EVENTID */ enum wmi_cfg_rx_chain_done_event_status { - WMI_CFG_RX_CHAIN_SUCCESS = 1, + WMI_CFG_RX_CHAIN_SUCCESS = 0x01, }; struct wmi_cfg_rx_chain_done_event { - __le32 rx_ring_tail_ptr; /* Rx V-Ring Tail pointer */ + /* V-Ring Tail pointer */ + __le32 rx_ring_tail_ptr; __le32 status; } __packed; -/* - * WMI_WBE_LINK_DOWN_EVENTID - */ +/* WMI_WBE_LINK_DOWN_EVENTID */ enum wmi_wbe_link_down_event_reason { - WMI_WBE_REASON_USER_REQUEST = 0, - WMI_WBE_REASON_RX_DISASSOC = 1, - WMI_WBE_REASON_BAD_PHY_LINK = 2, + WMI_WBE_REASON_USER_REQUEST = 0x00, + WMI_WBE_REASON_RX_DISASSOC = 0x01, + WMI_WBE_REASON_BAD_PHY_LINK = 0x02, }; +/* WMI_WBE_LINK_DOWN_EVENTID */ struct wmi_wbe_link_down_event { u8 cid; u8 reserved[3]; __le32 reason; } __packed; -/* - * WMI_DATA_PORT_OPEN_EVENTID - */ +/* WMI_DATA_PORT_OPEN_EVENTID */ struct wmi_data_port_open_event { u8 cid; u8 reserved[3]; } __packed; -/* - * WMI_VRING_EN_EVENTID - */ +/* WMI_VRING_EN_EVENTID */ struct wmi_vring_en_event { u8 vring_index; u8 reserved[3]; } __packed; -/* - * WMI_GET_PCP_CHANNEL_EVENTID - */ +/* WMI_GET_PCP_CHANNEL_EVENTID */ struct wmi_get_pcp_channel_event { u8 channel; u8 reserved[3]; } __packed; -/* - * WMI_P2P_CFG_DONE_EVENTID - */ +/* WMI_P2P_CFG_DONE_EVENTID */ struct wmi_p2p_cfg_done_event { - u8 status; /* wmi_fw_status */ + /* wmi_fw_status */ + u8 status; u8 reserved[3]; } __packed; -/* -* WMI_PORT_ALLOCATED_EVENTID -*/ +/* WMI_PORT_ALLOCATED_EVENTID */ struct wmi_port_allocated_event { - u8 status; /* wmi_fw_status */ + /* wmi_fw_status */ + u8 status; u8 reserved[3]; } __packed; -/* -* WMI_PORT_DELETED_EVENTID -*/ +/* WMI_PORT_DELETED_EVENTID */ struct wmi_port_deleted_event { - u8 status; /* wmi_fw_status */ + /* wmi_fw_status */ + u8 status; u8 reserved[3]; } __packed; -/* - * WMI_LISTEN_STARTED_EVENTID - */ +/* WMI_LISTEN_STARTED_EVENTID */ struct wmi_listen_started_event { - u8 status; /* wmi_fw_status */ + /* wmi_fw_status */ + u8 status; u8 reserved[3]; } __packed; -/* - * WMI_SEARCH_STARTED_EVENTID - */ +/* WMI_SEARCH_STARTED_EVENTID */ struct wmi_search_started_event { - u8 status; /* wmi_fw_status */ + /* wmi_fw_status */ + u8 status; u8 reserved[3]; } __packed; -/* - * WMI_PCP_STARTED_EVENTID - */ +/* WMI_PCP_STARTED_EVENTID */ struct wmi_pcp_started_event { - u8 status; /* wmi_fw_status */ + /* wmi_fw_status */ + u8 status; u8 reserved[3]; } __packed; -/* - * WMI_PCP_FACTOR_EVENTID - */ +/* WMI_PCP_FACTOR_EVENTID */ struct wmi_pcp_factor_event { __le32 pcp_factor; } __packed; -/* - * WMI_SW_TX_COMPLETE_EVENTID - */ enum wmi_sw_tx_status { - WMI_TX_SW_STATUS_SUCCESS = 0, - WMI_TX_SW_STATUS_FAILED_NO_RESOURCES = 1, - WMI_TX_SW_STATUS_FAILED_TX = 2, + WMI_TX_SW_STATUS_SUCCESS = 0x00, + WMI_TX_SW_STATUS_FAILED_NO_RESOURCES = 0x01, + WMI_TX_SW_STATUS_FAILED_TX = 0x02, }; +/* WMI_SW_TX_COMPLETE_EVENTID */ struct wmi_sw_tx_complete_event { - u8 status; /* enum wmi_sw_tx_status */ + /* enum wmi_sw_tx_status */ + u8 status; u8 reserved[3]; } __packed; -/* - * WMI_CORR_MEASURE_EVENTID - */ +/* WMI_CORR_MEASURE_EVENTID */ struct wmi_corr_measure_event { - s32 i; - s32 q; - s32 image_i; - s32 image_q; + /* signed */ + __le32 i; + /* signed */ + __le32 q; + /* signed */ + __le32 image_i; + /* signed */ + __le32 image_q; } __packed; -/* - * WMI_READ_RSSI_EVENTID - */ +/* WMI_READ_RSSI_EVENTID */ struct wmi_read_rssi_event { __le32 ina_rssi_adc_dbm; } __packed; -/* - * WMI_GET_SSID_EVENTID - */ +/* WMI_GET_SSID_EVENTID */ struct wmi_get_ssid_event { __le32 ssid_len; u8 ssid[WMI_MAX_SSID_LEN]; } __packed; -/* - * WMI_RX_MGMT_PACKET_EVENTID - */ +/* wmi_rx_mgmt_info */ struct wmi_rx_mgmt_info { u8 mcs; s8 snr; @@ -1346,39 +1288,65 @@ struct wmi_rx_mgmt_info { __le16 stype; __le16 status; __le32 len; + /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */ u8 qid; + /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */ u8 mid; u8 cid; - u8 channel; /* From Radio MNGR */ + /* From Radio MNGR */ + u8 channel; } __packed; -/* - * WMI_TX_MGMT_PACKET_EVENTID - */ +/* wmi_otp_read_write_cmd */ +struct wmi_otp_read_write_cmd { + __le32 addr; + __le32 size; + u8 values[0]; +} __packed; + +/* WMI_OTP_READ_RESULT_EVENTID */ +struct wmi_otp_read_result_event { + u8 payload[0]; +} __packed; + +/* WMI_TX_MGMT_PACKET_EVENTID */ struct wmi_tx_mgmt_packet_event { u8 payload[0]; } __packed; +/* WMI_RX_MGMT_PACKET_EVENTID */ struct wmi_rx_mgmt_packet_event { struct wmi_rx_mgmt_info info; u8 payload[0]; } __packed; -/* - * WMI_ECHO_RSP_EVENTID - */ -struct wmi_echo_event { +/* WMI_ECHO_RSP_EVENTID */ +struct wmi_echo_rsp_event { __le32 echoed_value; } __packed; -/* - * WMI_TEMP_SENSE_DONE_EVENTID +/* WMI_TEMP_SENSE_DONE_EVENTID * * Measure MAC and radio temperatures */ struct wmi_temp_sense_done_event { + /* Temperature times 1000 (actual temperature will be achieved by + * dividing the value by 1000) + */ __le32 baseband_t1000; + /* Temperature times 1000 (actual temperature will be achieved by + * dividing the value by 1000) + */ __le32 rf_t1000; } __packed; +#define WMI_SCAN_DWELL_TIME_MS (100) +#define WMI_SURVEY_TIMEOUT_MS (10000) + +enum wmi_hidden_ssid { + WMI_HIDDEN_SSID_DISABLED = 0x00, + WMI_HIDDEN_SSID_SEND_EMPTY = 0x10, + WMI_HIDDEN_SSID_CLEAR = 0xFE, +}; + #endif /* __WILOCITY_WMI_H__ */ diff --git a/drivers/pinctrl/qcom/pinctrl-msmcobalt.c b/drivers/pinctrl/qcom/pinctrl-msmcobalt.c index 27d692b66583..ef44df7bc6f1 100644 --- a/drivers/pinctrl/qcom/pinctrl-msmcobalt.c +++ b/drivers/pinctrl/qcom/pinctrl-msmcobalt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -61,6 +61,7 @@ .intr_enable_bit = 0, \ .intr_status_bit = 0, \ .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ .intr_raw_status_bit = 4, \ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile index 19ae5234a6d0..8bc7d8a498f6 100644 --- a/drivers/platform/msm/ipa/Makefile +++ b/drivers/platform/msm/ipa/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_IPA) += ipa_v2/ +obj-$(CONFIG_IPA) += ipa_v2/ ipa_clients/ obj-$(CONFIG_IPA3) += ipa_v3/ ipa_clients/ obj-$(CONFIG_IPA) += ipa_api.o diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 31db8ff2709f..04054fe1211f 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -1868,108 +1868,6 @@ bool ipa_get_client_uplink(int pipe_idx) EXPORT_SYMBOL(ipa_get_client_uplink); /** - * odu_bridge_init() - Initialize the ODU bridge driver - * @params: initialization parameters - * - * This function initialize all bridge internal data and register odu bridge to - * kernel for IOCTL and debugfs. - * Header addition and properties are registered to IPA driver. - * - * Return codes: 0: success, - * -EINVAL - Bad parameter - * Other negative value - Failure - */ -int odu_bridge_init(struct odu_bridge_params *params) -{ - int ret; - - IPA_API_DISPATCH_RETURN(odu_bridge_init, params); - - return ret; -} -EXPORT_SYMBOL(odu_bridge_init); - -/** - * odu_bridge_disconnect() - Disconnect odu bridge - * - * Disconnect all pipes and deletes IPA RM dependencies on bridge mode - * - * Return codes: 0- success, error otherwise - */ -int odu_bridge_disconnect(void) -{ - int ret; - - IPA_API_DISPATCH_RETURN(odu_bridge_disconnect); - - return ret; -} -EXPORT_SYMBOL(odu_bridge_disconnect); - -/** - * odu_bridge_connect() - Connect odu bridge. - * - * Call to the mode-specific connect function for connection IPA pipes - * and adding IPA RM dependencies - - * Return codes: 0: success - * -EINVAL: invalid parameters - * -EPERM: Operation not permitted as the bridge is already - * connected - */ -int odu_bridge_connect(void) -{ - int ret; - - IPA_API_DISPATCH_RETURN(odu_bridge_connect); - - return ret; -} -EXPORT_SYMBOL(odu_bridge_connect); - -/** - * odu_bridge_tx_dp() - Send skb to ODU bridge - * @skb: skb to send - * @metadata: metadata on packet - * - * This function handles uplink packet. - * In Router Mode: - * packet is sent directly to IPA. - * In Router Mode: - * packet is classified if it should arrive to network stack. - * QMI IP packet should arrive to APPS network stack - * IPv6 Multicast packet should arrive to APPS network stack and Q6 - * - * Return codes: 0- success, error otherwise - */ -int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) -{ - int ret; - - IPA_API_DISPATCH_RETURN(odu_bridge_tx_dp, skb, metadata); - - return ret; -} -EXPORT_SYMBOL(odu_bridge_tx_dp); - -/** - * odu_bridge_cleanup() - De-Initialize the ODU bridge driver - * - * Return codes: 0: success, - * -EINVAL - Bad parameter - * Other negative value - Failure - */ -int odu_bridge_cleanup(void) -{ - int ret; - - IPA_API_DISPATCH_RETURN(odu_bridge_cleanup); - - return ret; -} -EXPORT_SYMBOL(odu_bridge_cleanup); - -/** * ipa_dma_init() -Initialize IPADMA. * * This function initialize all IPADMA internal data and connect in dma: diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index e108f0ca0bae..04b7ba64a6aa 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -236,17 +236,6 @@ struct ipa_api_controller { bool (*ipa_get_client_uplink)(int pipe_idx); - int (*odu_bridge_init)(struct odu_bridge_params *params); - - int (*odu_bridge_connect)(void); - - int (*odu_bridge_disconnect)(void); - - int (*odu_bridge_tx_dp)(struct sk_buff *skb, - struct ipa_tx_meta *metadata); - - int (*odu_bridge_cleanup)(void); - int (*ipa_dma_init)(void); int (*ipa_dma_enable)(void); diff --git a/drivers/platform/msm/ipa/ipa_clients/Makefile b/drivers/platform/msm/ipa/ipa_clients/Makefile index eb0e91b70690..26b45a6c2b42 100644 --- a/drivers/platform/msm/ipa/ipa_clients/Makefile +++ b/drivers/platform/msm/ipa/ipa_clients/Makefile @@ -1 +1,2 @@ -obj-$(CONFIG_IPA3) += ipa_usb.o
\ No newline at end of file +obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o +obj-$(CONFIG_IPA) += odu_bridge.o
\ No newline at end of file diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index 9b9ec31f34fc..a0c94c8e37ec 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -1788,6 +1788,33 @@ connect_ul_fail: return result; } +static int ipa_usb_ipc_logging_init(void) +{ + int result; + + ipa3_usb_ctx->logbuf = ipc_log_context_create(IPA_USB_IPC_LOG_PAGES, + "ipa_usb", 0); + if (ipa3_usb_ctx->logbuf == NULL) { + /* we can't use ipa_usb print macros on failures */ + pr_err("ipa_usb: failed to get logbuf\n"); + return -ENOMEM; + } + + ipa3_usb_ctx->logbuf_low = ipc_log_context_create(IPA_USB_IPC_LOG_PAGES, + "ipa_usb_low", 0); + if (ipa3_usb_ctx->logbuf_low == NULL) { + pr_err("ipa_usb: failed to get logbuf_low\n"); + result = -ENOMEM; + goto fail_logbuf_low; + } + + return 0; + +fail_logbuf_low: + ipc_log_context_destroy(ipa3_usb_ctx->logbuf); + return result; +} + #ifdef CONFIG_DEBUG_FS static char dbg_buff[IPA_USB_MAX_MSG_LEN]; @@ -1949,7 +1976,7 @@ const struct file_operations ipa3_ipa_usb_ops = { .read = ipa3_read_usb_state_info, }; -void ipa_usb_debugfs_init(void) +static void ipa_usb_debugfs_init(void) { const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH; const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH | @@ -1987,45 +2014,18 @@ fail: ipa3_usb_ctx->dent = NULL; } -static int ipa_usb_ipc_logging_init(void) -{ - int result; - - ipa3_usb_ctx->logbuf = ipc_log_context_create(IPA_USB_IPC_LOG_PAGES, - "ipa_usb", 0); - if (ipa3_usb_ctx->logbuf == NULL) { - /* we can't use ipa_usb print macros on failures */ - pr_err("ipa_usb: failed to get logbuf\n"); - return -ENOMEM; - } - - ipa3_usb_ctx->logbuf_low = ipc_log_context_create(IPA_USB_IPC_LOG_PAGES, - "ipa_usb_low", 0); - if (ipa3_usb_ctx->logbuf_low == NULL) { - pr_err("ipa_usb: failed to get logbuf_low\n"); - result = -ENOMEM; - goto fail_logbuf_low; - } - - return 0; - -fail_logbuf_low: - ipc_log_context_destroy(ipa3_usb_ctx->logbuf); - return result; -} - -void ipa_usb_debugfs_remove(void) +static void ipa_usb_debugfs_remove(void) { if (IS_ERR(ipa3_usb_ctx->dent)) { - IPA_USB_ERR("ipa_debugfs_remove: folder was not created.\n"); + IPA_USB_ERR("ipa_usb debugfs folder was not created.\n"); return; } debugfs_remove_recursive(ipa3_usb_ctx->dent); } #else /* CONFIG_DEBUG_FS */ -void ipa_usb_debugfs_init(void){} -void ipa_usb_debugfs_remove(void){} +static void ipa_usb_debugfs_init(void){} +static void ipa_usb_debugfs_remove(void){} #endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/platform/msm/ipa/ipa_v2/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c index 9dbd2f6e8f79..c388925f4679 100644 --- a/drivers/platform/msm/ipa/ipa_v2/odu_bridge.c +++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,20 +23,55 @@ #include <linux/types.h> #include <linux/ipv6.h> #include <net/addrconf.h> +#include <linux/ipc_logging.h> #include <linux/ipa.h> -#include "ipa_i.h" +#include <linux/cdev.h> +#include <linux/ipa_odu_bridge.h> #define ODU_BRIDGE_DRV_NAME "odu_ipa_bridge" +#define ODU_IPC_LOG_PAGES 10 +#define ODU_IPC_LOG(buf, fmt, args...) \ + ipc_log_string((buf), \ + ODU_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + #define ODU_BRIDGE_DBG(fmt, args...) \ - pr_debug(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ - __func__, __LINE__, ## args) + do { \ + pr_debug(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + if (odu_bridge_ctx) { \ + ODU_IPC_LOG(odu_bridge_ctx->logbuf, \ + fmt, ## args); \ + ODU_IPC_LOG(odu_bridge_ctx->logbuf_low, \ + fmt, ## args); \ + } \ + } while (0) +#define ODU_BRIDGE_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + if (odu_bridge_ctx && \ + odu_bridge_ctx->enable_low_prio_print) { \ + ODU_IPC_LOG(odu_bridge_ctx->logbuf_low, \ + fmt, ## args); \ + } \ + } while (0) #define ODU_BRIDGE_ERR(fmt, args...) \ - pr_err(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_err(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + if (odu_bridge_ctx) { \ + ODU_IPC_LOG(odu_bridge_ctx->logbuf, \ + fmt, ## args); \ + ODU_IPC_LOG(odu_bridge_ctx->logbuf_low, \ + fmt, ## args); \ + } \ + } while (0) + #define ODU_BRIDGE_FUNC_ENTRY() \ - ODU_BRIDGE_DBG("ENTRY\n") + ODU_BRIDGE_DBG_LOW("ENTRY\n") #define ODU_BRIDGE_FUNC_EXIT() \ - ODU_BRIDGE_DBG("EXIT\n") + ODU_BRIDGE_DBG_LOW("EXIT\n") #define ODU_BRIDGE_IS_QMI_ADDR(daddr) \ @@ -54,6 +89,17 @@ compat_uptr_t) #endif +#define IPA_ODU_VER_CHECK() \ + do { \ + ret = 0;\ + if (ipa_get_hw_type() == IPA_HW_None) { \ + pr_err("IPA HW is unknown\n"); \ + ret = -EFAULT; \ + } \ + else if (ipa_get_hw_type() < IPA_HW_v3_0) \ + ret = 1; \ + } while (0) + /** * struct stats - driver statistics, viewable using debugfs * @num_ul_packets: number of packets bridged in uplink direction @@ -110,6 +156,9 @@ struct odu_bridge_ctx { u32 odu_emb_cons_hdl; u32 odu_teth_cons_hdl; u32 ipa_sys_desc_size; + void *logbuf; + void *logbuf_low; + u32 enable_low_prio_print; }; static struct odu_bridge_ctx *odu_bridge_ctx; @@ -149,7 +198,7 @@ static void odu_bridge_teth_cons_cb(void *priv, enum ipa_dp_evt_type evt, ipv6hdr = (struct ipv6hdr *)(skb->data + ETH_HLEN); if (ipv6hdr->version == 6 && ipv6_addr_is_multicast(&ipv6hdr->daddr)) { - ODU_BRIDGE_DBG("Multicast pkt, send to APPS and adapter\n"); + ODU_BRIDGE_DBG_LOW("Multicast pkt, send to APPS and adapter\n"); skb_copied = skb_clone(skb, GFP_KERNEL); if (skb_copied) { odu_bridge_ctx->tx_dp_notify(odu_bridge_ctx->priv, @@ -185,7 +234,7 @@ static int odu_bridge_connect_router(void) odu_prod_params.priv = odu_bridge_ctx->priv; odu_prod_params.notify = odu_bridge_ctx->tx_dp_notify; odu_prod_params.keep_ipa_awake = true; - res = ipa2_setup_sys_pipe(&odu_prod_params, + res = ipa_setup_sys_pipe(&odu_prod_params, &odu_bridge_ctx->odu_prod_hdl); if (res) { ODU_BRIDGE_ERR("fail to setup sys pipe ODU_PROD %d\n", res); @@ -200,7 +249,7 @@ static int odu_bridge_connect_router(void) odu_emb_cons_params.priv = odu_bridge_ctx->priv; odu_emb_cons_params.notify = odu_bridge_emb_cons_cb; odu_emb_cons_params.keep_ipa_awake = true; - res = ipa2_setup_sys_pipe(&odu_emb_cons_params, + res = ipa_setup_sys_pipe(&odu_emb_cons_params, &odu_bridge_ctx->odu_emb_cons_hdl); if (res) { ODU_BRIDGE_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res); @@ -215,7 +264,7 @@ static int odu_bridge_connect_router(void) return 0; fail_odu_emb_cons: - ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); + ipa_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); odu_bridge_ctx->odu_prod_hdl = 0; fail_odu_prod: return res; @@ -234,18 +283,18 @@ static int odu_bridge_connect_bridge(void) memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params)); /* Build IPA Resource manager dependency graph */ - ODU_BRIDGE_DBG("build dependency graph\n"); - res = ipa2_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, + ODU_BRIDGE_DBG_LOW("build dependency graph\n"); + res = ipa_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS); if (res && res != -EINPROGRESS) { - ODU_BRIDGE_ERR("ipa2_rm_add_dependency() failed\n"); + ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n"); goto fail_add_dependency_1; } - res = ipa2_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD, + res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS); if (res && res != -EINPROGRESS) { - ODU_BRIDGE_ERR("ipa2_rm_add_dependency() failed\n"); + ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n"); goto fail_add_dependency_2; } @@ -256,7 +305,7 @@ static int odu_bridge_connect_bridge(void) odu_prod_params.notify = odu_bridge_ctx->tx_dp_notify; odu_prod_params.keep_ipa_awake = true; odu_prod_params.skip_ep_cfg = true; - res = ipa2_setup_sys_pipe(&odu_prod_params, + res = ipa_setup_sys_pipe(&odu_prod_params, &odu_bridge_ctx->odu_prod_hdl); if (res) { ODU_BRIDGE_ERR("fail to setup sys pipe ODU_PROD %d\n", res); @@ -270,7 +319,7 @@ static int odu_bridge_connect_bridge(void) odu_teth_cons_params.notify = odu_bridge_teth_cons_cb; odu_teth_cons_params.keep_ipa_awake = true; odu_teth_cons_params.skip_ep_cfg = true; - res = ipa2_setup_sys_pipe(&odu_teth_cons_params, + res = ipa_setup_sys_pipe(&odu_teth_cons_params, &odu_bridge_ctx->odu_teth_cons_hdl); if (res) { ODU_BRIDGE_ERR("fail to setup sys pipe ODU_TETH_CONS %d\n", @@ -286,16 +335,16 @@ static int odu_bridge_connect_bridge(void) odu_emb_cons_params.priv = odu_bridge_ctx->priv; odu_emb_cons_params.notify = odu_bridge_emb_cons_cb; odu_emb_cons_params.keep_ipa_awake = true; - res = ipa2_setup_sys_pipe(&odu_emb_cons_params, + res = ipa_setup_sys_pipe(&odu_emb_cons_params, &odu_bridge_ctx->odu_emb_cons_hdl); if (res) { ODU_BRIDGE_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res); goto fail_odu_emb_cons; } - ODU_BRIDGE_DBG("odu_prod_hdl = %d, odu_emb_cons_hdl = %d\n", + ODU_BRIDGE_DBG_LOW("odu_prod_hdl = %d, odu_emb_cons_hdl = %d\n", odu_bridge_ctx->odu_prod_hdl, odu_bridge_ctx->odu_emb_cons_hdl); - ODU_BRIDGE_DBG("odu_teth_cons_hdl = %d\n", + ODU_BRIDGE_DBG_LOW("odu_teth_cons_hdl = %d\n", odu_bridge_ctx->odu_teth_cons_hdl); ODU_BRIDGE_FUNC_EXIT(); @@ -303,16 +352,16 @@ static int odu_bridge_connect_bridge(void) return 0; fail_odu_emb_cons: - ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_teth_cons_hdl); + ipa_teardown_sys_pipe(odu_bridge_ctx->odu_teth_cons_hdl); odu_bridge_ctx->odu_teth_cons_hdl = 0; fail_odu_teth_cons: - ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); + ipa_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); odu_bridge_ctx->odu_prod_hdl = 0; fail_odu_prod: - ipa2_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, + ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS); fail_add_dependency_2: - ipa2_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, + ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS); fail_add_dependency_1: return res; @@ -324,12 +373,12 @@ static int odu_bridge_disconnect_router(void) ODU_BRIDGE_FUNC_ENTRY(); - res = ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); + res = ipa_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); if (res) ODU_BRIDGE_ERR("teardown ODU PROD failed\n"); odu_bridge_ctx->odu_prod_hdl = 0; - res = ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_emb_cons_hdl); + res = ipa_teardown_sys_pipe(odu_bridge_ctx->odu_emb_cons_hdl); if (res) ODU_BRIDGE_ERR("teardown ODU EMB CONS failed\n"); odu_bridge_ctx->odu_emb_cons_hdl = 0; @@ -345,44 +394,44 @@ static int odu_bridge_disconnect_bridge(void) ODU_BRIDGE_FUNC_ENTRY(); - res = ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); + res = ipa_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl); if (res) ODU_BRIDGE_ERR("teardown ODU PROD failed\n"); odu_bridge_ctx->odu_prod_hdl = 0; - res = ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_teth_cons_hdl); + res = ipa_teardown_sys_pipe(odu_bridge_ctx->odu_teth_cons_hdl); if (res) ODU_BRIDGE_ERR("teardown ODU TETH CONS failed\n"); odu_bridge_ctx->odu_teth_cons_hdl = 0; - res = ipa2_teardown_sys_pipe(odu_bridge_ctx->odu_emb_cons_hdl); + res = ipa_teardown_sys_pipe(odu_bridge_ctx->odu_emb_cons_hdl); if (res) ODU_BRIDGE_ERR("teardown ODU EMB CONS failed\n"); odu_bridge_ctx->odu_emb_cons_hdl = 0; /* Delete IPA Resource manager dependency graph */ ODU_BRIDGE_DBG("deleting dependency graph\n"); - res = ipa2_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, + res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS); if (res && res != -EINPROGRESS) - ODU_BRIDGE_ERR("ipa2_rm_delete_dependency() failed\n"); + ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n"); - res = ipa2_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, + res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS); if (res && res != -EINPROGRESS) - ODU_BRIDGE_ERR("ipa2_rm_delete_dependency() failed\n"); + ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n"); return 0; } /** - * ipa2_odu_bridge_disconnect() - Disconnect odu bridge + * odu_bridge_disconnect() - Disconnect odu bridge * * Disconnect all pipes and deletes IPA RM dependencies on bridge mode * * Return codes: 0- success, error otherwise */ -int ipa2_odu_bridge_disconnect(void) +int odu_bridge_disconnect(void) { int res; @@ -420,9 +469,10 @@ out: ODU_BRIDGE_FUNC_EXIT(); return res; } +EXPORT_SYMBOL(odu_bridge_disconnect); /** - * ipa2_odu_bridge_connect() - Connect odu bridge. + * odu_bridge_connect() - Connect odu bridge. * * Call to the mode-specific connect function for connection IPA pipes * and adding IPA RM dependencies @@ -432,7 +482,7 @@ out: * -EPERM: Operation not permitted as the bridge is already * connected */ -int ipa2_odu_bridge_connect(void) +int odu_bridge_connect(void) { int res; @@ -470,6 +520,7 @@ bail: ODU_BRIDGE_FUNC_EXIT(); return res; } +EXPORT_SYMBOL(odu_bridge_connect); /** * odu_bridge_set_mode() - Set bridge mode to Router/Bridge @@ -486,11 +537,11 @@ static int odu_bridge_set_mode(enum odu_bridge_mode mode) return -EFAULT; } - ODU_BRIDGE_DBG("setting mode: %d\n", mode); + ODU_BRIDGE_DBG_LOW("setting mode: %d\n", mode); mutex_lock(&odu_bridge_ctx->lock); if (odu_bridge_ctx->mode == mode) { - ODU_BRIDGE_DBG("same mode\n"); + ODU_BRIDGE_DBG_LOW("same mode\n"); res = 0; goto bail; } @@ -553,7 +604,7 @@ static int odu_bridge_set_llv6_addr(struct in6_addr *llv6_addr) memcpy(&odu_bridge_ctx->llv6_addr, &llv6_addr_host, sizeof(odu_bridge_ctx->llv6_addr)); - ODU_BRIDGE_DBG("LLV6 addr: %pI6c\n", &odu_bridge_ctx->llv6_addr); + ODU_BRIDGE_DBG_LOW("LLV6 addr: %pI6c\n", &odu_bridge_ctx->llv6_addr); ODU_BRIDGE_FUNC_EXIT(); @@ -632,6 +683,7 @@ static long compat_odu_bridge_ioctl(struct file *file, static struct dentry *dent; static struct dentry *dfile_stats; static struct dentry *dfile_mode; +static struct dentry *dfile_low_prio; static ssize_t odu_debugfs_stats(struct file *file, char __user *ubuf, @@ -725,7 +777,7 @@ const struct file_operations odu_hw_bridge_mode_ops = { .write = odu_debugfs_hw_bridge_mode_write, }; -void odu_debugfs_init(void) +static void odu_debugfs_init(void) { const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH; const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH | @@ -754,6 +806,14 @@ void odu_debugfs_init(void) goto fail; } + dfile_low_prio = debugfs_create_u32("enable_low_prio_print", + read_write_mode, + dent, &odu_bridge_ctx->enable_low_prio_print); + if (!dfile_low_prio) { + ODU_BRIDGE_ERR("could not create enable_low_prio_print file\n"); + goto fail; + } + return; fail: debugfs_remove_recursive(dent); @@ -779,7 +839,7 @@ static const struct file_operations odu_bridge_drv_fops = { }; /** - * ipa2_odu_bridge_tx_dp() - Send skb to ODU bridge + * odu_bridge_tx_dp() - Send skb to ODU bridge * @skb: skb to send * @metadata: metadata on packet * @@ -793,7 +853,7 @@ static const struct file_operations odu_bridge_drv_fops = { * * Return codes: 0- success, error otherwise */ -int ipa2_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) +int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) { struct sk_buff *skb_copied = NULL; struct ipv6hdr *ipv6hdr; @@ -804,7 +864,7 @@ int ipa2_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) switch (odu_bridge_ctx->mode) { case ODU_BRIDGE_MODE_ROUTER: /* Router mode - pass skb to IPA */ - res = ipa2_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); + res = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); if (res) { ODU_BRIDGE_DBG("tx dp failed %d\n", res); goto out; @@ -816,7 +876,7 @@ int ipa2_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) ipv6hdr = (struct ipv6hdr *)(skb->data + ETH_HLEN); if (ipv6hdr->version == 6 && ODU_BRIDGE_IS_QMI_ADDR(ipv6hdr->daddr)) { - ODU_BRIDGE_DBG("QMI packet\n"); + ODU_BRIDGE_DBG_LOW("QMI packet\n"); skb_copied = skb_clone(skb, GFP_KERNEL); if (!skb_copied) { ODU_BRIDGE_ERR("No memory\n"); @@ -836,14 +896,15 @@ int ipa2_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) if (ipv6hdr->version == 6 && ipv6_addr_is_multicast(&ipv6hdr->daddr)) { - ODU_BRIDGE_DBG("Multicast pkt, send to APPS and IPA\n"); + ODU_BRIDGE_DBG_LOW( + "Multicast pkt, send to APPS and IPA\n"); skb_copied = skb_clone(skb, GFP_KERNEL); if (!skb_copied) { ODU_BRIDGE_ERR("No memory\n"); return -ENOMEM; } - res = ipa2_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); + res = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); if (res) { ODU_BRIDGE_DBG("tx dp failed %d\n", res); dev_kfree_skb(skb_copied); @@ -858,7 +919,7 @@ int ipa2_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) goto out; } - res = ipa2_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); + res = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); if (res) { ODU_BRIDGE_DBG("tx dp failed %d\n", res); goto out; @@ -876,6 +937,7 @@ out: ODU_BRIDGE_FUNC_EXIT(); return res; } +EXPORT_SYMBOL(odu_bridge_tx_dp); static int odu_bridge_add_hdrs(void) { @@ -916,7 +978,7 @@ static int odu_bridge_add_hdrs(void) ipv6_hdr->eth2_ofst = 0; hdrs->commit = 1; hdrs->num_hdrs = 2; - res = ipa2_add_hdr(hdrs); + res = ipa_add_hdr(hdrs); if (res) { ODU_BRIDGE_ERR("Fail on Header-Insertion(%d)\n", res); goto out_free_mem; @@ -961,9 +1023,9 @@ static void odu_bridge_del_hdrs(void) ipv4->hdl = odu_bridge_ctx->odu_br_ipv4_hdr_hdl; ipv6 = &del_hdr->hdl[1]; ipv6->hdl = odu_bridge_ctx->odu_br_ipv6_hdr_hdl; - result = ipa2_del_hdr(del_hdr); + result = ipa_del_hdr(del_hdr); if (result || ipv4->status || ipv6->status) - ODU_BRIDGE_ERR("ipa2_del_hdr failed"); + ODU_BRIDGE_ERR("ipa_del_hdr failed"); kfree(del_hdr); } @@ -1019,7 +1081,7 @@ static int odu_bridge_register_properties(void) rx_ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; rx_properties.num_props = 2; - res = ipa2_register_intf(odu_bridge_ctx->netdev_name, &tx_properties, + res = ipa_register_intf(odu_bridge_ctx->netdev_name, &tx_properties, &rx_properties); if (res) { ODU_BRIDGE_ERR("fail on Tx/Rx properties registration %d\n", @@ -1036,14 +1098,42 @@ static void odu_bridge_deregister_properties(void) int res; ODU_BRIDGE_FUNC_ENTRY(); - res = ipa2_deregister_intf(odu_bridge_ctx->netdev_name); + res = ipa_deregister_intf(odu_bridge_ctx->netdev_name); if (res) ODU_BRIDGE_ERR("Fail on Tx prop deregister %d\n", res); ODU_BRIDGE_FUNC_EXIT(); } +static int odu_bridge_ipc_logging_init(void) +{ + int result; + + odu_bridge_ctx->logbuf = ipc_log_context_create(ODU_IPC_LOG_PAGES, + "ipa_odu_bridge", 0); + if (odu_bridge_ctx->logbuf == NULL) { + /* we can't use odu_bridge print macros on failures */ + pr_err("odu_bridge: failed to get logbuf\n"); + return -ENOMEM; + } + + odu_bridge_ctx->logbuf_low = + ipc_log_context_create(ODU_IPC_LOG_PAGES, + "ipa_odu_bridge_low", 0); + if (odu_bridge_ctx->logbuf_low == NULL) { + pr_err("odu_bridge: failed to get logbuf_low\n"); + result = -ENOMEM; + goto fail_logbuf_low; + } + + return 0; + +fail_logbuf_low: + ipc_log_context_destroy(odu_bridge_ctx->logbuf); + return result; +} + /** - * ipa2_odu_bridge_init() - Initialize the ODU bridge driver + * odu_bridge_init() - Initialize the ODU bridge driver * @params: initialization parameters * * This function initialize all bridge internal data and register odu bridge to @@ -1054,7 +1144,7 @@ static void odu_bridge_deregister_properties(void) * -EINVAL - Bad parameter * Other negative value - Failure */ -int ipa2_odu_bridge_init(struct odu_bridge_params *params) +int odu_bridge_init(struct odu_bridge_params *params) { int res; @@ -1080,6 +1170,10 @@ int ipa2_odu_bridge_init(struct odu_bridge_params *params) ODU_BRIDGE_ERR("Already initialized\n"); return -EFAULT; } + if (!ipa_is_ready()) { + ODU_BRIDGE_ERR("IPA is not ready\n"); + return -EFAULT; + } ODU_BRIDGE_DBG("device_ethaddr=%pM\n", params->device_ethaddr); @@ -1089,6 +1183,13 @@ int ipa2_odu_bridge_init(struct odu_bridge_params *params) return -ENOMEM; } + res = odu_bridge_ipc_logging_init(); + if (res) { + /* ODU_BRIDGE_ERR will crash on NULL if we use it here*/ + pr_err("odu_bridge: failed to initialize ipc logging\n"); + res = -EFAULT; + goto fail_ipc_create; + } odu_bridge_ctx->class = class_create(THIS_MODULE, ODU_BRIDGE_DRV_NAME); if (!odu_bridge_ctx->class) { ODU_BRIDGE_ERR("Class_create err.\n"); @@ -1163,19 +1264,23 @@ fail_device_create: fail_alloc_chrdev_region: class_destroy(odu_bridge_ctx->class); fail_class_create: + ipc_log_context_destroy(odu_bridge_ctx->logbuf); + ipc_log_context_destroy(odu_bridge_ctx->logbuf_low); +fail_ipc_create: kfree(odu_bridge_ctx); odu_bridge_ctx = NULL; return res; } +EXPORT_SYMBOL(odu_bridge_init); /** - * ipa2_odu_bridge_cleanup() - De-Initialize the ODU bridge driver + * odu_bridge_cleanup() - De-Initialize the ODU bridge driver * * Return codes: 0: success, * -EINVAL - Bad parameter * Other negative value - Failure */ -int ipa2_odu_bridge_cleanup(void) +int odu_bridge_cleanup(void) { ODU_BRIDGE_FUNC_ENTRY(); @@ -1196,12 +1301,15 @@ int ipa2_odu_bridge_cleanup(void) device_destroy(odu_bridge_ctx->class, odu_bridge_ctx->dev_num); unregister_chrdev_region(odu_bridge_ctx->dev_num, 1); class_destroy(odu_bridge_ctx->class); + ipc_log_context_destroy(odu_bridge_ctx->logbuf); + ipc_log_context_destroy(odu_bridge_ctx->logbuf_low); kfree(odu_bridge_ctx); odu_bridge_ctx = NULL; ODU_BRIDGE_FUNC_EXIT(); return 0; } +EXPORT_SYMBOL(odu_bridge_cleanup); MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/msm/ipa/ipa_v2/Makefile b/drivers/platform/msm/ipa/ipa_v2/Makefile index c1ca6b7dba75..1bb9c91d3bd4 100644 --- a/drivers/platform/msm/ipa/ipa_v2/Makefile +++ b/drivers/platform/msm/ipa/ipa_v2/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_IPA) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ - ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o odu_bridge.o \ - ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o \ + ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o ipa_rm.o \ + ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o \ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o obj-$(CONFIG_RMNET_IPA) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index 1452c59e2787..761aa6f9a4a1 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.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 @@ -785,7 +785,11 @@ int __ipa_del_hdr(u32 hdr_hdl) return -EINVAL; } - IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len, + if (entry->is_hdr_proc_ctx) + IPADBG("del hdr of sz=%d hdr_cnt=%d phys_base=%pa\n", + entry->hdr_len, htbl->hdr_cnt, &entry->phys_base); + else + IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len, htbl->hdr_cnt, entry->offset_entry->offset); if (--entry->ref_cnt) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index f4148a5e52f1..3f538a3ed8cf 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -1838,20 +1838,6 @@ enum ipacm_client_enum ipa2_get_client(int pipe_idx); bool ipa2_get_client_uplink(int pipe_idx); /* - * ODU bridge - */ - -int ipa2_odu_bridge_init(struct odu_bridge_params *params); - -int ipa2_odu_bridge_connect(void); - -int ipa2_odu_bridge_disconnect(void); - -int ipa2_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata); - -int ipa2_odu_bridge_cleanup(void); - -/* * IPADMA */ int ipa2_dma_init(void); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index ca8b9c41f94a..888345a23ba5 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -5039,11 +5039,6 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_set_client = ipa2_set_client; api_ctrl->ipa_get_client = ipa2_get_client; api_ctrl->ipa_get_client_uplink = ipa2_get_client_uplink; - api_ctrl->odu_bridge_init = ipa2_odu_bridge_init; - api_ctrl->odu_bridge_connect = ipa2_odu_bridge_connect; - api_ctrl->odu_bridge_disconnect = ipa2_odu_bridge_disconnect; - api_ctrl->odu_bridge_tx_dp = ipa2_odu_bridge_tx_dp; - api_ctrl->odu_bridge_cleanup = ipa2_odu_bridge_cleanup; api_ctrl->ipa_dma_init = ipa2_dma_init; api_ctrl->ipa_dma_enable = ipa2_dma_enable; api_ctrl->ipa_dma_disable = ipa2_dma_disable; diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile index 6452b12f553a..2ba86bbfd80c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/Makefile +++ b/drivers/platform/msm/ipa/ipa_v3/Makefile @@ -2,8 +2,8 @@ obj-$(CONFIG_IPA3) += ipahal/ obj-$(CONFIG_IPA3) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ - ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o odu_bridge.o \ - ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o \ + ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o ipa_rm.o \ + ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o \ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o obj-$(CONFIG_RMNET_IPA3) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 30e554b648f5..d09363b725de 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4046,6 +4046,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge; ipa3_ctx->ipa_bam_remote_mode = resource_p->ipa_bam_remote_mode; ipa3_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt; + ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2; ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size; ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset; ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control; @@ -4549,6 +4550,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa3_hw_mode = 0; ipa_drv_res->ipa_bam_remote_mode = false; ipa_drv_res->modem_cfg_emb_pipe_flt = false; + ipa_drv_res->ipa_wdi2 = false; ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; ipa_drv_res->apply_rg10_wa = false; @@ -4609,6 +4611,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->modem_cfg_emb_pipe_flt ? "True" : "False"); + ipa_drv_res->ipa_wdi2 = + of_property_read_bool(pdev->dev.of_node, + "qcom,ipa-wdi2"); + IPADBG(": WDI-2.0 = %s\n", + ipa_drv_res->ipa_wdi2 + ? "True" : "False"); + ipa_drv_res->skip_uc_pipe_reset = of_property_read_bool(pdev->dev.of_node, "qcom,skip-uc-pipe-reset"); @@ -5203,6 +5212,11 @@ int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data) { struct ipa3_ready_cb_info *cb_info = NULL; + /* check ipa3_ctx existed or not */ + if (!ipa3_ctx) { + IPADBG("IPA driver haven't initialized\n"); + return -ENXIO; + } mutex_lock(&ipa3_ctx->lock); if (ipa3_ctx->ipa_initialization_complete) { mutex_unlock(&ipa3_ctx->lock); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index b8baa53ae9e9..f58751d4c0d3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -657,7 +657,11 @@ int __ipa3_del_hdr(u32 hdr_hdl) return -EINVAL; } - IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len, + if (entry->is_hdr_proc_ctx) + IPADBG("del hdr of sz=%d hdr_cnt=%d phys_base=%pa\n", + entry->hdr_len, htbl->hdr_cnt, &entry->phys_base); + else + IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len, htbl->hdr_cnt, entry->offset_entry->offset); if (--entry->ref_cnt) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 2b702daefddb..3fa7d4121a1b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -49,6 +49,9 @@ #define IPA_DL_CHECKSUM_LENGTH (8) #define IPA_NUM_DESC_PER_SW_TX (3) #define IPA_GENERIC_RX_POOL_SZ 192 +#define IPA_UC_FINISH_MAX 6 +#define IPA_UC_WAIT_MIN_SLEEP 1000 +#define IPA_UC_WAII_MAX_SLEEP 1200 #define IPA_MAX_STATUS_STAT_NUM 30 #define __FILENAME__ \ @@ -1385,6 +1388,14 @@ struct ipa3_uc_ctx { u32 uc_status; u32 uc_error_type; u32 uc_error_timestamp; + phys_addr_t rdy_ring_base_pa; + phys_addr_t rdy_ring_rp_pa; + u32 rdy_ring_size; + phys_addr_t rdy_comp_ring_base_pa; + phys_addr_t rdy_comp_ring_wp_pa; + u32 rdy_comp_ring_size; + u32 *rdy_ring_rp_va; + u32 *rdy_comp_ring_wp_va; }; /** @@ -1514,6 +1525,7 @@ struct ipa3_ready_cb_info { * @modem_cfg_emb_pipe_flt: modem configure embedded pipe filtering rules * @logbuf: ipc log buffer for high priority messages * @logbuf_low: ipc log buffer for low priority messages + * @ipa_wdi2: using wdi-2.0 * @ipa_bus_hdl: msm driver handle for the data path bus * @ctrl: holds the core specific operations based on * core version (vtable like) @@ -1610,6 +1622,7 @@ struct ipa3_context { bool use_ipa_teth_bridge; bool ipa_bam_remote_mode; bool modem_cfg_emb_pipe_flt; + bool ipa_wdi2; /* featurize if memory footprint becomes a concern */ struct ipa3_stats stats; void *smem_pipe_mem; @@ -1685,6 +1698,7 @@ struct ipa3_plat_drv_res { u32 ee; bool ipa_bam_remote_mode; bool modem_cfg_emb_pipe_flt; + bool ipa_wdi2; u32 wan_rx_ring_size; bool skip_uc_pipe_reset; enum ipa_transport_type transport_prototype; @@ -2088,20 +2102,6 @@ enum ipacm_client_enum ipa3_get_client(int pipe_idx); bool ipa3_get_client_uplink(int pipe_idx); /* - * ODU bridge - */ - -int ipa3_odu_bridge_init(struct odu_bridge_params *params); - -int ipa3_odu_bridge_connect(void); - -int ipa3_odu_bridge_disconnect(void); - -int ipa3_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata); - -int ipa3_odu_bridge_cleanup(void); - -/* * IPADMA */ int ipa3_dma_init(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 18784a64cf58..8ba2aa2a8b4d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -12,6 +12,7 @@ #include "ipa_i.h" #include <linux/dmapool.h> #include <linux/delay.h> +#include <linux/mm.h> #define IPA_HOLB_TMR_DIS 0x0 @@ -25,12 +26,14 @@ #define IPA_WDI_RESUMED BIT(2) #define IPA_UC_POLL_SLEEP_USEC 100 -#define IPA_WDI_RX_RING_RES 0 -#define IPA_WDI_RX_RING_RP_RES 1 -#define IPA_WDI_TX_RING_RES 2 -#define IPA_WDI_CE_RING_RES 3 -#define IPA_WDI_CE_DB_RES 4 -#define IPA_WDI_MAX_RES 5 +#define IPA_WDI_RX_RING_RES 0 +#define IPA_WDI_RX_RING_RP_RES 1 +#define IPA_WDI_RX_COMP_RING_RES 2 +#define IPA_WDI_RX_COMP_RING_WP_RES 3 +#define IPA_WDI_TX_RING_RES 4 +#define IPA_WDI_CE_RING_RES 5 +#define IPA_WDI_CE_DB_RES 6 +#define IPA_WDI_MAX_RES 7 struct ipa_wdi_res { struct ipa_wdi_buffer_info *res; @@ -232,6 +235,21 @@ struct IpaHwWdiTxSetUpCmdData_t { u8 reserved; } __packed; +struct IpaHwWdi2TxSetUpCmdData_t { + u32 comp_ring_base_pa; + u32 comp_ring_base_pa_hi; + u16 comp_ring_size; + u16 reserved_comp_ring; + u32 ce_ring_base_pa; + u32 ce_ring_base_pa_hi; + u16 ce_ring_size; + u16 reserved_ce_ring; + u32 ce_ring_doorbell_pa; + u32 ce_ring_doorbell_pa_hi; + u16 num_tx_buffers; + u8 ipa_pipe_number; + u8 reserved; +} __packed; /** * struct IpaHwWdiRxSetUpCmdData_t - Structure holding the parameters for * IPA_CPU_2_HW_CMD_WDI_RX_SET_UP command. @@ -253,6 +271,19 @@ struct IpaHwWdiRxSetUpCmdData_t { u8 ipa_pipe_number; } __packed; +struct IpaHwWdi2RxSetUpCmdData_t { + u32 rx_ring_base_pa; + u32 rx_ring_base_pa_hi; + u32 rx_ring_size; + u32 rx_ring_rp_pa; + u32 rx_ring_rp_pa_hi; + u32 rx_comp_ring_base_pa; + u32 rx_comp_ring_base_pa_hi; + u32 rx_comp_ring_size; + u32 rx_comp_ring_wp_pa; + u32 rx_comp_ring_wp_pa_hi; + u8 ipa_pipe_number; +} __packed; /** * union IpaHwWdiRxExtCfgCmdData_t - Structure holding the parameters for * IPA_CPU_2_HW_CMD_WDI_RX_EXT_CFG command. @@ -554,7 +585,10 @@ static void ipa_release_uc_smmu_mappings(enum ipa_client_type client) end = IPA_WDI_CE_DB_RES; } else { start = IPA_WDI_RX_RING_RES; - end = IPA_WDI_RX_RING_RP_RES; + if (ipa3_ctx->ipa_wdi2) + end = IPA_WDI_RX_COMP_RING_WP_RES; + else + end = IPA_WDI_RX_RING_RP_RES; } for (i = start; i <= end; i++) { @@ -656,6 +690,7 @@ static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en, if (wlan_smmu_en && ipa3_ctx->smmu_present) { switch (res_idx) { case IPA_WDI_RX_RING_RP_RES: + case IPA_WDI_RX_COMP_RING_WP_RES: case IPA_WDI_CE_DB_RES: if (ipa_create_uc_smmu_mapping_pa(pa, len, (res_idx == IPA_WDI_CE_DB_RES) ? true : false, @@ -667,6 +702,7 @@ static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en, ipa_save_uc_smmu_mapping_pa(res_idx, pa, *iova, len); break; case IPA_WDI_RX_RING_RES: + case IPA_WDI_RX_COMP_RING_RES: case IPA_WDI_TX_RING_RES: case IPA_WDI_CE_RING_RES: if (ipa_create_uc_smmu_mapping_sgt(sgt, iova)) { @@ -702,6 +738,9 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, struct ipa3_mem_buffer cmd; struct IpaHwWdiTxSetUpCmdData_t *tx; struct IpaHwWdiRxSetUpCmdData_t *rx; + struct IpaHwWdi2TxSetUpCmdData_t *tx_2; + struct IpaHwWdi2RxSetUpCmdData_t *rx_2; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; unsigned long va; phys_addr_t pa; @@ -749,7 +788,10 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPADBG("client=%d ep=%d\n", in->sys.client, ipa_ep_idx); if (IPA_CLIENT_IS_CONS(in->sys.client)) { - cmd.size = sizeof(*tx); + if (ipa3_ctx->ipa_wdi2) + cmd.size = sizeof(*tx_2); + else + cmd.size = sizeof(*tx); IPADBG("comp_ring_base_pa=0x%pa\n", &in->u.dl.comp_ring_base_pa); IPADBG("comp_ring_size=%d\n", in->u.dl.comp_ring_size); @@ -759,10 +801,54 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, &in->u.dl.ce_door_bell_pa); IPADBG("num_tx_buffers=%d\n", in->u.dl.num_tx_buffers); } else { - cmd.size = sizeof(*rx); - IPADBG("rx_ring_base_pa=0x%pa\n", &in->u.ul.rdy_ring_base_pa); - IPADBG("rx_ring_size=%d\n", in->u.ul.rdy_ring_size); - IPADBG("rx_ring_rp_pa=0x%pa\n", &in->u.ul.rdy_ring_rp_pa); + if (ipa3_ctx->ipa_wdi2) + cmd.size = sizeof(*rx_2); + else + cmd.size = sizeof(*rx); + IPADBG("rx_ring_base_pa=0x%pa\n", + &in->u.ul.rdy_ring_base_pa); + IPADBG("rx_ring_size=%d\n", + in->u.ul.rdy_ring_size); + IPADBG("rx_ring_rp_pa=0x%pa\n", + &in->u.ul.rdy_ring_rp_pa); + IPADBG("rdy_ring_rp value =%d\n", + *in->u.ul.rdy_ring_rp_va); + IPADBG("rx_comp_ring_base_pa=0x%pa\n", + &in->u.ul.rdy_comp_ring_base_pa); + IPADBG("rx_comp_ring_size=%d\n", + in->u.ul.rdy_comp_ring_size); + IPADBG("rx_comp_ring_wp_pa=0x%pa\n", + &in->u.ul.rdy_comp_ring_wp_pa); + IPADBG("rx_comp_ring_wp value=%d\n", + *in->u.ul.rdy_comp_ring_wp_va); + ipa3_ctx->uc_ctx.rdy_ring_base_pa = + in->u.ul.rdy_ring_base_pa; + ipa3_ctx->uc_ctx.rdy_ring_rp_pa = + in->u.ul.rdy_ring_rp_pa; + ipa3_ctx->uc_ctx.rdy_ring_size = + in->u.ul.rdy_ring_size; + ipa3_ctx->uc_ctx.rdy_comp_ring_base_pa = + in->u.ul.rdy_comp_ring_base_pa; + ipa3_ctx->uc_ctx.rdy_comp_ring_wp_pa = + in->u.ul.rdy_comp_ring_wp_pa; + ipa3_ctx->uc_ctx.rdy_comp_ring_size = + in->u.ul.rdy_comp_ring_size; + ipa3_ctx->uc_ctx.rdy_ring_rp_va = + in->u.ul.rdy_ring_rp_va; + ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va = + in->u.ul.rdy_comp_ring_wp_va; + /* check if the VA is empty */ + if (!in->u.ul.rdy_ring_rp_va && ipa3_ctx->ipa_wdi2) { + IPAERR("rdy_ring_rp_va is empty, wdi2.0(%d)\n", + ipa3_ctx->ipa_wdi2); + goto dma_alloc_fail; + } + if (!in->u.ul.rdy_comp_ring_wp_va && + ipa3_ctx->ipa_wdi2) { + IPAERR("comp_ring_wp_va is empty, wdi2.0(%d)\n", + ipa3_ctx->ipa_wdi2); + goto dma_alloc_fail; + } } cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size, @@ -774,14 +860,16 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, } if (IPA_CLIENT_IS_CONS(in->sys.client)) { - tx = (struct IpaHwWdiTxSetUpCmdData_t *)cmd.base; + if (ipa3_ctx->ipa_wdi2) { + tx_2 = (struct IpaHwWdi2TxSetUpCmdData_t *)cmd.base; - len = in->smmu_enabled ? in->u.dl_smmu.comp_ring_size : - in->u.dl.comp_ring_size; - IPADBG("TX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, + len = in->smmu_enabled ? in->u.dl_smmu.comp_ring_size : + in->u.dl.comp_ring_size; + IPADBG("TX_2 ring smmu_en=%d ring_size=%d %d\n", + in->smmu_enabled, in->u.dl_smmu.comp_ring_size, in->u.dl.comp_ring_size); - if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES, + if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES, in->smmu_enabled, in->u.dl.comp_ring_base_pa, &in->u.dl_smmu.comp_ring, @@ -791,90 +879,260 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPAERR("fail to create uc mapping TX ring.\n"); result = -ENOMEM; goto uc_timeout; - } - tx->comp_ring_base_pa = va; - tx->comp_ring_size = len; - - len = in->smmu_enabled ? in->u.dl_smmu.ce_ring_size : - in->u.dl.ce_ring_size; - IPADBG("TX CE ring smmu_en=%d ring_size=%d %d\n", - in->smmu_enabled, - in->u.dl_smmu.ce_ring_size, - in->u.dl.ce_ring_size); - if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES, + } + tx_2->comp_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + tx_2->comp_ring_base_pa = (u32) (va & 0xFFFFFFFF); + tx_2->comp_ring_size = len; + IPADBG("TX_2 comp_ring_base_pa_hi=0x%08x :0x%08x\n", + tx_2->comp_ring_base_pa_hi, + tx_2->comp_ring_base_pa); + + len = in->smmu_enabled ? in->u.dl_smmu.ce_ring_size : + in->u.dl.ce_ring_size; + IPADBG("TX_2 CE ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, - in->u.dl.ce_ring_base_pa, - &in->u.dl_smmu.ce_ring, - len, - false, - &va)) { + in->u.dl_smmu.ce_ring_size, + in->u.dl.ce_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES, + in->smmu_enabled, + in->u.dl.ce_ring_base_pa, + &in->u.dl_smmu.ce_ring, + len, + false, + &va)) { IPAERR("fail to create uc mapping CE ring.\n"); result = -ENOMEM; goto uc_timeout; - } - tx->ce_ring_base_pa = va; - tx->ce_ring_size = len; - - pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa : - in->u.dl.ce_door_bell_pa; - if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES, + } + tx_2->ce_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + tx_2->ce_ring_base_pa = (u32) (va & 0xFFFFFFFF); + tx_2->ce_ring_size = len; + IPADBG("TX_2 ce_ring_base_pa_hi=0x%08x :0x%08x\n", + tx_2->ce_ring_base_pa_hi, + tx_2->ce_ring_base_pa); + + pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa : + in->u.dl.ce_door_bell_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES, + in->smmu_enabled, + pa, + NULL, + 4, + true, + &va)) { + IPAERR("fail to create uc mapping CE DB.\n"); + result = -ENOMEM; + goto uc_timeout; + } + tx_2->ce_ring_doorbell_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + tx_2->ce_ring_doorbell_pa = (u32) (va & 0xFFFFFFFF); + IPADBG("TX_2 ce_ring_doorbell_pa_hi=0x%08x :0x%08x\n", + tx_2->ce_ring_doorbell_pa_hi, + tx_2->ce_ring_doorbell_pa); + + tx_2->num_tx_buffers = in->u.dl.num_tx_buffers; + tx_2->ipa_pipe_number = ipa_ep_idx; + } else { + tx = (struct IpaHwWdiTxSetUpCmdData_t *)cmd.base; + + len = in->smmu_enabled ? in->u.dl_smmu.comp_ring_size : + in->u.dl.comp_ring_size; + IPADBG("TX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, - pa, - NULL, - 4, - true, - &va)) { + in->u.dl_smmu.comp_ring_size, + in->u.dl.comp_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES, + in->smmu_enabled, + in->u.dl.comp_ring_base_pa, + &in->u.dl_smmu.comp_ring, + len, + false, + &va)) { + IPAERR("fail to create uc mapping TX ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + tx->comp_ring_base_pa = va; + tx->comp_ring_size = len; + len = in->smmu_enabled ? in->u.dl_smmu.ce_ring_size : + in->u.dl.ce_ring_size; + IPADBG("TX CE ring smmu_en=%d ring_size=%d %d\n", + in->smmu_enabled, + in->u.dl_smmu.ce_ring_size, + in->u.dl.ce_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES, + in->smmu_enabled, + in->u.dl.ce_ring_base_pa, + &in->u.dl_smmu.ce_ring, + len, + false, + &va)) { + IPAERR("fail to create uc mapping CE ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + tx->ce_ring_base_pa = va; + tx->ce_ring_size = len; + pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa : + in->u.dl.ce_door_bell_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES, + in->smmu_enabled, + pa, + NULL, + 4, + true, + &va)) { IPAERR("fail to create uc mapping CE DB.\n"); result = -ENOMEM; goto uc_timeout; + } + tx->ce_ring_doorbell_pa = va; + tx->num_tx_buffers = in->u.dl.num_tx_buffers; + tx->ipa_pipe_number = ipa_ep_idx; } - tx->ce_ring_doorbell_pa = va; - - tx->num_tx_buffers = in->u.dl.num_tx_buffers; - tx->ipa_pipe_number = ipa_ep_idx; out->uc_door_bell_pa = ipa3_ctx->ipa_wrapper_base + ipahal_get_reg_base() + ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n, IPA_HW_WDI_TX_MBOX_START_INDEX/32, IPA_HW_WDI_TX_MBOX_START_INDEX % 32); } else { - rx = (struct IpaHwWdiRxSetUpCmdData_t *)cmd.base; + if (ipa3_ctx->ipa_wdi2) { + rx_2 = (struct IpaHwWdi2RxSetUpCmdData_t *)cmd.base; - len = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_size : - in->u.ul.rdy_ring_size; - IPADBG("RX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, + len = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_size : + in->u.ul.rdy_ring_size; + IPADBG("RX_2 ring smmu_en=%d ring_size=%d %d\n", + in->smmu_enabled, in->u.ul_smmu.rdy_ring_size, in->u.ul.rdy_ring_size); - if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES, + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES, + in->smmu_enabled, + in->u.ul.rdy_ring_base_pa, + &in->u.ul_smmu.rdy_ring, + len, + false, + &va)) { + IPAERR("fail to create uc RX_2 ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx_2->rx_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_ring_base_pa = (u32) (va & 0xFFFFFFFF); + rx_2->rx_ring_size = len; + IPADBG("RX_2 rx_ring_base_pa_hi=0x%08x:0x%08x\n", + rx_2->rx_ring_base_pa_hi, + rx_2->rx_ring_base_pa); + + pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa : + in->u.ul.rdy_ring_rp_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES, + in->smmu_enabled, + pa, + NULL, + 4, + false, + &va)) { + IPAERR("fail to create uc RX_2 rng RP\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx_2->rx_ring_rp_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_ring_rp_pa = (u32) (va & 0xFFFFFFFF); + IPADBG("RX_2 rx_ring_rp_pa_hi=0x%08x :0x%08x\n", + rx_2->rx_ring_rp_pa_hi, + rx_2->rx_ring_rp_pa); + len = in->smmu_enabled ? + in->u.ul_smmu.rdy_comp_ring_size : + in->u.ul.rdy_comp_ring_size; + IPADBG("RX_2 ring smmu_en=%d comp_ring_size=%d %d\n", in->smmu_enabled, - in->u.ul.rdy_ring_base_pa, - &in->u.ul_smmu.rdy_ring, - len, - false, - &va)) { - IPAERR("fail to create uc mapping RX ring.\n"); + in->u.ul_smmu.rdy_comp_ring_size, + in->u.ul.rdy_comp_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_COMP_RING_RES, + in->smmu_enabled, + in->u.ul.rdy_comp_ring_base_pa, + &in->u.ul_smmu.rdy_comp_ring, + len, + false, + &va)) { + IPAERR("fail to create uc RX_2 comp_ring.\n"); result = -ENOMEM; goto uc_timeout; - } - rx->rx_ring_base_pa = va; - rx->rx_ring_size = len; - - pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa : - in->u.ul.rdy_ring_rp_pa; - if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES, + } + rx_2->rx_comp_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_comp_ring_base_pa = (u32) (va & 0xFFFFFFFF); + rx_2->rx_comp_ring_size = len; + IPADBG("RX_2 rx_comp_ring_base_pa_hi=0x%08x:0x%08x\n", + rx_2->rx_comp_ring_base_pa_hi, + rx_2->rx_comp_ring_base_pa); + + pa = in->smmu_enabled ? + in->u.ul_smmu.rdy_comp_ring_wp_pa : + in->u.ul.rdy_comp_ring_wp_pa; + if (ipa_create_uc_smmu_mapping( + IPA_WDI_RX_COMP_RING_WP_RES, + in->smmu_enabled, + pa, + NULL, + 4, + false, + &va)) { + IPAERR("fail to create uc RX_2 comp_rng WP\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx_2->rx_comp_ring_wp_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_comp_ring_wp_pa = (u32) (va & 0xFFFFFFFF); + IPADBG("RX_2 rx_comp_ring_wp_pa_hi=0x%08x:0x%08x\n", + rx_2->rx_comp_ring_wp_pa_hi, + rx_2->rx_comp_ring_wp_pa); + rx_2->ipa_pipe_number = ipa_ep_idx; + } else { + rx = (struct IpaHwWdiRxSetUpCmdData_t *)cmd.base; + + len = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_size : + in->u.ul.rdy_ring_size; + IPADBG("RX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, - pa, - NULL, - 4, - false, - &va)) { + in->u.ul_smmu.rdy_ring_size, + in->u.ul.rdy_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES, + in->smmu_enabled, + in->u.ul.rdy_ring_base_pa, + &in->u.ul_smmu.rdy_ring, + len, + false, + &va)) { + IPAERR("fail to create uc mapping RX ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx->rx_ring_base_pa = va; + rx->rx_ring_size = len; + + pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa : + in->u.ul.rdy_ring_rp_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES, + in->smmu_enabled, + pa, + NULL, + 4, + false, + &va)) { IPAERR("fail to create uc mapping RX rng RP\n"); result = -ENOMEM; goto uc_timeout; + } + rx->rx_ring_rp_pa = va; + rx->ipa_pipe_number = ipa_ep_idx; } - rx->rx_ring_rp_pa = va; - - rx->ipa_pipe_number = ipa_ep_idx; out->uc_door_bell_pa = ipa3_ctx->ipa_wrapper_base + ipahal_get_reg_base() + ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n, @@ -1083,6 +1341,7 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) union IpaHwWdiCommonChCmdData_t disable; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; u32 prod_hdl; + int i; if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || ipa3_ctx->ep[clnt_hdl].valid == 0) { @@ -1094,6 +1353,28 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) if (result) return result; + /* checking rdy_ring_rp_pa matches the rdy_comp_ring_wp_pa on WDI2.0 */ + if (ipa3_ctx->ipa_wdi2) { + for (i = 0; i < IPA_UC_FINISH_MAX; i++) { + IPADBG("(%d) rp_value(%u), comp_wp_value(%u)\n", + i, + *ipa3_ctx->uc_ctx.rdy_ring_rp_va, + *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va); + if (*ipa3_ctx->uc_ctx.rdy_ring_rp_va != + *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va) { + usleep_range(IPA_UC_WAIT_MIN_SLEEP, + IPA_UC_WAII_MAX_SLEEP); + } else { + break; + } + } + /* In case ipa_uc still haven't processed all + * pending descriptors, we have to assert + */ + if (i == IPA_UC_FINISH_MAX) + WARN_ON(1); + } + IPADBG("ep=%d\n", clnt_hdl); ep = &ipa3_ctx->ep[clnt_hdl]; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index f1ec3069d365..1c4f812bc40f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -4543,11 +4543,6 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_set_client = ipa3_set_client; api_ctrl->ipa_get_client = ipa3_get_client; api_ctrl->ipa_get_client_uplink = ipa3_get_client_uplink; - api_ctrl->odu_bridge_init = ipa3_odu_bridge_init; - api_ctrl->odu_bridge_connect = ipa3_odu_bridge_connect; - api_ctrl->odu_bridge_disconnect = ipa3_odu_bridge_disconnect; - api_ctrl->odu_bridge_tx_dp = ipa3_odu_bridge_tx_dp; - api_ctrl->odu_bridge_cleanup = ipa3_odu_bridge_cleanup; api_ctrl->ipa_dma_init = ipa3_dma_init; api_ctrl->ipa_dma_enable = ipa3_dma_enable; api_ctrl->ipa_dma_disable = ipa3_dma_disable; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index 2677c9e0c83c..f7a74283056c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include <linux/ipc_logging.h> +#include <linux/debugfs.h> #include "ipahal.h" #include "ipahal_i.h" #include "ipahal_reg_i.h" @@ -531,7 +533,7 @@ static int ipahal_imm_cmd_init(enum ipa_hw_type ipa_hw_type) int j; struct ipahal_imm_cmd_obj zero_obj; - IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type); + IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type); memset(&zero_obj, 0, sizeof(zero_obj)); for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) { @@ -592,7 +594,8 @@ u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd) return -EFAULT; } - IPAHAL_DBG("Get opcode of IMM_CMD=%s\n", ipahal_imm_cmd_name_str(cmd)); + IPAHAL_DBG_LOW("Get opcode of IMM_CMD=%s\n", + ipahal_imm_cmd_name_str(cmd)); opcode = ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].opcode; if (opcode == -1) { IPAHAL_ERR("Try to get opcode of obsolete IMM_CMD=%s\n", @@ -624,7 +627,8 @@ u16 ipahal_imm_cmd_get_opcode_param(enum ipahal_imm_cmd_name cmd, int param) return -EFAULT; } - IPAHAL_DBG("Get opcode of IMM_CMD=%s\n", ipahal_imm_cmd_name_str(cmd)); + IPAHAL_DBG_LOW("Get opcode of IMM_CMD=%s\n", + ipahal_imm_cmd_name_str(cmd)); if (!ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].dyn_op) { IPAHAL_ERR("IMM_CMD=%s does not support dynamic opcode\n", @@ -681,7 +685,7 @@ struct ipahal_imm_cmd_pyld *ipahal_construct_imm_cmd( return NULL; } - IPAHAL_DBG("construct IMM_CMD:%s\n", ipahal_imm_cmd_name_str(cmd)); + IPAHAL_DBG_LOW("construct IMM_CMD:%s\n", ipahal_imm_cmd_name_str(cmd)); return ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].construct( cmd, params, is_atomic_ctx); } @@ -895,7 +899,7 @@ static int ipahal_pkt_status_init(enum ipa_hw_type ipa_hw_type) int i; struct ipahal_pkt_status_obj zero_obj; - IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type); + IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type); /* * Since structure alignment is implementation dependent, @@ -960,7 +964,7 @@ void ipahal_pkt_status_parse(const void *unparsed_status, return; } - IPAHAL_DBG("Parse Status Packet\n"); + IPAHAL_DBG_LOW("Parse Status Packet\n"); memset(status, 0, sizeof(*status)); ipahal_pkt_status_objs[ipahal_ctx->hw_type].parse(unparsed_status, status); @@ -983,6 +987,72 @@ const char *ipahal_pkt_status_exception_str( return ipahal_pkt_status_exception_to_str[exception]; } +static int ipahal_ipc_logging_init(void) +{ + ipahal_ctx->ipc_logbuf = + ipc_log_context_create(IPAHAL_IPC_LOG_PAGES, "ipahal", 0); + if (!ipahal_ctx->ipc_logbuf) { + /* Cannot use the logging macros as no log buffers yet */ + pr_err("ipaghal: failed to create ipc_logbuf\n"); + return -ENOMEM; + } + + ipahal_ctx->ipc_logbuf_low = + ipc_log_context_create(IPAHAL_IPC_LOG_PAGES, "ipahal_low", 0); + if (!ipahal_ctx->ipc_logbuf_low) { + /* Cannot use the logging macros as no log buffers yet */ + pr_err("ipaghal: failed to create ipc_logbuf_low\n"); + ipc_log_context_destroy(ipahal_ctx->ipc_logbuf); + return -ENOMEM; + } + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void ipahal_debugfs_init(void) +{ + const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH | + S_IWUSR | S_IWGRP; + + ipahal_ctx->dent = debugfs_create_dir("ipahal", 0); + if (!ipahal_ctx->dent || IS_ERR(ipahal_ctx->dent)) { + IPAHAL_ERR("fail to create ipahal debugfs folder\n"); + return; + } + + ipahal_ctx->dfile_enable_low_prio_ipc = + debugfs_create_u32("enable_low_prio_log", read_write_mode, + ipahal_ctx->dent, &ipahal_ctx->enable_low_prio_ipc); + if (!ipahal_ctx->dfile_enable_low_prio_ipc || + IS_ERR(ipahal_ctx->dfile_enable_low_prio_ipc)) { + IPAHAL_ERR("fail create enable_low_prio_log debugfs file\n"); + goto fail; + } + + return; +fail: + debugfs_remove_recursive(ipahal_ctx->dent); + ipahal_ctx->dent = NULL; +} + +static void ipahal_debugfs_remove(void) +{ + if (!ipahal_ctx) + return; + + if (IS_ERR(ipahal_ctx->dent)) { + IPAHAL_ERR("ipahal debugfs folder was not created\n"); + return; + } + + debugfs_remove_recursive(ipahal_ctx->dent); +} +#else /* CONFIG_DEBUG_FS */ +static void ipahal_debugfs_init(void) {} +static void ipahal_debugfs_remove(void) {} +#endif /* CONFIG_DEBUG_FS */ + int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base) { int result; @@ -997,16 +1067,23 @@ int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base) goto bail_err_exit; } + if (ipahal_ipc_logging_init()) { + /* Cannot use the logging macros as no log buffers yet */ + pr_err("ipahal: failed to initialize ipc logging\n"); + result = -ENOMEM; + goto bail_free_ctx; + } + if (ipa_hw_type < IPA_HW_v3_0) { IPAHAL_ERR("ipahal supported on IPAv3 and later only\n"); result = -EINVAL; - goto bail_free_ctx; + goto bail_destroy_ipc; } if (!base) { IPAHAL_ERR("invalid memory io mapping addr\n"); result = -EINVAL; - goto bail_free_ctx; + goto bail_destroy_ipc; } ipahal_ctx->hw_type = ipa_hw_type; @@ -1015,23 +1092,28 @@ int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base) if (ipahal_reg_init(ipa_hw_type)) { IPAHAL_ERR("failed to init ipahal reg\n"); result = -EFAULT; - goto bail_free_ctx; + goto bail_destroy_ipc; } if (ipahal_imm_cmd_init(ipa_hw_type)) { IPAHAL_ERR("failed to init ipahal imm cmd\n"); result = -EFAULT; - goto bail_free_ctx; + goto bail_destroy_ipc; } if (ipahal_pkt_status_init(ipa_hw_type)) { IPAHAL_ERR("failed to init ipahal pkt status\n"); result = -EFAULT; - goto bail_free_ctx; + goto bail_destroy_ipc; } + ipahal_debugfs_init(); + return 0; +bail_destroy_ipc: + ipc_log_context_destroy(ipahal_ctx->ipc_logbuf_low); + ipc_log_context_destroy(ipahal_ctx->ipc_logbuf); bail_free_ctx: kfree(ipahal_ctx); ipahal_ctx = NULL; @@ -1042,7 +1124,7 @@ bail_err_exit: void ipahal_destroy(void) { IPAHAL_DBG("Entry\n"); - + ipahal_debugfs_remove(); kfree(ipahal_ctx); ipahal_ctx = NULL; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h index c5dbf0185267..3c513a7d4dc1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h @@ -14,20 +14,65 @@ #define _IPAHAL_I_H_ #define IPAHAL_DRV_NAME "ipahal" + +#define IPAHAL_IPC_LOG_PAGES 10 +#define IPAHAL_IPC_LOG(buf, fmt, args...) \ + ipc_log_string((buf), \ + IPAHAL_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + #define IPAHAL_DBG(fmt, args...) \ - pr_debug(IPAHAL_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_debug(IPAHAL_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + if (likely(ipahal_ctx)) { \ + IPAHAL_IPC_LOG(ipahal_ctx->ipc_logbuf, fmt, ## args); \ + IPAHAL_IPC_LOG(ipahal_ctx->ipc_logbuf_low, \ + fmt, ## args); \ + } \ + } while (0) + +#define IPAHAL_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(IPAHAL_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + if (likely(ipahal_ctx) && \ + ipahal_ctx->enable_low_prio_ipc) { \ + IPAHAL_IPC_LOG(ipahal_ctx->ipc_logbuf_low, \ + fmt, ## args); \ + } \ + } while (0) + #define IPAHAL_ERR(fmt, args...) \ - pr_err(IPAHAL_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_err(IPAHAL_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + if (likely(ipahal_ctx)) { \ + IPAHAL_IPC_LOG(ipahal_ctx->ipc_logbuf, fmt, ## args); \ + IPAHAL_IPC_LOG(ipahal_ctx->ipc_logbuf_low, \ + fmt, ## args); \ + } \ + } while (0) /* * struct ipahal_context - HAL global context data * @hw_type: IPA H/W type/version. * @base: Base address to be used for accessing IPA memory. This is * I/O memory mapped address. + * @ipc_logbuf: IPC debug logs buffer + * @ipc_logbuf_low: IPC Low priority debug logs buffer + * @enable_low_prio_ipc: Flag telling to enable low priority logging + * Controlled by debugfs. default is off + * @dent: Debugfs folder dir entry + * @dfile_enable_low_prio_ipc: Debugfs file for enable_low_prio_ipc */ struct ipahal_context { enum ipa_hw_type hw_type; void __iomem *base; + void *ipc_logbuf; + void *ipc_logbuf_low; + u32 enable_low_prio_ipc; + struct dentry *dent; + struct dentry *dfile_enable_low_prio_ipc; }; extern struct ipahal_context *ipahal_ctx; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 1e5733d3101c..cf0fa16b2bbc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include <linux/ipc_logging.h> #include <linux/init.h> #include <linux/ipa.h> #include <linux/kernel.h> @@ -1064,7 +1065,7 @@ int ipahal_reg_init(enum ipa_hw_type ipa_hw_type) int j; struct ipahal_reg_obj zero_obj; - IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type); + IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type); memset(&zero_obj, 0, sizeof(zero_obj)); for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) { @@ -1131,7 +1132,7 @@ u32 ipahal_read_reg_n(enum ipahal_reg_name reg, u32 n) return -EFAULT; } - IPAHAL_DBG("read from %s n=%u\n", + IPAHAL_DBG_LOW("read from %s n=%u\n", ipahal_reg_name_str(reg), n); offset = ipahal_reg_objs[ipahal_ctx->hw_type][reg].offset; @@ -1157,7 +1158,7 @@ void ipahal_write_reg_mn(enum ipahal_reg_name reg, u32 m, u32 n, u32 val) return; } - IPAHAL_DBG("write to %s m=%u n=%u val=%u\n", + IPAHAL_DBG_LOW("write to %s m=%u n=%u val=%u\n", ipahal_reg_name_str(reg), m, n, val); offset = ipahal_reg_objs[ipahal_ctx->hw_type][reg].offset; if (offset == -1) { @@ -1197,7 +1198,7 @@ u32 ipahal_read_reg_n_fields(enum ipahal_reg_name reg, u32 n, void *fields) return -EFAULT; } - IPAHAL_DBG("read from %s n=%u and parse it\n", + IPAHAL_DBG_LOW("read from %s n=%u and parse it\n", ipahal_reg_name_str(reg), n); offset = ipahal_reg_objs[ipahal_ctx->hw_type][reg].offset; if (offset == -1) { @@ -1232,7 +1233,7 @@ void ipahal_write_reg_n_fields(enum ipahal_reg_name reg, u32 n, return; } - IPAHAL_DBG("write to %s n=%u after constructing it\n", + IPAHAL_DBG_LOW("write to %s n=%u after constructing it\n", ipahal_reg_name_str(reg), n); offset = ipahal_reg_objs[ipahal_ctx->hw_type][reg].offset; if (offset == -1) { @@ -1260,7 +1261,7 @@ u32 ipahal_get_reg_mn_ofst(enum ipahal_reg_name reg, u32 m, u32 n) return -EFAULT; } - IPAHAL_DBG("get offset of %s m=%u n=%u\n", + IPAHAL_DBG_LOW("get offset of %s m=%u n=%u\n", ipahal_reg_name_str(reg), m, n); offset = ipahal_reg_objs[ipahal_ctx->hw_type][reg].offset; if (offset == -1) { diff --git a/drivers/platform/msm/ipa/ipa_v3/odu_bridge.c b/drivers/platform/msm/ipa/ipa_v3/odu_bridge.c deleted file mode 100644 index aef1e5130421..000000000000 --- a/drivers/platform/msm/ipa/ipa_v3/odu_bridge.c +++ /dev/null @@ -1,1233 +0,0 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/debugfs.h> -#include <linux/export.h> -#include <linux/fs.h> -#include <linux/if_ether.h> -#include <linux/ioctl.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/msm_ipa.h> -#include <linux/mutex.h> -#include <linux/skbuff.h> -#include <linux/types.h> -#include <linux/ipv6.h> -#include <net/addrconf.h> -#include <linux/ipa.h> -#include "ipa_i.h" - -#define ODU_BRIDGE_DRV_NAME "odu_ipa_bridge" - -#define ODU_BRIDGE_DBG(fmt, args...) \ - pr_debug(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, \ - __func__, __LINE__, ## args) -#define ODU_BRIDGE_ERR(fmt, args...) \ - pr_err(ODU_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) -#define ODU_BRIDGE_FUNC_ENTRY() \ - ODU_BRIDGE_DBG("ENTRY\n") -#define ODU_BRIDGE_FUNC_EXIT() \ - ODU_BRIDGE_DBG("EXIT\n") - - -#define ODU_BRIDGE_IS_QMI_ADDR(daddr) \ - (memcmp(&(daddr), &ipa3_odu_bridge_ctx->llv6_addr, sizeof((daddr))) \ - == 0) - -#define ODU_BRIDGE_IPV4_HDR_NAME "odu_br_ipv4" -#define ODU_BRIDGE_IPV6_HDR_NAME "odu_br_ipv6" - -#define IPA_ODU_SYS_DESC_FIFO_SZ 0x800 - -#ifdef CONFIG_COMPAT -#define ODU_BRIDGE_IOC_SET_LLV6_ADDR32 _IOW(ODU_BRIDGE_IOC_MAGIC, \ - ODU_BRIDGE_IOCTL_SET_LLV6_ADDR, \ - compat_uptr_t) -#endif - -/** - * struct stats - driver statistics, viewable using debugfs - * @num_ul_packets: number of packets bridged in uplink direction - * @num_dl_packets: number of packets bridged in downink direction - * bridge - * @num_lan_packets: number of packets bridged to APPS on bridge mode - */ -struct stats { - u64 num_ul_packets; - u64 num_dl_packets; - u64 num_lan_packets; -}; - -/** - * struct ipa3_odu_bridge_ctx - ODU bridge driver context information - * @class: kernel class pointer - * @dev_num: kernel device number - * @dev: kernel device struct pointer - * @cdev: kernel character device struct - * @netdev_name: network interface name - * @device_ethaddr: network interface ethernet address - * @priv: client's private data. to be used in client's callbacks - * @tx_dp_notify: client callback for handling IPA ODU_PROD callback - * @send_dl_skb: client callback for sending skb in downlink direction - * @stats: statistics, how many packets were transmitted using the SW bridge - * @is_conencted: is bridge connected ? - * @mode: ODU mode (router/bridge) - * @lock: for the initialization, connect and disconnect synchronization - * @llv6_addr: link local IPv6 address of ODU network interface - * @odu_br_ipv4_hdr_hdl: handle for partial ipv4 ethernet header - * @odu_br_ipv6_hdr_hdl: handle for partial ipv6 ethernet header - * @odu_prod_hdl: handle for IPA_CLIENT_ODU_PROD pipe - * @odu_emb_cons_hdl: handle for IPA_CLIENT_ODU_EMB_CONS pipe - * @odu_teth_cons_hdl: handle for IPA_CLIENT_ODU_TETH_CONS pipe - */ -struct ipa3_odu_bridge_ctx { - struct class *class; - dev_t dev_num; - struct device *dev; - struct cdev cdev; - char netdev_name[IPA_RESOURCE_NAME_MAX]; - u8 device_ethaddr[ETH_ALEN]; - void *priv; - ipa_notify_cb tx_dp_notify; - int (*send_dl_skb)(void *priv, struct sk_buff *skb); - struct stats stats; - bool is_connected; - enum odu_bridge_mode mode; - struct mutex lock; - struct in6_addr llv6_addr; - uint32_t odu_br_ipv4_hdr_hdl; - uint32_t odu_br_ipv6_hdr_hdl; - u32 odu_prod_hdl; - u32 odu_emb_cons_hdl; - u32 odu_teth_cons_hdl; - u32 ipa_sys_desc_size; -}; -static struct ipa3_odu_bridge_ctx *ipa3_odu_bridge_ctx; - -#ifdef CONFIG_DEBUG_FS -#define ODU_MAX_MSG_LEN 512 -static char dbg_buff[ODU_MAX_MSG_LEN]; -#endif - -static void ipa3_odu_bridge_emb_cons_cb(void *priv, enum ipa_dp_evt_type evt, - unsigned long data) -{ - ODU_BRIDGE_FUNC_ENTRY(); - if (evt != IPA_RECEIVE) { - ODU_BRIDGE_ERR("unexpected event\n"); - WARN_ON(1); - return; - } - ipa3_odu_bridge_ctx->send_dl_skb(priv, (struct sk_buff *)data); - ipa3_odu_bridge_ctx->stats.num_dl_packets++; - ODU_BRIDGE_FUNC_EXIT(); -} - -static void ipa3_odu_bridge_teth_cons_cb(void *priv, enum ipa_dp_evt_type evt, - unsigned long data) -{ - struct ipv6hdr *ipv6hdr; - struct sk_buff *skb = (struct sk_buff *)data; - struct sk_buff *skb_copied; - - ODU_BRIDGE_FUNC_ENTRY(); - if (evt != IPA_RECEIVE) { - ODU_BRIDGE_ERR("unexpected event\n"); - WARN_ON(1); - return; - } - - ipv6hdr = (struct ipv6hdr *)(skb->data + ETH_HLEN); - if (ipv6hdr->version == 6 && - ipv6_addr_is_multicast(&ipv6hdr->daddr)) { - ODU_BRIDGE_DBG("Multicast pkt, send to APPS and adapter\n"); - skb_copied = skb_clone(skb, GFP_KERNEL); - if (skb_copied) { - ipa3_odu_bridge_ctx-> - tx_dp_notify(ipa3_odu_bridge_ctx->priv, - IPA_RECEIVE, - (unsigned long) skb_copied); - ipa3_odu_bridge_ctx->stats.num_lan_packets++; - } else { - ODU_BRIDGE_ERR("No memory\n"); - } - } - - ipa3_odu_bridge_ctx->send_dl_skb(priv, skb); - ipa3_odu_bridge_ctx->stats.num_dl_packets++; - ODU_BRIDGE_FUNC_EXIT(); -} - -static int ipa3_odu_bridge_connect_router(void) -{ - struct ipa_sys_connect_params odu_prod_params; - struct ipa_sys_connect_params odu_emb_cons_params; - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - memset(&odu_prod_params, 0, sizeof(odu_prod_params)); - memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params)); - - /* configure RX (ODU->IPA) EP */ - odu_prod_params.client = IPA_CLIENT_ODU_PROD; - odu_prod_params.ipa_ep_cfg.hdr.hdr_len = ETH_HLEN; - odu_prod_params.ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT; - odu_prod_params.desc_fifo_sz = ipa3_odu_bridge_ctx->ipa_sys_desc_size; - odu_prod_params.priv = ipa3_odu_bridge_ctx->priv; - odu_prod_params.notify = ipa3_odu_bridge_ctx->tx_dp_notify; - odu_prod_params.keep_ipa_awake = true; - res = ipa3_setup_sys_pipe(&odu_prod_params, - &ipa3_odu_bridge_ctx->odu_prod_hdl); - if (res) { - ODU_BRIDGE_ERR("fail to setup sys pipe ODU_PROD %d\n", res); - goto fail_odu_prod; - } - - /* configure TX (IPA->ODU) EP */ - odu_emb_cons_params.client = IPA_CLIENT_ODU_EMB_CONS; - odu_emb_cons_params.ipa_ep_cfg.hdr.hdr_len = ETH_HLEN; - odu_emb_cons_params.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; - odu_emb_cons_params.desc_fifo_sz = - ipa3_odu_bridge_ctx->ipa_sys_desc_size; - odu_emb_cons_params.priv = ipa3_odu_bridge_ctx->priv; - odu_emb_cons_params.notify = ipa3_odu_bridge_emb_cons_cb; - odu_emb_cons_params.keep_ipa_awake = true; - res = ipa3_setup_sys_pipe(&odu_emb_cons_params, - &ipa3_odu_bridge_ctx->odu_emb_cons_hdl); - if (res) { - ODU_BRIDGE_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res); - goto fail_odu_emb_cons; - } - - ODU_BRIDGE_DBG("odu_prod_hdl = %d, odu_emb_cons_hdl = %d\n", - ipa3_odu_bridge_ctx->odu_prod_hdl, - ipa3_odu_bridge_ctx->odu_emb_cons_hdl); - - ODU_BRIDGE_FUNC_EXIT(); - - return 0; - -fail_odu_emb_cons: - ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_prod_hdl); - ipa3_odu_bridge_ctx->odu_prod_hdl = 0; -fail_odu_prod: - return res; -} - -static int ipa3_odu_bridge_connect_bridge(void) -{ - struct ipa_sys_connect_params odu_prod_params; - struct ipa_sys_connect_params odu_emb_cons_params; - struct ipa_sys_connect_params odu_teth_cons_params; - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - memset(&odu_prod_params, 0, sizeof(odu_prod_params)); - memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params)); - - /* Build IPA Resource manager dependency graph */ - ODU_BRIDGE_DBG("build dependency graph\n"); - res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, - IPA_RM_RESOURCE_Q6_CONS); - if (res && res != -EINPROGRESS) { - ODU_BRIDGE_ERR("ipa3_rm_add_dependency() failed\n"); - goto fail_add_dependency_1; - } - - res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD, - IPA_RM_RESOURCE_ODU_ADAPT_CONS); - if (res && res != -EINPROGRESS) { - ODU_BRIDGE_ERR("ipa3_rm_add_dependency() failed\n"); - goto fail_add_dependency_2; - } - - /* configure RX (ODU->IPA) EP */ - odu_prod_params.client = IPA_CLIENT_ODU_PROD; - odu_prod_params.desc_fifo_sz = IPA_ODU_SYS_DESC_FIFO_SZ; - odu_prod_params.priv = ipa3_odu_bridge_ctx->priv; - odu_prod_params.notify = ipa3_odu_bridge_ctx->tx_dp_notify; - odu_prod_params.keep_ipa_awake = true; - odu_prod_params.skip_ep_cfg = true; - res = ipa3_setup_sys_pipe(&odu_prod_params, - &ipa3_odu_bridge_ctx->odu_prod_hdl); - if (res) { - ODU_BRIDGE_ERR("fail to setup sys pipe ODU_PROD %d\n", res); - goto fail_odu_prod; - } - - /* configure TX tethered (IPA->ODU) EP */ - odu_teth_cons_params.client = IPA_CLIENT_ODU_TETH_CONS; - odu_teth_cons_params.desc_fifo_sz = IPA_ODU_SYS_DESC_FIFO_SZ; - odu_teth_cons_params.priv = ipa3_odu_bridge_ctx->priv; - odu_teth_cons_params.notify = ipa3_odu_bridge_teth_cons_cb; - odu_teth_cons_params.keep_ipa_awake = true; - odu_teth_cons_params.skip_ep_cfg = true; - res = ipa3_setup_sys_pipe(&odu_teth_cons_params, - &ipa3_odu_bridge_ctx->odu_teth_cons_hdl); - if (res) { - ODU_BRIDGE_ERR("fail to setup sys pipe ODU_TETH_CONS %d\n", - res); - goto fail_odu_teth_cons; - } - - /* configure TX embedded(IPA->ODU) EP */ - odu_emb_cons_params.client = IPA_CLIENT_ODU_EMB_CONS; - odu_emb_cons_params.ipa_ep_cfg.hdr.hdr_len = ETH_HLEN; - odu_emb_cons_params.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; - odu_emb_cons_params.desc_fifo_sz = IPA_ODU_SYS_DESC_FIFO_SZ; - odu_emb_cons_params.priv = ipa3_odu_bridge_ctx->priv; - odu_emb_cons_params.notify = ipa3_odu_bridge_emb_cons_cb; - odu_emb_cons_params.keep_ipa_awake = true; - res = ipa3_setup_sys_pipe(&odu_emb_cons_params, - &ipa3_odu_bridge_ctx->odu_emb_cons_hdl); - if (res) { - ODU_BRIDGE_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res); - goto fail_odu_emb_cons; - } - - ODU_BRIDGE_DBG("odu_prod_hdl = %d, odu_emb_cons_hdl = %d\n", - ipa3_odu_bridge_ctx->odu_prod_hdl, - ipa3_odu_bridge_ctx->odu_emb_cons_hdl); - ODU_BRIDGE_DBG("odu_teth_cons_hdl = %d\n", - ipa3_odu_bridge_ctx->odu_teth_cons_hdl); - - ODU_BRIDGE_FUNC_EXIT(); - - return 0; - -fail_odu_emb_cons: - ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_teth_cons_hdl); - ipa3_odu_bridge_ctx->odu_teth_cons_hdl = 0; -fail_odu_teth_cons: - ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_prod_hdl); - ipa3_odu_bridge_ctx->odu_prod_hdl = 0; -fail_odu_prod: - ipa3_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, - IPA_RM_RESOURCE_ODU_ADAPT_CONS); -fail_add_dependency_2: - ipa3_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, - IPA_RM_RESOURCE_Q6_CONS); -fail_add_dependency_1: - return res; -} - -static int ipa3_odu_bridge_disconnect_router(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - res = ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_prod_hdl); - if (res) - ODU_BRIDGE_ERR("teardown ODU PROD failed\n"); - ipa3_odu_bridge_ctx->odu_prod_hdl = 0; - - res = ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_emb_cons_hdl); - if (res) - ODU_BRIDGE_ERR("teardown ODU EMB CONS failed\n"); - ipa3_odu_bridge_ctx->odu_emb_cons_hdl = 0; - - ODU_BRIDGE_FUNC_EXIT(); - - return 0; -} - -static int ipa3_odu_bridge_disconnect_bridge(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - res = ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_prod_hdl); - if (res) - ODU_BRIDGE_ERR("teardown ODU PROD failed\n"); - ipa3_odu_bridge_ctx->odu_prod_hdl = 0; - - res = ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_teth_cons_hdl); - if (res) - ODU_BRIDGE_ERR("teardown ODU TETH CONS failed\n"); - ipa3_odu_bridge_ctx->odu_teth_cons_hdl = 0; - - res = ipa3_teardown_sys_pipe(ipa3_odu_bridge_ctx->odu_emb_cons_hdl); - if (res) - ODU_BRIDGE_ERR("teardown ODU EMB CONS failed\n"); - ipa3_odu_bridge_ctx->odu_emb_cons_hdl = 0; - - /* Delete IPA Resource manager dependency graph */ - ODU_BRIDGE_DBG("deleting dependency graph\n"); - res = ipa3_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, - IPA_RM_RESOURCE_Q6_CONS); - if (res && res != -EINPROGRESS) - ODU_BRIDGE_ERR("ipa3_rm_delete_dependency() failed\n"); - - res = ipa3_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, - IPA_RM_RESOURCE_ODU_ADAPT_CONS); - if (res && res != -EINPROGRESS) - ODU_BRIDGE_ERR("ipa3_rm_delete_dependency() failed\n"); - - return 0; -} - -/** - * ipa3_odu_bridge_disconnect() - Disconnect odu bridge - * - * Disconnect all pipes and deletes IPA RM dependencies on bridge mode - * - * Return codes: 0- success, error otherwise - */ -int ipa3_odu_bridge_disconnect(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - if (!ipa3_odu_bridge_ctx) { - ODU_BRIDGE_ERR("Not initialized\n"); - return -EFAULT; - } - - if (!ipa3_odu_bridge_ctx->is_connected) { - ODU_BRIDGE_ERR("Not connected\n"); - return -EFAULT; - } - - mutex_lock(&ipa3_odu_bridge_ctx->lock); - if (ipa3_odu_bridge_ctx->mode == ODU_BRIDGE_MODE_ROUTER) { - res = ipa3_odu_bridge_disconnect_router(); - if (res) { - ODU_BRIDGE_ERR("disconnect_router failed %d\n", res); - goto out; - } - } else { - res = ipa3_odu_bridge_disconnect_bridge(); - if (res) { - ODU_BRIDGE_ERR("disconnect_bridge failed %d\n", res); - goto out; - } - } - - ipa3_odu_bridge_ctx->is_connected = false; - res = 0; -out: - mutex_unlock(&ipa3_odu_bridge_ctx->lock); - ODU_BRIDGE_FUNC_EXIT(); - return res; -} - -/** - * ipa3_odu_bridge_connect() - Connect odu bridge. - * - * Call to the mode-specific connect function for connection IPA pipes - * and adding IPA RM dependencies - - * Return codes: 0: success - * -EINVAL: invalid parameters - * -EPERM: Operation not permitted as the bridge is already - * connected - */ -int ipa3_odu_bridge_connect(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - if (!ipa3_odu_bridge_ctx) { - ODU_BRIDGE_ERR("Not initialized\n"); - return -EFAULT; - } - - if (ipa3_odu_bridge_ctx->is_connected) { - ODU_BRIDGE_ERR("already connected\n"); - return -EFAULT; - } - - mutex_lock(&ipa3_odu_bridge_ctx->lock); - if (ipa3_odu_bridge_ctx->mode == ODU_BRIDGE_MODE_ROUTER) { - res = ipa3_odu_bridge_connect_router(); - if (res) { - ODU_BRIDGE_ERR("connect_router failed\n"); - goto bail; - } - } else { - res = ipa3_odu_bridge_connect_bridge(); - if (res) { - ODU_BRIDGE_ERR("connect_bridge failed\n"); - goto bail; - } - } - - ipa3_odu_bridge_ctx->is_connected = true; - res = 0; -bail: - mutex_unlock(&ipa3_odu_bridge_ctx->lock); - ODU_BRIDGE_FUNC_EXIT(); - return res; -} - -/** - * ipa3_odu_bridge_set_mode() - Set bridge mode to Router/Bridge - * @mode: mode to be set - */ -static int ipa3_odu_bridge_set_mode(enum odu_bridge_mode mode) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - if (mode < 0 || mode >= ODU_BRIDGE_MODE_MAX) { - ODU_BRIDGE_ERR("Unsupported mode: %d\n", mode); - return -EFAULT; - } - - ODU_BRIDGE_DBG("setting mode: %d\n", mode); - mutex_lock(&ipa3_odu_bridge_ctx->lock); - - if (ipa3_odu_bridge_ctx->mode == mode) { - ODU_BRIDGE_DBG("same mode\n"); - res = 0; - goto bail; - } - - if (ipa3_odu_bridge_ctx->is_connected) { - /* first disconnect the old configuration */ - if (ipa3_odu_bridge_ctx->mode == ODU_BRIDGE_MODE_ROUTER) { - res = ipa3_odu_bridge_disconnect_router(); - if (res) { - ODU_BRIDGE_ERR("disconnect_router failed\n"); - goto bail; - } - } else { - res = ipa3_odu_bridge_disconnect_bridge(); - if (res) { - ODU_BRIDGE_ERR("disconnect_bridge failed\n"); - goto bail; - } - } - - /* connect the new configuration */ - if (mode == ODU_BRIDGE_MODE_ROUTER) { - res = ipa3_odu_bridge_connect_router(); - if (res) { - ODU_BRIDGE_ERR("connect_router failed\n"); - goto bail; - } - } else { - res = ipa3_odu_bridge_connect_bridge(); - if (res) { - ODU_BRIDGE_ERR("connect_bridge failed\n"); - goto bail; - } - } - } - ipa3_odu_bridge_ctx->mode = mode; - res = 0; -bail: - mutex_unlock(&ipa3_odu_bridge_ctx->lock); - ODU_BRIDGE_FUNC_EXIT(); - return res; -}; - -/** - * ipa3_odu_bridge_set_llv6_addr() - Set link local ipv6 address - * @llv6_addr: odu network interface link local address - * - * This function sets the link local ipv6 address provided by IOCTL - */ -static int ipa3_odu_bridge_set_llv6_addr(struct in6_addr *llv6_addr) -{ - struct in6_addr llv6_addr_host; - - ODU_BRIDGE_FUNC_ENTRY(); - - llv6_addr_host.s6_addr32[0] = ntohl(llv6_addr->s6_addr32[0]); - llv6_addr_host.s6_addr32[1] = ntohl(llv6_addr->s6_addr32[1]); - llv6_addr_host.s6_addr32[2] = ntohl(llv6_addr->s6_addr32[2]); - llv6_addr_host.s6_addr32[3] = ntohl(llv6_addr->s6_addr32[3]); - - memcpy(&ipa3_odu_bridge_ctx->llv6_addr, &llv6_addr_host, - sizeof(ipa3_odu_bridge_ctx->llv6_addr)); - ODU_BRIDGE_DBG("LLV6 addr: %pI6c\n", &ipa3_odu_bridge_ctx->llv6_addr); - - ODU_BRIDGE_FUNC_EXIT(); - - return 0; -}; - -static long ipa3_odu_bridge_ioctl(struct file *filp, - unsigned int cmd, - unsigned long arg) -{ - int res = 0; - struct in6_addr llv6_addr; - - ODU_BRIDGE_DBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd)); - - if ((_IOC_TYPE(cmd) != ODU_BRIDGE_IOC_MAGIC) || - (_IOC_NR(cmd) >= ODU_BRIDGE_IOCTL_MAX)) { - ODU_BRIDGE_ERR("Invalid ioctl\n"); - return -ENOIOCTLCMD; - } - - switch (cmd) { - case ODU_BRIDGE_IOC_SET_MODE: - ODU_BRIDGE_DBG("ODU_BRIDGE_IOC_SET_MODE ioctl called\n"); - res = ipa3_odu_bridge_set_mode(arg); - if (res) { - ODU_BRIDGE_ERR("Error, res = %d\n", res); - break; - } - break; - - case ODU_BRIDGE_IOC_SET_LLV6_ADDR: - ODU_BRIDGE_DBG("ODU_BRIDGE_IOC_SET_LLV6_ADDR ioctl called\n"); - res = copy_from_user(&llv6_addr, - (struct in6_addr *)arg, - sizeof(llv6_addr)); - if (res) { - ODU_BRIDGE_ERR("Error, res = %d\n", res); - res = -EFAULT; - break; - } - - res = ipa3_odu_bridge_set_llv6_addr(&llv6_addr); - if (res) { - ODU_BRIDGE_ERR("Error, res = %d\n", res); - break; - } - break; - - default: - ODU_BRIDGE_ERR("Unknown ioctl: %d\n", cmd); - WARN_ON(1); - } - - return res; -} - -#ifdef CONFIG_COMPAT -static long ipa3_compat_odu_bridge_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case ODU_BRIDGE_IOC_SET_LLV6_ADDR32: - cmd = ODU_BRIDGE_IOC_SET_LLV6_ADDR; - break; - case ODU_BRIDGE_IOC_SET_MODE: - break; - default: - return -ENOIOCTLCMD; - } - return ipa3_odu_bridge_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); -} -#endif - -#ifdef CONFIG_DEBUG_FS -static struct dentry *dent; -static struct dentry *dfile_stats; -static struct dentry *dfile_mode; - -static ssize_t ipa3_odu_debugfs_stats(struct file *file, - char __user *ubuf, - size_t count, - loff_t *ppos) -{ - int nbytes = 0; - - nbytes += scnprintf(&dbg_buff[nbytes], - ODU_MAX_MSG_LEN - nbytes, - "UL packets: %lld\n", - ipa3_odu_bridge_ctx->stats.num_ul_packets); - nbytes += scnprintf(&dbg_buff[nbytes], - ODU_MAX_MSG_LEN - nbytes, - "DL packets: %lld\n", - ipa3_odu_bridge_ctx->stats.num_dl_packets); - nbytes += scnprintf(&dbg_buff[nbytes], - ODU_MAX_MSG_LEN - nbytes, - "LAN packets: %lld\n", - ipa3_odu_bridge_ctx->stats.num_lan_packets); - return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes); -} - -static ssize_t ipa3_odu_debugfs_hw_bridge_mode_write(struct file *file, - const char __user *ubuf, - size_t count, - loff_t *ppos) -{ - unsigned long missing; - enum odu_bridge_mode mode; - - if (sizeof(dbg_buff) < count + 1) - return -EFAULT; - - missing = copy_from_user(dbg_buff, ubuf, count); - if (missing) - return -EFAULT; - - if (count > 0) - dbg_buff[count-1] = '\0'; - - if (strcmp(dbg_buff, "router") == 0) { - mode = ODU_BRIDGE_MODE_ROUTER; - } else if (strcmp(dbg_buff, "bridge") == 0) { - mode = ODU_BRIDGE_MODE_BRIDGE; - } else { - ODU_BRIDGE_ERR("Bad mode, got %s,\n" - "Use <router> or <bridge>.\n", dbg_buff); - return count; - } - - ipa3_odu_bridge_set_mode(mode); - return count; -} - -static ssize_t ipa3_odu_debugfs_hw_bridge_mode_read(struct file *file, - char __user *ubuf, - size_t count, - loff_t *ppos) -{ - int nbytes = 0; - - switch (ipa3_odu_bridge_ctx->mode) { - case ODU_BRIDGE_MODE_ROUTER: - nbytes += scnprintf(&dbg_buff[nbytes], - ODU_MAX_MSG_LEN - nbytes, - "router\n"); - break; - case ODU_BRIDGE_MODE_BRIDGE: - nbytes += scnprintf(&dbg_buff[nbytes], - ODU_MAX_MSG_LEN - nbytes, - "bridge\n"); - break; - default: - nbytes += scnprintf(&dbg_buff[nbytes], - ODU_MAX_MSG_LEN - nbytes, - "mode error\n"); - break; - - } - - return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes); -} - -const struct file_operations ipa3_odu_stats_ops = { - .read = ipa3_odu_debugfs_stats, -}; - -const struct file_operations ipa3_odu_hw_bridge_mode_ops = { - .read = ipa3_odu_debugfs_hw_bridge_mode_read, - .write = ipa3_odu_debugfs_hw_bridge_mode_write, -}; - -void ipa3_odu_debugfs_init(void) -{ - const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH; - const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH | - S_IWUSR | S_IWGRP | S_IWOTH; - - dent = debugfs_create_dir("odu_ipa_bridge", 0); - if (IS_ERR(dent)) { - ODU_BRIDGE_ERR("fail to create folder odu_ipa_bridge\n"); - return; - } - - dfile_stats = - debugfs_create_file("stats", read_only_mode, dent, - 0, &ipa3_odu_stats_ops); - if (!dfile_stats || IS_ERR(dfile_stats)) { - ODU_BRIDGE_ERR("fail to create file stats\n"); - goto fail; - } - - dfile_mode = - debugfs_create_file("mode", read_write_mode, - dent, 0, &ipa3_odu_hw_bridge_mode_ops); - if (!dfile_mode || - IS_ERR(dfile_mode)) { - ODU_BRIDGE_ERR("fail to create file dfile_mode\n"); - goto fail; - } - - return; -fail: - debugfs_remove_recursive(dent); -} - -static void ipa3_odu_debugfs_destroy(void) -{ - debugfs_remove_recursive(dent); -} - -#else -static void ipa3_odu_debugfs_init(void) {} -static void ipa3_odu_debugfs_destroy(void) {} -#endif /* CONFIG_DEBUG_FS */ - - -static const struct file_operations ipa3_odu_bridge_drv_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = ipa3_odu_bridge_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ipa3_compat_odu_bridge_ioctl, -#endif -}; - -/** - * ipa3_odu_bridge_tx_dp() - Send skb to ODU bridge - * @skb: skb to send - * @metadata: metadata on packet - * - * This function handles uplink packet. - * In Router Mode: - * packet is sent directly to IPA. - * In Router Mode: - * packet is classified if it should arrive to network stack. - * QMI IP packet should arrive to APPS network stack - * IPv6 Multicast packet should arrive to APPS network stack and Q6 - * - * Return codes: 0- success, error otherwise - */ -int ipa3_odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata) -{ - struct sk_buff *skb_copied = NULL; - struct ipv6hdr *ipv6hdr; - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - switch (ipa3_odu_bridge_ctx->mode) { - case ODU_BRIDGE_MODE_ROUTER: - /* Router mode - pass skb to IPA */ - res = ipa3_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); - if (res) { - ODU_BRIDGE_DBG("tx dp failed %d\n", res); - goto out; - } - ipa3_odu_bridge_ctx->stats.num_ul_packets++; - goto out; - - case ODU_BRIDGE_MODE_BRIDGE: - ipv6hdr = (struct ipv6hdr *)(skb->data + ETH_HLEN); - if (ipv6hdr->version == 6 && - ODU_BRIDGE_IS_QMI_ADDR(ipv6hdr->daddr)) { - ODU_BRIDGE_DBG("QMI packet\n"); - skb_copied = skb_clone(skb, GFP_KERNEL); - if (!skb_copied) { - ODU_BRIDGE_ERR("No memory\n"); - return -ENOMEM; - } - ipa3_odu_bridge_ctx-> - tx_dp_notify(ipa3_odu_bridge_ctx->priv, - IPA_RECEIVE, - (unsigned long)skb_copied); - ipa3_odu_bridge_ctx-> - tx_dp_notify(ipa3_odu_bridge_ctx->priv, - IPA_WRITE_DONE, - (unsigned long)skb); - ipa3_odu_bridge_ctx->stats.num_ul_packets++; - ipa3_odu_bridge_ctx->stats.num_lan_packets++; - res = 0; - goto out; - } - - if (ipv6hdr->version == 6 && - ipv6_addr_is_multicast(&ipv6hdr->daddr)) { - ODU_BRIDGE_DBG("Multicast pkt, send to APPS and IPA\n"); - skb_copied = skb_clone(skb, GFP_KERNEL); - if (!skb_copied) { - ODU_BRIDGE_ERR("No memory\n"); - return -ENOMEM; - } - - res = ipa3_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); - if (res) { - ODU_BRIDGE_DBG("tx dp failed %d\n", res); - dev_kfree_skb(skb_copied); - goto out; - } - - ipa3_odu_bridge_ctx->tx_dp_notify( - ipa3_odu_bridge_ctx->priv, - IPA_RECEIVE, - (unsigned long)skb_copied); - ipa3_odu_bridge_ctx->stats.num_ul_packets++; - ipa3_odu_bridge_ctx->stats.num_lan_packets++; - goto out; - } - - res = ipa3_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); - if (res) { - ODU_BRIDGE_DBG("tx dp failed %d\n", res); - goto out; - } - ipa3_odu_bridge_ctx->stats.num_ul_packets++; - goto out; - - default: - ODU_BRIDGE_ERR("Unsupported mode: %d\n", - ipa3_odu_bridge_ctx->mode); - WARN_ON(1); - res = -EFAULT; - - } -out: - ODU_BRIDGE_FUNC_EXIT(); - return res; -} - -static int ipa3_odu_bridge_add_hdrs(void) -{ - struct ipa_ioc_add_hdr *hdrs; - struct ipa_hdr_add *ipv4_hdr; - struct ipa_hdr_add *ipv6_hdr; - struct ethhdr *eth_ipv4; - struct ethhdr *eth_ipv6; - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - hdrs = kzalloc(sizeof(*hdrs) + sizeof(*ipv4_hdr) + sizeof(*ipv6_hdr), - GFP_KERNEL); - if (!hdrs) { - ODU_BRIDGE_ERR("no mem\n"); - res = -ENOMEM; - goto out; - } - ipv4_hdr = &hdrs->hdr[0]; - eth_ipv4 = (struct ethhdr *)(ipv4_hdr->hdr); - ipv6_hdr = &hdrs->hdr[1]; - eth_ipv6 = (struct ethhdr *)(ipv6_hdr->hdr); - strlcpy(ipv4_hdr->name, ODU_BRIDGE_IPV4_HDR_NAME, - IPA_RESOURCE_NAME_MAX); - memcpy(eth_ipv4->h_source, - ipa3_odu_bridge_ctx->device_ethaddr, - ETH_ALEN); - eth_ipv4->h_proto = htons(ETH_P_IP); - ipv4_hdr->hdr_len = ETH_HLEN; - ipv4_hdr->is_partial = 1; - ipv4_hdr->is_eth2_ofst_valid = 1; - ipv4_hdr->eth2_ofst = 0; - strlcpy(ipv6_hdr->name, ODU_BRIDGE_IPV6_HDR_NAME, - IPA_RESOURCE_NAME_MAX); - memcpy(eth_ipv6->h_source, - ipa3_odu_bridge_ctx->device_ethaddr, - ETH_ALEN); - eth_ipv6->h_proto = htons(ETH_P_IPV6); - ipv6_hdr->hdr_len = ETH_HLEN; - ipv6_hdr->is_partial = 1; - ipv6_hdr->is_eth2_ofst_valid = 1; - ipv6_hdr->eth2_ofst = 0; - hdrs->commit = 1; - hdrs->num_hdrs = 2; - res = ipa3_add_hdr(hdrs); - if (res) { - ODU_BRIDGE_ERR("Fail on Header-Insertion(%d)\n", res); - goto out_free_mem; - } - if (ipv4_hdr->status) { - ODU_BRIDGE_ERR("Fail on Header-Insertion ipv4(%d)\n", - ipv4_hdr->status); - res = ipv4_hdr->status; - goto out_free_mem; - } - if (ipv6_hdr->status) { - ODU_BRIDGE_ERR("Fail on Header-Insertion ipv6(%d)\n", - ipv6_hdr->status); - res = ipv6_hdr->status; - goto out_free_mem; - } - ipa3_odu_bridge_ctx->odu_br_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl; - ipa3_odu_bridge_ctx->odu_br_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl; - - res = 0; -out_free_mem: - kfree(hdrs); -out: - ODU_BRIDGE_FUNC_EXIT(); - return res; -} - -static void ipa3_odu_bridge_del_hdrs(void) -{ - struct ipa_ioc_del_hdr *del_hdr; - struct ipa_hdr_del *ipv4; - struct ipa_hdr_del *ipv6; - int result; - - del_hdr = kzalloc(sizeof(*del_hdr) + sizeof(*ipv4) + - sizeof(*ipv6), GFP_KERNEL); - if (!del_hdr) - return; - del_hdr->commit = 1; - del_hdr->num_hdls = 2; - ipv4 = &del_hdr->hdl[0]; - ipv4->hdl = ipa3_odu_bridge_ctx->odu_br_ipv4_hdr_hdl; - ipv6 = &del_hdr->hdl[1]; - ipv6->hdl = ipa3_odu_bridge_ctx->odu_br_ipv6_hdr_hdl; - result = ipa3_del_hdr(del_hdr); - if (result || ipv4->status || ipv6->status) - ODU_BRIDGE_ERR("ipa3_del_hdr failed"); - kfree(del_hdr); -} - -/** - * ipa3_odu_bridge_register_properties() - set Tx/Rx properties for ipacm - * - * Register the network interface interface with Tx and Rx properties - * Tx properties are for data flowing from IPA to adapter, they - * have Header-Insertion properties both for Ipv4 and Ipv6 Ethernet framing. - * Rx properties are for data flowing from adapter to IPA, they have - * simple rule which always "hit". - * - */ -static int ipa3_odu_bridge_register_properties(void) -{ - struct ipa_tx_intf tx_properties = {0}; - struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} }; - struct ipa_ioc_tx_intf_prop *ipv4_property; - struct ipa_ioc_tx_intf_prop *ipv6_property; - struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} }; - struct ipa_rx_intf rx_properties = {0}; - struct ipa_ioc_rx_intf_prop *rx_ipv4_property; - struct ipa_ioc_rx_intf_prop *rx_ipv6_property; - int res = 0; - - ODU_BRIDGE_FUNC_ENTRY(); - - tx_properties.prop = properties; - ipv4_property = &tx_properties.prop[0]; - ipv4_property->ip = IPA_IP_v4; - ipv4_property->dst_pipe = IPA_CLIENT_ODU_EMB_CONS; - ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - strlcpy(ipv4_property->hdr_name, ODU_BRIDGE_IPV4_HDR_NAME, - IPA_RESOURCE_NAME_MAX); - ipv6_property = &tx_properties.prop[1]; - ipv6_property->ip = IPA_IP_v6; - ipv6_property->dst_pipe = IPA_CLIENT_ODU_EMB_CONS; - ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - strlcpy(ipv6_property->hdr_name, ODU_BRIDGE_IPV6_HDR_NAME, - IPA_RESOURCE_NAME_MAX); - tx_properties.num_props = 2; - - rx_properties.prop = rx_ioc_properties; - rx_ipv4_property = &rx_properties.prop[0]; - rx_ipv4_property->ip = IPA_IP_v4; - rx_ipv4_property->attrib.attrib_mask = 0; - rx_ipv4_property->src_pipe = IPA_CLIENT_ODU_PROD; - rx_ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - rx_ipv6_property = &rx_properties.prop[1]; - rx_ipv6_property->ip = IPA_IP_v6; - rx_ipv6_property->attrib.attrib_mask = 0; - rx_ipv6_property->src_pipe = IPA_CLIENT_ODU_PROD; - rx_ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - rx_properties.num_props = 2; - - res = ipa3_register_intf(ipa3_odu_bridge_ctx->netdev_name, - &tx_properties, - &rx_properties); - if (res) { - ODU_BRIDGE_ERR("fail on Tx/Rx properties registration %d\n", - res); - } - - ODU_BRIDGE_FUNC_EXIT(); - - return res; -} - -static void ipa3_odu_bridge_deregister_properties(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - res = ipa3_deregister_intf(ipa3_odu_bridge_ctx->netdev_name); - if (res) - ODU_BRIDGE_ERR("Fail on Tx prop deregister %d\n", res); - ODU_BRIDGE_FUNC_EXIT(); -} - -/** - * ipa3_odu_bridge_init() - Initialize the ODU bridge driver - * @params: initialization parameters - * - * This function initialize all bridge internal data and register odu bridge to - * kernel for IOCTL and debugfs. - * Header addition and properties are registered to IPA driver. - * - * Return codes: 0: success, - * -EINVAL - Bad parameter - * Other negative value - Failure - */ -int ipa3_odu_bridge_init(struct odu_bridge_params *params) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - if (!params) { - ODU_BRIDGE_ERR("null pointer params\n"); - return -EINVAL; - } - if (!params->netdev_name) { - ODU_BRIDGE_ERR("null pointer params->netdev_name\n"); - return -EINVAL; - } - if (!params->tx_dp_notify) { - ODU_BRIDGE_ERR("null pointer params->tx_dp_notify\n"); - return -EINVAL; - } - if (!params->send_dl_skb) { - ODU_BRIDGE_ERR("null pointer params->send_dl_skb\n"); - return -EINVAL; - } - if (ipa3_odu_bridge_ctx) { - ODU_BRIDGE_ERR("Already initialized\n"); - return -EFAULT; - } - if (!ipa3_is_ready()) { - ODU_BRIDGE_ERR("IPA is not ready\n"); - return -EFAULT; - } - - ODU_BRIDGE_DBG("device_ethaddr=%pM\n", params->device_ethaddr); - - ipa3_odu_bridge_ctx = kzalloc(sizeof(*ipa3_odu_bridge_ctx), GFP_KERNEL); - if (!ipa3_odu_bridge_ctx) { - ODU_BRIDGE_ERR("kzalloc err.\n"); - return -ENOMEM; - } - - ipa3_odu_bridge_ctx->class = class_create(THIS_MODULE, - ODU_BRIDGE_DRV_NAME); - if (!ipa3_odu_bridge_ctx->class) { - ODU_BRIDGE_ERR("Class_create err.\n"); - res = -ENODEV; - goto fail_class_create; - } - - res = alloc_chrdev_region(&ipa3_odu_bridge_ctx->dev_num, 0, 1, - ODU_BRIDGE_DRV_NAME); - if (res) { - ODU_BRIDGE_ERR("alloc_chrdev_region err.\n"); - res = -ENODEV; - goto fail_alloc_chrdev_region; - } - - ipa3_odu_bridge_ctx->dev = device_create(ipa3_odu_bridge_ctx->class, - NULL, - ipa3_odu_bridge_ctx->dev_num, - ipa3_odu_bridge_ctx, - ODU_BRIDGE_DRV_NAME); - if (IS_ERR(ipa3_odu_bridge_ctx->dev)) { - ODU_BRIDGE_ERR(":device_create err.\n"); - res = -ENODEV; - goto fail_device_create; - } - - cdev_init(&ipa3_odu_bridge_ctx->cdev, &ipa3_odu_bridge_drv_fops); - ipa3_odu_bridge_ctx->cdev.owner = THIS_MODULE; - ipa3_odu_bridge_ctx->cdev.ops = &ipa3_odu_bridge_drv_fops; - - res = cdev_add(&ipa3_odu_bridge_ctx->cdev, - ipa3_odu_bridge_ctx->dev_num, - 1); - if (res) { - ODU_BRIDGE_ERR(":cdev_add err=%d\n", -res); - res = -ENODEV; - goto fail_cdev_add; - } - - ipa3_odu_debugfs_init(); - - strlcpy(ipa3_odu_bridge_ctx->netdev_name, params->netdev_name, - IPA_RESOURCE_NAME_MAX); - ipa3_odu_bridge_ctx->priv = params->priv; - ipa3_odu_bridge_ctx->tx_dp_notify = params->tx_dp_notify; - ipa3_odu_bridge_ctx->send_dl_skb = params->send_dl_skb; - memcpy(ipa3_odu_bridge_ctx->device_ethaddr, params->device_ethaddr, - ETH_ALEN); - ipa3_odu_bridge_ctx->ipa_sys_desc_size = params->ipa_desc_size; - ipa3_odu_bridge_ctx->mode = ODU_BRIDGE_MODE_ROUTER; - - mutex_init(&ipa3_odu_bridge_ctx->lock); - - res = ipa3_odu_bridge_add_hdrs(); - if (res) { - ODU_BRIDGE_ERR("fail on odu_bridge_add_hdr %d\n", res); - goto fail_add_hdrs; - } - - res = ipa3_odu_bridge_register_properties(); - if (res) { - ODU_BRIDGE_ERR("fail on register properties %d\n", res); - goto fail_register_properties; - } - - ODU_BRIDGE_FUNC_EXIT(); - return 0; - -fail_register_properties: - ipa3_odu_bridge_del_hdrs(); -fail_add_hdrs: - ipa3_odu_debugfs_destroy(); -fail_cdev_add: - device_destroy(ipa3_odu_bridge_ctx->class, - ipa3_odu_bridge_ctx->dev_num); -fail_device_create: - unregister_chrdev_region(ipa3_odu_bridge_ctx->dev_num, 1); -fail_alloc_chrdev_region: - class_destroy(ipa3_odu_bridge_ctx->class); -fail_class_create: - kfree(ipa3_odu_bridge_ctx); - ipa3_odu_bridge_ctx = NULL; - return res; -} - -/** - * ipa3_odu_bridge_cleanup() - De-Initialize the ODU bridge driver - * - * Return codes: 0: success, - * -EINVAL - Bad parameter - * Other negative value - Failure - */ -int ipa3_odu_bridge_cleanup(void) -{ - ODU_BRIDGE_FUNC_ENTRY(); - - if (!ipa3_odu_bridge_ctx) { - ODU_BRIDGE_ERR("Not initialized\n"); - return -EFAULT; - } - - if (ipa3_odu_bridge_ctx->is_connected) { - ODU_BRIDGE_ERR("cannot deinit while bridge is conncetd\n"); - return -EFAULT; - } - - ipa3_odu_bridge_deregister_properties(); - ipa3_odu_bridge_del_hdrs(); - ipa3_odu_debugfs_destroy(); - cdev_del(&ipa3_odu_bridge_ctx->cdev); - device_destroy(ipa3_odu_bridge_ctx->class, - ipa3_odu_bridge_ctx->dev_num); - unregister_chrdev_region(ipa3_odu_bridge_ctx->dev_num, 1); - class_destroy(ipa3_odu_bridge_ctx->class); - kfree(ipa3_odu_bridge_ctx); - ipa3_odu_bridge_ctx = NULL; - - ODU_BRIDGE_FUNC_EXIT(); - return 0; -} - - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ODU bridge driver"); diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index ec2e15e9478a..35f461f4fcac 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -900,9 +900,8 @@ static void ops_uninit(void *handle) ops_suspend(ctx); } -static int ops_notify_crash(void *handle) +static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx) { - struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle; int rc; if (ctx->subsys) { @@ -919,6 +918,23 @@ static int ops_notify_crash(void *handle) return 0; } +static int ops_notify(void *handle, enum wil_platform_event evt) +{ + struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle; + int rc = 0; + + switch (evt) { + case WIL_PLATFORM_EVT_FW_CRASH: + rc = msm_11ad_notify_crash(ctx); + break; + default: + pr_debug("%s: Unhandled event %d\n", __func__, evt); + break; + } + + return rc; +} + void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops, const struct wil_platform_rops *rops, void *wil_handle) { @@ -957,7 +973,7 @@ void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops, ops->suspend = ops_suspend; ops->resume = ops_resume; ops->uninit = ops_uninit; - ops->notify_crash = ops_notify_crash; + ops->notify = ops_notify; return ctx; } diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c index 087b6a8364f8..a4f51489f764 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -5839,8 +5839,7 @@ int cpr3_regulator_register(struct platform_device *pdev, } } - if (ctrl->supports_hw_closed_loop && ctrl->ctrl_type != - CPR_CTRL_TYPE_CPRH) { + if (ctrl->supports_hw_closed_loop) { rc = msm_spm_probe_done(); if (rc) { if (rc != -EPROBE_DEFER) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e9bf44e6d79d..a14feed47dcb 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -210,6 +210,15 @@ config QCOM_SMEM The driver provides an interface to items in a heap shared among all processors in a Qualcomm platform. +config MSM_SERVICE_LOCATOR + bool "Service Locator" + depends on MSM_QMI_INTERFACE + help + The Service Locator provides a library to retrieve location + information given a service identifier. Location here translates + to what process domain exports the service, and which subsystem + that process domain will execute in. + config MSM_HVC bool "MSM Hypervisor Call Support" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 66a97b1f0a11..13c63d6e59bf 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -82,3 +82,4 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_kryo.o obj-$(CONFIG_MSM_KERNEL_PROTECT) += kernel_protect.o obj-$(CONFIG_MSM_RTB) += msm_rtb-hotplug.o obj-$(CONFIG_QCOM_REMOTEQDSS) += remoteqdss.o +obj-$(CONFIG_MSM_SERVICE_LOCATOR) += service-locator.o diff --git a/drivers/soc/qcom/glink_smd_xprt.c b/drivers/soc/qcom/glink_smd_xprt.c index c4ac66f81af4..c3fb34773db0 100644 --- a/drivers/soc/qcom/glink_smd_xprt.c +++ b/drivers/soc/qcom/glink_smd_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -113,6 +113,7 @@ struct edge_info { * @name: The name of this channel. * @lcid: The local channel id the core uses for this channel. * @rcid: The true remote channel id for this channel. + * @ch_probe_lock: Lock to protect channel probe status. * @wait_for_probe: This channel is waiting for a probe from SMD. * @had_probed: This channel probed in the past and may skip probe. * @edge: Handle to the edge_info this channel is associated with. @@ -138,6 +139,7 @@ struct channel { char name[GLINK_NAME_SIZE]; uint32_t lcid; uint32_t rcid; + struct mutex ch_probe_lock; bool wait_for_probe; bool had_probed; struct edge_info *edge; @@ -321,6 +323,7 @@ static void process_ctl_event(struct work_struct *work) } strlcpy(ch->name, name, GLINK_NAME_SIZE); ch->edge = einfo; + mutex_init(&ch->ch_probe_lock); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->used_intents); spin_lock_init(&ch->intents_lock); @@ -879,10 +882,11 @@ static void smd_data_ch_close(struct channel *ch) __func__, ch->lcid); ch->is_closing = true; - ch->wait_for_probe = false; ch->tx_resume_needed = false; flush_workqueue(ch->wq); + mutex_lock(&ch->ch_probe_lock); + ch->wait_for_probe = false; if (ch->smd_ch) { smd_close(ch->smd_ch); ch->smd_ch = NULL; @@ -893,6 +897,7 @@ static void smd_data_ch_close(struct channel *ch) ch->lcid); mutex_unlock(&ch->edge->rx_cmd_lock); } + mutex_unlock(&ch->ch_probe_lock); ch->local_legacy = false; @@ -965,13 +970,17 @@ static int channel_probe(struct platform_device *pdev) if (!found) return -EPROBE_DEFER; - if (!ch->wait_for_probe) + mutex_lock(&ch->ch_probe_lock); + if (!ch->wait_for_probe) { + mutex_unlock(&ch->ch_probe_lock); return -EPROBE_DEFER; + } ch->wait_for_probe = false; ch->had_probed = true; data_ch_probe_body(ch); + mutex_unlock(&ch->ch_probe_lock); return 0; } @@ -1012,6 +1021,7 @@ static int add_platform_driver(struct channel *ch) static bool first = true; mutex_lock(&pdrv_list_mutex); + mutex_lock(&ch->ch_probe_lock); ch->wait_for_probe = true; list_for_each_entry(pdrv, &pdrv_list, node) { if (!strcmp(ch->name, pdrv->pdrv.driver.name)) { @@ -1021,10 +1031,13 @@ static int add_platform_driver(struct channel *ch) } if (!found) { + mutex_unlock(&ch->ch_probe_lock); pdrv = kzalloc(sizeof(*pdrv), GFP_KERNEL); if (!pdrv) { ret = -ENOMEM; + mutex_lock(&ch->ch_probe_lock); ch->wait_for_probe = false; + mutex_unlock(&ch->ch_probe_lock); goto out; } pdrv->pdrv.driver.name = ch->name; @@ -1035,12 +1048,14 @@ static int add_platform_driver(struct channel *ch) if (ret) { list_del(&pdrv->node); kfree(pdrv); + mutex_lock(&ch->ch_probe_lock); ch->wait_for_probe = false; + mutex_unlock(&ch->ch_probe_lock); } } else { if (ch->had_probed) data_ch_probe_body(ch); - + mutex_unlock(&ch->ch_probe_lock); /* * channel_probe might have seen the device we want, but * returned EPROBE_DEFER so we need to kick the deferred list @@ -1170,6 +1185,7 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid, } strlcpy(ch->name, name, GLINK_NAME_SIZE); ch->edge = einfo; + mutex_init(&ch->ch_probe_lock); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->used_intents); spin_lock_init(&ch->intents_lock); @@ -1445,14 +1461,16 @@ static int ssr(struct glink_transport_if *if_ptr) spin_lock_irqsave(&einfo->channels_lock, flags); list_for_each_entry(ch, &einfo->channels, node) { - if (!ch->smd_ch) - continue; spin_unlock_irqrestore(&einfo->channels_lock, flags); ch->is_closing = true; - ch->wait_for_probe = false; flush_workqueue(ch->wq); - smd_close(ch->smd_ch); - ch->smd_ch = NULL; + mutex_lock(&ch->ch_probe_lock); + ch->wait_for_probe = false; + if (ch->smd_ch) { + smd_close(ch->smd_ch); + ch->smd_ch = NULL; + } + mutex_unlock(&ch->ch_probe_lock); ch->local_legacy = false; ch->remote_legacy = false; ch->rcid = 0; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index e9f7b8931d9b..84b47f789214 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -86,9 +86,9 @@ static struct { struct work_struct qmi_event_work; struct work_struct qmi_recv_msg_work; struct workqueue_struct *qmi_event_wq; - phys_addr_t msa_phys; + phys_addr_t msa_pa; uint32_t msa_mem_size; - void *msa_addr; + void *msa_va; uint32_t state; struct wlfw_rf_chip_info_s_v01 chip_info; struct wlfw_rf_board_info_s_v01 board_info; @@ -99,6 +99,7 @@ static struct { u32 rf_pin_result; struct icnss_mem_region_info icnss_mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01]; + bool skip_qmi; } *penv; static int icnss_qmi_event_post(enum icnss_qmi_event_type type, void *data) @@ -192,7 +193,7 @@ static int wlfw_msa_mem_info_send_sync_msg(void) memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); - req.msa_addr = penv->msa_phys; + req.msa_addr = penv->msa_pa; req.size = penv->msa_mem_size; req_desc.max_msg_len = WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN; @@ -629,48 +630,39 @@ static int icnss_qmi_event_server_arrive(void *data) if (ret < 0) { pr_err("%s: Failed to send indication message: %d\n", __func__, ret); - goto out; + goto fail; } - if (penv->msa_mem_size) { - penv->msa_addr = dma_alloc_coherent(&penv->pdev->dev, - penv->msa_mem_size, &penv->msa_phys, - GFP_KERNEL); - - pr_debug("%s: MSA addr: %p, MSA phys: %pa\n", __func__, - penv->msa_addr, &penv->msa_phys); - - if (penv->msa_addr) { - ret = wlfw_msa_mem_info_send_sync_msg(); - if (ret < 0) { - pr_err("%s: Failed to send MSA info: %d\n", - __func__, ret); - goto out; - } - ret = wlfw_msa_ready_send_sync_msg(); - if (ret < 0) { - pr_err("%s: Failed to send MSA ready : %d\n", - __func__, ret); - goto out; - } + if (penv->msa_va) { + ret = wlfw_msa_mem_info_send_sync_msg(); + if (ret < 0) { + pr_err("%s: Failed to send MSA info: %d\n", + __func__, ret); + goto fail; + } + ret = wlfw_msa_ready_send_sync_msg(); + if (ret < 0) { + pr_err("%s: Failed to send MSA ready : %d\n", + __func__, ret); + goto fail; } + } else { + pr_err("%s: Invalid MSA address\n", __func__); + ret = -EINVAL; + goto fail; } ret = wlfw_cap_send_sync_msg(); if (ret < 0) { pr_err("%s: Failed to get capability: %d\n", __func__, ret); - goto out; + goto fail; } return ret; fail: qmi_handle_destroy(penv->wlfw_clnt); penv->wlfw_clnt = NULL; out: - if (penv->msa_addr) { - dma_free_coherent(&penv->pdev->dev, penv->msa_mem_size, - penv->msa_addr, penv->msa_phys); - } ICNSS_ASSERT(0); return ret; } @@ -683,10 +675,7 @@ static int icnss_qmi_event_server_exit(void *data) pr_info("%s: QMI Service Disconnected\n", __func__); qmi_handle_destroy(penv->wlfw_clnt); - if (penv->msa_addr) { - dma_free_coherent(&penv->pdev->dev, penv->msa_mem_size, - penv->msa_addr, penv->msa_phys); - } + penv->state = 0; penv->wlfw_clnt = NULL; @@ -810,6 +799,9 @@ int icnss_register_driver(struct icnss_driver_ops *ops) } penv->ops = ops; + if (penv->skip_qmi) + penv->state |= ICNSS_FW_READY; + /* check for all conditions before invoking probe */ if (ICNSS_IS_FW_READY(penv->state) && penv->ops->probe) { ret = penv->ops->probe(&pdev->dev); @@ -1045,7 +1037,7 @@ int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, memset(&req, 0, sizeof(req)); - if (mode == ICNSS_WALTEST) + if (mode == ICNSS_WALTEST || mode == ICNSS_CCPM) goto skip; else if (!config || !host_version) { pr_err("%s: Invalid cfg pointer\n", __func__); @@ -1101,6 +1093,9 @@ skip: if (ret) pr_err("%s: Failed to send mode, ret = %d\n", __func__, ret); out: + if (penv->skip_qmi) + ret = 0; + return ret; } EXPORT_SYMBOL(icnss_wlan_enable); @@ -1124,13 +1119,44 @@ int icnss_get_ce_id(int irq) } EXPORT_SYMBOL(icnss_get_ce_id); +static ssize_t icnss_wlan_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int val; + int ret; + + if (!penv) + return -ENODEV; + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + if (val == ICNSS_WALTEST || val == ICNSS_CCPM) { + pr_debug("%s: WLAN Test Mode -> %d\n", __func__, val); + ret = icnss_wlan_enable(NULL, val, NULL); + if (ret) + pr_err("%s: WLAN Test Mode %d failed with %d\n", + __func__, val, ret); + } else { + pr_err("%s: Mode %d is not supported from command line\n", + __func__, val); + ret = -EINVAL; + } + + return ret; +} + +static DEVICE_ATTR(icnss_wlan_mode, S_IWUSR, NULL, icnss_wlan_mode_store); + static int icnss_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; int i; struct device *dev = &pdev->dev; - u32 msa_mem_size = 0; if (penv) return -EEXIST; @@ -1167,19 +1193,43 @@ static int icnss_probe(struct platform_device *pdev) } if (of_property_read_u32(dev->of_node, "qcom,wlan-msa-memory", - &msa_mem_size) == 0) { - penv->msa_mem_size = msa_mem_size; + &penv->msa_mem_size) == 0) { + if (penv->msa_mem_size) { + penv->msa_va = dma_alloc_coherent(&pdev->dev, + penv->msa_mem_size, + &penv->msa_pa, + GFP_KERNEL); + if (!penv->msa_va) { + pr_err("%s: DMA alloc failed\n", __func__); + ret = -EINVAL; + goto out; + } + pr_debug("%s: MAS va: %p, MSA pa: %pa\n", + __func__, penv->msa_va, &penv->msa_pa); + } } else { - pr_err("icnss: Fail to get MSA Memory Size\n"); + pr_err("%s: Fail to get MSA Memory Size\n", __func__); ret = -ENODEV; goto out; } + penv->skip_qmi = of_property_read_bool(dev->of_node, + "qcom,skip-qmi"); + + ret = device_create_file(dev, &dev_attr_icnss_wlan_mode); + if (ret) { + pr_err("%s: wlan_mode sys file creation failed\n", + __func__); + goto err_wlan_mode; + } + + spin_lock_init(&penv->qmi_event_lock); + penv->qmi_event_wq = alloc_workqueue("icnss_qmi_event", 0, 0); if (!penv->qmi_event_wq) { pr_err("%s: workqueue creation failed\n", __func__); ret = -EFAULT; - goto out; + goto err_workqueue; } INIT_WORK(&penv->qmi_event_work, icnss_qmi_wlfw_event_work); @@ -1192,11 +1242,22 @@ static int icnss_probe(struct platform_device *pdev) &wlfw_clnt_nb); if (ret < 0) { pr_err("%s: notifier register failed\n", __func__); - destroy_workqueue(penv->qmi_event_wq); - goto out; + goto err_qmi; } pr_debug("icnss: Platform driver probed successfully\n"); + + return ret; + +err_qmi: + if (penv->qmi_event_wq) + destroy_workqueue(penv->qmi_event_wq); +err_workqueue: + device_remove_file(&pdev->dev, &dev_attr_icnss_wlan_mode); +err_wlan_mode: + if (penv->msa_va) + dma_free_coherent(&pdev->dev, penv->msa_mem_size, + penv->msa_va, penv->msa_pa); out: return ret; } @@ -1209,6 +1270,10 @@ static int icnss_remove(struct platform_device *pdev) &wlfw_clnt_nb); if (penv->qmi_event_wq) destroy_workqueue(penv->qmi_event_wq); + device_remove_file(&pdev->dev, &dev_attr_icnss_wlan_mode); + if (penv->msa_va) + dma_free_coherent(&pdev->dev, penv->msa_mem_size, + penv->msa_va, penv->msa_pa); return 0; } diff --git a/drivers/soc/qcom/ipc_router_mhi_xprt.c b/drivers/soc/qcom/ipc_router_mhi_xprt.c index faf01c8aa013..9a0624804c21 100644 --- a/drivers/soc/qcom/ipc_router_mhi_xprt.c +++ b/drivers/soc/qcom/ipc_router_mhi_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,18 +39,15 @@ if (ipc_router_mhi_xprt_debug_mask) \ #define IPC_ROUTER_MHI_XPRT_NUM_TRBS 10 /** - * ipc_router_mhi_addr_map - DMA to virtual address mapping for an IPC Router - * packet. + * ipc_router_mhi_addr_map - Struct for virtual address to IPC Router + * packet mapping. * @list_node: Address mapping list node used by mhi transport map list. * @virt_addr: The virtual address in mapping. - * @dma_addr: The dma address in mapping. - * @pkt: The IPC Router packet for which the virtual address of skbs are mapped - * to DMA address during TX/RX operations. + * @pkt: The IPC Router packet for the virtual address */ struct ipc_router_mhi_addr_map { struct list_head list_node; void *virt_addr; - dma_addr_t dma_addr; struct rr_packet *pkt; }; @@ -109,10 +106,10 @@ struct ipc_router_mhi_channel { * @xprt_option: XPRT specific options to be handled by IPC Router. * @tx_addr_map_list_lock: The lock to protect the address mapping list for TX * operations. - * @tx_addr_map_list: DMA to virtual address mapping list for TX operations. + * @tx_addr_map_list: Virtual address mapping list for TX operations. * @rx_addr_map_list_lock: The lock to protect the address mapping list for RX * operations. - * @rx_addr_map_list: DMA to virtual address mapping list for RX operations. + * @rx_addr_map_list: Virtual address mapping list for RX operations. */ struct ipc_router_mhi_xprt { struct list_head list; @@ -177,13 +174,13 @@ void ipc_router_mhi_release_pkt(struct kref *ref) * ipc_router_mhi_xprt_find_addr_map() - Search the mapped virtual address * @addr_map_list: The list of address mappings. * @addr_map_list_lock: Reference to the lock that protects the @addr_map_list. - * @addr: The dma address for which mapped virtual address need to be found. + * @addr: The virtual address that needs to be found. * * Return: The mapped virtual Address if found, NULL otherwise. */ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list, struct mutex *addr_map_list_lock, - dma_addr_t addr) + void *addr) { struct ipc_router_mhi_addr_map *addr_mapping; struct ipc_router_mhi_addr_map *tmp_addr_mapping; @@ -194,7 +191,7 @@ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list, mutex_lock(addr_map_list_lock); list_for_each_entry_safe(addr_mapping, tmp_addr_mapping, addr_map_list, list_node) { - if (addr_mapping->dma_addr == addr) { + if (addr_mapping->virt_addr == addr) { virt_addr = addr_mapping->virt_addr; list_del(&addr_mapping->list_node); if (addr_mapping->pkt) @@ -207,26 +204,23 @@ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list, } mutex_unlock(addr_map_list_lock); IPC_RTR_ERR( - "%s: Virtual address mapping for DMA addr [%p] not found\n", + "%s: Virtual address mapping [%p] not found\n", __func__, (void *)addr); return NULL; } /* - * ipc_router_mhi_xprt_add_addr_map() - Add a mapping of virtual address to dma - * address + * ipc_router_mhi_xprt_add_addr_map() - Add a virtual address mapping structure * @addr_map_list: The list of address mappings. * @addr_map_list_lock: Reference to the lock that protects the @addr_map_list. * @pkt: The IPC Router packet that contains the virtual address in skbs. - * @addr: The virtual address which needs to be added. - * @dma_addr: The dma address which needs to be added. + * @virt_addr: The virtual address which needs to be added. * * Return: 0 on success, standard Linux error code otherwise. */ int ipc_router_mhi_xprt_add_addr_map(struct list_head *addr_map_list, struct mutex *addr_map_list_lock, - struct rr_packet *pkt, void *virt_addr, - dma_addr_t dma_addr) + struct rr_packet *pkt, void *virt_addr) { struct ipc_router_mhi_addr_map *addr_mapping; @@ -236,7 +230,6 @@ int ipc_router_mhi_xprt_add_addr_map(struct list_head *addr_map_list, if (!addr_mapping) return -ENOMEM; addr_mapping->virt_addr = virt_addr; - addr_mapping->dma_addr = dma_addr; addr_mapping->pkt = pkt; mutex_lock(addr_map_list_lock); if (addr_mapping->pkt) @@ -258,9 +251,8 @@ int mhi_xprt_queue_in_buffers(struct ipc_router_mhi_xprt *mhi_xprtp, { int i; struct sk_buff *skb; - dma_addr_t dma_addr; uint32_t buf_size = mhi_xprtp->ch_hndl.max_packet_size; - enum MHI_STATUS rc_val = MHI_STATUS_SUCCESS; + int rc_val = 0; for (i = 0; i < num_trbs; i++) { skb = alloc_skb(buf_size, GFP_KERNEL); @@ -269,31 +261,21 @@ int mhi_xprt_queue_in_buffers(struct ipc_router_mhi_xprt *mhi_xprtp, __func__, (i + 1)); break; } - dma_addr = dma_map_single(NULL, skb->data, - buf_size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(NULL, dma_addr)) { - IPC_RTR_ERR("%s: Failed to map DMA for SKB # %d\n", - __func__, (i + 1)); - kfree_skb(skb); - break; - } if (ipc_router_mhi_xprt_add_addr_map( &mhi_xprtp->rx_addr_map_list, &mhi_xprtp->rx_addr_map_list_lock, NULL, - skb->data, dma_addr) < 0) { - IPC_RTR_ERR("%s: Could not map %d SKB->DMA address\n", + skb->data) < 0) { + IPC_RTR_ERR("%s: Could not map %d SKB address\n", __func__, (i + 1)); break; } mutex_lock(&mhi_xprtp->ch_hndl.in_skbq_lock); rc_val = mhi_queue_xfer(mhi_xprtp->ch_hndl.in_handle, - dma_addr, buf_size, MHI_EOT); - if (rc_val != MHI_STATUS_SUCCESS) { + skb->data, buf_size, MHI_EOT); + if (rc_val) { mutex_unlock(&mhi_xprtp->ch_hndl.in_skbq_lock); IPC_RTR_ERR("%s: Failed to queue TRB # %d into MHI\n", __func__, (i + 1)); - dma_unmap_single(NULL, dma_addr, - buf_size, DMA_TO_DEVICE); kfree_skb(skb); break; } @@ -388,7 +370,6 @@ static int ipc_router_mhi_write_skb(struct ipc_router_mhi_xprt *mhi_xprtp, size_t sz_to_write = 0; size_t offset = 0; int rc; - dma_addr_t dma_addr; while (offset < skb->len) { wait_event(mhi_xprtp->write_wait_q, @@ -404,29 +385,20 @@ static int ipc_router_mhi_write_skb(struct ipc_router_mhi_xprt *mhi_xprtp, sz_to_write = min((size_t)(skb->len - offset), (size_t)IPC_ROUTER_MHI_XPRT_MAX_PKT_SIZE); - dma_addr = dma_map_single(NULL, skb->data + offset, - sz_to_write, DMA_TO_DEVICE); - if (dma_mapping_error(NULL, dma_addr)) { - mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); - IPC_RTR_ERR("%s: Failed to map DMA 0x%zx\n", - __func__, sz_to_write); - return -ENOMEM; - } if (ipc_router_mhi_xprt_add_addr_map( &mhi_xprtp->tx_addr_map_list, &mhi_xprtp->tx_addr_map_list_lock, pkt, - skb->data + offset, dma_addr) < 0) { - IPC_RTR_ERR("%s: Could not map SKB->DMA address\n", + skb->data + offset) < 0) { + IPC_RTR_ERR("%s: Could not map SKB address\n", __func__); break; } rc = mhi_queue_xfer(mhi_xprtp->ch_hndl.out_handle, - dma_addr, sz_to_write, MHI_EOT | MHI_EOB); - if (rc != 0) { + skb->data + offset, sz_to_write, + MHI_EOT | MHI_EOB); + if (rc) { mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); - dma_unmap_single(NULL, dma_addr, sz_to_write, - DMA_TO_DEVICE); IPC_RTR_ERR("%s: Error queueing mhi_xfer 0x%zx\n", __func__, sz_to_write); return -EFAULT; @@ -496,7 +468,7 @@ static int ipc_router_mhi_write(void *data, */ static void mhi_xprt_read_data(struct work_struct *work) { - dma_addr_t data_addr; + void *data_addr; ssize_t data_sz; void *skb_data; struct sk_buff *skb; @@ -520,15 +492,15 @@ static void mhi_xprt_read_data(struct work_struct *work) while (1) { rc = mhi_poll_inbound(mhi_xprtp->ch_hndl.in_handle, &result); - if (rc || !result.payload_buf || !result.bytes_xferd) { - if (rc != MHI_STATUS_RING_EMPTY) + if (rc || !result.buf_addr || !result.bytes_xferd) { + if (rc != -ENODATA) IPC_RTR_ERR("%s: Poll failed %s:%d:%p:%u\n", __func__, mhi_xprtp->xprt_name, rc, - (void *)result.payload_buf, - result.bytes_xferd); + result.buf_addr, + (unsigned int) result.bytes_xferd); break; } - data_addr = result.payload_buf; + data_addr = result.buf_addr; data_sz = result.bytes_xferd; /* Create a new rr_packet, if first fragment */ @@ -547,7 +519,6 @@ static void mhi_xprt_read_data(struct work_struct *work) &mhi_xprtp->rx_addr_map_list_lock, data_addr); - dma_unmap_single(NULL, data_addr, data_sz, DMA_BIDIRECTIONAL); if (!skb_data) continue; mutex_lock(&mhi_xprtp->ch_hndl.in_skbq_lock); @@ -638,7 +609,7 @@ static void mhi_xprt_enable_event(struct work_struct *work) if (xprt_work->chan_id == mhi_xprtp->ch_hndl.out_chan_id) { rc = mhi_open_channel(mhi_xprtp->ch_hndl.out_handle); - if (rc != MHI_STATUS_SUCCESS) { + if (rc) { IPC_RTR_ERR("%s Failed to open chan 0x%x, rc %d\n", __func__, mhi_xprtp->ch_hndl.out_chan_id, rc); goto out_enable_event; @@ -650,7 +621,7 @@ static void mhi_xprt_enable_event(struct work_struct *work) mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); } else if (xprt_work->chan_id == mhi_xprtp->ch_hndl.in_chan_id) { rc = mhi_open_channel(mhi_xprtp->ch_hndl.in_handle); - if (rc != MHI_STATUS_SUCCESS) { + if (rc) { IPC_RTR_ERR("%s Failed to open chan 0x%x, rc %d\n", __func__, mhi_xprtp->ch_hndl.in_chan_id, rc); goto out_enable_event; @@ -743,17 +714,15 @@ static void mhi_xprt_disable_event(struct work_struct *work) static void mhi_xprt_xfer_event(struct mhi_cb_info *cb_info) { struct ipc_router_mhi_xprt *mhi_xprtp; - dma_addr_t out_dma_addr; + void *out_addr; mhi_xprtp = (struct ipc_router_mhi_xprt *)(cb_info->result->user_data); if (cb_info->chan == mhi_xprtp->ch_hndl.out_chan_id) { - out_dma_addr = (dma_addr_t)cb_info->result->payload_buf; - dma_unmap_single(NULL, out_dma_addr, - cb_info->result->bytes_xferd, DMA_TO_DEVICE); + out_addr = cb_info->result->buf_addr; mutex_lock(&mhi_xprtp->ch_hndl.state_lock); ipc_router_mhi_xprt_find_addr_map(&mhi_xprtp->tx_addr_map_list, &mhi_xprtp->tx_addr_map_list_lock, - out_dma_addr); + out_addr); wake_up(&mhi_xprtp->write_wait_q); mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); } else if (cb_info->chan == mhi_xprtp->ch_hndl.in_chan_id) { @@ -821,13 +790,13 @@ static void ipc_router_mhi_xprt_cb(struct mhi_cb_info *cb_info) static int ipc_router_mhi_driver_register( struct ipc_router_mhi_xprt *mhi_xprtp) { - enum MHI_STATUS rc_status; + int rc_status; rc_status = mhi_register_channel(&mhi_xprtp->ch_hndl.out_handle, mhi_xprtp->ch_hndl.out_chan_id, 0, &mhi_xprtp->ch_hndl.out_clnt_info, (void *)mhi_xprtp); - if (rc_status != MHI_STATUS_SUCCESS) { + if (rc_status) { IPC_RTR_ERR("%s: Error %d registering out_chan for %s\n", __func__, rc_status, mhi_xprtp->xprt_name); return -EFAULT; @@ -837,7 +806,7 @@ static int ipc_router_mhi_driver_register( mhi_xprtp->ch_hndl.in_chan_id, 0, &mhi_xprtp->ch_hndl.in_clnt_info, (void *)mhi_xprtp); - if (rc_status != MHI_STATUS_SUCCESS) { + if (rc_status) { mhi_deregister_channel(mhi_xprtp->ch_hndl.out_handle); IPC_RTR_ERR("%s: Error %d registering in_chan for %s\n", __func__, rc_status, mhi_xprtp->xprt_name); diff --git a/drivers/soc/qcom/msm-spm.c b/drivers/soc/qcom/msm-spm.c index 4a42d9a213f9..14ecea1636e1 100644 --- a/drivers/soc/qcom/msm-spm.c +++ b/drivers/soc/qcom/msm-spm.c @@ -94,6 +94,33 @@ static uint32_t msm_spm_reg_offsets_saw2_v3_0[MSM_SPM_REG_NR] = { [MSM_SPM_REG_SAW_VERSION] = 0xFD0, }; +static uint32_t msm_spm_reg_offsets_saw2_v4_1[MSM_SPM_REG_NR] = { + [MSM_SPM_REG_SAW_SECURE] = 0xC00, + [MSM_SPM_REG_SAW_ID] = 0xC04, + [MSM_SPM_REG_SAW_STS2] = 0xC10, + [MSM_SPM_REG_SAW_SPM_STS] = 0xC0C, + [MSM_SPM_REG_SAW_AVS_STS] = 0xC14, + [MSM_SPM_REG_SAW_PMIC_STS] = 0xC18, + [MSM_SPM_REG_SAW_RST] = 0xC1C, + [MSM_SPM_REG_SAW_VCTL] = 0x900, + [MSM_SPM_REG_SAW_AVS_CTL] = 0x904, + [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x908, + [MSM_SPM_REG_SAW_AVS_DLY] = 0x90C, + [MSM_SPM_REG_SAW_SPM_CTL] = 0x0, + [MSM_SPM_REG_SAW_SPM_DLY] = 0x4, + [MSM_SPM_REG_SAW_CFG] = 0x0C, + [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40, + [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44, + [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48, + [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C, + [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50, + [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54, + [MSM_SPM_REG_SAW_PMIC_DATA_6] = 0x58, + [MSM_SPM_REG_SAW_PMIC_DATA_7] = 0x5C, + [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x400, + [MSM_SPM_REG_SAW_VERSION] = 0xFD0, +}; + static struct saw2_data saw2_info[] = { [0] = { "SAW_v2.1", @@ -113,6 +140,12 @@ static struct saw2_data saw2_info[] = { 0x0, msm_spm_reg_offsets_saw2_v3_0, }, + [3] = { + "SAW_v4.0", + 0x4, + 0x1, + msm_spm_reg_offsets_saw2_v4_1, + }, }; static uint32_t num_pmic_data; diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index 95b67fcaafd2..7589ea3b747e 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -984,6 +984,7 @@ int glink_pkt_release(struct inode *inode, struct file *file) { int ret = 0; struct glink_pkt_dev *devp = file->private_data; + unsigned long flags; GLINK_PKT_INFO("%s() on dev id:%d by [%s] ref_cnt[%d]\n", __func__, devp->i, current->comm, devp->ref_cnt); @@ -1011,7 +1012,12 @@ int glink_pkt_release(struct inode *inode, struct file *file) mutex_lock(&devp->ch_lock); } devp->poll_mode = 0; - devp->ws_locked = 0; + spin_lock_irqsave(&devp->pa_spinlock, flags); + if (devp->ws_locked) { + __pm_relax(&devp->pa_ws); + devp->ws_locked = 0; + } + spin_unlock_irqrestore(&devp->pa_spinlock, flags); devp->sigs_updated = false; devp->in_reset = 0; } @@ -1050,6 +1056,7 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i) devp->open_cfg.notify_state = glink_pkt_notify_state; devp->open_cfg.notify_rx_intent_req = glink_pkt_rmt_rx_intent_req_cb; devp->open_cfg.notify_rx_sigs = glink_pkt_notify_rx_sigs; + devp->open_cfg.options |= GLINK_OPT_INITIAL_XPORT; devp->open_cfg.priv = devp; devp->i = i; diff --git a/drivers/soc/qcom/service-locator-private.h b/drivers/soc/qcom/service-locator-private.h new file mode 100644 index 000000000000..df42080e362b --- /dev/null +++ b/drivers/soc/qcom/service-locator-private.h @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef SERVICE_LOCATOR_V01_H +#define SERVICE_LOCATOR_V01_H + +#include <linux/qmi_encdec.h> + +#include <soc/qcom/msm_qmi_interface.h> +#include <soc/qcom/service-locator.h> + +#define SERVREG_LOC_SERVICE_ID_V01 0x40 +#define SERVREG_LOC_SERVICE_VERS_V01 0x01 + +#define QMI_SERVREG_LOC_INDICATION_REGISTER_RESP_V01 0x0020 +#define QMI_SERVREG_LOC_REGISTER_SERVICE_LIST_REQ_V01 0x0022 +#define QMI_SERVREG_LOC_GET_DOMAIN_LIST_REQ_V01 0x0021 +#define QMI_SERVREG_LOC_GET_DOMAIN_LIST_RESP_V01 0x0021 +#define QMI_SERVREG_LOC_DATABASE_UPDATED_IND_V01 0x0023 +#define QMI_SERVREG_LOC_INDICATION_REGISTER_REQ_V01 0x0020 +#define QMI_SERVREG_LOC_REGISTER_SERVICE_LIST_RESP_V01 0x0022 + +#define QMI_SERVREG_LOC_NAME_LENGTH_V01 64 +#define QMI_SERVREG_LOC_LIST_LENGTH_V01 32 + +enum qmi_servreg_loc_service_instance_enum_type_v01 { + QMI_SERVREG_LOC_SERVICE_INSTANCE_ENUM_TYPE_MIN_VAL_V01 = INT_MIN, + QMI_SERVREG_LOC_SERVICE_INSTANCE_APSS_V01 = 0x1, + QMI_SERVREG_LOC_SERVICE_INSTANCE_ENUM_TYPE_MAX_VAL_V01 = INT_MAX, +}; + +struct qmi_servreg_loc_indication_register_req_msg_v01 { + uint8_t enable_database_updated_indication_valid; + uint8_t enable_database_updated_indication; +}; +#define QMI_SERVREG_LOC_INDICATION_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 4 +struct elem_info qmi_servreg_loc_indication_register_req_msg_v01_ei[]; + +struct qmi_servreg_loc_indication_register_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; +#define QMI_SERVREG_LOC_INDICATION_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 7 +struct elem_info qmi_servreg_loc_indication_register_resp_msg_v01_ei[]; + +struct qmi_servreg_loc_get_domain_list_req_msg_v01 { + char service_name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; + uint8_t domain_offset_valid; + uint32_t domain_offset; +}; +#define QMI_SERVREG_LOC_GET_DOMAIN_LIST_REQ_MSG_V01_MAX_MSG_LEN 74 +struct elem_info qmi_servreg_loc_get_domain_list_req_msg_v01_ei[]; + +struct qmi_servreg_loc_get_domain_list_resp_msg_v01 { + struct qmi_response_type_v01 resp; + uint8_t total_domains_valid; + uint16_t total_domains; + uint8_t db_rev_count_valid; + uint16_t db_rev_count; + uint8_t domain_list_valid; + uint32_t domain_list_len; + struct servreg_loc_entry_v01 + domain_list[QMI_SERVREG_LOC_LIST_LENGTH_V01]; +}; +#define QMI_SERVREG_LOC_GET_DOMAIN_LIST_RESP_MSG_V01_MAX_MSG_LEN 2389 +struct elem_info qmi_servreg_loc_get_domain_list_resp_msg_v01_ei[]; + +struct qmi_servreg_loc_register_service_list_req_msg_v01 { + char domain_name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; + uint32_t service_list_len; + struct servreg_loc_entry_v01 + service_list[QMI_SERVREG_LOC_LIST_LENGTH_V01]; +}; +#define QMI_SERVREG_LOC_REGISTER_SERVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 2439 +struct elem_info qmi_servreg_loc_register_service_list_req_msg_v01_ei[]; + +struct qmi_servreg_loc_register_service_list_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; +#define QMI_SERVREG_LOC_REGISTER_SERVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 7 +struct elem_info qmi_servreg_loc_register_service_list_resp_msg_v01_ei[]; + +struct qmi_servreg_loc_database_updated_ind_msg_v01 { + char placeholder; +}; +#define QMI_SERVREG_LOC_DATABASE_UPDATED_IND_MSG_V01_MAX_MSG_LEN 0 +struct elem_info qmi_servreg_loc_database_updated_ind_msg_v01_ei[]; + +#define QMI_EOTI_DATA_TYPE \ +{ \ + .data_type = QMI_EOTI, \ + .elem_len = 0, \ + .elem_size = 0, \ + .is_array = NO_ARRAY, \ + .tlv_type = 0x00, \ + .offset = 0, \ + .ei_array = NULL, \ +}, + +static struct elem_info servreg_loc_entry_v01_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_loc_entry_v01, + name), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_loc_entry_v01, + instance_id), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_loc_entry_v01, + service_data_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_loc_entry_v01, + service_data), + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_indication_register_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + qmi_servreg_loc_indication_register_req_msg_v01, + enable_database_updated_indication_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + qmi_servreg_loc_indication_register_req_msg_v01, + enable_database_updated_indication), + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_indication_register_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + qmi_servreg_loc_indication_register_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_get_domain_list_req_msg_v01_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_req_msg_v01, + service_name), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_req_msg_v01, + domain_offset_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_req_msg_v01, + domain_offset), + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_get_domain_list_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + total_domains_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + total_domains), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + db_rev_count_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + db_rev_count), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + domain_list_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + domain_list_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_SERVREG_LOC_LIST_LENGTH_V01, + .elem_size = sizeof(struct servreg_loc_entry_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct + qmi_servreg_loc_get_domain_list_resp_msg_v01, + domain_list), + .ei_array = servreg_loc_entry_v01_ei, + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_register_service_list_req_msg_v01_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct + qmi_servreg_loc_register_service_list_req_msg_v01, + domain_name), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + qmi_servreg_loc_register_service_list_req_msg_v01, + service_list_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_SERVREG_LOC_LIST_LENGTH_V01, + .elem_size = sizeof(struct servreg_loc_entry_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + qmi_servreg_loc_register_service_list_req_msg_v01, + service_list), + .ei_array = servreg_loc_entry_v01_ei, + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_register_service_list_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + qmi_servreg_loc_register_service_list_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + QMI_EOTI_DATA_TYPE +}; + +struct elem_info qmi_servreg_loc_database_updated_ind_msg_v01_ei[] = { + QMI_EOTI_DATA_TYPE +}; + +#endif diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c new file mode 100644 index 000000000000..49fce3602cd4 --- /dev/null +++ b/drivers/soc/qcom/service-locator.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "servloc: %s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/string.h> +#include <linux/completion.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/debugfs.h> + +#include <soc/qcom/msm_qmi_interface.h> +#include <soc/qcom/service-locator.h> +#include "service-locator-private.h" + +#define SERVREG_LOC_SERVICE_INSTANCE_ID 1 + +#define QMI_RESP_BIT_SHIFT(x) (x << 16) +#define QMI_SERVREG_LOC_SERVER_INITIAL_TIMEOUT 2000 +#define QMI_SERVREG_LOC_SERVER_TIMEOUT 2000 +#define INITIAL_TIMEOUT 100000 + +#define LOCATOR_NOT_PRESENT 0 +#define LOCATOR_PRESENT 1 +#define LOCATOR_UNKNOWN -1 + +static u32 locator_status = LOCATOR_UNKNOWN; +static bool service_inited; + +DECLARE_COMPLETION(locator_status_known); + +static void service_locator_svc_arrive(struct work_struct *work); +static void service_locator_svc_exit(struct work_struct *work); +static void service_locator_recv_msg(struct work_struct *work); + +struct workqueue_struct *servloc_wq; + +struct pd_qmi_data { + struct work_struct svc_arrive; + struct work_struct svc_exit; + struct work_struct svc_rcv_msg; + struct notifier_block notifier; + struct completion service_available; + struct mutex service_mutex; + struct qmi_handle *clnt_handle; +}; + +DEFINE_MUTEX(service_init_mutex); +struct pd_qmi_data service_locator; + +/* Please refer soc/qcom/service-locator.h for use about APIs defined here */ + +static ssize_t show_service_locator_status(struct class *cl, + struct class_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%x\n", locator_status); +} + +static ssize_t store_service_locator_status(struct class *cl, + struct class_attribute *attr, + const char *buf, size_t size) +{ + u32 val; + + if (kstrtos32(buf, 10, &val) < 0) + goto err; + if (val != LOCATOR_NOT_PRESENT && val != LOCATOR_PRESENT) + goto err; + + mutex_lock(&service_init_mutex); + locator_status = val; + complete_all(&locator_status_known); + mutex_unlock(&service_init_mutex); + return size; +err: + pr_err("Invalid input parameters\n"); + return -EINVAL; +} + +static struct class_attribute service_locator_class_attr[] = { + __ATTR(service_locator_status, S_IRUGO | S_IWUSR, + show_service_locator_status, + store_service_locator_status), + __ATTR_NULL, +}; + +static struct class service_locator_class = { + .name = "service_locator", + .owner = THIS_MODULE, + .class_attrs = service_locator_class_attr, +}; + +static int service_locator_svc_event_notify(struct notifier_block *this, + unsigned long code, + void *_cmd) +{ + switch (code) { + case QMI_SERVER_ARRIVE: + queue_work(servloc_wq, &service_locator.svc_arrive); + break; + case QMI_SERVER_EXIT: + queue_work(servloc_wq, &service_locator.svc_exit); + break; + default: + break; + } + return 0; +} + +static void service_locator_clnt_notify(struct qmi_handle *handle, + enum qmi_event_type event, void *notify_priv) +{ + switch (event) { + case QMI_RECV_MSG: + schedule_work(&service_locator.svc_rcv_msg); + break; + default: + break; + } +} + +static void service_locator_svc_arrive(struct work_struct *work) +{ + int rc = 0; + + /* Create a Local client port for QMI communication */ + mutex_lock(&service_locator.service_mutex); + service_locator.clnt_handle = + qmi_handle_create(service_locator_clnt_notify, NULL); + if (!service_locator.clnt_handle) { + service_locator.clnt_handle = NULL; + mutex_unlock(&service_locator.service_mutex); + pr_err("Service locator QMI client handle alloc failed!\n"); + return; + } + + /* Connect to service */ + rc = qmi_connect_to_service(service_locator.clnt_handle, + SERVREG_LOC_SERVICE_ID_V01, SERVREG_LOC_SERVICE_VERS_V01, + SERVREG_LOC_SERVICE_INSTANCE_ID); + if (rc) { + qmi_handle_destroy(service_locator.clnt_handle); + service_locator.clnt_handle = NULL; + mutex_unlock(&service_locator.service_mutex); + pr_err("Unable to connnect to service\n"); + return; + } + if (!service_inited) + complete_all(&service_locator.service_available); + mutex_unlock(&service_locator.service_mutex); + pr_info("Connection established with the Service locator\n"); +} + +static void service_locator_svc_exit(struct work_struct *work) +{ + mutex_lock(&service_locator.service_mutex); + qmi_handle_destroy(service_locator.clnt_handle); + service_locator.clnt_handle = NULL; + mutex_unlock(&service_locator.service_mutex); + pr_info("Connection with service locator lost\n"); +} + +static void service_locator_recv_msg(struct work_struct *work) +{ + int ret; + + do { + pr_debug("Notified about a Receive event\n"); + } while ((ret = qmi_recv_msg(service_locator.clnt_handle)) == 0); + + if (ret != -ENOMSG) + pr_err("Error receiving message\n"); +} + +static void store_get_domain_list_response(struct pd_qmi_client_data *pd, + struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp, + int offset) +{ + int i; + + for (i = offset; i < resp->domain_list_len; i++) { + pd->domain_list[i].instance_id = + resp->domain_list[i].instance_id; + strlcpy(pd->domain_list[i].name, resp->domain_list[i].name, + QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1); + pd->domain_list[i].service_data_valid = + resp->domain_list[i].service_data_valid; + pd->domain_list[i].service_data = + resp->domain_list[i].service_data; + } +} + +static int servreg_loc_send_msg(struct msg_desc *req_desc, + struct msg_desc *resp_desc, + struct qmi_servreg_loc_get_domain_list_req_msg_v01 *req, + struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp, + struct pd_qmi_client_data *pd) +{ + int rc; + + /* + * Send msg and get response. There is a chance that the service went + * away since the time we last checked for it to be available and + * actually made this call. In that case the call just fails. + */ + rc = qmi_send_req_wait(service_locator.clnt_handle, req_desc, req, + sizeof(*req), resp_desc, resp, sizeof(*resp), + msecs_to_jiffies(QMI_SERVREG_LOC_SERVER_TIMEOUT)); + if (rc < 0) { + pr_err("QMI send req failed for client %s, ret - %d\n", + pd->client_name, rc); + return rc; + } + + /* Check the response */ + if (QMI_RESP_BIT_SHIFT(resp->resp.result) != QMI_RESULT_SUCCESS_V01) { + pr_err("QMI request for client %s failed 0x%x\n", + pd->client_name, QMI_RESP_BIT_SHIFT(resp->resp.error)); + return -EREMOTEIO; + } + return rc; +} + +static int service_locator_send_msg(struct pd_qmi_client_data *pd) +{ + struct msg_desc req_desc, resp_desc; + struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp; + struct qmi_servreg_loc_get_domain_list_req_msg_v01 *req; + int rc; + int db_rev_count = 0, domains_read = 0; + + if (!service_locator.clnt_handle) { + pr_err("Service locator not available!\n"); + return -EAGAIN; + } + + req = kmalloc(sizeof( + struct qmi_servreg_loc_get_domain_list_req_msg_v01), + GFP_KERNEL); + if (!req) { + pr_err("Unable to allocate memory for req message\n"); + rc = -ENOMEM; + goto out; + } + resp = kmalloc(sizeof( + struct qmi_servreg_loc_get_domain_list_resp_msg_v01), + GFP_KERNEL); + if (!resp) { + pr_err("Unable to allocate memory for resp message\n"); + rc = -ENOMEM; + goto out; + } + /* Prepare req and response message formats */ + req_desc.msg_id = QMI_SERVREG_LOC_GET_DOMAIN_LIST_REQ_V01; + req_desc.max_msg_len = + QMI_SERVREG_LOC_GET_DOMAIN_LIST_REQ_MSG_V01_MAX_MSG_LEN; + req_desc.ei_array = qmi_servreg_loc_get_domain_list_req_msg_v01_ei; + + resp_desc.msg_id = QMI_SERVREG_LOC_GET_DOMAIN_LIST_RESP_V01; + resp_desc.max_msg_len = + QMI_SERVREG_LOC_GET_DOMAIN_LIST_RESP_MSG_V01_MAX_MSG_LEN; + resp_desc.ei_array = qmi_servreg_loc_get_domain_list_resp_msg_v01_ei; + + /* Prepare req and response message */ + strlcpy(req->service_name, pd->service_name, + QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1); + req->domain_offset_valid = true; + req->domain_offset = 0; + + pd->domain_list = NULL; + do { + req->domain_offset += domains_read; + rc = servreg_loc_send_msg(&req_desc, &resp_desc, req, resp, + pd); + if (rc < 0) { + pr_err("send msg failed! 0x%x\n", rc); + goto out; + } + if (!domains_read) { + db_rev_count = pd->db_rev_count = resp->db_rev_count; + pd->total_domains = resp->total_domains; + if (!pd->total_domains && resp->domain_list_len) { + pr_err("total domains not set\n"); + pd->total_domains = resp->domain_list_len; + } + pd->domain_list = kmalloc( + sizeof(struct servreg_loc_entry_v01) * + resp->total_domains, GFP_KERNEL); + if (!pd->domain_list) { + pr_err("Cannot allocate domain list\n"); + rc = -ENOMEM; + goto out; + } + } + if (db_rev_count != resp->db_rev_count) { + pr_err("Service Locator DB updated for client %s\n", + pd->client_name); + kfree(pd->domain_list); + rc = -EAGAIN; + goto out; + } + /* Copy the response*/ + store_get_domain_list_response(pd, resp, domains_read); + domains_read += resp->domain_list_len; + } while (domains_read < resp->total_domains); + rc = 0; +out: + kfree(req); + kfree(resp); + return rc; +} + +static int init_service_locator(void) +{ + static bool service_inited; + int rc = 0; + + mutex_lock(&service_init_mutex); + if (locator_status == LOCATOR_NOT_PRESENT) { + pr_err("Service Locator not present\n"); + rc = -ENODEV; + goto inited; + } + if (service_inited) + goto inited; + + if (locator_status != LOCATOR_PRESENT) { + mutex_unlock(&service_init_mutex); + rc = wait_for_completion_timeout(&locator_status_known, + msecs_to_jiffies(INITIAL_TIMEOUT)); + if (!rc) { + locator_status = LOCATOR_NOT_PRESENT; + pr_err("Timed out waiting for Service Locator\n"); + return -ENODEV; + } + mutex_lock(&service_init_mutex); + if (locator_status == LOCATOR_NOT_PRESENT) { + pr_err("Service Locator not present\n"); + rc = -ENODEV; + goto inited; + } + } + + service_locator.notifier.notifier_call = + service_locator_svc_event_notify; + init_completion(&service_locator.service_available); + mutex_init(&service_locator.service_mutex); + + servloc_wq = create_singlethread_workqueue("servloc_wq"); + if (!servloc_wq) { + rc = -ENOMEM; + pr_err("Could not create workqueue\n"); + goto inited; + } + + INIT_WORK(&service_locator.svc_arrive, service_locator_svc_arrive); + INIT_WORK(&service_locator.svc_exit, service_locator_svc_exit); + INIT_WORK(&service_locator.svc_rcv_msg, service_locator_recv_msg); + + rc = qmi_svc_event_notifier_register(SERVREG_LOC_SERVICE_ID_V01, + SERVREG_LOC_SERVICE_VERS_V01, SERVREG_LOC_SERVICE_INSTANCE_ID, + &service_locator.notifier); + if (rc < 0) { + pr_err("Notifier register failed!\n"); + goto inited; + } + + rc = wait_for_completion_timeout(&service_locator.service_available, + msecs_to_jiffies(QMI_SERVREG_LOC_SERVER_INITIAL_TIMEOUT)); + if (!rc) { + rc = -ENODEV; + mutex_unlock(&service_init_mutex); + pr_err("Process domain service locator response timeout!\n"); + goto error; + } + service_inited = true; + mutex_unlock(&service_init_mutex); + pr_info("Service locator initialized\n"); + return 0; +error: + qmi_svc_event_notifier_unregister(SERVREG_LOC_SERVICE_ID_V01, + SERVREG_LOC_SERVICE_VERS_V01, SERVREG_LOC_SERVICE_INSTANCE_ID, + &service_locator.notifier); + destroy_workqueue(servloc_wq); +inited: + mutex_unlock(&service_init_mutex); + return rc; +} + +int get_service_location(struct pd_qmi_client_data *data) +{ + int rc = 0; + + if (!data || !data->client_name || !data->service_name) { + rc = -EINVAL; + pr_err("Invalid input!\n"); + goto err; + } + rc = init_service_locator(); + if (rc) { + pr_err("Unable to connect to service locator!, rc = %d\n", rc); + goto err; + } + rc = service_locator_send_msg(data); + if (rc) + pr_err("Failed to get process domains for %s for client %s\n", + data->service_name, data->client_name); +err: + return rc; +} +EXPORT_SYMBOL(get_service_location); + +int find_subsys(const char *pd_path, char *subsys) +{ + char *start, *end; + + if (!subsys || !pd_path) + return -EINVAL; + + start = strnstr(pd_path, "/", QMI_SERVREG_LOC_NAME_LENGTH_V01); + if (!start) + return -EINVAL; + start++; + end = strnstr(start, "/", QMI_SERVREG_LOC_NAME_LENGTH_V01); + if (!end || start == end) + return -EINVAL; + + strlcpy(subsys, start, end - start + 1); + return 0; +} +EXPORT_SYMBOL(find_subsys); + +static struct pd_qmi_client_data test_data; + +static ssize_t show_servloc(struct seq_file *f, void *unused) +{ + int rc = 0, i = 0; + char subsys[QMI_SERVREG_LOC_NAME_LENGTH_V01]; + + rc = get_service_location(&test_data); + if (rc) { + seq_printf(f, "Failed to get process domain!, rc = %d\n", rc); + return -EIO; + } + + seq_printf(f, "Service Name: %s\tTotal Domains: %d\n", + test_data.service_name, test_data.total_domains); + for (i = 0; i < test_data.total_domains; i++) { + seq_printf(f, "Instance ID: %d\t ", + test_data.domain_list[i].instance_id); + seq_printf(f, "Domain Name: %s\n", + test_data.domain_list[i].name); + rc = find_subsys(test_data.domain_list[i].name, subsys); + if (rc < 0) + seq_printf(f, "No valid subsys found for %s!\n", + test_data.domain_list[i].name); + else + seq_printf(f, "Subsys: %s\n", subsys); + } + return 0; +} + +static ssize_t store_servloc(struct file *fp, const char __user *buf, + size_t count, loff_t *unused) +{ + if (!buf) + return -EIO; + snprintf(test_data.service_name, sizeof(test_data.service_name), + "%.*s", (int) min((size_t)count - 1, + (sizeof(test_data.service_name) - 1)), buf); + return count; +} + +static int servloc_open(struct inode *inode, struct file *file) +{ + return single_open(file, (void *)show_servloc, inode->i_private); +} + +static const struct file_operations servloc_fops = { + .open = servloc_open, + .read = seq_read, + .write = store_servloc, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct dentry *test_servloc_file; + +static int __init service_locator_init(void) +{ + class_register(&service_locator_class); + test_servloc_file = debugfs_create_file("test_servloc", + S_IRUGO | S_IWUSR, NULL, NULL, + &servloc_fops); + if (!test_servloc_file) + pr_err("Could not create test_servloc debugfs entry!"); + return 0; +} + +static void __exit service_locator_exit(void) +{ + class_unregister(&service_locator_class); + debugfs_remove(test_servloc_file); +} + +module_init(service_locator_init); +module_exit(service_locator_exit); diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index 5a7c6dd17b09..0a9cfc3827df 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,14 +40,8 @@ #define STOP_ACK_TIMEOUT_MS 1000 #define CRASH_STOP_ACK_TO_MS 200 -#define COLD_BOOT_DONE 0 -#define GDSC_DONE 1 -#define RAM_WIPE_DONE 2 -#define CPU_BOOT_DONE 3 -#define WDOG_BITE 4 -#define CLR_WDOG_BITE 5 -#define ERR_READY 6 -#define PBL_DONE 7 +#define ERR_READY 1 +#define PBL_DONE 2 #define desc_to_data(d) container_of(d, struct pil_tz_data, desc) #define subsys_to_data(d) container_of(d, struct pil_tz_data, subsys_desc) @@ -89,7 +83,7 @@ struct reg_info { * @desc: PIL descriptor * @subsys: subsystem device pointer * @subsys_desc: subsystem descriptor - * @u32 bits_arr[8]: array of bit positions in SCSR registers + * @u32 bits_arr[2]: array of bit positions in SCSR registers */ struct pil_tz_data { struct reg_info *regs; @@ -114,7 +108,8 @@ struct pil_tz_data { void __iomem *irq_clear; void __iomem *irq_mask; void __iomem *err_status; - u32 bits_arr[8]; + void __iomem *err_status_spare; + u32 bits_arr[2]; }; enum scm_cmd { @@ -913,50 +908,63 @@ static irqreturn_t subsys_stop_ack_intr_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t subsys_generic_handler(int irq, void *dev_id) +static void check_pbl_done(struct pil_tz_data *d) { - struct pil_tz_data *d = subsys_to_data(dev_id); - uint32_t status_val, clear_val, err_value; + uint32_t err_value; - if (subsys_get_crash_status(d->subsys)) - return IRQ_HANDLED; + err_value = __raw_readl(d->err_status); + pr_debug("PBL_DONE received from %s!\n", d->subsys_desc.name); + if (!err_value) + __raw_writel(BIT(d->bits_arr[PBL_DONE]), d->irq_clear); + else + pr_err("PBL error status register: 0x%08x\n", err_value); +} - /* Masking interrupts not handled by HLOS */ - clear_val = __raw_readl(d->irq_mask); - __raw_writel(clear_val | BIT(d->bits_arr[COLD_BOOT_DONE]) | - BIT(d->bits_arr[GDSC_DONE]) | BIT(d->bits_arr[RAM_WIPE_DONE]) | - BIT(d->bits_arr[CPU_BOOT_DONE]), d->irq_mask); - status_val = __raw_readl(d->irq_status); +static void check_err_ready(struct pil_tz_data *d) +{ + uint32_t err_value; - if (status_val & BIT(d->bits_arr[WDOG_BITE])) { + err_value = __raw_readl(d->err_status_spare); + if (!err_value) { + pr_debug("Subsystem error services up received from %s!\n", + d->subsys_desc.name); + __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear); + complete_err_ready(d->subsys); + } else { pr_err("wdog bite received from %s!\n", d->subsys_desc.name); - clear_val = __raw_readl(d->irq_clear); - __raw_writel(clear_val | BIT(d->bits_arr[CLR_WDOG_BITE]), - d->irq_clear); + __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear); subsys_set_crash_status(d->subsys, true); log_failure_reason(d); subsystem_restart_dev(d->subsys); - } else if (status_val & BIT(d->bits_arr[ERR_READY])) { - pr_debug("Subsystem error services up received from %s!\n", - d->subsys_desc.name); - clear_val = __raw_readl(d->irq_clear); - __raw_writel(clear_val | BIT(d->bits_arr[ERR_READY]), - d->irq_clear); - complete_err_ready(d->subsys); - } else if (status_val & BIT(d->bits_arr[PBL_DONE])) { - err_value = __raw_readl(d->err_status); - pr_debug("PBL_DONE received from %s!\n", - d->subsys_desc.name); - if (!err_value) { - clear_val = __raw_readl(d->irq_clear); - __raw_writel(clear_val | BIT(d->bits_arr[PBL_DONE]), - d->irq_clear); - } else - pr_err("SP-PBL rmb error status: 0x%08x\n", err_value); } +} + +static irqreturn_t subsys_generic_handler(int irq, void *dev_id) +{ + struct pil_tz_data *d = subsys_to_data(dev_id); + uint32_t status_val; + + if (subsys_get_crash_status(d->subsys)) + return IRQ_HANDLED; + + status_val = __raw_readl(d->irq_status); + + if (status_val & BIT(d->bits_arr[ERR_READY])) + check_err_ready(d); + else if (status_val & BIT(d->bits_arr[PBL_DONE])) + check_pbl_done(d); return IRQ_HANDLED; } +static void mask_scsr_irqs(struct pil_tz_data *d) +{ + uint32_t mask_val; + /* Masking all interrupts not handled by HLOS */ + mask_val = ~0; + __raw_writel(mask_val & ~BIT(d->bits_arr[ERR_READY]) & + ~BIT(d->bits_arr[PBL_DONE]), d->irq_mask); +} + static int pil_tz_driver_probe(struct platform_device *pdev) { struct pil_tz_data *d; @@ -1046,11 +1054,16 @@ static int pil_tz_driver_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_err"); d->err_status = devm_ioremap_resource(&pdev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "rmb_err_spare2"); + d->err_status_spare = devm_ioremap_resource(&pdev->dev, res); rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,spss-scsr-bits", d->bits_arr, sizeof(d->bits_arr)/ sizeof(d->bits_arr[0])); if (rc) dev_err(&pdev->dev, "Failed to read qcom,spss-scsr-bits"); + mask_scsr_irqs(d); + } else { d->subsys_desc.err_fatal_handler = subsys_err_fatal_intr_handler; diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.h b/drivers/soc/qcom/wlan_firmware_service_v01.h index 6d007c297cf6..6e96cbabd9d8 100644 --- a/drivers/soc/qcom/wlan_firmware_service_v01.h +++ b/drivers/soc/qcom/wlan_firmware_service_v01.h @@ -60,6 +60,8 @@ enum wlfw_driver_mode_enum_v01 { QMI_WLFW_EPPING_V01 = 2, QMI_WLFW_WALTEST_V01 = 3, QMI_WLFW_OFF_V01 = 4, + QMI_WLFW_CCPM_V01 = 5, + QMI_WLFW_QVIT_V01 = 6, WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX, }; diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 296a6557a8a1..5c0225cd4e24 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -264,7 +264,7 @@ static void ion_system_secure_heap_unmap_dma(struct ion_heap *heap, struct ion_system_secure_heap, heap); - secure_heap->sys_heap->ops->map_dma(secure_heap->sys_heap, + secure_heap->sys_heap->ops->unmap_dma(secure_heap->sys_heap, buffer); } diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 424343f9c549..b9be6d9a52ef 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -42,6 +42,8 @@ #include <linux/rcupdate.h> #include <linux/profile.h> #include <linux/notifier.h> +#include <linux/mutex.h> +#include <linux/delay.h> #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" @@ -79,6 +81,24 @@ static unsigned long lowmem_count(struct shrinker *s, global_page_state(NR_INACTIVE_FILE); } +static int test_task_flag(struct task_struct *p, int flag) +{ + struct task_struct *t = p; + + do { + task_lock(t); + if (test_tsk_thread_flag(t, flag)) { + task_unlock(t); + return 1; + } + task_unlock(t); + } while_each_thread(p, t); + + return 0; +} + +static DEFINE_MUTEX(scan_mutex); + static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) { struct task_struct *tsk; @@ -91,8 +111,14 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int selected_tasksize = 0; short selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); - int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; - int other_file = global_page_state(NR_FILE_PAGES) - + int other_free; + int other_file; + + if (mutex_lock_interruptible(&scan_mutex) < 0) + return 0; + + other_free = global_page_state(NR_FREE_PAGES); + other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM) - total_swapcache_pages(); @@ -115,6 +141,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) { lowmem_print(5, "lowmem_scan %lu, %x, return 0\n", sc->nr_to_scan, sc->gfp_mask); + mutex_unlock(&scan_mutex); return 0; } @@ -128,16 +155,20 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) if (tsk->flags & PF_KTHREAD) continue; + if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { + if (test_task_flag(tsk, TIF_MEMDIE)) { + rcu_read_unlock(); + /* give the system time to free up the memory */ + msleep_interruptible(20); + mutex_unlock(&scan_mutex); + return 0; + } + } + p = find_lock_task_mm(tsk); if (!p) continue; - if (test_tsk_thread_flag(p, TIF_MEMDIE) && - time_before_eq(jiffies, lowmem_deathpending_timeout)) { - task_unlock(p); - rcu_read_unlock(); - return 0; - } oom_score_adj = p->signal->oom_score_adj; if (oom_score_adj < min_score_adj) { task_unlock(p); @@ -189,11 +220,14 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) free); lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; + /* give the system time to free up the memory */ + msleep_interruptible(20); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); rcu_read_unlock(); + mutex_unlock(&scan_mutex); return rem; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3da70925d565..448cbdf6fa40 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2094,6 +2094,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g) unsigned long flags; int irq; + pm_runtime_get_sync(dwc->dev); + dbg_event(0xFF, "Stop gsync", + atomic_read(&dwc->dev->power.usage_count)); dwc3_gadget_disable_irq(dwc); tasklet_kill(&dwc->bh); @@ -2107,6 +2110,10 @@ static int dwc3_gadget_stop(struct usb_gadget *g) spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_mark_last_busy(dwc->dev); + pm_runtime_put_autosuspend(dwc->dev); + dbg_event(0xFF, "Auto_susgsync", 0); + irq = platform_get_irq(to_platform_device(dwc->dev), 0); free_irq(irq, dwc); diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index de246efcbb58..1eb0c8d6b62f 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -46,6 +46,13 @@ #define FREEZIO_N BIT(1) #define POWER_DOWN BIT(0) +#define QUSB2PHY_PWR_CTRL1 0x210 +#define PWR_CTRL1_CLAMP_N_EN BIT(1) +#define PWR_CTRL1_POWR_DOWN BIT(0) + +#define QUSB2PHY_PLL_COMMON_STATUS_ONE 0x1A0 +#define CORE_READY_STATUS BIT(0) + #define QUSB2PHY_PORT_UTMI_CTRL1 0xC0 #define TERM_SELECT BIT(4) #define XCVR_SELECT_FS BIT(2) @@ -117,6 +124,7 @@ struct qusb_phy { int vdd_levels[3]; /* none, low, high */ int init_seq_len; int *qusb_phy_init_seq; + u32 major_rev; u32 tune2_val; int tune2_efuse_bit_pos; @@ -410,6 +418,8 @@ static int qusb_phy_init(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); int ret, reset_val = 0; + u8 reg; + bool pll_lock_fail = false; dev_dbg(phy->dev, "%s\n", __func__); @@ -466,8 +476,13 @@ static int qusb_phy_init(struct usb_phy *phy) } /* Disable the PHY */ - writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, - qphy->base + QUSB2PHY_PORT_POWERDOWN); + if (qphy->major_rev < 2) + writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, + qphy->base + QUSB2PHY_PORT_POWERDOWN); + else + writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) | + PWR_CTRL1_POWR_DOWN, + qphy->base + QUSB2PHY_PWR_CTRL1); /* configure for ULPI mode if requested */ if (qphy->ulpi_mode) @@ -508,8 +523,13 @@ static int qusb_phy_init(struct usb_phy *phy) wmb(); /* Enable the PHY */ - writel_relaxed(CLAMP_N_EN | FREEZIO_N, - qphy->base + QUSB2PHY_PORT_POWERDOWN); + if (qphy->major_rev < 2) + writel_relaxed(CLAMP_N_EN | FREEZIO_N, + qphy->base + QUSB2PHY_PORT_POWERDOWN); + else + writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) & + ~PWR_CTRL1_POWR_DOWN, + qphy->base + QUSB2PHY_PWR_CTRL1); /* Ensure above write is completed before turning ON ref clk */ wmb(); @@ -529,18 +549,29 @@ static int qusb_phy_init(struct usb_phy *phy) writel_relaxed(reset_val, qphy->base + QUSB2PHY_PLL_TEST); } - } - /* Make sure that above write is completed to get PLL source clock */ - wmb(); + /* Make sure above write is completed to get PLL source clock */ + wmb(); - /* Required to get PHY PLL lock successfully */ - usleep_range(100, 110); + /* Required to get PHY PLL lock successfully */ + usleep_range(100, 110); + } + + if (qphy->major_rev < 2) { + reg = readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS); + dev_dbg(phy->dev, "QUSB2PHY_PLL_STATUS:%x\n", reg); + if (!(reg & QUSB2PHY_PLL_LOCK)) + pll_lock_fail = true; + } else { + reg = readb_relaxed(qphy->base + + QUSB2PHY_PLL_COMMON_STATUS_ONE); + dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg); + if (!(reg & CORE_READY_STATUS)) + pll_lock_fail = true; + } - if (!(readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS) & - QUSB2PHY_PLL_LOCK)) { - dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", - readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS)); + if (pll_lock_fail) { + dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg); WARN_ON(1); } @@ -556,8 +587,13 @@ static void qusb_phy_shutdown(struct usb_phy *phy) qusb_phy_enable_clocks(qphy, true); /* Disable the PHY */ - writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, - qphy->base + QUSB2PHY_PORT_POWERDOWN); + if (qphy->major_rev < 2) + writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, + qphy->base + QUSB2PHY_PORT_POWERDOWN); + else + writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) | + PWR_CTRL1_POWR_DOWN, + qphy->base + QUSB2PHY_PWR_CTRL1); wmb(); qusb_phy_enable_clocks(qphy, false); @@ -976,6 +1012,12 @@ static int qusb_phy_probe(struct platform_device *pdev) } hold_phy_reset = of_property_read_bool(dev->of_node, "qcom,hold-reset"); + + /* use default major revision as 2 */ + qphy->major_rev = 2; + ret = of_property_read_u32(dev->of_node, "qcom,major-rev", + &qphy->major_rev); + ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level", (u32 *) qphy->vdd_levels, ARRAY_SIZE(qphy->vdd_levels)); diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h index a411520a83b2..7211c48dbc7b 100644 --- a/include/linux/bluetooth-power.h +++ b/include/linux/bluetooth-power.h @@ -27,6 +27,8 @@ struct bt_power_vreg_data { /* voltage levels to be set */ unsigned int low_vol_level; unsigned int high_vol_level; + /* current level to be set */ + unsigned int load_uA; /* * is set voltage supported for this regulator? * false => set voltage is not supported diff --git a/include/linux/ipa.h b/include/linux/ipa.h index fe99c620b85b..3a87177b623f 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -907,12 +907,23 @@ struct IpaHwStatsWDIInfoData_t { * Rx buffers) * @rdy_ring_size: size of the Rx ring in bytes * @rdy_ring_rp_pa: physical address of the location through which IPA uc is + * reading (WDI-1.0) + * @rdy_comp_ring_base_pa: physical address of the base of the Rx completion + * ring (WDI-2.0) + * @rdy_comp_ring_wp_pa: physical address of the location through which IPA + * uc is writing (WDI-2.0) + * @rdy_comp_ring_size: size of the Rx_completion ring in bytes * expected to communicate about the Read pointer into the Rx Ring */ struct ipa_wdi_ul_params { phys_addr_t rdy_ring_base_pa; u32 rdy_ring_size; phys_addr_t rdy_ring_rp_pa; + phys_addr_t rdy_comp_ring_base_pa; + phys_addr_t rdy_comp_ring_wp_pa; + u32 rdy_comp_ring_size; + u32 *rdy_ring_rp_va; + u32 *rdy_comp_ring_wp_va; }; /** @@ -926,6 +937,9 @@ struct ipa_wdi_ul_params_smmu { struct sg_table rdy_ring; u32 rdy_ring_size; phys_addr_t rdy_ring_rp_pa; + struct sg_table rdy_comp_ring; + phys_addr_t rdy_comp_ring_wp_pa; + u32 rdy_comp_ring_size; }; /** @@ -1038,30 +1052,6 @@ struct ipa_wdi_buffer_info { }; /** - * struct odu_bridge_params - parameters for odu bridge initialization API - * - * @netdev_name: network interface name - * @priv: private data that will be supplied to client's callback - * @tx_dp_notify: callback for handling SKB. the following event are supported: - * IPA_WRITE_DONE: will be called after client called to odu_bridge_tx_dp() - * Client is expected to free the skb. - * IPA_RECEIVE: will be called for delivering skb to APPS. - * Client is expected to deliver the skb to network stack. - * @send_dl_skb: callback for sending skb on downlink direction to adapter. - * Client is expected to free the skb. - * @device_ethaddr: device Ethernet address in network order. - * @ipa_desc_size: IPA Sys Pipe Desc Size - */ -struct odu_bridge_params { - const char *netdev_name; - void *priv; - ipa_notify_cb tx_dp_notify; - int (*send_dl_skb)(void *priv, struct sk_buff *skb); - u8 device_ethaddr[ETH_ALEN]; - u32 ipa_desc_size; -}; - -/** * enum ipa_mhi_event_type - event type for mhi callback * * @IPA_MHI_EVENT_READY: IPA MHI is ready and IPA uC is loaded. After getting @@ -1424,20 +1414,6 @@ enum ipacm_client_enum ipa_get_client(int pipe_idx); bool ipa_get_client_uplink(int pipe_idx); /* - * ODU bridge - */ - -int odu_bridge_init(struct odu_bridge_params *params); - -int odu_bridge_connect(void); - -int odu_bridge_disconnect(void); - -int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata); - -int odu_bridge_cleanup(void); - -/* * IPADMA */ int ipa_dma_init(void); @@ -2090,36 +2066,6 @@ static inline bool ipa_get_client_uplink(int pipe_idx) return -EPERM; } - -/* - * ODU bridge - */ -static inline int odu_bridge_init(struct odu_bridge_params *params) -{ - return -EPERM; -} - -static inline int odu_bridge_disconnect(void) -{ - return -EPERM; -} - -static inline int odu_bridge_connect(void) -{ - return -EPERM; -} - -static inline int odu_bridge_tx_dp(struct sk_buff *skb, - struct ipa_tx_meta *metadata) -{ - return -EPERM; -} - -static inline int odu_bridge_cleanup(void) -{ - return -EPERM; -} - /* * IPADMA */ diff --git a/include/linux/ipa_odu_bridge.h b/include/linux/ipa_odu_bridge.h new file mode 100644 index 000000000000..5d30a9784998 --- /dev/null +++ b/include/linux/ipa_odu_bridge.h @@ -0,0 +1,84 @@ +/* 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 + * 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 _IPA_ODO_BRIDGE_H_ +#define _IPA_ODO_BRIDGE_H_ + +#include <linux/ipa.h> + +/** + * struct odu_bridge_params - parameters for odu bridge initialization API + * + * @netdev_name: network interface name + * @priv: private data that will be supplied to client's callback + * @tx_dp_notify: callback for handling SKB. the following event are supported: + * IPA_WRITE_DONE: will be called after client called to odu_bridge_tx_dp() + * Client is expected to free the skb. + * IPA_RECEIVE: will be called for delivering skb to APPS. + * Client is expected to deliver the skb to network stack. + * @send_dl_skb: callback for sending skb on downlink direction to adapter. + * Client is expected to free the skb. + * @device_ethaddr: device Ethernet address in network order. + * @ipa_desc_size: IPA Sys Pipe Desc Size + */ +struct odu_bridge_params { + const char *netdev_name; + void *priv; + ipa_notify_cb tx_dp_notify; + int (*send_dl_skb)(void *priv, struct sk_buff *skb); + u8 device_ethaddr[ETH_ALEN]; + u32 ipa_desc_size; +}; + +#if defined CONFIG_IPA || defined CONFIG_IPA3 + +int odu_bridge_init(struct odu_bridge_params *params); + +int odu_bridge_connect(void); + +int odu_bridge_disconnect(void); + +int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata); + +int odu_bridge_cleanup(void); + +#else + +static inline int odu_bridge_init(struct odu_bridge_params *params) +{ + return -EPERM; +} + +static inline int odu_bridge_disconnect(void) +{ + return -EPERM; +} + +static inline int odu_bridge_connect(void) +{ + return -EPERM; +} + +static inline int odu_bridge_tx_dp(struct sk_buff *skb, + struct ipa_tx_meta *metadata) +{ + return -EPERM; +} + +static inline int odu_bridge_cleanup(void) +{ + return -EPERM; +} + +#endif /* CONFIG_IPA || defined CONFIG_IPA3 */ + +#endif /* _IPA_ODO_BRIDGE_H */ diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 66c0e8f43883..fb650ab2693f 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -135,8 +135,8 @@ struct msm_actuator_params_t32 { uint16_t init_setting_size; uint32_t i2c_addr; enum i2c_freq_mode_t i2c_freq_mode; - enum msm_actuator_addr_type i2c_addr_type; - enum msm_actuator_data_type i2c_data_type; + enum msm_camera_i2c_reg_addr_type i2c_addr_type; + enum msm_camera_i2c_data_type i2c_data_type; compat_uptr_t reg_tbl_params; compat_uptr_t init_settings; struct park_lens_data_t park_lens; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1d67f3873e10..63568caf0de8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -712,6 +712,8 @@ struct cfg80211_acl_data { * @p2p_opp_ps: P2P opportunistic PS * @acl: ACL configuration used by the drivers which has support for * MAC address based access control + * @pbss: If set, start as a PCP instead of AP. Relevant for DMG + * networks. */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -730,6 +732,7 @@ struct cfg80211_ap_settings { u8 p2p_ctwindow; bool p2p_opp_ps; const struct cfg80211_acl_data *acl; + bool pbss; }; /** @@ -1888,6 +1891,8 @@ struct cfg80211_ibss_params { * @ht_capa_mask: The bits of ht_capa which are to be used. * @vht_capa: VHT Capability overrides * @vht_capa_mask: The bits of vht_capa which are to be used. + * @pbss: if set, connect to a PCP instead of AP. Valid for DMG + * networks. */ struct cfg80211_connect_params { struct ieee80211_channel *channel; @@ -1910,6 +1915,7 @@ struct cfg80211_connect_params { struct ieee80211_ht_cap ht_capa_mask; struct ieee80211_vht_cap vht_capa; struct ieee80211_vht_cap vht_capa_mask; + bool pbss; }; /** @@ -3488,6 +3494,7 @@ struct cfg80211_cached_keys; * registered for unexpected class 3 frames (AP mode) * @conn: (private) cfg80211 software SME connection state machine data * @connect_keys: (private) keys to set after connection is established + * @conn_bss_type: connecting/connected BSS type * @ibss_fixed: (private) IBSS is using fixed BSSID * @ibss_dfs_possible: (private) IBSS may change to a DFS channel * @event_list: (private) list for internal event processing @@ -3518,6 +3525,7 @@ struct wireless_dev { u8 ssid_len, mesh_id_len, mesh_id_up_len; struct cfg80211_conn *conn; struct cfg80211_cached_keys *connect_keys; + enum ieee80211_bss_type conn_bss_type; struct list_head event_list; spinlock_t event_lock; diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 14a22fd1b55f..27ae1332947c 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -72,6 +72,8 @@ enum icnss_driver_mode { ICNSS_EPPING, ICNSS_WALTEST, ICNSS_OFF, + ICNSS_CCPM, + ICNSS_QVIT, }; struct icnss_soc_info { diff --git a/include/soc/qcom/service-locator.h b/include/soc/qcom/service-locator.h new file mode 100644 index 000000000000..be1a2b431dd9 --- /dev/null +++ b/include/soc/qcom/service-locator.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Process Domain Service Locator API header + */ + +#ifndef _SERVICE_LOCATOR_H +#define _SERVICE_LOCATOR_H + +#define QMI_SERVREG_LOC_NAME_LENGTH_V01 64 +#define QMI_SERVREG_LOC_LIST_LENGTH_V01 32 + +/* + * @name: The full process domain path for a process domain which provides + * a particular service + * @instance_id: The QMI instance id corresponding to the root process + * domain which is responsible for notifications for this + * process domain + * @service_data_valid: Indicates if service_data field has valid data + * @service_data: Optional service data provided by the service locator + */ +struct servreg_loc_entry_v01 { + char name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; + uint32_t instance_id; + uint8_t service_data_valid; + uint32_t service_data; +}; + +/* + * @client_name: Name of the client calling the api + * @service_name: Name of the service for which the list of process domains + * is requested + * @total_domains: Length of the process domain list + * @db_rev_count: Process domain list database revision number + * @domain_list: List of process domains providing the service + */ +struct pd_qmi_client_data { + char client_name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; + char service_name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; + int total_domains; + int db_rev_count; + struct servreg_loc_entry_v01 *domain_list; +}; + +#if defined(CONFIG_MSM_SERVICE_LOCATOR) +/* + * Use this api to request information regarding the process domains on which + * a particular service runs. The client name and the service name inside the + * pd_qmi_client_data structure need to be filled in by the client calling the + * api. The total domains, db revision and the domain list will be filled in + * by the service locator. + * Returns 0 on success; otherwise a value < 0 if no valid subsystem is found. + */ +int get_service_location(struct pd_qmi_client_data *data); + +/* + * Use this api to request information regarding the subsystem the process + * domain runs on. + * @pd_path: The name field from inside the servreg_loc_entry that one + * gets back using the get_processdomains api. + * Returns 0 on success; otherwise a value < 0 if no valid subsystem is found. + */ +int find_subsys(const char *pd_path, char *subsys); + +#else + +static inline int get_service_location(struct pd_qmi_client_data *data) +{ + return 0; +} + +static inline int find_subsys(const char *pd_path, const char *subsys) +{ + return 0; +} + +#endif /* CONFIG_MSM_SERVICE_LOCATOR */ + +#endif diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h index c83caede1763..d8ee4d523880 100644 --- a/include/soc/qcom/smem.h +++ b/include/soc/qcom/smem.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -76,7 +76,7 @@ enum { SMEM_SMD_BASE_ID, SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS, SMEM_SMEM_LOG_EVENTS, - SMEM_SMEM_STATIC_LOG_IDX, + SMEM_XBL_LOADER_CORE_INFO, SMEM_SMEM_STATIC_LOG_EVENTS, SMEM_SMEM_SLOW_CLOCK_SYNC, SMEM_SMEM_SLOW_CLOCK_VALUE, diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1f0b4cf5dd03..25627f584405 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1783,6 +1783,11 @@ enum nl80211_commands { * between scans. The scan plans are executed sequentially. * Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan. * + * @NL80211_ATTR_PBSS: flag attribute. If set it means operate + * in a PBSS. Specified in %NL80211_CMD_CONNECT to request + * connecting to a PCP, and in %NL80211_CMD_START_AP to start + * a PCP instead of AP. Relevant for DMG networks only. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2157,6 +2162,8 @@ enum nl80211_attrs { NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS, NL80211_ATTR_SCHED_SCAN_PLANS, + NL80211_ATTR_PBSS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h index c534911d864a..d83e00876fd5 100644 --- a/include/uapi/media/msm_cam_sensor.h +++ b/include/uapi/media/msm_cam_sensor.h @@ -409,8 +409,8 @@ struct msm_actuator_params_t { uint16_t init_setting_size; uint32_t i2c_addr; enum i2c_freq_mode_t i2c_freq_mode; - enum msm_actuator_addr_type i2c_addr_type; - enum msm_actuator_data_type i2c_data_type; + enum msm_camera_i2c_reg_addr_type i2c_addr_type; + enum msm_camera_i2c_data_type i2c_data_type; struct msm_actuator_reg_params_t *reg_tbl_params; struct reg_settings_t *init_settings; struct park_lens_data_t park_lens; diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h index eab853bf137f..3985e9750af7 100644 --- a/include/uapi/media/msm_camsensor_sdk.h +++ b/include/uapi/media/msm_camsensor_sdk.h @@ -367,9 +367,9 @@ struct region_params_t { struct reg_settings_t { unsigned short reg_addr; - enum msm_actuator_addr_type addr_type; + enum msm_camera_i2c_reg_addr_type addr_type; unsigned short reg_data; - enum msm_actuator_data_type data_type; + enum msm_camera_i2c_data_type data_type; enum msm_actuator_i2c_operation i2c_operation; unsigned int delay; }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b30a0a8030d3..816c9075ba3c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -401,6 +401,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, + [NL80211_ATTR_PBSS] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -3461,6 +3462,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) return PTR_ERR(params.acl); } + params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); + if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) + return -EOPNOTSUPP; + wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { @@ -7951,6 +7956,12 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) connect.flags |= ASSOC_REQ_USE_RRM; } + connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); + if (connect.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) { + kzfree(connkeys); + return -EOPNOTSUPP; + } + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8020b5b094d4..79bd3a171caa 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -264,7 +264,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) wdev->conn->params.bssid, wdev->conn->params.ssid, wdev->conn->params.ssid_len, - IEEE80211_BSS_TYPE_ESS, + wdev->conn_bss_type, IEEE80211_PRIVACY(wdev->conn->params.privacy)); if (!bss) return NULL; @@ -687,7 +687,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, - IEEE80211_BSS_TYPE_ESS, + wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); if (bss) cfg80211_hold_bss(bss_from_pub(bss)); @@ -846,7 +846,7 @@ void cfg80211_roamed(struct net_device *dev, bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, wdev->ssid_len, - IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); + wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); if (WARN_ON(!bss)) return; @@ -1017,6 +1017,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, memcpy(wdev->ssid, connect->ssid, connect->ssid_len); wdev->ssid_len = connect->ssid_len; + wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS : + IEEE80211_BSS_TYPE_ESS; + if (!rdev->ops->connect) err = cfg80211_sme_connect(wdev, connect, prev_bssid); else diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig index 6a4f5099833f..e8fc5f622c3e 100644 --- a/sound/soc/msm/Kconfig +++ b/sound/soc/msm/Kconfig @@ -114,4 +114,31 @@ config SND_SOC_MSM8996 the machine driver and the corresponding DAI-links +config SND_SOC_MSMCOBALT + tristate "SoC Machine driver for MSMCOBALT boards" + depends on ARCH_QCOM + select SND_SOC_COMPRESS + select SND_SOC_QDSP6V2 + select SND_SOC_MSM_STUB + select SND_SOC_MSM_HOSTLESS_PCM + select SND_DYNAMIC_MINORS + select MSM_QDSP6_APRV2 + select MSM_QDSP6V2_CODECS + select SND_SOC_WCD9335 + select SND_SOC_WSA881X + select SND_SOC_MSM_HDMI_CODEC_RX + select DTS_SRS_TM + select QTI_PP + select SND_SOC_CPE + select MSM_ULTRASOUND + select DOLBY_DS2 + select SND_HWDEP + select DTS_EAGLE + help + To add support for SoC audio on MSMCOBALT. + This will enable sound soc drivers which + interfaces with DSP, also it will enable + the machine driver and the corresponding + DAI-links + endmenu diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile index 12514d9775c6..3ad34be41578 100644 --- a/sound/soc/msm/Makefile +++ b/sound/soc/msm/Makefile @@ -15,3 +15,7 @@ obj-$(CONFIG_SND_SOC_CPE) += snd-soc-cpe.o # for MSM8996 sound card driver snd-soc-msm8996-objs := msm8996.o obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-msm8996.o + +# for MSMCOBALT sound card driver +snd-soc-msmcobalt-objs := msmcobalt.o +obj-$(CONFIG_SND_SOC_MSMCOBALT) += snd-soc-msmcobalt.o diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c new file mode 100644 index 000000000000..c78265e5a23c --- /dev/null +++ b/sound/soc/msm/msmcobalt.c @@ -0,0 +1,2828 @@ +/* + * 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/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/switch.h> +#include <linux/input.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/pcm.h> +#include <sound/jack.h> +#include <sound/q6afe-v2.h> +#include <sound/q6core.h> +#include <sound/pcm_params.h> +#include <sound/info.h> +#include <device_event.h> +#include "qdsp6v2/msm-pcm-routing-v2.h" +#include "../codecs/wcd9335.h" +#include "../codecs/wsa881x.h" + +#define DRV_NAME "msmcobalt-asoc-snd" + +#define __CHIPSET__ "MSMCOBALT " +#define MSM_DAILINK_NAME(name) (__CHIPSET__#name) + +#define SAMPLING_RATE_8KHZ 8000 +#define SAMPLING_RATE_16KHZ 16000 +#define SAMPLING_RATE_32KHZ 32000 +#define SAMPLING_RATE_44P1KHZ 44100 +#define SAMPLING_RATE_48KHZ 48000 +#define SAMPLING_RATE_96KHZ 96000 +#define SAMPLING_RATE_192KHZ 192000 + +#define WCD9XXX_MBHC_DEF_BUTTONS 8 +#define WCD9XXX_MBHC_DEF_RLOADS 5 +#define CODEC_EXT_CLK_RATE 9600000 +#define ADSP_STATE_READY_TIMEOUT_MS 3000 +#define DEV_NAME_STR_LEN 32 + +#define WSA8810_NAME_1 "wsa881x.20170211" +#define WSA8810_NAME_2 "wsa881x.20170212" + +enum { + SLIM_RX_0 = 0, + SLIM_RX_1, + SLIM_RX_2, + SLIM_RX_3, + SLIM_RX_4, + SLIM_RX_5, + SLIM_RX_MAX, +}; + +enum { + SLIM_TX_0 = 0, + SLIM_TX_1, + SLIM_TX_2, + SLIM_TX_3, + SLIM_TX_4, + SLIM_TX_5, + SLIM_TX_6, + SLIM_TX_7, + SLIM_TX_MAX, +}; + +struct slim_ch_config { + u32 sample_rate; + u32 bit_format; + u32 channels; +}; + +struct msm_wsa881x_dev_info { + struct device_node *of_node; + u32 index; +}; + +struct msm_asoc_mach_data { + u32 mclk_freq; + int us_euro_gpio; + int hph_en1_gpio; + int hph_en0_gpio; + struct snd_info_entry *codec_root; +}; + +struct msm_asoc_wcd93xx_codec { + void* (*get_afe_config_fn)(struct snd_soc_codec *codec, + enum afe_config_type config_type); + void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec); +}; + +/* Default configuration of slimbus channels */ +static struct slim_ch_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}, + [SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct slim_ch_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}, + [SLIM_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_7] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +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", + "Five", "Six", "Seven", + "Eight"}; +static const char *const vi_feed_ch_text[] = {"One", "Two"}; +static char const *bit_format_text[] = {"S16_LE", "S24_LE"}; +static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", + "KHZ_32", "KHZ_44P1", "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); +static SOC_ENUM_SINGLE_EXT_DECL(slim_1_tx_chs, slim_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_chs, slim_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_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_0_tx_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); + +static struct platform_device *spdev; + +static bool codec_reg_done; +static struct snd_soc_aux_dev *msm_aux_dev; +static struct snd_soc_codec_conf *msm_codec_conf; +static struct msm_asoc_wcd93xx_codec msm_codec_fn; +static void *adsp_state_notifier; + +static void *def_tasha_mbhc_cal(void); +static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, + int enable, bool dapm); +static int msm_wsa881x_init(struct snd_soc_component *component); + +/* + * Need to report LINEIN + * if R/L channel impedance is larger than 5K ohm + */ +static struct wcd_mbhc_config wcd_mbhc_cfg = { + .read_fw_bin = false, + .calibration = NULL, + .detect_extn_cable = true, + .mono_stero_detection = false, + .swap_gnd_mic = NULL, + .hs_ext_micbias = true, + .key_code[0] = KEY_MEDIA, + .key_code[1] = KEY_VOICECOMMAND, + .key_code[2] = KEY_VOLUMEUP, + .key_code[3] = KEY_VOLUMEDOWN, + .key_code[4] = 0, + .key_code[5] = 0, + .key_code[6] = 0, + .key_code[7] = 0, + .linein_th = 5000, + .moist_cfg = { V_45_MV, I_3P0_UA }, +}; + +static struct snd_soc_dapm_route wcd9335_audio_paths[] = { + {"MIC BIAS1", NULL, "MCLK"}, + {"MIC BIAS2", NULL, "MCLK"}, + {"MIC BIAS3", NULL, "MCLK"}, + {"MIC BIAS4", NULL, "MCLK"}, +}; + +static int slim_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 6; + break; + default: + sample_rate_val = 4; + break; + } + return sample_rate_val; +} + +static int slim_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_192KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int slim_get_bit_format_val(int bit_format) +{ + int val = 0; + + switch (bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + val = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + val = 0; + break; + } + return val; +} + +static int slim_get_bit_format(int val) +{ + int bit_fmt = SNDRV_PCM_FORMAT_S16_LE; + + switch (val) { + case 0: + bit_fmt = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + bit_fmt = SNDRV_PCM_FORMAT_S24_LE; + break; + default: + bit_fmt = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return bit_fmt; +} + +static int slim_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int port_id = 0; + + if (strnstr(kcontrol->id.name, "SLIM_0_RX", sizeof("SLIM_0_RX"))) + port_id = SLIM_RX_0; + else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX"))) + port_id = SLIM_RX_5; + else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX"))) + port_id = SLIM_TX_0; + else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX"))) + port_id = SLIM_TX_1; + else { + pr_err("%s: unsupported channel: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + + return port_id; +} + +static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_sample_rate_val(slim_rx_cfg[ch_num].sample_rate); + + pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_cfg[ch_num].sample_rate = + slim_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_sample_rate_val(slim_tx_cfg[ch_num].sample_rate); + + pr_debug("%s: slim[%d]_tx_sample_rate = %d, item = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate = 0; + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + sample_rate = slim_get_sample_rate(ucontrol->value.enumerated.item[0]); + if (sample_rate == SAMPLING_RATE_44P1KHZ) { + pr_err("%s: Unsupported sample rate %d: for Tx path\n", + __func__, sample_rate); + return -EINVAL; + } + slim_tx_cfg[ch_num].sample_rate = sample_rate; + + pr_debug("%s: slim[%d]_tx_sample_rate = %d, value = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_bit_format_val(slim_rx_cfg[ch_num].bit_format); + + pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_rx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_cfg[ch_num].bit_format = + slim_get_bit_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_rx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_bit_format_val(slim_tx_cfg[ch_num].bit_format); + + pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_tx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_tx_cfg[ch_num].bit_format = + slim_get_bit_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_tx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].channels); + ucontrol->value.enumerated.item[0] = slim_rx_cfg[ch_num].channels - 1; + + return 0; +} + +static int msm_slim_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].channels); + + return 1; +} + +static int msm_slim_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].channels); + ucontrol->value.enumerated.item[0] = slim_tx_cfg[ch_num].channels - 1; + + return 0; +} + +static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_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); + + return 1; +} + +static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1; + pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch); + return 1; +} + +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), + SOC_ENUM_EXT("SLIM_0_TX Channels", slim_0_tx_chs, + msm_slim_tx_ch_get, msm_slim_tx_ch_put), + SOC_ENUM_EXT("SLIM_1_TX Channels", slim_1_tx_chs, + msm_slim_tx_ch_get, msm_slim_tx_ch_put), + SOC_ENUM_EXT("SLIM_5_RX Channels", slim_5_rx_chs, + msm_slim_rx_ch_get, msm_slim_rx_ch_put), + SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs, + msm_vi_feed_tx_ch_get, msm_vi_feed_tx_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, + slim_rx_bit_format_get, slim_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format, + slim_tx_bit_format_get, slim_tx_bit_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, + slim_tx_sample_rate_get, slim_tx_sample_rate_put), + SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate, + slim_rx_sample_rate_get, slim_rx_sample_rate_put), +}; + +static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, + int enable, bool dapm) +{ + int ret = 0; + + if (!strcmp(dev_name(codec->dev), "tasha_codec")) + ret = tasha_cdc_mclk_enable(codec, enable, dapm); + else { + dev_err(codec->dev, "%s: unknown codec to enable ext clk\n", + __func__); + ret = -EINVAL; + } + return ret; +} + +static int msm_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + pr_debug("%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return msm_snd_enable_codec_ext_clk(codec, 1, true); + case SND_SOC_DAPM_POST_PMD: + return msm_snd_enable_codec_ext_clk(codec, 0, true); + } + return 0; +} + +static const struct snd_soc_dapm_widget msm_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + msm_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SPK("Lineout_1 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_3 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_2 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_4 amp", NULL), + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL), + SND_SOC_DAPM_MIC("Analog Mic5", NULL), + SND_SOC_DAPM_MIC("Analog Mic6", NULL), + + SND_SOC_DAPM_MIC("Digital Mic0", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), + SND_SOC_DAPM_MIC("Digital Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic5", NULL), +}; + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, + int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + +static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int rc = 0; + void *config = NULL; + struct snd_soc_codec *codec = NULL; + + pr_debug("%s: format = %d, rate = %d\n", + __func__, params_format(params), params_rate(params)); + + switch (dai_link->be_id) { + case MSM_BACKEND_DAI_SLIMBUS_0_RX: + case MSM_BACKEND_DAI_SLIMBUS_1_RX: + case MSM_BACKEND_DAI_SLIMBUS_3_RX: + case MSM_BACKEND_DAI_SLIMBUS_4_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[0].bit_format); + rate->min = rate->max = slim_rx_cfg[0].sample_rate; + channels->min = channels->max = slim_rx_cfg[0].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_0_TX: + case MSM_BACKEND_DAI_SLIMBUS_3_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_tx_cfg[0].bit_format); + rate->min = rate->max = slim_tx_cfg[0].sample_rate; + channels->min = channels->max = slim_tx_cfg[0].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_1_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_tx_cfg[1].bit_format); + rate->min = rate->max = slim_tx_cfg[1].sample_rate; + channels->min = channels->max = slim_tx_cfg[1].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_4_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S32_LE); + rate->min = rate->max = SAMPLING_RATE_8KHZ; + channels->min = channels->max = msm_vi_feed_tx_ch; + break; + + case MSM_BACKEND_DAI_SLIMBUS_5_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[5].bit_format); + rate->min = rate->max = slim_rx_cfg[5].sample_rate; + channels->min = channels->max = slim_rx_cfg[5].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_5_TX: + codec = rtd->codec; + rate->min = rate->max = SAMPLING_RATE_16KHZ; + channels->min = channels->max = 1; + + config = msm_codec_fn.get_afe_config_fn(codec, + AFE_SLIMBUS_SLAVE_PORT_CONFIG); + if (config) { + rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, + config, SLIMBUS_5_TX); + if (rc) + pr_err("%s: Failed to set slimbus slave port config %d\n", + __func__, rc); + } + break; + + default: + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + } + return 0; +} + +static bool msm_swap_gnd_mic(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = codec->component.card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int value = gpio_get_value_cansleep(pdata->us_euro_gpio); + + pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value); + gpio_set_value_cansleep(pdata->us_euro_gpio, !value); + return true; +} + +static int msm_afe_set_config(struct snd_soc_codec *codec) +{ + int ret = 0; + void *config_data = NULL; + + if (!msm_codec_fn.get_afe_config_fn) { + dev_err(codec->dev, "%s: codec get afe config not init'ed\n", + __func__); + return -EINVAL; + } + + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_CDC_REGISTERS_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0); + if (ret) { + dev_err(codec->dev, + "%s: Failed to set codec registers config %d\n", + __func__, ret); + return ret; + } + } + + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_CDC_REGISTER_PAGE_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data, + 0); + if (ret) + dev_err(codec->dev, + "%s: Failed to set cdc register page config\n", + __func__); + } + + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_SLIMBUS_SLAVE_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0); + if (ret) { + dev_err(codec->dev, + "%s: Failed to set slimbus slave config %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +static void msm_afe_clear_config(void) +{ + afe_clear_config(AFE_CDC_REGISTERS_CONFIG); + afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG); +} + +static int msm_adsp_power_up_config(struct snd_soc_codec *codec) +{ + int ret = 0; + unsigned long timeout; + int adsp_ready = 0; + + timeout = jiffies + + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); + + do { + if (q6core_is_adsp_ready()) { + pr_debug("%s: ADSP Audio is ready\n", __func__); + adsp_ready = 1; + break; + } + } while (time_after(timeout, jiffies)); + + if (!adsp_ready) { + pr_err("%s: timed out waiting for ADSP Audio\n", __func__); + ret = -ETIMEDOUT; + goto err_fail; + } + + ret = msm_afe_set_config(codec); + if (ret) + pr_err("%s: Failed to set AFE config. err %d\n", + __func__, ret); + + return 0; + +err_fail: + return ret; +} + +static int msm_adsp_state_callback(struct notifier_block *nb, + unsigned long value, void *priv) +{ + int ret = NOTIFY_OK; + struct snd_soc_card *card = NULL; + const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + + if (!spdev) + return -EINVAL; + + card = platform_get_drvdata(spdev); + rtd = snd_soc_get_pcm_runtime(card, be_dl_name); + if (!rtd) { + dev_err(card->dev, + "%s: snd_soc_get_pcm_runtime for %s failed!\n", + __func__, be_dl_name); + ret = -EINVAL; + goto err_pcm_runtime; + } + + codec = rtd->codec; + if (value == SUBSYS_BEFORE_SHUTDOWN) { + pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n", + __func__); + msm_afe_clear_config(); + } else if (value == SUBSYS_AFTER_POWERUP) { + ret = msm_adsp_power_up_config(codec); + if (ret) { + ret = -EINVAL; + } else { + pr_debug("%s: ADSP is up\n", __func__); + ret = NOTIFY_OK; + } + } + +err_pcm_runtime: + return ret; +} + +static struct notifier_block adsp_state_notifier_block = { + .notifier_call = msm_adsp_state_callback, + .priority = -INT_MAX, +}; + +static int msm_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high) +{ + struct snd_soc_card *card = codec->component.card; + struct msm_asoc_mach_data *pdata; + int val; + + if (!card) + return 0; + + pdata = snd_soc_card_get_drvdata(card); + if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio)) + return 0; + + val = gpio_get_value_cansleep(pdata->hph_en0_gpio); + if ((!!val) == high) + return 0; + + gpio_direction_output(pdata->hph_en0_gpio, (int)high); + + return 1; +} + +static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret = 0; + void *config_data; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux; + struct snd_card *card; + struct snd_info_entry *entry; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + /* Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156}; + unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev)); + + rtd->pmdown_time = 0; + + ret = snd_soc_add_codec_controls(codec, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + if (ret < 0) { + pr_err("%s: add_codec_controls failed, err %d\n", + __func__, ret); + return ret; + } + + snd_soc_dapm_new_controls(dapm, msm_dapm_widgets, + ARRAY_SIZE(msm_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths, + ARRAY_SIZE(wcd9335_audio_paths)); + + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic5"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6"); + snd_soc_dapm_ignore_suspend(dapm, "MADINPUT"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT"); + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4"); + snd_soc_dapm_ignore_suspend(dapm, "ANC EAR"); + snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1"); + snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI"); + snd_soc_dapm_ignore_suspend(dapm, "VIINPUT"); + + snd_soc_dapm_sync(dapm); + + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + msm_codec_fn.get_afe_config_fn = tasha_get_afe_config; + msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit; + + ret = msm_adsp_power_up_config(codec); + if (ret) { + pr_err("%s: Failed to set AFE config %d\n", __func__, ret); + goto err_afe_cfg; + } + + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_AANC_VERSION); + if (config_data) { + ret = afe_set_config(AFE_AANC_VERSION, config_data, 0); + if (ret) { + pr_err("%s: Failed to set aanc version %d\n", + __func__, ret); + goto err_afe_cfg; + } + } + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_CDC_CLIP_REGISTERS_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG, + config_data, 0); + if (ret) { + pr_err("%s: Failed to set clip registers %d\n", + __func__, ret); + goto err_afe_cfg; + } + } + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_CLIP_BANK_SEL); + if (config_data) { + ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0); + if (ret) { + pr_err("%s: Failed to set AFE bank selection %d\n", + __func__, ret); + goto err_afe_cfg; + } + } + adsp_state_notifier = subsys_notif_register_notifier("adsp", + &adsp_state_notifier_block); + if (!adsp_state_notifier) { + pr_err("%s: Failed to register adsp state notifier\n", + __func__); + ret = -EFAULT; + goto err_adsp_notify; + } + /* + * Send speaker configuration only for WSA8810. + * Defalut configuration is for WSA8815. + */ + if (rtd_aux && rtd_aux->component) + if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) || + !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) { + tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1); + tasha_set_spkr_gain_offset(rtd->codec, + RX_GAIN_OFFSET_M1P5_DB); + } + codec_reg_done = true; + + card = rtd->card->snd_card; + entry = snd_register_module_info(card->module, "codecs", + card->proc_root); + if (!entry) { + pr_debug("%s: Cannot create codecs module entry\n", + __func__); + ret = 0; + goto err_snd_module; + } + pdata->codec_root = entry; + tasha_codec_info_create_codec_entry(pdata->codec_root, codec); + + return 0; + +err_snd_module: +err_adsp_notify: +err_afe_cfg: + return ret; +} + +static void *def_tasha_mbhc_cal(void) +{ + void *tasha_wcd_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_high; + + tasha_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS, + WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!tasha_wcd_cal) + return NULL; + +#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y)) + S(v_hs_max, 1500); +#undef S +#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y)) + S(num_btn, WCD_MBHC_DEF_BUTTONS); +#undef S + + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal); + btn_high = ((void *)&btn_cfg->_v_btn_low) + + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); + + btn_high[0] = 75; + btn_high[1] = 150; + btn_high[2] = 237; + btn_high[3] = 500; + btn_high[4] = 500; + btn_high[5] = 500; + btn_high[6] = 500; + btn_high[7] = 500; + + return tasha_wcd_cal; +} + +static int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + int ret = 0; + u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + u32 user_set_tx_ch = 0; + u32 rx_ch_count; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err_ch_map; + } + if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_5_RX) { + pr_debug("%s: rx_5_ch=%d\n", __func__, + slim_rx_cfg[5].channels); + rx_ch_count = slim_rx_cfg[5].channels; + } else { + pr_debug("%s: rx_0_ch=%d\n", __func__, + slim_rx_cfg[0].channels); + rx_ch_count = slim_rx_cfg[0].channels; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + rx_ch_count, rx_ch); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err_ch_map; + } + } else { + + pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__, + codec_dai->name, codec_dai->id, user_set_tx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map\n, err:%d\n", + __func__, ret); + goto err_ch_map; + } + /* For <codec>_tx1 case */ + if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_0_TX) + user_set_tx_ch = slim_tx_cfg[0].channels; + /* For <codec>_tx3 case */ + else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_1_TX) + user_set_tx_ch = slim_tx_cfg[1].channels; + else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX) + user_set_tx_ch = msm_vi_feed_tx_ch; + else + user_set_tx_ch = tx_ch_cnt; + + pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), be_id (%d)\n", + __func__, slim_tx_cfg[0].channels, user_set_tx_ch, + tx_ch_cnt, dai_link->be_id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + user_set_tx_ch, tx_ch, 0, 0); + if (ret < 0) + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + } + +err_ch_map: + return ret; +} + +static int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + int ret = 0; + u32 tx_ch[SLIM_MAX_TX_PORTS]; + u32 tx_ch_cnt = 0; + u32 user_set_tx_ch = 0; + + if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) { + pr_err("%s: Invalid stream type %d\n", + __func__, substream->stream); + ret = -EINVAL; + goto err_stream_type; + } + + pr_debug("%s: %s_tx_dai_id_%d\n", __func__, + codec_dai->name, codec_dai->id); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, NULL, NULL); + if (ret < 0) { + pr_err("%s: failed to get codec chan map\n, err:%d\n", + __func__, ret); + goto err_ch_map; + } + + user_set_tx_ch = tx_ch_cnt; + + pr_debug("%s: tx_ch_cnt(%d) be_id %d\n", + __func__, tx_ch_cnt, dai_link->be_id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + user_set_tx_ch, tx_ch, 0, 0); + if (ret < 0) + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); +err_ch_map: +err_stream_type: + return ret; +} + +static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0; + unsigned int num_tx_ch = 0; + unsigned int num_rx_ch = 0; + int ret = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + num_rx_ch = params_channels(params); + pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__, + codec_dai->name, codec_dai->id, num_rx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err_ch_map; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + num_rx_ch, rx_ch); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err_ch_map; + } + } else { + num_tx_ch = params_channels(params); + pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__, + codec_dai->name, codec_dai->id, num_tx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err_ch_map; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, + num_tx_ch, tx_ch, 0, 0); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err_ch_map; + } + } + +err_ch_map: + return ret; +} + +static struct snd_soc_ops msm_be_ops = { + .hw_params = msm_snd_hw_params, +}; + +static struct snd_soc_ops msm_cpe_ops = { + .hw_params = msm_snd_cpe_hw_params, +}; + +static struct snd_soc_ops msm_slimbus_2_be_ops = { + .hw_params = msm_slimbus_2_hw_params, +}; + +static int msm_get_ll_qos_val(struct snd_pcm_runtime *runtime) +{ + int usecs; + + /* take 10% of period time as the deadline */ + usecs = (100000 / runtime->rate) * runtime->period_size; + usecs += ((100000 % runtime->rate) * runtime->period_size) / + runtime->rate; + + return usecs; +} + +static int msm_mm5_prepare(struct snd_pcm_substream *substream) +{ + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); + pm_qos_add_request(&substream->latency_pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + msm_get_ll_qos_val(substream->runtime)); + return 0; +} + +static struct snd_soc_ops msm_mm5_ops = { + .prepare = msm_mm5_prepare, +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link msm_common_dai_links[] = { + /* FrontEnd DAI Links */ + { + .name = MSM_DAILINK_NAME(Media1), + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1 + }, + { + .name = MSM_DAILINK_NAME(Media2), + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2, + }, + { + .name = "VoiceMMode1", + .stream_name = "VoiceMMode1", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_VOICEMMODE1, + }, + { + .name = "MSM VoIP", + .stream_name = "VoIP", + .cpu_dai_name = "VoIP", + .platform_name = "msm-voip-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_VOIP, + }, + { + .name = MSM_DAILINK_NAME(ULL), + .stream_name = "MultiMedia3", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-dsp.2", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3, + }, + /* Hostless PCM purpose */ + { + .name = "SLIMBUS_0 Hostless", + .stream_name = "SLIMBUS_0 Hostless", + .cpu_dai_name = "SLIMBUS0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "MSM AFE-PCM RX", + .stream_name = "AFE-PROXY RX", + .cpu_dai_name = "msm-dai-q6-dev.241", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .platform_name = "msm-pcm-afe", + .dpcm_playback = 1, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + }, + { + .name = "MSM AFE-PCM TX", + .stream_name = "AFE-PROXY TX", + .cpu_dai_name = "msm-dai-q6-dev.240", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .platform_name = "msm-pcm-afe", + .dpcm_capture = 1, + .ignore_suspend = 1, + }, + { + .name = MSM_DAILINK_NAME(Compress1), + .stream_name = "Compress1", + .cpu_dai_name = "MultiMedia4", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4, + }, + { + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_1 Hostless", + .stream_name = "SLIMBUS_1 Hostless", + .cpu_dai_name = "SLIMBUS1_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_3 Hostless", + .stream_name = "SLIMBUS_3 Hostless", + .cpu_dai_name = "SLIMBUS3_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_4 Hostless", + .stream_name = "SLIMBUS_4 Hostless", + .cpu_dai_name = "SLIMBUS4_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = MSM_DAILINK_NAME(LowLatency), + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, + .ops = &msm_mm5_ops, + }, + { + .name = "Listen 1 Audio Service", + .stream_name = "Listen 1 Audio Service", + .cpu_dai_name = "LSM1", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM1, + }, + /* Multiple Tunnel instances */ + { + .name = MSM_DAILINK_NAME(Compress2), + .stream_name = "Compress2", + .cpu_dai_name = "MultiMedia7", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7, + }, + { + .name = MSM_DAILINK_NAME(Compress3), + .stream_name = "Compress3", + .cpu_dai_name = "MultiMedia10", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10, + }, + { + .name = MSM_DAILINK_NAME(Compr8), + .stream_name = "COMPR8", + .cpu_dai_name = "MultiMedia8", + .platform_name = "msm-compr-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8, + }, + /* HDMI Hostless */ + { + .name = "HDMI_RX_HOSTLESS", + .stream_name = "HDMI_RX_HOSTLESS", + .cpu_dai_name = "HDMI_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "VoiceMMode2", + .stream_name = "VoiceMMode2", + .cpu_dai_name = "VoiceMMode2", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_VOICEMMODE2, + }, + /* LSM FE */ + { + .name = "Listen 2 Audio Service", + .stream_name = "Listen 2 Audio Service", + .cpu_dai_name = "LSM2", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM2, + }, + { + .name = "Listen 3 Audio Service", + .stream_name = "Listen 3 Audio Service", + .cpu_dai_name = "LSM3", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM3, + }, + { + .name = "Listen 4 Audio Service", + .stream_name = "Listen 4 Audio Service", + .cpu_dai_name = "LSM4", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM4, + }, + { + .name = "Listen 5 Audio Service", + .stream_name = "Listen 5 Audio Service", + .cpu_dai_name = "LSM5", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM5, + }, + { + .name = "Listen 6 Audio Service", + .stream_name = "Listen 6 Audio Service", + .cpu_dai_name = "LSM6", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM6, + }, + { + .name = "Listen 7 Audio Service", + .stream_name = "Listen 7 Audio Service", + .cpu_dai_name = "LSM7", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM7, + }, + { + .name = "Listen 8 Audio Service", + .stream_name = "Listen 8 Audio Service", + .cpu_dai_name = "LSM8", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_LSM8, + }, + { + .name = MSM_DAILINK_NAME(Media9), + .stream_name = "MultiMedia9", + .cpu_dai_name = "MultiMedia9", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9, + }, + { + .name = MSM_DAILINK_NAME(Compress4), + .stream_name = "Compress4", + .cpu_dai_name = "MultiMedia11", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11, + }, + { + .name = MSM_DAILINK_NAME(Compress5), + .stream_name = "Compress5", + .cpu_dai_name = "MultiMedia12", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12, + }, + { + .name = MSM_DAILINK_NAME(Compress6), + .stream_name = "Compress6", + .cpu_dai_name = "MultiMedia13", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13, + }, + { + .name = MSM_DAILINK_NAME(Compress7), + .stream_name = "Compress7", + .cpu_dai_name = "MultiMedia14", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14, + }, + { + .name = MSM_DAILINK_NAME(Compress8), + .stream_name = "Compress8", + .cpu_dai_name = "MultiMedia15", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, + }, + { + .name = MSM_DAILINK_NAME(Compress9), + .stream_name = "Compress9", + .cpu_dai_name = "MultiMedia16", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16, + }, +}; + +static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_4_TX, + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", + .platform_name = "msm-pcm-hostless", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_vifeedback", + .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + }, + /* Ultrasound RX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Playback", + .stream_name = "SLIMBUS_2 Hostless Playback", + .cpu_dai_name = "msm-dai-q6-dev.16388", + .platform_name = "msm-pcm-hostless", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_rx2", + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_slimbus_2_be_ops, + }, + /* Ultrasound TX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Capture", + .stream_name = "SLIMBUS_2 Hostless Capture", + .cpu_dai_name = "msm-dai-q6-dev.16389", + .platform_name = "msm-pcm-hostless", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx2", + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_slimbus_2_be_ops, + }, + /* CPE LSM direct dai-link */ + { + .name = "CPE Listen service", + .stream_name = "CPE Listen Audio Service", + .cpu_dai_name = "msm-dai-slim", + .platform_name = "msm-cpe-lsm", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "tasha_mad1", + .codec_name = "tasha_codec", + .ops = &msm_cpe_ops, + }, +}; + +static struct snd_soc_dai_link msm_common_be_dai_links[] = { + /* Backend AFE DAI Links */ + { + .name = LPASS_BE_AFE_PCM_RX, + .stream_name = "AFE Playback", + .cpu_dai_name = "msm-dai-q6-dev.224", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_AFE_PCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AFE_PCM_TX, + .stream_name = "AFE Capture", + .cpu_dai_name = "msm-dai-q6-dev.225", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_AFE_PCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Record Uplink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_TX, + .stream_name = "Voice Uplink Capture", + .cpu_dai_name = "msm-dai-q6-dev.32772", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Record Downlink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_RX, + .stream_name = "Voice Downlink Capture", + .cpu_dai_name = "msm-dai-q6-dev.32771", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Music BACK END DAI Link */ + { + .name = LPASS_BE_VOICE_PLAYBACK_TX, + .stream_name = "Voice Farend Playback", + .cpu_dai_name = "msm-dai-q6-dev.32773", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Music 2 BACK END DAI Link */ + { + .name = LPASS_BE_VOICE2_PLAYBACK_TX, + .stream_name = "Voice2 Farend Playback", + .cpu_dai_name = "msm-dai-q6-dev.32770", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + } +}; + +static struct snd_soc_dai_link msm_tasha_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_0_RX, + .stream_name = "Slimbus Playback", + .cpu_dai_name = "msm-dai-q6-dev.16384", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX, + .init = &msm_audrx_init, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_0_TX, + .stream_name = "Slimbus Capture", + .cpu_dai_name = "msm-dai-q6-dev.16385", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_1_RX, + .stream_name = "Slimbus1 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16386", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_1_TX, + .stream_name = "Slimbus1 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16387", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx3", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_RX, + .stream_name = "Slimbus3 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16390", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_TX, + .stream_name = "Slimbus3 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16391", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_4_RX, + .stream_name = "Slimbus4 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16392", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_5_RX, + .stream_name = "Slimbus5 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16394", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_rx3", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + /* MAD BE */ + { + .name = LPASS_BE_SLIMBUS_5_TX, + .stream_name = "Slimbus5 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16395", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mad1", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .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)]; + +static int msm_snd_card_late_probe(struct snd_soc_card *card) +{ + const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX; + struct snd_soc_pcm_runtime *rtd; + int ret = 0; + void *mbhc_calibration; + + rtd = snd_soc_get_pcm_runtime(card, be_dl_name); + if (!rtd) { + dev_err(card->dev, + "%s: snd_soc_get_pcm_runtime for %s failed!\n", + __func__, be_dl_name); + ret = -EINVAL; + goto err_pcm_runtime; + } + + tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, rtd->codec); + + mbhc_calibration = def_tasha_mbhc_cal(); + if (!mbhc_calibration) { + ret = -ENOMEM; + goto err_mbhc_cal; + } + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = tasha_mbhc_hs_detect(rtd->codec, &wcd_mbhc_cfg); + if (ret) { + dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n", + __func__, ret); + goto err_hs_detect; + } + return 0; + +err_hs_detect: + kfree(mbhc_calibration); +err_mbhc_cal: +err_pcm_runtime: + return ret; +} + +struct snd_soc_card snd_soc_card_tasha_msm = { + .name = "msmcobalt-tasha-snd-card", + .late_probe = msm_snd_card_late_probe, +}; + +static int msm_populate_dai_link_component_of_node( + struct snd_soc_card *card) +{ + int i, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *np; + + if (!cdev) { + pr_err("%s: Sound card device memory NULL\n", __func__); + return -ENODEV; + } + + for (i = 0; i < card->num_links; i++) { + if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node) + continue; + + /* populate platform_of_node for snd card dai links */ + if (dai_link[i].platform_name && + !dai_link[i].platform_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-platform-names", + dai_link[i].platform_name); + if (index < 0) { + pr_err("%s: No match found for platform name: %s\n", + __func__, dai_link[i].platform_name); + ret = index; + goto err; + } + np = of_parse_phandle(cdev->of_node, "asoc-platform", + index); + if (!np) { + pr_err("%s: retrieving phandle for platform %s, index %d failed\n", + __func__, dai_link[i].platform_name, + index); + ret = -ENODEV; + goto err; + } + dai_link[i].platform_of_node = np; + dai_link[i].platform_name = NULL; + } + + /* populate cpu_of_node for snd card dai links */ + if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-cpu-names", + dai_link[i].cpu_dai_name); + if (index >= 0) { + np = of_parse_phandle(cdev->of_node, "asoc-cpu", + index); + if (!np) { + pr_err("%s: retrieving phandle for cpu dai %s failed\n", + __func__, + dai_link[i].cpu_dai_name); + ret = -ENODEV; + goto err; + } + dai_link[i].cpu_of_node = np; + dai_link[i].cpu_dai_name = NULL; + } + } + + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].codec_name && !dai_link[i].codec_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codec_name); + if (index < 0) + continue; + np = of_parse_phandle(cdev->of_node, "asoc-codec", + index); + if (!np) { + pr_err("%s: retrieving phandle for codec %s failed\n", + __func__, dai_link[i].codec_name); + ret = -ENODEV; + goto err; + } + dai_link[i].codec_of_node = np; + dai_link[i].codec_name = NULL; + } + } + +err: + return ret; +} + +static int msm_prepare_us_euro(struct snd_soc_card *card) +{ + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0; + + if (pdata->us_euro_gpio >= 0) { + dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__, + pdata->us_euro_gpio); + ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO"); + if (ret) { + dev_err(card->dev, + "%s: Failed to request codec US/EURO gpio %d error %d\n", + __func__, pdata->us_euro_gpio, ret); + } + } + + return ret; +} + +static int msm_prepare_hifi(struct snd_soc_card *card) +{ + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0; + + if (gpio_is_valid(pdata->hph_en1_gpio)) { + dev_dbg(card->dev, "%s: hph_en1_gpio request %d\n", __func__, + pdata->hph_en1_gpio); + ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio"); + if (ret) { + dev_err(card->dev, + "%s: hph_en1_gpio request failed, ret:%d\n", + __func__, ret); + goto err; + } + } + if (gpio_is_valid(pdata->hph_en0_gpio)) { + dev_dbg(card->dev, "%s: hph_en0_gpio request %d\n", __func__, + pdata->hph_en0_gpio); + ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio"); + if (ret) + dev_err(card->dev, + "%s: hph_en0_gpio request failed, ret:%d\n", + __func__, ret); + } + +err: + return ret; +} + +static const struct of_device_id msmcobalt_asoc_machine_of_match[] = { + { .compatible = "qcom,msmcobalt-asoc-snd-tasha", + .data = "tasha_codec"}, + {}, +}; + +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; + const struct of_device_id *match; + + match = of_match_node(msmcobalt_asoc_machine_of_match, dev->of_node); + if (!match) { + dev_err(dev, "%s: No DT match found for sound card\n", + __func__); + return NULL; + } + + 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); + + memcpy(msm_tasha_dai_links, + msm_common_dai_links, + sizeof(msm_common_dai_links)); + memcpy(msm_tasha_dai_links + len_1, + msm_tasha_fe_dai_links, + sizeof(msm_tasha_fe_dai_links)); + memcpy(msm_tasha_dai_links + len_2, + msm_common_be_dai_links, + sizeof(msm_common_be_dai_links)); + memcpy(msm_tasha_dai_links + len_3, + msm_tasha_be_dai_links, + sizeof(msm_tasha_be_dai_links)); + + dailink = msm_tasha_dai_links; + len_4 = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links); + } + dev_dbg(dev, "%s(): No hdmi audio support\n", __func__); + + if (card) { + card->dai_link = dailink; + card->num_links = len_4; + } + + return card; +} + +static int msm_wsa881x_init(struct snd_soc_component *component) +{ + u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106}; + u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107}; + unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200}; + unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3}; + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + struct msm_asoc_mach_data *pdata; + struct snd_soc_dapm_context *dapm; + int ret = 0; + + if (!codec) { + pr_err("%s codec is NULL\n", __func__); + return -EINVAL; + } + + dapm = snd_soc_codec_get_dapm(codec); + + if (!strcmp(component->name_prefix, "SpkrLeft")) { + dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n", + __func__, codec->component.name); + wsa881x_set_channel_map(codec, &spkleft_ports[0], + WSA881X_MAX_SWR_PORTS, &ch_mask[0], + &ch_rate[0]); + if (dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN"); + snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR"); + } + } else if (!strcmp(component->name_prefix, "SpkrRight")) { + dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n", + __func__, codec->component.name); + wsa881x_set_channel_map(codec, &spkright_ports[0], + WSA881X_MAX_SWR_PORTS, &ch_mask[0], + &ch_rate[0]); + if (dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN"); + snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR"); + } + } else { + dev_err(codec->dev, "%s: wrong codec name %s\n", __func__, + codec->component.name); + ret = -EINVAL; + goto err_codec; + } + pdata = snd_soc_card_get_drvdata(component->card); + if (pdata && pdata->codec_root) + wsa881x_codec_info_create_codec_entry(pdata->codec_root, + codec); + +err_codec: + return ret; +} + +static int msm_init_wsa_dev(struct platform_device *pdev, + struct snd_soc_card *card) +{ + struct device_node *wsa_of_node; + u32 wsa_max_devs; + u32 wsa_dev_cnt; + int i; + struct msm_wsa881x_dev_info *wsa881x_dev_info; + const char *wsa_auxdev_name_prefix[1]; + char *dev_name_str = NULL; + int found = 0; + int ret = 0; + + /* Get maximum WSA device count for this platform */ + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa-max-devs", &wsa_max_devs); + if (ret) { + dev_dbg(&pdev->dev, + "%s: wsa-max-devs property missing in DT %s, ret = %d\n", + __func__, pdev->dev.of_node->full_name, ret); + goto err_dt; + } + if (wsa_max_devs == 0) { + dev_warn(&pdev->dev, + "%s: Max WSA devices is 0 for this target?\n", + __func__); + goto err_dt; + } + + /* Get count of WSA device phandles for this platform */ + wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node, + "qcom,wsa-devs", NULL); + if (wsa_dev_cnt == -ENOENT) { + dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n", + __func__); + goto err_dt; + } else if (wsa_dev_cnt <= 0) { + dev_err(&pdev->dev, + "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n", + __func__, wsa_dev_cnt); + ret = -EINVAL; + goto err_dt; + } + + /* + * Expect total phandles count to be NOT less than maximum possible + * WSA count. However, if it is less, then assign same value to + * max count as well. + */ + if (wsa_dev_cnt < wsa_max_devs) { + dev_dbg(&pdev->dev, + "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n", + __func__, wsa_max_devs, wsa_dev_cnt); + wsa_max_devs = wsa_dev_cnt; + } + + /* Make sure prefix string passed for each WSA device */ + ret = of_property_count_strings(pdev->dev.of_node, + "qcom,wsa-aux-dev-prefix"); + if (ret != wsa_dev_cnt) { + dev_err(&pdev->dev, + "%s: expecting %d wsa prefix. Defined only %d in DT\n", + __func__, wsa_dev_cnt, ret); + ret = -EINVAL; + goto err_dt; + } + + /* + * Alloc mem to store phandle and index info of WSA device, if already + * registered with ALSA core + */ + wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs, + sizeof(struct msm_wsa881x_dev_info), + GFP_KERNEL); + if (!wsa881x_dev_info) { + ret = -ENOMEM; + goto err_mem; + } + + /* + * search and check whether all WSA devices are already + * registered with ALSA core or not. If found a node, store + * the node and the index in a local array of struct for later + * use. + */ + for (i = 0; i < wsa_dev_cnt; i++) { + wsa_of_node = of_parse_phandle(pdev->dev.of_node, + "qcom,wsa-devs", i); + if (unlikely(!wsa_of_node)) { + /* we should not be here */ + dev_err(&pdev->dev, + "%s: wsa dev node is not present\n", + __func__); + ret = -EINVAL; + goto err_dev_node; + } + if (soc_find_component(wsa_of_node, NULL)) { + /* WSA device registered with ALSA core */ + wsa881x_dev_info[found].of_node = wsa_of_node; + wsa881x_dev_info[found].index = i; + found++; + if (found == wsa_max_devs) + break; + } + } + + if (found < wsa_max_devs) { + dev_dbg(&pdev->dev, + "%s: failed to find %d components. Found only %d\n", + __func__, wsa_max_devs, found); + return -EPROBE_DEFER; + } + dev_info(&pdev->dev, + "%s: found %d wsa881x devices registered with ALSA core\n", + __func__, found); + + card->num_aux_devs = wsa_max_devs; + card->num_configs = wsa_max_devs; + + /* Alloc array of AUX devs struct */ + msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs, + sizeof(struct snd_soc_aux_dev), + GFP_KERNEL); + if (!msm_aux_dev) { + ret = -ENOMEM; + goto err_auxdev_mem; + } + + /* Alloc array of codec conf struct */ + msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs, + sizeof(struct snd_soc_codec_conf), + GFP_KERNEL); + if (!msm_codec_conf) { + ret = -ENOMEM; + goto err_codec_conf; + } + + for (i = 0; i < card->num_aux_devs; i++) { + dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN, + GFP_KERNEL); + if (!dev_name_str) { + ret = -ENOMEM; + goto err_dev_str; + } + + ret = of_property_read_string_index(pdev->dev.of_node, + "qcom,wsa-aux-dev-prefix", + wsa881x_dev_info[i].index, + wsa_auxdev_name_prefix); + if (ret) { + dev_err(&pdev->dev, + "%s: failed to read wsa aux dev prefix, ret = %d\n", + __func__, ret); + ret = -EINVAL; + goto err_dt_prop; + } + + snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i); + msm_aux_dev[i].name = dev_name_str; + msm_aux_dev[i].codec_name = NULL; + msm_aux_dev[i].codec_of_node = + wsa881x_dev_info[i].of_node; + msm_aux_dev[i].init = msm_wsa881x_init; + msm_codec_conf[i].dev_name = NULL; + msm_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0]; + msm_codec_conf[i].of_node = + wsa881x_dev_info[i].of_node; + } + card->codec_conf = msm_codec_conf; + card->aux_dev = msm_aux_dev; + + return 0; + +err_dt_prop: + devm_kfree(&pdev->dev, dev_name_str); +err_dev_str: + devm_kfree(&pdev->dev, msm_codec_conf); +err_codec_conf: + devm_kfree(&pdev->dev, msm_aux_dev); +err_auxdev_mem: +err_dev_node: + devm_kfree(&pdev->dev, wsa881x_dev_info); +err_mem: +err_dt: + return ret; +} + +static int msm_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct msm_asoc_mach_data *pdata; + const char *mbhc_audio_jack_type = NULL; + char *mclk_freq_prop_name; + const struct of_device_id *match; + int ret; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "No platform supplied from device tree\n"); + return -EINVAL; + } + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm_asoc_mach_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + card = populate_snd_card_dailinks(&pdev->dev); + if (!card) { + dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__); + ret = -EINVAL; + goto err; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, pdata); + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(&pdev->dev, "parse card name failed, err:%d\n", + ret); + goto err; + } + + ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing"); + if (ret) { + dev_err(&pdev->dev, "parse audio routing failed, err:%d\n", + ret); + goto err; + } + + match = of_match_node(msmcobalt_asoc_machine_of_match, + pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "%s: no matched codec is found.\n", + __func__); + goto err; + } + + mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq"; + + ret = of_property_read_u32(pdev->dev.of_node, + mclk_freq_prop_name, &pdata->mclk_freq); + if (ret) { + dev_err(&pdev->dev, + "Looking up %s property in node %s failed, err%d\n", + mclk_freq_prop_name, + pdev->dev.of_node->full_name, ret); + goto err; + } + + if (pdata->mclk_freq != CODEC_EXT_CLK_RATE) { + dev_err(&pdev->dev, "unsupported mclk freq %u\n", + pdata->mclk_freq); + ret = -EINVAL; + goto err; + } + + spdev = pdev; + + ret = msm_populate_dai_link_component_of_node(card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + ret = msm_init_wsa_dev(pdev, card); + if (ret) + goto err; + + pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,hph-en1-gpio", 0); + if (pdata->hph_en1_gpio < 0) { + dev_dbg(&pdev->dev, "%s: %s property not found %d\n", + __func__, "qcom,hph-en1-gpio", pdata->hph_en1_gpio); + } + + pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,hph-en0-gpio", 0); + if (pdata->hph_en0_gpio < 0) { + dev_dbg(&pdev->dev, "%s: %s property not found %d\n", + __func__, "qcom,hph-en0-gpio", pdata->hph_en0_gpio); + } + ret = msm_prepare_hifi(card); + if (ret) + dev_dbg(&pdev->dev, "msm_prepare_hifi failed (%d)\n", + ret); + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret == -EPROBE_DEFER) { + if (codec_reg_done) + ret = -EINVAL; + goto err; + } else if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err; + } + dev_info(&pdev->dev, "Sound card %s registered\n", card->name); + + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "Looking up %s property in node %s failed", + "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + dev_dbg(&pdev->dev, "Jack type properties set to default"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + else + dev_dbg(&pdev->dev, "Unknown value, set to default"); + } + /* + * Parse US-Euro gpio info from DT. Report no error if us-euro + * entry is not found in DT file as some targets do not support + * US-Euro detection + */ + pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,us-euro-gpios", 0); + if (pdata->us_euro_gpio < 0) { + dev_info(&pdev->dev, "property %s not detected in node %s", + "qcom,us-euro-gpios", + pdev->dev.of_node->full_name); + } else { + dev_dbg(&pdev->dev, "%s detected %d", + "qcom,us-euro-gpios", pdata->us_euro_gpio); + wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; + } + + ret = msm_prepare_us_euro(card); + if (ret) + dev_info(&pdev->dev, "msm_prepare_us_euro failed (%d)\n", + ret); + return 0; +err: + if (pdata->us_euro_gpio > 0) { + dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n", + __func__, pdata->us_euro_gpio); + gpio_free(pdata->us_euro_gpio); + pdata->us_euro_gpio = 0; + } + if (pdata->hph_en1_gpio > 0) { + dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n", + __func__, pdata->hph_en1_gpio); + gpio_free(pdata->hph_en1_gpio); + pdata->hph_en1_gpio = 0; + } + if (pdata->hph_en0_gpio > 0) { + dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n", + __func__, pdata->hph_en0_gpio); + gpio_free(pdata->hph_en0_gpio); + pdata->hph_en0_gpio = 0; + } + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int msm_asoc_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + gpio_free(pdata->us_euro_gpio); + gpio_free(pdata->hph_en1_gpio); + gpio_free(pdata->hph_en0_gpio); + + snd_soc_unregister_card(card); + return 0; +} + +static struct platform_driver msmcobalt_asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = msmcobalt_asoc_machine_of_match, + }, + .probe = msm_asoc_machine_probe, + .remove = msm_asoc_machine_remove, +}; +module_platform_driver(msmcobalt_asoc_machine_driver); + +MODULE_DESCRIPTION("ALSA SoC msm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, msmcobalt_asoc_machine_of_match); |
