OSDN Git Service

Merge "mm-camera2:isp2: Avoid use after free buffer"
authorLinux Build Service Account <lnxbuild@localhost>
Tue, 27 Mar 2018 01:57:01 +0000 (18:57 -0700)
committerGerrit - the friendly Code Review server <code-review@localhost>
Tue, 27 Mar 2018 01:57:01 +0000 (18:57 -0700)
28 files changed:
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi.dts
arch/arm64/configs/msm-auto-perf_defconfig
arch/arm64/configs/msm-auto_defconfig
drivers/gpu/drm/msm/sde/sde_kms.c
drivers/media/i2c/adv7481.c
drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c
drivers/net/can/spi/qti-can.c
drivers/net/wireless/cnss2/Kconfig
drivers/net/wireless/cnss2/main.h
drivers/net/wireless/cnss2/pci.c
drivers/net/wireless/cnss2/pci.h
drivers/net/wireless/cnss2/power.c
drivers/soc/qcom/glink_smem_native_xprt.c
drivers/usb/misc/ehset.c
drivers/video/fbdev/msm/mdss_hdmi_tx.c
drivers/video/fbdev/msm/mdss_hdmi_tx.h
include/net/cnss2.h
include/sound/apr_audio-v2.h
include/sound/q6adm-v2.h
include/sound/q6asm-v2.h
kernel/softirq.c
sound/soc/msm/msm-dai-fe.c
sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
sound/soc/msm/qdsp6v2/q6adm.c
sound/soc/msm/qdsp6v2/q6asm.c
sound/soc/msm/qdsp6v2/q6core.c

index e2b4ae1..7314af2 100644 (file)
                qcom,smmu-enabled;
        };
 
+       qcom,hab {
+               compatible = "qcom,hab";
+               vmid = <2>;
+
+               mmidgrp100: mmidgrp100 {
+                       grp-start-id = <100>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp200: mmidgrp200 {
+                       grp-start-id = <200>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp300: mmidgrp300 {
+                       grp-start-id = <300>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp400: mmidgrp400 {
+                       grp-start-id = <400>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp500: mmidgrp500 {
+                       grp-start-id = <500>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp600: mmidgrp600 {
+                       grp-start-id = <600>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp700: mmidgrp700 {
+                       grp-start-id = <700>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp800: mmidgrp800 {
+                       grp-start-id = <800>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp900: mmidgrp900 {
+                       grp-start-id = <900>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+
+               mmidgrp1000: mmidgrp1000 {
+                       grp-start-id = <1000>;
+                       role = "fe";
+                       remote-vmids = <0>;
+               };
+       };
+
        qcom,cnss {
                compatible = "qcom,cnss";
                wlan-bootstrap-gpio = <&tlmm 46 0>;
index 69d857b..0c5e1a8 100644 (file)
@@ -419,6 +419,7 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_DWC3=y
 CONFIG_USB_ISP1760=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QTI_KS_BRIDGE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_MSM_SSPHY_QMP=y
index 8be1b84..ca4f8da 100644 (file)
@@ -423,6 +423,7 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_DWC3=y
 CONFIG_USB_ISP1760=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QTI_KS_BRIDGE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_MSM_SSPHY_QMP=y
index 93b8a69..59bc1a4 100644 (file)
@@ -345,8 +345,9 @@ static void sde_kms_prepare_commit(struct msm_kms *kms,
 
        if (sde_kms->splash_info.handoff)
                sde_splash_clean_up_exit_lk(kms);
-
-       sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+       else
+               sde_power_resource_enable(&priv->phandle,
+                               sde_kms->core_client, true);
 }
 
 static void sde_kms_commit(struct msm_kms *kms,
index ce321e9..9c8159c 100644 (file)
@@ -60,6 +60,7 @@
 
 #define ONE_MHZ_TO_HZ          1000000
 #define I2C_BLOCK_WRITE_SIZE    1024
+#define ADV_REG_STABLE_DELAY    70      /* ms*/
 
 enum adv7481_gpio_t {
 
@@ -476,7 +477,7 @@ static irqreturn_t adv7481_irq(int irq, void *dev)
        struct adv7481_state *state = dev;
 
        schedule_delayed_work(&state->irq_delayed_work,
-                                               msecs_to_jiffies(0));
+                               msecs_to_jiffies(ADV_REG_STABLE_DELAY));
        return IRQ_HANDLED;
 }
 
index fa7a933..885f09c 100644 (file)
@@ -163,59 +163,6 @@ int msm_ais_enable_clocks(void)
                return rc;
        }
 
-       if (new_early_cam_dev->pdev->dev.of_node)
-               of_property_read_u32((&new_early_cam_dev->pdev->dev)->of_node,
-                       "cell-index", &new_early_cam_dev->pdev->id);
-
-       rc = msm_camera_get_clk_info_and_rates(new_early_cam_dev->pdev,
-               &new_early_cam_dev->early_cam_clk_info,
-               &new_early_cam_dev->early_cam_clk,
-               &new_early_cam_dev->early_cam_clk_rates,
-               &new_early_cam_dev->num_clk_cases,
-               &new_early_cam_dev->num_clk);
-       if (rc < 0) {
-               pr_err("%s: msm_early_cam_get_clk_info() failed", __func__);
-               return -EFAULT;
-       }
-
-       rc = msm_camera_get_dt_vreg_data(
-               new_early_cam_dev->pdev->dev.of_node,
-               &(new_early_cam_dev->early_cam_vreg),
-               &(new_early_cam_dev->regulator_count));
-       if (rc < 0) {
-               pr_err("%s: msm_camera_get_dt_vreg_data fail\n", __func__);
-               rc = -EFAULT;
-               return rc;
-       }
-
-       if ((new_early_cam_dev->regulator_count < 0) ||
-               (new_early_cam_dev->regulator_count > MAX_REGULATOR)) {
-               pr_err("%s: invalid reg count = %d, max is %d\n", __func__,
-                       new_early_cam_dev->regulator_count, MAX_REGULATOR);
-               rc = -EFAULT;
-               return rc;
-       }
-
-       rc = msm_camera_config_vreg(&new_early_cam_dev->pdev->dev,
-               new_early_cam_dev->early_cam_vreg,
-               new_early_cam_dev->regulator_count,
-               NULL,
-               0,
-               &new_early_cam_dev->early_cam_reg_ptr[0], 1);
-       if (rc < 0)
-               pr_err("%s:%d early_cam config_vreg failed\n", __func__,
-                       __LINE__);
-
-       rc = msm_camera_enable_vreg(&new_early_cam_dev->pdev->dev,
-               new_early_cam_dev->early_cam_vreg,
-               new_early_cam_dev->regulator_count,
-               NULL,
-               0,
-               &new_early_cam_dev->early_cam_reg_ptr[0], 1);
-       if (rc < 0)
-               pr_err("%s:%d early_cam enable_vreg failed\n", __func__,
-               __LINE__);
-
        rc = msm_camera_clk_enable(&new_early_cam_dev->pdev->dev,
                new_early_cam_dev->early_cam_clk_info,
                new_early_cam_dev->early_cam_clk,
@@ -357,12 +304,10 @@ static int msm_early_cam_probe(struct platform_device *pdev)
                of_property_read_u32((&pdev->dev)->of_node,
                        "cell-index", &pdev->id);
 
-       rc = msm_camera_get_clk_info_and_rates(pdev,
-               &new_early_cam_dev->early_cam_clk_info,
-               &new_early_cam_dev->early_cam_clk,
-               &new_early_cam_dev->early_cam_clk_rates,
-               &new_early_cam_dev->num_clk_cases,
-               &new_early_cam_dev->num_clk);
+       rc = msm_camera_get_clk_info(pdev,
+                               &new_early_cam_dev->early_cam_clk_info,
+                               &new_early_cam_dev->early_cam_clk,
+                               &new_early_cam_dev->num_clk);
        if (rc < 0) {
                pr_err("%s: msm_early_cam_get_clk_info() failed", __func__);
                kfree(new_early_cam_dev);
index a6fc665..7db6ecf 100644 (file)
@@ -44,7 +44,7 @@
 #define DRIVER_MODE_RAW_FRAMES         0
 #define DRIVER_MODE_PROPERTIES         1
 #define DRIVER_MODE_AMB                        2
-#define QUERY_FIRMWARE_TIMEOUT_MS      20
+#define QUERY_FIRMWARE_TIMEOUT_MS      100
 
 struct qti_can {
        struct net_device       **netdev;
index 8bc9cc6..17c6860 100644 (file)
@@ -1,10 +1,12 @@
 config CNSS2
        tristate "CNSS2 Platform Driver for Wi-Fi Module"
-       depends on !CNSS && PCI_MSM
+       depends on !CNSS && (PCI_MSM || PCI_HOST_GENERIC)
        select CNSS_UTILS
        ---help---
          This module adds the support for Connectivity Subsystem (CNSS) used
          for PCIe based Wi-Fi devices with QCA6174/QCA6290 chipsets.
+         This module in metal case depends on PCI_MSM, while in GVM case
+         depends on PCI_HOST_GENERIC.
          This driver also adds support to integrate WLAN module to subsystem
          restart framework.
 
index 81b5de8..f658b6d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -213,8 +213,21 @@ int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
                           u32 flags, void *data);
 int cnss_get_vreg(struct cnss_plat_data *plat_priv);
 int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
+
+#ifndef CONFIG_MSM_GVM_QUIN
 int cnss_power_on_device(struct cnss_plat_data *plat_priv);
 void cnss_power_off_device(struct cnss_plat_data *plat_priv);
+#else /* CONFIG_MSM_GVM_QUIN */
+static inline int cnss_power_on_device(struct cnss_plat_data *plat_priv)
+{
+       return 0;
+}
+
+static inline void cnss_power_off_device(struct cnss_plat_data *plat_priv)
+{
+}
+#endif /* CONFIG_MSM_GVM_QUIN */
+
 int cnss_register_subsys(struct cnss_plat_data *plat_priv);
 void cnss_unregister_subsys(struct cnss_plat_data *plat_priv);
 int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
index 227919a..39deddd 100644 (file)
@@ -44,7 +44,9 @@
 #define MAX_M3_FILE_NAME_LENGTH                13
 #define DEFAULT_M3_FILE_NAME           "m3.bin"
 
+#ifdef CONFIG_PCI_MSM
 static DEFINE_SPINLOCK(pci_link_down_lock);
+#endif
 
 static unsigned int pci_link_down_panic;
 module_param(pci_link_down_panic, uint, 0600);
@@ -91,6 +93,7 @@ static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save)
        return 0;
 }
 
+#ifdef CONFIG_PCI_MSM
 static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
 {
        int ret = 0;
@@ -217,6 +220,13 @@ int cnss_pci_link_down(struct device *dev)
 }
 EXPORT_SYMBOL(cnss_pci_link_down);
 
+#else /* CONFIG_PCI_MSM */
+static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_MSM */
+
 static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
 {
        int ret = 0;
@@ -277,6 +287,7 @@ static void cnss_pci_deinit_smmu(struct cnss_pci_data *pci_priv)
        pci_priv->smmu_mapping = NULL;
 }
 
+#ifdef CONFIG_PCI_MSM
 static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
 {
        unsigned long flags;
@@ -595,6 +606,17 @@ int cnss_wlan_pm_control(struct device *dev, bool vote)
 }
 EXPORT_SYMBOL(cnss_wlan_pm_control);
 
+#else /* CONFIG_PCI_MSM */
+static int cnss_reg_pci_event(struct cnss_pci_data *pci_priv)
+{
+       return 0;
+}
+
+static void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv)
+{
+}
+#endif /* CONFIG_PCI_MSM */
+
 int cnss_auto_suspend(struct device *dev)
 {
        int ret = 0;
@@ -952,6 +974,31 @@ void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
 }
 EXPORT_SYMBOL(cnss_get_msi_address);
 
+#ifdef CONFIG_PCI_MSM
+static inline int cnss_pci_set_dma_mask(struct pci_dev *pci_dev)
+{
+       int ret;
+
+       ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
+       if (ret) {
+               cnss_pr_err("PCI DMA mask: %d, err: %d\n", PCI_DMA_MASK, ret);
+               return ret;
+       }
+
+       ret = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
+       if (ret)
+               cnss_pr_err("PCI consistent DMA mask: %d, err: %d\n",
+                           PCI_DMA_MASK, ret);
+
+       return ret;
+}
+#else /* CONFIG_PCI_MSM */
+static inline int cnss_pci_set_dma_mask(struct pci_dev *pci_dev)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_MSM */
+
 static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
 {
        int ret = 0;
@@ -984,19 +1031,9 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
                goto disable_device;
        }
 
-       ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
-       if (ret) {
-               cnss_pr_err("Failed to set PCI DMA mask (%d), err = %d\n",
-                           ret, PCI_DMA_MASK);
-               goto release_region;
-       }
-
-       ret = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
-       if (ret) {
-               cnss_pr_err("Failed to set PCI consistent DMA mask (%d), err = %d\n",
-                           ret, PCI_DMA_MASK);
+       ret = cnss_pci_set_dma_mask(pci_dev);
+       if (ret)
                goto release_region;
-       }
 
        pci_set_master(pci_dev);
 
@@ -1565,6 +1602,7 @@ static const struct pci_device_id cnss_pci_id_table[] = {
 };
 MODULE_DEVICE_TABLE(pci, cnss_pci_id_table);
 
+#ifdef CONFIG_PCI_MSM
 static const struct dev_pm_ops cnss_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend, cnss_pci_resume)
        SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend_noirq,
@@ -1572,20 +1610,24 @@ static const struct dev_pm_ops cnss_pm_ops = {
        SET_RUNTIME_PM_OPS(cnss_pci_runtime_suspend, cnss_pci_runtime_resume,
                           cnss_pci_runtime_idle)
 };
+#endif
 
 struct pci_driver cnss_pci_driver = {
        .name     = "cnss_pci",
        .id_table = cnss_pci_id_table,
        .probe    = cnss_pci_probe,
        .remove   = cnss_pci_remove,
+#ifdef CONFIG_PCI_MSM
        .driver = {
                .pm = &cnss_pm_ops,
        },
+#endif
 };
 
-int cnss_pci_init(struct cnss_plat_data *plat_priv)
+#ifdef CONFIG_PCI_MSM
+static inline int cnss_msm_pcie_enumerate(struct cnss_plat_data *plat_priv)
 {
-       int ret = 0;
+       int ret;
        struct device *dev = &plat_priv->plat_dev->dev;
        u32 rc_num;
 
@@ -1602,6 +1644,25 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv)
                goto out;
        }
 
+       return 0;
+out:
+       return ret;
+}
+#else /* CONFIG_PCI_MSM */
+static inline int cnss_msm_pcie_enumerate(struct cnss_plat_data *plat_priv)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_MSM */
+
+int cnss_pci_init(struct cnss_plat_data *plat_priv)
+{
+       int ret;
+
+       ret = cnss_msm_pcie_enumerate(plat_priv);
+       if (ret)
+               goto out;
+
        ret = pci_register_driver(&cnss_pci_driver);
        if (ret) {
                cnss_pr_err("Failed to register to PCI framework, err = %d\n",
index 89edc60..a00ca61 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -124,8 +124,21 @@ static inline int cnss_pci_get_auto_suspended(void *bus_priv)
        return atomic_read(&pci_priv->auto_suspended);
 }
 
+#ifdef CONFIG_PCI_MSM
 int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv);
 int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
+#else /* CONFIG_PCI_MSM */
+static inline int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv)
+{
+       return 0;
+}
+
+static inline int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_MSM */
+
 int cnss_pci_init(struct cnss_plat_data *plat_priv);
 void cnss_pci_deinit(struct cnss_plat_data *plat_priv);
 int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);
index 8ed1507..8a58a53 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -110,6 +110,7 @@ out:
        return ret;
 }
 
+#ifndef CONFIG_MSM_GVM_QUIN
 static int cnss_vreg_on(struct cnss_plat_data *plat_priv)
 {
        int ret = 0;
@@ -229,6 +230,7 @@ static int cnss_vreg_off(struct cnss_plat_data *plat_priv)
 
        return ret;
 }
+#endif /* CONFIG_MSM_GVM_QUIN */
 
 int cnss_get_pinctrl(struct cnss_plat_data *plat_priv)
 {
@@ -285,6 +287,7 @@ out:
        return ret;
 }
 
+#ifndef CONFIG_MSM_GVM_QUIN
 static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
                                     bool state)
 {
@@ -368,6 +371,7 @@ void cnss_power_off_device(struct cnss_plat_data *plat_priv)
        cnss_select_pinctrl_state(plat_priv, false);
        cnss_vreg_off(plat_priv);
 }
+#endif /* CONFIG_MSM_GVM_QUIN */
 
 void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv)
 {
index 4407dfb..df94bbc 100644 (file)
@@ -539,6 +539,12 @@ static int fifo_write(struct edge_info *einfo, const void *data, int len)
        uint32_t write_index = einfo->tx_ch_desc->write_index;
 
        len = fifo_write_body(einfo, data, len, &write_index);
+
+       /* All data writes need to be flushed to memory before the write index
+        * is updated. This protects against a race condition where the remote
+        * reads stale data because the write index was written before the data.
+        */
+       wmb();
        einfo->tx_ch_desc->write_index = write_index;
        send_irq(einfo);
 
@@ -574,6 +580,12 @@ static int fifo_write_complex(struct edge_info *einfo,
        len1 = fifo_write_body(einfo, data1, len1, &write_index);
        len2 = fifo_write_body(einfo, data2, len2, &write_index);
        len3 = fifo_write_body(einfo, data3, len3, &write_index);
+
+       /* All data writes need to be flushed to memory before the write index
+        * is updated. This protects against a race condition where the remote
+        * reads stale data because the write index was written before the data.
+        */
+       wmb();
        einfo->tx_ch_desc->write_index = write_index;
        send_irq(einfo);
 
index c31b4a3..0efcd48 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, 2018, 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
 #define TEST_SINGLE_STEP_GET_DEV_DESC          0x0107
 #define TEST_SINGLE_STEP_SET_FEATURE           0x0108
 
-static int ehset_probe(struct usb_interface *intf,
-                      const struct usb_device_id *id)
+static u8 numPorts;
+
+static int ehset_get_port_num(struct device *dev, const char *buf,
+                                                       unsigned long *val)
+{
+       int ret;
+
+       ret = kstrtoul(buf, 10, val);
+       if (ret < 0) {
+               dev_err(dev, "couldn't parse string %d\n", ret);
+               return ret;
+       }
+
+       if (!*val || *val > numPorts) {
+               dev_err(dev, "Invalid port num entered\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ehset_clear_port_feature(struct usb_device *udev, int feature,
+                               int port1)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+               USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
+               NULL, 0, 1000);
+}
+
+static int ehset_set_port_feature(struct usb_device *udev, int feature,
+                       int port1, int timeout)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+               USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
+               NULL, 0, timeout);
+}
+
+static int ehset_set_testmode(struct device *dev, struct usb_device *child_udev,
+                       struct usb_device *hub_udev, int test_id, int port)
 {
-       int ret = -EINVAL;
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_device *hub_udev = dev->parent;
        struct usb_device_descriptor *buf;
-       u8 portnum = dev->portnum;
-       u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
+       int ret = -EINVAL;
 
-       switch (test_pid) {
+       switch (test_id) {
        case TEST_SE0_NAK_PID:
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_TEST,
-                                       (TEST_SE0_NAK << 8) | portnum,
-                                       NULL, 0, 1000);
+               ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST,
+                                       (TEST_SE0_NAK << 8) | port, 1000);
                break;
        case TEST_J_PID:
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_TEST,
-                                       (TEST_J << 8) | portnum,
-                                       NULL, 0, 1000);
+               ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST,
+                                       (TEST_J << 8) | port, 1000);
                break;
        case TEST_K_PID:
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_TEST,
-                                       (TEST_K << 8) | portnum,
-                                       NULL, 0, 1000);
+               ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST,
+                                       (TEST_K << 8) | port, 1000);
                break;
        case TEST_PACKET_PID:
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_TEST,
-                                       (TEST_PACKET << 8) | portnum,
-                                       NULL, 0, 1000);
+               ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST,
+                                       (TEST_PACKET << 8) | port, 1000);
                break;
        case TEST_HS_HOST_PORT_SUSPEND_RESUME:
                /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
                msleep(15 * 1000);
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_SUSPEND, portnum,
-                                       NULL, 0, 1000);
-               if (ret < 0)
+               ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_SUSPEND,
+                                                       port, 1000);
+               if (ret)
                        break;
 
                msleep(15 * 1000);
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_CLEAR_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_SUSPEND, portnum,
-                                       NULL, 0, 1000);
+               ret = ehset_clear_port_feature(hub_udev, USB_PORT_FEAT_SUSPEND,
+                                                       port);
                break;
        case TEST_SINGLE_STEP_GET_DEV_DESC:
                /* Test: wait for 15secs -> GetDescriptor request */
                msleep(15 * 1000);
                buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
-               if (!buf)
-                       return -ENOMEM;
+               if (!buf) {
+                       ret = -ENOMEM;
+                       break;
+               }
 
-               ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               ret = usb_control_msg(child_udev,
+                                       usb_rcvctrlpipe(child_udev, 0),
                                        USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                                        USB_DT_DEVICE << 8, 0,
                                        buf, USB_DT_DEVICE_SIZE,
@@ -103,28 +123,212 @@ static int ehset_probe(struct usb_interface *intf,
                 * SetPortFeature handling can only be done inside the HCD's
                 * hub_control callback function.
                 */
-               if (hub_udev != dev->bus->root_hub) {
-                       dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
+               if (hub_udev != child_udev->bus->root_hub) {
+                       dev_err(dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
                        break;
                }
 
-               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
-                                       USB_PORT_FEAT_TEST,
-                                       (6 << 8) | portnum,
-                                       NULL, 0, 60 * 1000);
+               ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST,
+                                               (6 << 8) | port, 60 * 1000);
 
                break;
        default:
-               dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
-                       __func__, test_pid);
+               dev_err(dev, "%s: unsupported test ID: 0x%x\n",
+                       __func__, test_id);
+       }
+
+       return ret;
+}
+
+static ssize_t test_se0_nak_portnum_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned long portnum;
+       int ret;
+
+       ret = ehset_get_port_num(dev, buf, &portnum);
+       if (ret)
+               return ret;
+
+       usb_lock_device(udev);
+       ret = ehset_set_testmode(dev, NULL, udev, TEST_SE0_NAK_PID, portnum);
+       usb_unlock_device(udev);
+       if (ret) {
+               dev_err(dev, "Error %d while SE0_NAK test\n", ret);
+               return ret;
        }
 
+       return count;
+}
+static DEVICE_ATTR_WO(test_se0_nak_portnum);
+
+static ssize_t test_j_portnum_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned long portnum;
+       int ret;
+
+       ret = ehset_get_port_num(dev, buf, &portnum);
+       if (ret)
+               return ret;
+
+       usb_lock_device(udev);
+       ret = ehset_set_testmode(dev, NULL, udev, TEST_J_PID, portnum);
+       usb_unlock_device(udev);
+       if (ret) {
+               dev_err(dev, "Error %d while J state test\n", ret);
+               return ret;
+       }
+
+       return count;
+}
+static DEVICE_ATTR_WO(test_j_portnum);
+
+static ssize_t test_k_portnum_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned long portnum;
+       int ret;
+
+       ret = ehset_get_port_num(dev, buf, &portnum);
+       if (ret)
+               return ret;
+
+       usb_lock_device(udev);
+       ret = ehset_set_testmode(dev, NULL, udev, TEST_K_PID, portnum);
+       usb_unlock_device(udev);
+       if (ret) {
+               dev_err(dev, "Error %d while K state test\n", ret);
+               return ret;
+       }
+
+       return count;
+}
+static DEVICE_ATTR_WO(test_k_portnum);
+
+static ssize_t test_packet_portnum_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned long portnum;
+       int ret;
+
+       ret = ehset_get_port_num(dev, buf, &portnum);
+       if (ret)
+               return ret;
+
+       usb_lock_device(udev);
+       ret = ehset_set_testmode(dev, NULL, udev, TEST_PACKET_PID, portnum);
+       usb_unlock_device(udev);
+       if (ret) {
+               dev_err(dev, "Error %d while sending test packets\n", ret);
+               return ret;
+       }
+
+       return count;
+}
+static DEVICE_ATTR_WO(test_packet_portnum);
+
+static ssize_t test_port_susp_resume_portnum_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned long portnum;
+       int ret;
+
+       ret = ehset_get_port_num(dev, buf, &portnum);
+       if (ret)
+               return ret;
+
+       usb_lock_device(udev);
+       ret = ehset_set_testmode(dev, NULL, udev,
+                               TEST_HS_HOST_PORT_SUSPEND_RESUME, portnum);
+       usb_unlock_device(udev);
+       if (ret) {
+               dev_err(dev, "Error %d while port suspend resume test\n", ret);
+               return ret;
+       }
+
+       return count;
+}
+static DEVICE_ATTR_WO(test_port_susp_resume_portnum);
+
+static struct attribute *ehset_attributes[] = {
+       &dev_attr_test_se0_nak_portnum.attr,
+       &dev_attr_test_j_portnum.attr,
+       &dev_attr_test_k_portnum.attr,
+       &dev_attr_test_packet_portnum.attr,
+       &dev_attr_test_port_susp_resume_portnum.attr,
+       NULL
+};
+
+static const struct attribute_group ehset_attr_group = {
+       .attrs = ehset_attributes,
+};
+
+static int ehset_probe(struct usb_interface *intf,
+                      const struct usb_device_id *id)
+{
+       int ret = -EINVAL;
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_device *hub_udev = dev->parent;
+       u8 portnum = dev->portnum;
+       u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
+
+       /*
+        * If an external hub does not support the EHSET test fixture, then user
+        * can forcefully unbind the external hub from the hub driver (to which
+        * an external hub gets bound by default) and bind it to this driver, so
+        * as to send test signals on any downstream port of the hub.
+        */
+       if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) {
+               struct usb_hub_descriptor *descriptor;
+
+               descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL);
+               if (!descriptor)
+                       return -ENOMEM;
+
+               ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+                               USB_DT_HUB << 8, 0, descriptor,
+                               USB_DT_HUB_NONVAR_SIZE, USB_CTRL_GET_TIMEOUT);
+               if (ret < 0) {
+                       dev_err(&intf->dev, "%s: Failed to get hub desc %d\n",
+                                                               __func__, ret);
+                       kfree(descriptor);
+                       return ret;
+               }
+
+               numPorts = descriptor->bNbrPorts;
+               ret = sysfs_create_group(&intf->dev.kobj, &ehset_attr_group);
+               if (ret < 0)
+                       dev_err(&intf->dev, "%s: Failed to create sysfs nodes %d\n",
+                                                               __func__, ret);
+
+               kfree(descriptor);
+               return ret;
+       }
+
+       ret = ehset_set_testmode(&intf->dev, dev, hub_udev, test_pid, portnum);
+
        return (ret < 0) ? ret : 0;
 }
 
 static void ehset_disconnect(struct usb_interface *intf)
 {
+       struct usb_device *dev = interface_to_usbdev(intf);
+
+       numPorts = 0;
+       if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
+               sysfs_remove_group(&intf->dev.kobj, &ehset_attr_group);
 }
 
 static const struct usb_device_id ehset_id_table[] = {
index 5d9e707..4f30f78 100644 (file)
@@ -120,6 +120,8 @@ static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev,
        struct msm_ext_disp_audio_edid_blk *blk);
 static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote);
 static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm);
+static int hdmi_tx_enable_pll_update(struct hdmi_tx_ctrl *hdmi_ctrl,
+       int enable);
 
 static struct mdss_hw hdmi_tx_hw = {
        .hw_ndx = MDSS_HW_HDMI,
@@ -1368,6 +1370,59 @@ end:
        return ret;
 }
 
+static ssize_t hdmi_tx_sysfs_rda_pll_enable(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       ssize_t ret;
+       struct hdmi_tx_ctrl *hdmi_ctrl =
+               hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+       if (!hdmi_ctrl) {
+               pr_err("invalid input\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&hdmi_ctrl->tx_lock);
+       ret = snprintf(buf, PAGE_SIZE, "%d\n",
+               hdmi_ctrl->pll_update_enable);
+       pr_debug("HDMI PLL update: %s\n",
+                       hdmi_ctrl->pll_update_enable ? "enable" : "disable");
+
+       mutex_unlock(&hdmi_ctrl->tx_lock);
+
+       return ret;
+} /* hdmi_tx_sysfs_rda_pll_enable */
+
+
+static ssize_t hdmi_tx_sysfs_wta_pll_enable(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       int enable, rc;
+       struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+       hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+       if (!hdmi_ctrl) {
+               DEV_ERR("%s: invalid input\n", __func__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&hdmi_ctrl->tx_lock);
+
+       rc = kstrtoint(buf, 10, &enable);
+       if (rc) {
+               DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+               goto end;
+       }
+
+       hdmi_tx_enable_pll_update(hdmi_ctrl, enable);
+
+       rc = strnlen(buf, PAGE_SIZE);
+end:
+       mutex_unlock(&hdmi_ctrl->tx_lock);
+       return rc;
+} /* hdmi_tx_sysfs_wta_pll_enable */
+
 static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
 static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug);
 static DEVICE_ATTR(sim_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_sim_mode,
@@ -1390,6 +1445,9 @@ static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v);
 static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream);
 static DEVICE_ATTR(hdmi_ppm, S_IRUGO | S_IWUSR, NULL,
        hdmi_tx_sysfs_wta_hdmi_ppm);
+static DEVICE_ATTR(pll_enable, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_pll_enable,
+       hdmi_tx_sysfs_wta_pll_enable);
+
 
 static struct attribute *hdmi_tx_fs_attrs[] = {
        &dev_attr_connected.attr,
@@ -1406,6 +1464,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = {
        &dev_attr_5v.attr,
        &dev_attr_hdr_stream.attr,
        &dev_attr_hdmi_ppm.attr,
+       &dev_attr_pll_enable.attr,
        NULL,
 };
 static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -1575,12 +1634,14 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
                        rc = hdmi_tx_config_avmute(hdmi_ctrl, false);
                }
 
-               if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present)
-                       hdcp1_set_enc(true);
+               if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) {
+                       if (!hdmi_ctrl->hdcp22_present)
+                               hdcp1_set_enc(true);
+               }
                break;
        case HDCP_STATE_AUTH_FAIL:
                if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) {
-                       if (hdmi_ctrl->auth_state)
+                       if (hdmi_ctrl->auth_state && !hdmi_ctrl->hdcp22_present)
                                hdcp1_set_enc(false);
                }
 
@@ -3626,6 +3687,7 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
        hdmi_ctrl->hpd_state = false;
        hdmi_ctrl->hpd_initialized = false;
        hdmi_ctrl->hpd_off_pending = false;
+       hdmi_ctrl->pll_update_enable = false;
        init_completion(&hdmi_ctrl->hpd_int_done);
 
        INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
@@ -3799,6 +3861,11 @@ static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm)
                return -EINVAL;
        }
 
+       if (!hdmi_ctrl->pll_update_enable) {
+               pr_err("PLL update feature not enabled\n");
+               return -EINVAL;
+       }
+
        /* get current pclk */
        cur_pclk = pinfo->clk_rate;
        /* get desired pclk */
@@ -3822,6 +3889,49 @@ static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm)
        return rc;
 }
 
+static int hdmi_tx_enable_pll_update(struct hdmi_tx_ctrl *hdmi_ctrl,
+       int enable)
+{
+       struct mdss_panel_info *pinfo = NULL;
+       int rc = 0;
+
+       if (!hdmi_ctrl) {
+               pr_err("invalid input\n");
+               return -EINVAL;
+       }
+
+       /* only available in case HDMI is up */
+       if (!hdmi_tx_is_panel_on(hdmi_ctrl)) {
+               pr_err("hdmi is not on\n");
+               return -EINVAL;
+       }
+
+       enable = !!enable;
+       if (hdmi_ctrl->pll_update_enable == enable) {
+               pr_warn("HDMI PLL update already %s\n",
+                       hdmi_ctrl->pll_update_enable ? "enabled" : "disabled");
+               return -EINVAL;
+       }
+
+       pinfo = &hdmi_ctrl->panel_data.panel_info;
+
+       if (!enable && hdmi_ctrl->actual_clk_rate != pinfo->clk_rate) {
+               if (hdmi_ctrl->actual_clk_rate) {
+                       /* reset pixel clock when disable */
+                       pinfo->clk_rate = hdmi_ctrl->actual_clk_rate;
+                       rc = hdmi_tx_update_pixel_clk(hdmi_ctrl);
+               }
+       }
+
+       hdmi_ctrl->actual_clk_rate = pinfo->clk_rate;
+       hdmi_ctrl->pll_update_enable = enable;
+
+       pr_debug("HDMI PLL update: %s\n",
+                       hdmi_ctrl->pll_update_enable ? "enable" : "disable");
+
+       return rc;
+}
+
 static int hdmi_tx_evt_handle_register(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
        int rc = 0;
@@ -3994,6 +4104,7 @@ static int hdmi_tx_evt_handle_panel_off(struct hdmi_tx_ctrl *hdmi_ctrl)
        }
 
        hdmi_ctrl->timing_gen_on = false;
+       hdmi_ctrl->pll_update_enable = false;
 end:
        return rc;
 }
index ad02003..92b9d84 100644 (file)
@@ -143,6 +143,9 @@ struct hdmi_tx_ctrl {
 
        char disp_switch_name[MAX_SWITCH_NAME_SIZE];
 
+       u64 actual_clk_rate;
+       bool pll_update_enable;
+
        /* pre/post is done in the context without tx_lock */
        hdmi_tx_evt_handler pre_evt_handler[MDSS_EVENT_MAX - 1];
        hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX - 1];
index ca2de60..0531149 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -146,7 +146,19 @@ enum cnss_recovery_reason {
 extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
 extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
 extern void cnss_device_crashed(struct device *dev);
+#ifdef CONFIG_PCI_MSM
 extern int cnss_pci_link_down(struct device *dev);
+extern int cnss_wlan_pm_control(struct device *dev, bool vote);
+#else /* CONFIG_PCI_MSM */
+static inline int cnss_pci_link_down(struct device *dev)
+{
+       return 0;
+}
+static inline int cnss_wlan_pm_control(struct device *dev, bool vote)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_MSM */
 extern void cnss_schedule_recovery(struct device *dev,
                                   enum cnss_recovery_reason reason);
 extern int cnss_self_recovery(struct device *dev,
@@ -166,7 +178,6 @@ extern void cnss_request_pm_qos(struct device *dev, u32 qos_val);
 extern void cnss_remove_pm_qos(struct device *dev);
 extern void cnss_lock_pm_sem(struct device *dev);
 extern void cnss_release_pm_sem(struct device *dev);
-extern int cnss_wlan_pm_control(struct device *dev, bool vote);
 extern int cnss_auto_suspend(struct device *dev);
 extern int cnss_auto_resume(struct device *dev);
 extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
index 65316c6..0393c88 100644 (file)
@@ -505,6 +505,39 @@ struct adm_cmd_device_open_v6 {
  */
 } __packed;
 
+/* ADM device open endpoint payload the
+*   #ADM_CMD_DEVICE_OPEN_V8 command.
+*/
+struct adm_device_endpoint_payload {
+              u16                  dev_num_channel;
+       /* Number of channels the audio COPP sends to/receives from
+           * the endpoint.
+           * Supported values: 1 to 32.
+           * The value is ignored for the voice processor Tx block,
+           * where channel
+           * configuration is derived from the topology ID.
+           */
+
+              u16                  bit_width;
+       /* Bit width (in bits) that the audio COPP sends to/receives
+           * from the
+           * endpoint. The value is ignored for the voice processing
+           * Tx block,
+           * where the PCM width is 16 bits.
+           */
+
+              u32                  sample_rate;
+       /* Sampling rate at which the audio COPP/voice processor
+            * Tx block
+            * interfaces with the endpoint.
+            * Supported values for voice processor Tx: 8000, 16000,
+            * 48000 Hz
+            * Supported values for audio COPP: >0 and <=192 kHz
+            */
+
+             u8                    dev_channel_mapping[32];
+} __packed;
+
 /*  ADM device open command payload of the
 *   #ADM_CMD_DEVICE_OPEN_V8 command.
 */
@@ -571,111 +604,6 @@ struct adm_cmd_device_open_v8 {
  */
        u16                  endpoint_id_3;
        u16                  reserved;
-
-       u16                  dev_num_channel;
-/* Number of channels the audio COPP sends to/receives from
- * the endpoint.
- * Supported values: 1 to 32.
- * The value is ignored for the voice processor Tx block,
- * where channel
- * configuration is derived from the topology ID.
- */
-
-       u16                  bit_width;
-/* Bit width (in bits) that the audio COPP sends to/receives
- * from the
- * endpoint. The value is ignored for the voice processing
- * Tx block,
- * where the PCM width is 16 bits.
- */
-
-       u32                  sample_rate;
-/* Sampling rate at which the audio COPP/voice processor
- * Tx block
- * interfaces with the endpoint.
- * Supported values for voice processor Tx: 8000, 16000,
- * 48000 Hz
- * Supported values for audio COPP: >0 and <=192 kHz
- */
-
-       u8                   dev_channel_mapping[32];
-/* Array of channel mapping of buffers that the audio COPP
- * sends to the endpoint. Channel[i] mapping describes channel
- * I inside the buffer, where 0 < i < dev_num_channel.
- * This value is relevant only for an audio Rx COPP.
- * For the voice processor block and Tx audio block, this field
- * is set to zero and is ignored.
- */
-
-       u16                  dev_num_channel_eid2;
-/* Number of channels the audio COPP sends to/receives from
- * the endpoint.
- * Supported values: 1 to 32.
- * The value is ignored for the voice processor Tx block,
- * where channel
- * configuration is derived from the topology ID.
- */
-
-       u16                  bit_width_eid2;
-/* Bit width (in bits) that the audio COPP sends to/receives
- * from the
- * endpoint. The value is ignored for the voice processing
- * Tx block,
- * where the PCM width is 16 bits.
- */
-
-       u32                  sample_rate_eid2;
-/* Sampling rate at which the audio COPP/voice processor
- * Tx block
- * interfaces with the endpoint.
- * Supported values for voice processor Tx: 8000, 16000,
- * 48000 Hz
- * Supported values for audio COPP: >0 and <=192 kHz
- */
-
-       u8                   dev_channel_mapping_eid2[32];
-/* Array of channel mapping of buffers that the audio COPP
- * sends to the endpoint. Channel[i] mapping describes channel
- * I inside the buffer, where 0 < i < dev_num_channel.
- * This value is relevant only for an audio Rx COPP.
- * For the voice processor block and Tx audio block, this field
- * is set to zero and is ignored.
- */
-
-       u16                  dev_num_channel_eid3;
-/* Number of channels the audio COPP sends to/receives from
- * the endpoint.
- * Supported values: 1 to 32.
- * The value is ignored for the voice processor Tx block,
- * where channel
- * configuration is derived from the topology ID.
- */
-
-       u16                  bit_width_eid3;
-/* Bit width (in bits) that the audio COPP sends to/receives
- * from the
- * endpoint. The value is ignored for the voice processing
- * Tx block,
- * where the PCM width is 16 bits.
- */
-
-       u32                  sample_rate_eid3;
-/* Sampling rate at which the audio COPP/voice processor
- * Tx block
- * interfaces with the endpoint.
- * Supported values for voice processor Tx: 8000, 16000,
- * 48000 Hz
- * Supported values for audio COPP: >0 and <=192 kHz
- */
-
-       u8                   dev_channel_mapping_eid3[32];
-/* Array of channel mapping of buffers that the audio COPP
- * sends to the endpoint. Channel[i] mapping describes channel
- * I inside the buffer, where 0 < i < dev_num_channel.
- * This value is relevant only for an audio Rx COPP.
- * For the voice processor block and Tx audio block, this field
- * is set to zero and is ignored.
- */
 } __packed;
 
 /*
index e3cfb10..4545f2c 100644 (file)
@@ -61,7 +61,7 @@ enum adm_status_flags {
 };
 
 #define MAX_COPPS_PER_PORT 0x8
-#define ADM_MAX_CHANNELS 8
+#define ADM_MAX_CHANNELS 32
 
 /* multiple copp per stream. */
 struct route_payload {
@@ -223,4 +223,5 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
                        int session_type,
                        struct msm_pcm_channel_mixer *ch_mixer,
                        int channel_index);
+void adm_set_native_mode(int mode);
 #endif /* __Q6_ADM_V2_H__ */
index 285d32e..9df3e77 100644 (file)
@@ -114,6 +114,7 @@ enum {
        PCM_MEDIA_FORMAT_V2 = 0,
        PCM_MEDIA_FORMAT_V3,
        PCM_MEDIA_FORMAT_V4,
+       PCM_MEDIA_FORMAT_V5,
 };
 
 /* PCM format modes in DSP */
@@ -288,6 +289,9 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
 int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
                       uint16_t bits_per_sample, bool ts_mode);
 
+int q6asm_open_read_v5(struct audio_client *ac, uint32_t format,
+                      uint16_t bits_per_sample, bool ts_mode);
+
 int q6asm_open_write(struct audio_client *ac, uint32_t format
                /*, uint16_t bits_per_sample*/);
 
@@ -303,6 +307,8 @@ int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
 int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
                        uint16_t bits_per_sample);
 
+int q6asm_open_write_v5(struct audio_client *ac, uint32_t format,
+                       uint16_t bits_per_sample);
 int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
                               uint16_t bits_per_sample, int32_t stream_id,
                               bool is_gapless_mode);
@@ -450,6 +456,13 @@ int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
                                            uint16_t endianness,
                                            uint16_t mode);
 
+int q6asm_enc_cfg_blk_pcm_format_support_v5(struct audio_client *ac,
+                                           uint32_t rate, uint32_t channels,
+                                           uint16_t bits_per_sample,
+                                           uint16_t sample_word_size,
+                                           uint16_t endianness,
+                                           uint16_t mode);
+
 int q6asm_set_encdec_chan_map(struct audio_client *ac,
                uint32_t num_channels);
 
@@ -545,6 +558,15 @@ int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
                                             uint16_t endianness,
                                             uint16_t mode);
 
+int q6asm_media_format_block_multi_ch_pcm_v5(struct audio_client *ac,
+                                            uint32_t rate, uint32_t channels,
+                                            bool use_default_chmap,
+                                            char *channel_map,
+                                            uint16_t bits_per_sample,
+                                            uint16_t sample_word_size,
+                                            uint16_t endianness,
+                                            uint16_t mode);
+
 int q6asm_media_format_block_aac(struct audio_client *ac,
                        struct asm_aac_cfg *cfg);
 
@@ -704,4 +726,5 @@ uint8_t q6asm_get_stream_id_from_token(uint32_t token);
 int q6asm_adjust_session_clock(struct audio_client *ac,
                uint32_t adjust_time_lsw,
                uint32_t adjust_time_msw);
+int q6asm_get_svc_version(uint32_t service_id);
 #endif /* __Q6_ASM_H__ */
index 615ba59..d69b77f 100644 (file)
@@ -234,8 +234,16 @@ static inline bool lockdep_softirq_start(void) { return false; }
 static inline void lockdep_softirq_end(bool in_hardirq) { }
 #endif
 
-#define long_softirq_pending() (local_softirq_pending() & LONG_SOFTIRQ_MASK)
-#define defer_for_rt()         (long_softirq_pending() && cpupri_check_rt())
+#define softirq_deferred_for_rt(pending)               \
+({                                                     \
+       __u32 deferred = 0;                             \
+       if (cpupri_check_rt()) {                        \
+               deferred = pending & LONG_SOFTIRQ_MASK; \
+               pending &= ~LONG_SOFTIRQ_MASK;          \
+       }                                               \
+       deferred;                                       \
+})
+
 asmlinkage __visible void __softirq_entry __do_softirq(void)
 {
        unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -243,6 +251,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
        int max_restart = MAX_SOFTIRQ_RESTART;
        struct softirq_action *h;
        bool in_hardirq;
+       __u32 deferred;
        __u32 pending;
        int softirq_bit;
 
@@ -254,14 +263,14 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
        current->flags &= ~PF_MEMALLOC;
 
        pending = local_softirq_pending();
+       deferred = softirq_deferred_for_rt(pending);
        account_irq_enter_time(current);
-
        __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
        in_hardirq = lockdep_softirq_start();
 
 restart:
        /* Reset the pending bitmask before enabling irqs */
-       set_softirq_pending(0);
+       set_softirq_pending(deferred);
        __this_cpu_write(active_softirqs, pending);
 
        local_irq_enable();
@@ -297,15 +306,16 @@ restart:
        local_irq_disable();
 
        pending = local_softirq_pending();
+       deferred = softirq_deferred_for_rt(pending);
+
        if (pending) {
                if (time_before(jiffies, end) && !need_resched() &&
-                   !defer_for_rt() &&
                    --max_restart)
                        goto restart;
-
-               wakeup_softirqd();
        }
 
+       if (pending | deferred)
+               wakeup_softirqd();
        lockdep_softirq_end(in_hardirq);
        account_irq_exit_time(current);
        __local_bh_enable(SOFTIRQ_OFFSET);
@@ -352,7 +362,7 @@ void irq_enter(void)
 
 static inline void invoke_softirq(void)
 {
-       if (!force_irqthreads && !defer_for_rt()) {
+       if (!force_irqthreads) {
 #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
                /*
                 * We can safely execute softirq on the current stack if
index 3326c99..c9178fb 100644 (file)
@@ -99,7 +99,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     384000,
                },
@@ -113,7 +113,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -132,7 +132,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     384000,
                },
@@ -146,7 +146,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -217,7 +217,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 6,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -231,7 +231,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -250,7 +250,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -270,7 +270,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -284,7 +284,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -303,7 +303,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -317,7 +317,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -336,7 +336,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -356,7 +356,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                                SNDRV_PCM_FMTBIT_S24_3LE |
                                                SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -370,7 +370,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -2155,7 +2155,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     384000,
                },
@@ -2166,7 +2166,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                  SNDRV_PCM_RATE_KNOT),
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -2372,7 +2372,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2392,7 +2392,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2412,7 +2412,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2432,7 +2432,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2452,7 +2452,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2472,7 +2472,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2492,7 +2492,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max = 384000,
                },
@@ -2506,7 +2506,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -2574,7 +2574,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     192000,
                },
@@ -2593,7 +2593,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     192000,
                },
@@ -2612,7 +2612,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     192000,
                },
@@ -2632,7 +2632,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     384000,
                },
@@ -2646,7 +2646,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -2665,7 +2665,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 384000,
                },
@@ -2679,7 +2679,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     48000,
                },
@@ -2698,7 +2698,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 384000,
                },
@@ -2717,7 +2717,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 384000,
                },
@@ -2736,7 +2736,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 384000,
                },
@@ -2755,7 +2755,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 384000,
                },
@@ -2774,7 +2774,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_3LE |
                                    SNDRV_PCM_FMTBIT_S32_LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 384000,
                },
@@ -2793,7 +2793,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min = 8000,
                        .rate_max = 192000,
                },
@@ -2812,7 +2812,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     192000,
                },
@@ -2831,7 +2831,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
                                    SNDRV_PCM_FMTBIT_S24_LE |
                                    SNDRV_PCM_FMTBIT_S24_3LE),
                        .channels_min = 1,
-                       .channels_max = 8,
+                       .channels_max = 32,
                        .rate_min =     8000,
                        .rate_max =     192000,
                },
index d54c357..a0364bb 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/of_device.h>
 #include <sound/tlv.h>
 #include <sound/pcm_params.h>
+#include <sound/q6core.h>
 
 #include "msm-pcm-q6-v2.h"
 #include "msm-pcm-routing-v2.h"
@@ -384,8 +385,13 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
                        return -ENOMEM;
                }
        } else {
-               ret = q6asm_open_write_v4(prtd->audio_client,
-                       fmt_type, bits_per_sample);
+               if (q6asm_get_svc_version(APR_SVC_ASM) >=
+                               ADSP_ASM_API_VERSION_V2)
+                       ret = q6asm_open_write_v5(prtd->audio_client,
+                               fmt_type, bits_per_sample);
+               else
+                       ret = q6asm_open_write_v4(prtd->audio_client,
+                               fmt_type, bits_per_sample);
 
                if (ret < 0) {
                        pr_err("%s: q6asm_open_write_v4 failed (%d)\n",
@@ -425,7 +431,16 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
                        runtime->channels, !prtd->set_channel_map,
                        prtd->channel_map, bits_per_sample);
        } else {
-               ret = q6asm_media_format_block_multi_ch_pcm_v4(
+               if (q6asm_get_svc_version(APR_SVC_ASM) >=
+                               ADSP_ASM_API_VERSION_V2)
+                       ret = q6asm_media_format_block_multi_ch_pcm_v5(
+                               prtd->audio_client, runtime->rate,
+                               runtime->channels, !prtd->set_channel_map,
+                               prtd->channel_map, bits_per_sample,
+                               sample_word_size, ASM_LITTLE_ENDIAN,
+                               DEFAULT_QF);
+               else
+                       ret = q6asm_media_format_block_multi_ch_pcm_v4(
                                prtd->audio_client, runtime->rate,
                                runtime->channels, !prtd->set_channel_map,
                                prtd->channel_map, bits_per_sample,
@@ -489,8 +504,15 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
                                __func__, params_channels(params),
                                prtd->audio_client->perf_mode);
 
-               ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
-                               bits_per_sample, false);
+               if (q6asm_get_svc_version(APR_SVC_ASM) >=
+                               ADSP_ASM_API_VERSION_V2)
+                       ret = q6asm_open_read_v5(prtd->audio_client,
+                                       FORMAT_LINEAR_PCM,
+                                       bits_per_sample, false);
+               else
+                       ret = q6asm_open_read_v4(prtd->audio_client,
+                                       FORMAT_LINEAR_PCM,
+                                       bits_per_sample, false);
                if (ret < 0) {
                        pr_err("%s: q6asm_open_read failed\n", __func__);
                        q6asm_audio_client_free(prtd->audio_client);
@@ -557,13 +579,25 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
        pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
                        __func__, prtd->samp_rate, prtd->channel_mode,
                        bits_per_sample, sample_word_size);
-       ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client,
-                                                     prtd->samp_rate,
-                                                     prtd->channel_mode,
-                                                     bits_per_sample,
-                                                     sample_word_size,
-                                                     ASM_LITTLE_ENDIAN,
-                                                     DEFAULT_QF);
+       if (q6asm_get_svc_version(APR_SVC_ASM) >=
+                               ADSP_ASM_API_VERSION_V2)
+               ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
+                                       prtd->audio_client,
+                                       prtd->samp_rate,
+                                       prtd->channel_mode,
+                                       bits_per_sample,
+                                       sample_word_size,
+                                       ASM_LITTLE_ENDIAN,
+                                       DEFAULT_QF);
+       else
+               ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
+                                       prtd->audio_client,
+                                       prtd->samp_rate,
+                                       prtd->channel_mode,
+                                       bits_per_sample,
+                                       sample_word_size,
+                                       ASM_LITTLE_ENDIAN,
+                                       DEFAULT_QF);
        if (ret < 0)
                pr_debug("%s: cmd cfg pcm was block failed", __func__);
 
index f9c0c03..afe3144 100644 (file)
@@ -104,7 +104,7 @@ struct msm_audio {
        int mmap_flag;
        atomic_t pending_buffer;
        bool set_channel_map;
-       char channel_map[8];
+       char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL_V2];
        int cmd_interrupt;
        bool meta_data_mode;
        uint32_t volume;
index 18438b5..2b712be 100644 (file)
@@ -83,6 +83,7 @@ static int msm_route_ext_ec_ref;
 static bool is_custom_stereo_on;
 static bool is_ds2_on;
 static bool swap_ch;
+static int msm_native_mode;
 
 #define WEIGHT_0_DB 0x4000
 /* all the FEs which can support channel mixer */
@@ -3475,6 +3476,65 @@ static const struct snd_kcontrol_new channel_mixer_controls[] = {
        .private_value = (unsigned long)&(mm1_ch8_enum)
        },
 };
+
+static int msm_native_mode_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       switch (msm_native_mode) {
+       case 3:
+       case 2:
+       case 1:
+               ucontrol->value.integer.value[0] = msm_native_mode;
+               break;
+       default:
+               ucontrol->value.integer.value[0] = 0;
+               break;
+       }
+
+       pr_debug("%s: msm_native_mode = %d ucontrol value %ld\n",
+               __func__, msm_native_mode,
+               ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int msm_native_mode_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       /* native flag shift from bit 11 in flags when open adm
+        * 1 << 11: use bit width native mode
+        * 2 << 11: use channel native mode
+        * 3 << 11: use bit width and channel native mode
+       */
+       switch (ucontrol->value.integer.value[0]) {
+       case 3:
+       case 2:
+       case 1:
+               msm_native_mode = ucontrol->value.integer.value[0];
+               break;
+       default:
+               msm_native_mode = 0;
+               break;
+       }
+
+       pr_debug("%s: msm_native_mode = %d ucontrol value %ld\n",
+               __func__, msm_native_mode,
+               ucontrol->value.integer.value[0]);
+       adm_set_native_mode(msm_native_mode);
+       return 0;
+}
+
+static const char *const native_mode_text[] = {"NonNative", "NativeBit",
+               "NativeCh", "NativeChBit"};
+
+static const struct soc_enum native_mode_enum[] = {
+       SOC_ENUM_SINGLE_EXT(4, native_mode_text),
+};
+
+static const struct snd_kcontrol_new native_mode_controls[] = {
+       SOC_ENUM_EXT("Native Mode Config", native_mode_enum[0],
+               msm_native_mode_get, msm_native_mode_put),
+};
+
 static int msm_ec_ref_ch_get(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
@@ -16835,6 +16895,9 @@ static int msm_routing_probe(struct snd_soc_platform *platform)
        snd_soc_add_platform_controls(platform, channel_mixer_controls,
                                ARRAY_SIZE(channel_mixer_controls));
 
+       snd_soc_add_platform_controls(platform, native_mode_controls,
+                               ARRAY_SIZE(native_mode_controls));
+
        msm_qti_pp_add_controls(platform);
 
        msm_dts_srs_tm_add_controls(platform);
index 3dad2c4..4b76f1b 100644 (file)
@@ -25,6 +25,7 @@
 #include <sound/q6common.h>
 #include <sound/audio_cal_utils.h>
 #include <sound/asound.h>
+#include <sound/q6core.h>
 #include "msm-dts-srs-tm-config.h"
 #include <sound/adsp_err.h>
 
@@ -99,6 +100,8 @@ struct adm_ctl {
        int num_ec_ref_rx_chans;
        int ec_ref_rx_bit_width;
        int ec_ref_rx_sampling_rate;
+
+       int native_mode;
 };
 
 static struct adm_ctl                  this_adm;
@@ -256,6 +259,38 @@ static int adm_get_next_available_copp(int port_idx)
        return idx;
 }
 
+static int adm_get_svc_version(uint32_t service_id)
+{
+       int ret = 0;
+       static int adm_cached_version;
+       size_t ver_size;
+       struct avcs_fwk_ver_info *ver_info = NULL;
+
+       if (service_id == AVCS_SERVICE_ID_ALL) {
+               pr_err("%s: Invalid service id: %d", __func__,
+                                       AVCS_SERVICE_ID_ALL);
+               return -EINVAL;
+       }
+
+       if (adm_cached_version != 0)
+               return adm_cached_version;
+
+       ver_size = sizeof(struct avcs_get_fwk_version) +
+                       sizeof(struct avs_svc_api_info);
+       ver_info = kzalloc(ver_size, GFP_KERNEL);
+       if (ver_info == NULL)
+               return -ENOMEM;
+
+       ret = q6core_get_service_version(service_id, ver_info, ver_size);
+       if (ret < 0)
+               goto done;
+
+       ret = ver_info->services[0].api_version;
+       adm_cached_version = ret;
+done:
+       kfree(ver_info);
+       return ret;
+}
 int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
                      void *srs_params)
 {
@@ -1375,6 +1410,7 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
                        case ADM_CMD_DEVICE_OPEN_V5:
                        case ADM_CMD_DEVICE_CLOSE_V5:
                        case ADM_CMD_DEVICE_OPEN_V6:
+                       case ADM_CMD_DEVICE_OPEN_V8:
                        case ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1:
                                pr_debug("%s: Basic callback received, wake up.\n",
                                        __func__);
@@ -1474,7 +1510,8 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
 
                switch (data->opcode) {
                case ADM_CMDRSP_DEVICE_OPEN_V5:
-               case ADM_CMDRSP_DEVICE_OPEN_V6: {
+               case ADM_CMDRSP_DEVICE_OPEN_V6:
+               case ADM_CMDRSP_DEVICE_OPEN_V8: {
                        struct adm_cmd_rsp_device_open_v5 *open =
                        (struct adm_cmd_rsp_device_open_v5 *)data->payload;
 
@@ -2265,11 +2302,510 @@ int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
        return rc;
 }
 
-int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
-            int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
+static int adm_arrange_mch_map_v8(
+               struct adm_device_endpoint_payload *ep_payload,
+               int path,
+               int channel_mode)
 {
+       int rc = 0, idx;
+
+       memset(ep_payload->dev_channel_mapping,
+                       0, PCM_FORMAT_MAX_NUM_CHANNEL_V2);
+       switch (path) {
+       case ADM_PATH_PLAYBACK:
+               idx = ADM_MCH_MAP_IDX_PLAYBACK;
+               break;
+       case ADM_PATH_LIVE_REC:
+       case ADM_PATH_NONLIVE_REC:
+               idx = ADM_MCH_MAP_IDX_REC;
+               break;
+       default:
+               goto non_mch_path;
+       };
+
+       if ((ep_payload->dev_num_channel > 2) &&
+                       multi_ch_maps[idx].set_channel_map) {
+               memcpy(ep_payload->dev_channel_mapping,
+                       multi_ch_maps[idx].channel_mapping,
+                       PCM_FORMAT_MAX_NUM_CHANNEL);
+       } else {
+               if (channel_mode == 1) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FC;
+               } else if (channel_mode == 2) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               } else if (channel_mode == 3) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+               } else if (channel_mode == 4) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_RS;
+               } else if (channel_mode == 5) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_RS;
+               } else if (channel_mode == 6) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+               } else if (channel_mode == 7) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_LFE;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LB;
+                       ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RB;
+                       ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_CS;
+               } else if (channel_mode == 8) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+                       ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+                       ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+               } else if (channel_mode == 10) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+                       ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+                       ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+                       ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+                       ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+               } else if (channel_mode == 16) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+                       ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+                       ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+                       ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+                       ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+                       ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_CVH;
+                       ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_MS;
+                       ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
+                       ep_payload->dev_channel_mapping[13] = PCM_CHANNEL_FRC;
+                       ep_payload->dev_channel_mapping[14] = PCM_CHANNEL_RLC;
+                       ep_payload->dev_channel_mapping[15] = PCM_CHANNEL_RRC;
+               } else if (channel_mode == 32) {
+                       ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+                       ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+                       ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+                       ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+                       ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+                       ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+                       ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_CVH;
+                       ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_MS;
+                       ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
+                       ep_payload->dev_channel_mapping[13] = PCM_CHANNEL_FRC;
+                       ep_payload->dev_channel_mapping[14] = PCM_CHANNEL_RLC;
+                       ep_payload->dev_channel_mapping[15] = PCM_CHANNEL_RRC;
+                       ep_payload->dev_channel_mapping[16] = PCM_CHANNEL_LFE2;
+                       ep_payload->dev_channel_mapping[17] = PCM_CHANNEL_SL;
+                       ep_payload->dev_channel_mapping[18] = PCM_CHANNEL_SR;
+                       ep_payload->dev_channel_mapping[19] = PCM_CHANNEL_TFL;
+                       ep_payload->dev_channel_mapping[20] = PCM_CHANNEL_TFR;
+                       ep_payload->dev_channel_mapping[21] = PCM_CHANNEL_TC;
+                       ep_payload->dev_channel_mapping[22] = PCM_CHANNEL_TBL;
+                       ep_payload->dev_channel_mapping[23] = PCM_CHANNEL_TBR;
+                       ep_payload->dev_channel_mapping[24] = PCM_CHANNEL_TSL;
+                       ep_payload->dev_channel_mapping[25] = PCM_CHANNEL_TSR;
+                       ep_payload->dev_channel_mapping[26] = PCM_CHANNEL_TBC;
+                       ep_payload->dev_channel_mapping[27] = PCM_CHANNEL_BFC;
+                       ep_payload->dev_channel_mapping[28] = PCM_CHANNEL_BFL;
+                       ep_payload->dev_channel_mapping[29] = PCM_CHANNEL_BFR;
+                       ep_payload->dev_channel_mapping[30] = PCM_CHANNEL_LW;
+                       ep_payload->dev_channel_mapping[31] = PCM_CHANNEL_RW;
+               } else {
+                       pr_err("%s: invalid num_chan %d\n", __func__,
+                               channel_mode);
+                       rc = -EINVAL;
+                       goto inval_ch_mod;
+               }
+       }
+
+non_mch_path:
+inval_ch_mod:
+       return rc;
+}
+
+static int adm_arrange_mch_ep2_map_v8(
+               struct adm_device_endpoint_payload *ep_payload,
+               int channel_mode)
+{
+       int rc = 0;
+
+       memset(ep_payload->dev_channel_mapping, 0,
+              PCM_FORMAT_MAX_NUM_CHANNEL_V2);
+
+       if (channel_mode == 1)  {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FC;
+       } else if (channel_mode == 2) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+       } else if (channel_mode == 3)   {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+       } else if (channel_mode == 4) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_RS;
+       } else if (channel_mode == 5) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_RS;
+       } else if (channel_mode == 6) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+               ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+       } else if (channel_mode == 8) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+               ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+               ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+               ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+       }  else if (channel_mode == 10) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+               ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+               ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+               ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+               ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+               ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+       } else if (channel_mode == 16) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+               ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+               ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+               ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+               ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+               ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+               ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_CVH;
+               ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_MS;
+               ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
+               ep_payload->dev_channel_mapping[13] = PCM_CHANNEL_FRC;
+               ep_payload->dev_channel_mapping[14] = PCM_CHANNEL_RLC;
+               ep_payload->dev_channel_mapping[15] = PCM_CHANNEL_RRC;
+       } else if (channel_mode == 32) {
+               ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+               ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+               ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+               ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+               ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+               ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+               ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+               ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+               ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+               ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_CVH;
+               ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_MS;
+               ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
+               ep_payload->dev_channel_mapping[13] = PCM_CHANNEL_FRC;
+               ep_payload->dev_channel_mapping[14] = PCM_CHANNEL_RLC;
+               ep_payload->dev_channel_mapping[15] = PCM_CHANNEL_RRC;
+               ep_payload->dev_channel_mapping[16] = PCM_CHANNEL_LFE2;
+               ep_payload->dev_channel_mapping[17] = PCM_CHANNEL_SL;
+               ep_payload->dev_channel_mapping[18] = PCM_CHANNEL_SR;
+               ep_payload->dev_channel_mapping[19] = PCM_CHANNEL_TFL;
+               ep_payload->dev_channel_mapping[20] = PCM_CHANNEL_TFR;
+               ep_payload->dev_channel_mapping[21] = PCM_CHANNEL_TC;
+               ep_payload->dev_channel_mapping[22] = PCM_CHANNEL_TBL;
+               ep_payload->dev_channel_mapping[23] = PCM_CHANNEL_TBR;
+               ep_payload->dev_channel_mapping[24] = PCM_CHANNEL_TSL;
+               ep_payload->dev_channel_mapping[25] = PCM_CHANNEL_TSR;
+               ep_payload->dev_channel_mapping[26] = PCM_CHANNEL_TBC;
+               ep_payload->dev_channel_mapping[27] = PCM_CHANNEL_BFC;
+               ep_payload->dev_channel_mapping[28] = PCM_CHANNEL_BFL;
+               ep_payload->dev_channel_mapping[29] = PCM_CHANNEL_BFR;
+               ep_payload->dev_channel_mapping[30] = PCM_CHANNEL_LW;
+               ep_payload->dev_channel_mapping[31] = PCM_CHANNEL_RW;
+       } else {
+               pr_err("%s: invalid num_chan %d\n", __func__,
+                       channel_mode);
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
+static int adm_open_v8(int tmp_port, int port_idx, int copp_idx,
+               int flags, int path,
+               int channel_mode, uint16_t bit_width,
+               int rate, int topology,
+               int perf_mode)
+{
+       int ret = 0;
+       struct adm_cmd_device_open_v8   open_v8;
+       struct adm_device_endpoint_payload ep1_payload;
+       struct adm_device_endpoint_payload ep2_payload;
+       int ep1_payload_size = 0;
+       int ep2_payload_size = 0;
+       void *adm_params = NULL;
+       int param_size;
+
+       if (channel_mode < 0 || channel_mode > 32) {
+               pr_err("%s: Invalid channel number 0x%x\n",
+                               __func__, channel_mode);
+               return -EINVAL;
+       }
+
+       memset(&open_v8, 0, sizeof(open_v8));
+       memset(&ep1_payload, 0, sizeof(ep1_payload));
+       memset(&ep2_payload, 0, sizeof(ep2_payload));
+
+       open_v8.hdr.hdr_field = APR_HDR_FIELD(
+                       APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE),
+                       APR_PKT_VER);
+       open_v8.hdr.src_svc = APR_SVC_ADM;
+       open_v8.hdr.src_domain = APR_DOMAIN_APPS;
+       open_v8.hdr.src_port = tmp_port;
+       open_v8.hdr.dest_svc = APR_SVC_ADM;
+       open_v8.hdr.dest_domain = APR_DOMAIN_ADSP;
+       open_v8.hdr.dest_port = tmp_port;
+       open_v8.hdr.token = port_idx << 16 | copp_idx;
+       open_v8.hdr.opcode = ADM_CMD_DEVICE_OPEN_V8;
+
+       if (this_adm.native_mode != 0) {
+               open_v8.flags = flags |
+                       (this_adm.native_mode << 11);
+               this_adm.native_mode = 0;
+       } else {
+               open_v8.flags = flags;
+       }
+
+       open_v8.mode_of_operation = path;
+       open_v8.endpoint_id_1 = tmp_port;
+       open_v8.endpoint_id_2 = 0xFFFF;
+       open_v8.endpoint_id_3 = 0xFFFF;
+
+       if (this_adm.ec_ref_rx && (path != 1)) {
+               open_v8.endpoint_id_2 = this_adm.ec_ref_rx;
+               this_adm.ec_ref_rx = -1;
+       }
+
+       open_v8.topology_id = topology;
+       open_v8.reserved = 0;
+
+       /*variable endpoint payload*/
+       ep1_payload.dev_num_channel = channel_mode & 0x00FF;
+       ep1_payload.bit_width = bit_width;
+       ep1_payload.sample_rate  = rate;
+       ret = adm_arrange_mch_map_v8(&ep1_payload, path,
+                       channel_mode);
+       if (ret)
+               return ret;
+
+       pr_debug("%s: port_id=0x%x %x %x topology_id=0x%X flags %x ref_ch %x\n",
+               __func__, open_v8.endpoint_id_1,
+               open_v8.endpoint_id_2,
+               open_v8.endpoint_id_3,
+               open_v8.topology_id,
+               open_v8.flags,
+               this_adm.num_ec_ref_rx_chans);
+
+       ep1_payload_size = 8 +
+                       roundup(ep1_payload.dev_num_channel, 4);
+       param_size = sizeof(struct adm_cmd_device_open_v8)
+                       + ep1_payload_size;
+
+       atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+       if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1)
+               && (open_v8.endpoint_id_2 != 0xFFFF)) {
+               ep2_payload.dev_num_channel =
+                       this_adm.num_ec_ref_rx_chans;
+               this_adm.num_ec_ref_rx_chans = 0;
+
+               if (this_adm.ec_ref_rx_bit_width != 0) {
+                       ep2_payload.bit_width =
+                               this_adm.ec_ref_rx_bit_width;
+                       this_adm.ec_ref_rx_bit_width = 0;
+               } else {
+                       ep2_payload.bit_width = bit_width;
+               }
+
+               if (this_adm.ec_ref_rx_sampling_rate != 0) {
+                       ep2_payload.sample_rate =
+                       this_adm.ec_ref_rx_sampling_rate;
+                       this_adm.ec_ref_rx_sampling_rate = 0;
+               } else {
+                       ep2_payload.sample_rate = rate;
+               }
+
+               pr_debug("%s: adm open_v8 eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+                       __func__,
+                       ep2_payload.dev_num_channel,
+                       ep2_payload.bit_width,
+                       ep2_payload.sample_rate);
+
+               ret = adm_arrange_mch_ep2_map_v8(&ep2_payload,
+                       ep2_payload.dev_num_channel);
+
+               if (ret)
+                       return ret;
+               ep2_payload_size = 8 +
+                       roundup(ep2_payload.dev_num_channel, 4);
+               param_size += ep2_payload_size;
+       }
+
+       adm_params = kzalloc(param_size, GFP_KERNEL);
+       if (!adm_params)
+               return -ENOMEM;
+       open_v8.hdr.pkt_size = param_size;
+       memcpy(adm_params, &open_v8, sizeof(open_v8));
+       memcpy(adm_params + sizeof(open_v8),
+                       (void *)&ep1_payload,
+                       ep1_payload_size);
+       memcpy(adm_params + sizeof(open_v8)
+                       + ep1_payload_size,
+                       (void *)&ep2_payload,
+                       ep2_payload_size);
+
+       ret = apr_send_pkt(this_adm.apr,
+                       (uint32_t *)adm_params);
+       kfree(adm_params);
+       return ret;
+}
+
+static int adm_open_v5_v6(int tmp_port, int port_idx, int copp_idx,
+               int flags, int path,
+               int channel_mode, uint16_t bit_width,
+               int rate, int topology,
+               int perf_mode)
+{
+       int ret = 0;
        struct adm_cmd_device_open_v5   open;
        struct adm_cmd_device_open_v6   open_v6;
+
+       memset(&open, 0, sizeof(open));
+       memset(&open_v6, 0, sizeof(open_v6));
+
+       open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                                          APR_HDR_LEN(APR_HDR_SIZE),
+                                          APR_PKT_VER);
+       open.hdr.pkt_size = sizeof(open);
+       open.hdr.src_svc = APR_SVC_ADM;
+       open.hdr.src_domain = APR_DOMAIN_APPS;
+       open.hdr.src_port = tmp_port;
+       open.hdr.dest_svc = APR_SVC_ADM;
+       open.hdr.dest_domain = APR_DOMAIN_ADSP;
+       open.hdr.dest_port = tmp_port;
+       open.hdr.token = port_idx << 16 | copp_idx;
+       open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+       open.flags = flags;
+       open.mode_of_operation = path;
+       open.endpoint_id_1 = tmp_port;
+       open.endpoint_id_2 = 0xFFFF;
+
+       if (this_adm.ec_ref_rx && (path != 1)) {
+               open.endpoint_id_2 = this_adm.ec_ref_rx;
+               this_adm.ec_ref_rx = -1;
+       }
+
+       open.topology_id = topology;
+
+       open.dev_num_channel = channel_mode & 0x00FF;
+       open.bit_width = bit_width;
+       WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
+               (rate != ULL_SUPPORTED_SAMPLE_RATE));
+       open.sample_rate  = rate;
+
+       ret = adm_arrange_mch_map(&open, path, channel_mode);
+
+       if (ret)
+               return ret;
+
+       pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
+               __func__, open.endpoint_id_1, open.sample_rate,
+               open.topology_id);
+
+       atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+       if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
+               (open.endpoint_id_2 != 0xFFFF)) {
+               memset(&open_v6, 0,
+                       sizeof(struct adm_cmd_device_open_v6));
+               memcpy(&open_v6, &open,
+                       sizeof(struct adm_cmd_device_open_v5));
+               open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
+               open_v6.hdr.pkt_size = sizeof(open_v6);
+               open_v6.dev_num_channel_eid2 =
+                       this_adm.num_ec_ref_rx_chans;
+               this_adm.num_ec_ref_rx_chans = 0;
+
+               if (this_adm.ec_ref_rx_bit_width != 0) {
+                       open_v6.bit_width_eid2 =
+                               this_adm.ec_ref_rx_bit_width;
+                       this_adm.ec_ref_rx_bit_width = 0;
+               } else {
+                       open_v6.bit_width_eid2 = bit_width;
+               }
+
+               if (this_adm.ec_ref_rx_sampling_rate != 0) {
+                       open_v6.sample_rate_eid2 =
+                               this_adm.ec_ref_rx_sampling_rate;
+                       this_adm.ec_ref_rx_sampling_rate = 0;
+               } else {
+                       open_v6.sample_rate_eid2 = rate;
+               }
+
+               pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+                       __func__, open_v6.dev_num_channel_eid2,
+                       open_v6.bit_width_eid2,
+                       open_v6.sample_rate_eid2);
+
+               ret = adm_arrange_mch_ep2_map(&open_v6,
+                       open_v6.dev_num_channel_eid2);
+
+               if (ret)
+                       return ret;
+
+               ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
+       } else {
+               ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+       }
+
+       return ret;
+}
+
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
+            int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
+{
        int ret = 0;
        int port_idx, flags;
        int copp_idx = -1;
@@ -2392,89 +2928,20 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
                (uint32_t)this_adm.outband_memmap.size);
                }
        }
-               open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-                                                  APR_HDR_LEN(APR_HDR_SIZE),
-                                                  APR_PKT_VER);
-               open.hdr.pkt_size = sizeof(open);
-               open.hdr.src_svc = APR_SVC_ADM;
-               open.hdr.src_domain = APR_DOMAIN_APPS;
-               open.hdr.src_port = tmp_port;
-               open.hdr.dest_svc = APR_SVC_ADM;
-               open.hdr.dest_domain = APR_DOMAIN_ADSP;
-               open.hdr.dest_port = tmp_port;
-               open.hdr.token = port_idx << 16 | copp_idx;
-               open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
-               open.flags = flags;
-               open.mode_of_operation = path;
-               open.endpoint_id_1 = tmp_port;
-               open.endpoint_id_2 = 0xFFFF;
-
-               if (this_adm.ec_ref_rx && (path != 1)) {
-                       open.endpoint_id_2 = this_adm.ec_ref_rx;
-                       this_adm.ec_ref_rx = -1;
-               }
 
-               open.topology_id = topology;
-
-               open.dev_num_channel = channel_mode & 0x00FF;
-               open.bit_width = bit_width;
-               WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
-                       (rate != ULL_SUPPORTED_SAMPLE_RATE));
-               open.sample_rate  = rate;
-
-               ret = adm_arrange_mch_map(&open, path, channel_mode);
-
-               if (ret)
-                       return ret;
-
-               pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
-                       __func__, open.endpoint_id_1, open.sample_rate,
-                       open.topology_id);
-
-               atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
-
-               if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
-                       (open.endpoint_id_2 != 0xFFFF)) {
-                       memset(&open_v6, 0,
-                               sizeof(struct adm_cmd_device_open_v6));
-                       memcpy(&open_v6, &open,
-                               sizeof(struct adm_cmd_device_open_v5));
-                       open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
-                       open_v6.hdr.pkt_size = sizeof(open_v6);
-                       open_v6.dev_num_channel_eid2 =
-                               this_adm.num_ec_ref_rx_chans;
-                       this_adm.num_ec_ref_rx_chans = 0;
-
-                       if (this_adm.ec_ref_rx_bit_width != 0) {
-                               open_v6.bit_width_eid2 =
-                                       this_adm.ec_ref_rx_bit_width;
-                               this_adm.ec_ref_rx_bit_width = 0;
-                       } else {
-                               open_v6.bit_width_eid2 = bit_width;
-                       }
-
-                       if (this_adm.ec_ref_rx_sampling_rate != 0) {
-                               open_v6.sample_rate_eid2 =
-                                       this_adm.ec_ref_rx_sampling_rate;
-                               this_adm.ec_ref_rx_sampling_rate = 0;
-                       } else {
-                               open_v6.sample_rate_eid2 = rate;
-                       }
-
-                       pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
-                               __func__, open_v6.dev_num_channel_eid2,
-                               open_v6.bit_width_eid2,
-                               open_v6.sample_rate_eid2);
-
-                       ret = adm_arrange_mch_ep2_map(&open_v6,
-                               open_v6.dev_num_channel_eid2);
-
-                       if (ret)
-                               return ret;
-
-                       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
+               if (adm_get_svc_version(APR_SVC_ADM) >=
+                       ADSP_ADM_API_VERSION_V3) {
+                       ret = adm_open_v8(tmp_port, port_idx, copp_idx,
+                                       flags, path,
+                                       channel_mode, bit_width,
+                                       rate, topology,
+                                       perf_mode);
                } else {
-                       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+                       ret = adm_open_v5_v6(tmp_port, port_idx, copp_idx,
+                                       flags, path,
+                                       channel_mode, bit_width,
+                                       rate, topology,
+                                       perf_mode);
                }
                if (ret < 0) {
                        pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
@@ -2861,6 +3328,13 @@ void adm_ec_ref_rx_sampling_rate(int sampling_rate)
                __func__, this_adm.ec_ref_rx_sampling_rate);
 }
 
+void adm_set_native_mode(int mode)
+{
+       this_adm.native_mode = mode;
+       pr_debug("%s: enable native_mode :%d\n",
+               __func__, this_adm.native_mode);
+}
+
 int adm_close(int port_id, int perf_mode, int copp_idx)
 {
        struct apr_hdr close;
index 9e14b34..e9592cf 100644 (file)
@@ -195,6 +195,39 @@ static int is_adsp_raise_event(uint32_t cmd)
        return -EINVAL;
 }
 
+int q6asm_get_svc_version(uint32_t service_id)
+{
+       int ret = 0;
+       static int asm_cached_version;
+       size_t ver_size;
+       struct avcs_fwk_ver_info *ver_info = NULL;
+
+       if (service_id == AVCS_SERVICE_ID_ALL) {
+               pr_err("%s: Invalid service id: %d", __func__,
+                                       AVCS_SERVICE_ID_ALL);
+               return -EINVAL;
+       }
+
+       if (asm_cached_version != 0)
+               return asm_cached_version;
+
+       ver_size = sizeof(struct avcs_get_fwk_version) +
+                       sizeof(struct avs_svc_api_info);
+       ver_info = kzalloc(ver_size, GFP_KERNEL);
+       if (ver_info == NULL)
+               return -ENOMEM;
+
+       ret = q6core_get_service_version(service_id, ver_info, ver_size);
+       if (ret < 0)
+               goto done;
+
+       ret = ver_info->services[0].api_version;
+       asm_cached_version = ret;
+done:
+       kfree(ver_info);
+       return ret;
+}
+
 static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
                                           int flag, int flag_offset)
 {
@@ -228,6 +261,9 @@ static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver)
        uint32_t pcm_format_id;
 
        switch (media_format_block_ver) {
+       case PCM_MEDIA_FORMAT_V5:
+               pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V5;
+               break;
        case PCM_MEDIA_FORMAT_V4:
                pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4;
                break;
@@ -2869,6 +2905,23 @@ int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
 }
 EXPORT_SYMBOL(q6asm_open_read_v4);
 
+/*
+ * asm_open_read_v5 - Opens audio capture session
+ *
+ * @ac: Client session handle
+ * @format: encoder format
+ * @bits_per_sample: bit width of capture session
+ * @ts_mode: timestamp mode
+ */
+int q6asm_open_read_v5(struct audio_client *ac, uint32_t format,
+                       uint16_t bits_per_sample, bool ts_mode)
+{
+       return __q6asm_open_read(ac, format, bits_per_sample,
+                                PCM_MEDIA_FORMAT_V5 /*media fmt block ver*/,
+                                ts_mode);
+}
+EXPORT_SYMBOL(q6asm_open_read_v5);
+
 int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
                                uint32_t passthrough_flag)
 {
@@ -3172,6 +3225,22 @@ int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
 }
 EXPORT_SYMBOL(q6asm_open_write_v4);
 
+/*
+ * q6asm_open_write_v5 - Opens audio playback session
+ *
+ * @ac: Client session handle
+ * @format: decoder format
+ * @bits_per_sample: bit width of playback session
+ */
+int q6asm_open_write_v5(struct audio_client *ac, uint32_t format,
+                       uint16_t bits_per_sample)
+{
+       return __q6asm_open_write(ac, format, bits_per_sample,
+                                 ac->stream_id, false /*gapless*/,
+                                 PCM_MEDIA_FORMAT_V5 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_open_write_v5);
+
 int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
                               uint16_t bits_per_sample, int32_t stream_id,
                               bool is_gapless_mode)
@@ -4239,6 +4308,108 @@ fail_cmd:
 }
 
 /*
+ * q6asm_enc_cfg_blk_pcm_v5 - sends encoder configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map  to be used
+ * @use_back_flavor: to configure back left and right channel
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+static int q6asm_enc_cfg_blk_pcm_v5(struct audio_client *ac,
+                            uint32_t rate, uint32_t channels,
+                            uint16_t bits_per_sample, bool use_default_chmap,
+                            bool use_back_flavor, u8 *channel_map,
+                            uint16_t sample_word_size, uint16_t endianness,
+                            uint16_t mode)
+{
+       struct asm_multi_channel_pcm_enc_cfg_v5 enc_cfg;
+       struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
+       u8 *channel_mapping;
+       u32 frames_per_buf = 0;
+       int rc;
+
+       if (!use_default_chmap && (channel_map == NULL)) {
+               pr_err("%s: No valid chan map and can't use default\n",
+                               __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+                ac->session, rate, channels,
+                bits_per_sample, sample_word_size);
+
+       memset(&enc_cfg, 0, sizeof(enc_cfg));
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+       atomic_set(&ac->cmd_state, -1);
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+       enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+                                   sizeof(enc_cfg.encdec);
+       enc_cfg.encblk.frames_per_buf = frames_per_buf;
+       enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+                                         sizeof(enc_fg_blk);
+       enc_cfg.num_channels = channels;
+       enc_cfg.bits_per_sample = bits_per_sample;
+       enc_cfg.sample_rate = rate;
+       enc_cfg.is_signed = 1;
+       enc_cfg.sample_word_size = sample_word_size;
+       enc_cfg.endianness = endianness;
+       enc_cfg.mode = mode;
+       channel_mapping = enc_cfg.channel_mapping;
+
+       memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V2);
+
+       if (use_default_chmap) {
+               pr_debug("%s: setting default channel map for %d channels",
+                        __func__, channels);
+               if (q6asm_map_channels(channel_mapping, channels,
+                                       use_back_flavor)) {
+                       pr_err("%s: map channels failed %d\n",
+                              __func__, channels);
+                       rc = -EINVAL;
+                       goto fail_cmd;
+               }
+       } else {
+               pr_debug("%s: Using pre-defined channel map", __func__);
+               memcpy(channel_mapping, channel_map,
+                       PCM_FORMAT_MAX_NUM_CHANNEL_V2);
+       }
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("%s: Command open failed %d\n", __func__, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout opcode[0x%x]\n",
+                      __func__, enc_cfg.hdr.opcode);
+               rc = -ETIMEDOUT;
+               goto fail_cmd;
+       }
+       if (atomic_read(&ac->cmd_state) > 0) {
+               pr_err("%s: DSP returned error[%s]\n",
+                      __func__, adsp_err_get_err_str(
+                      atomic_read(&ac->cmd_state)));
+               rc = adsp_err_get_lnx_err_code(
+                               atomic_read(&ac->cmd_state));
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return rc;
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v5);
+
+/*
  * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
  *
  * @ac: Client session handle
@@ -4516,6 +4687,18 @@ fail_cmd:
        return rc;
 }
 
+static int __q6asm_enc_cfg_blk_pcm_v5(struct audio_client *ac,
+                                     uint32_t rate, uint32_t channels,
+                                     uint16_t bits_per_sample,
+                                     uint16_t sample_word_size,
+                                     uint16_t endianness,
+                                     uint16_t mode)
+{
+       return q6asm_enc_cfg_blk_pcm_v5(ac, rate, channels,
+                                       bits_per_sample, true, false, NULL,
+                                       sample_word_size, endianness, mode);
+}
+
 static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
                                      uint32_t rate, uint32_t channels,
                                      uint16_t bits_per_sample,
@@ -4602,6 +4785,31 @@ int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
 }
 EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
 
+/*
+ * q6asm_enc_cfg_blk_pcm_format_support_v5 - sends encoder configuration
+ *                                           parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_enc_cfg_blk_pcm_format_support_v5(struct audio_client *ac,
+                                           uint32_t rate, uint32_t channels,
+                                           uint16_t bits_per_sample,
+                                           uint16_t sample_word_size,
+                                           uint16_t endianness,
+                                           uint16_t mode)
+{
+        return __q6asm_enc_cfg_blk_pcm_v5(ac, rate, channels,
+                                          bits_per_sample, sample_word_size,
+                                          endianness, mode);
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v5);
+
 int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
                        uint32_t rate, uint32_t channels)
 {
@@ -4727,6 +4935,67 @@ static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
                lchannel_mapping[5] = PCM_CHANNEL_RB;
                lchannel_mapping[6] = PCM_CHANNEL_LS;
                lchannel_mapping[7] = PCM_CHANNEL_RS;
+       } else if (channels == 10) {
+               lchannel_mapping[0] = PCM_CHANNEL_FL;
+               lchannel_mapping[1] = PCM_CHANNEL_FR;
+               lchannel_mapping[2] = PCM_CHANNEL_LFE;
+               lchannel_mapping[3] = PCM_CHANNEL_FC;
+               lchannel_mapping[4] = PCM_CHANNEL_LS;
+               lchannel_mapping[5] = PCM_CHANNEL_RS;
+               lchannel_mapping[6] = PCM_CHANNEL_LB;
+               lchannel_mapping[7] = PCM_CHANNEL_RB;
+               lchannel_mapping[8] = PCM_CHANNEL_CS;
+               lchannel_mapping[9] = PCM_CHANNELS;
+       } else if (channels == 16) {
+               lchannel_mapping[0] = PCM_CHANNEL_FL;
+               lchannel_mapping[1] = PCM_CHANNEL_FR;
+               lchannel_mapping[2] = PCM_CHANNEL_LFE;
+               lchannel_mapping[3] = PCM_CHANNEL_FC;
+               lchannel_mapping[4] = PCM_CHANNEL_LS;
+               lchannel_mapping[5] = PCM_CHANNEL_RS;
+               lchannel_mapping[6] = PCM_CHANNEL_LB;
+               lchannel_mapping[7] = PCM_CHANNEL_RB;
+               lchannel_mapping[8] = PCM_CHANNEL_CS;
+               lchannel_mapping[9] = PCM_CHANNELS;
+               lchannel_mapping[10] = PCM_CHANNEL_CVH;
+               lchannel_mapping[11] = PCM_CHANNEL_MS;
+               lchannel_mapping[12] = PCM_CHANNEL_FLC;
+               lchannel_mapping[13] = PCM_CHANNEL_FRC;
+               lchannel_mapping[14] = PCM_CHANNEL_RLC;
+               lchannel_mapping[15] = PCM_CHANNEL_RRC;
+       } else if (channels == 32) {
+               lchannel_mapping[0] = PCM_CHANNEL_FL;
+               lchannel_mapping[1] = PCM_CHANNEL_FR;
+               lchannel_mapping[2] = PCM_CHANNEL_LFE;
+               lchannel_mapping[3] = PCM_CHANNEL_FC;
+               lchannel_mapping[4] = PCM_CHANNEL_LS;
+               lchannel_mapping[5] = PCM_CHANNEL_RS;
+               lchannel_mapping[6] = PCM_CHANNEL_LB;
+               lchannel_mapping[7] = PCM_CHANNEL_RB;
+               lchannel_mapping[8] = PCM_CHANNEL_CS;
+               lchannel_mapping[9] = PCM_CHANNELS;
+               lchannel_mapping[10] = PCM_CHANNEL_CVH;
+               lchannel_mapping[11] = PCM_CHANNEL_MS;
+               lchannel_mapping[12] = PCM_CHANNEL_FLC;
+               lchannel_mapping[13] = PCM_CHANNEL_FRC;
+               lchannel_mapping[14] = PCM_CHANNEL_RLC;
+               lchannel_mapping[15] = PCM_CHANNEL_RRC;
+               lchannel_mapping[16] = PCM_CHANNEL_LFE2;
+               lchannel_mapping[17] = PCM_CHANNEL_SL;
+               lchannel_mapping[18] = PCM_CHANNEL_SR;
+               lchannel_mapping[19] = PCM_CHANNEL_TFL;
+               lchannel_mapping[20] = PCM_CHANNEL_TFR;
+               lchannel_mapping[21] = PCM_CHANNEL_TC;
+               lchannel_mapping[22] = PCM_CHANNEL_TBL;
+               lchannel_mapping[23] = PCM_CHANNEL_TBR;
+               lchannel_mapping[24] = PCM_CHANNEL_TSL;
+               lchannel_mapping[25] = PCM_CHANNEL_TSR;
+               lchannel_mapping[26] = PCM_CHANNEL_TBC;
+               lchannel_mapping[27] = PCM_CHANNEL_BFC;
+               lchannel_mapping[28] = PCM_CHANNEL_BFL;
+               lchannel_mapping[29] = PCM_CHANNEL_BFR;
+               lchannel_mapping[30] = PCM_CHANNEL_LW;
+               lchannel_mapping[31] = PCM_CHANNEL_RW;
        } else {
                pr_err("%s: ERROR.unsupported num_ch = %u\n",
                 __func__, channels);
@@ -5647,6 +5916,79 @@ fail_cmd:
        return rc;
 }
 
+static int __q6asm_media_format_block_multi_ch_pcm_v5(struct audio_client *ac,
+                                                     uint32_t rate,
+                                                     uint32_t channels,
+                                                     bool use_default_chmap,
+                                                     char *channel_map,
+                                                     uint16_t bits_per_sample,
+                                                     uint16_t sample_word_size,
+                                                     uint16_t endianness,
+                                                     uint16_t mode)
+{
+       struct asm_multi_channel_pcm_fmt_blk_param_v5 fmt;
+       u8 *channel_mapping;
+       int rc;
+
+       pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+                ac->session, rate, channels,
+                bits_per_sample, sample_word_size);
+
+       memset(&fmt, 0, sizeof(fmt));
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+       atomic_set(&ac->cmd_state, -1);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+       fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+                                       sizeof(fmt.fmt_blk);
+       fmt.param.num_channels = channels;
+       fmt.param.bits_per_sample = bits_per_sample;
+       fmt.param.sample_rate = rate;
+       fmt.param.is_signed = 1;
+       fmt.param.sample_word_size = sample_word_size;
+       fmt.param.endianness = endianness;
+       fmt.param.mode = mode;
+       channel_mapping = fmt.param.channel_mapping;
+
+       memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V2);
+
+       if (use_default_chmap) {
+               if (q6asm_map_channels(channel_mapping, channels, false)) {
+                       pr_err("%s: map channels failed %d\n",
+                              __func__, channels);
+                       rc = -EINVAL;
+                       goto fail_cmd;
+               }
+       } else {
+               memcpy(channel_mapping, channel_map,
+                        PCM_FORMAT_MAX_NUM_CHANNEL_V2);
+       }
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout. waited for format update\n", __func__);
+               rc = -ETIMEDOUT;
+               goto fail_cmd;
+       }
+       if (atomic_read(&ac->cmd_state) > 0) {
+               pr_err("%s: DSP returned error[%s]\n",
+                      __func__, adsp_err_get_err_str(
+                      atomic_read(&ac->cmd_state)));
+               rc = adsp_err_get_lnx_err_code(
+                               atomic_read(&ac->cmd_state));
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return rc;
+}
+
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
                uint32_t rate, uint32_t channels,
                bool use_default_chmap, char *channel_map)
@@ -5727,6 +6069,40 @@ int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
 EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
 
 /*
+ * q6asm_media_format_block_multi_ch_pcm_v5 - sends pcm decoder configuration
+ *                                            parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map  to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_media_format_block_multi_ch_pcm_v5(struct audio_client *ac,
+                                            uint32_t rate, uint32_t channels,
+                                            bool use_default_chmap,
+                                            char *channel_map,
+                                            uint16_t bits_per_sample,
+                                            uint16_t sample_word_size,
+                                            uint16_t endianness,
+                                            uint16_t mode)
+{
+       return __q6asm_media_format_block_multi_ch_pcm_v5(ac, rate, channels,
+                                                         use_default_chmap,
+                                                         channel_map,
+                                                         bits_per_sample,
+                                                         sample_word_size,
+                                                         endianness,
+                                                         mode);
+}
+EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v5);
+
+
+/*
  * q6asm_media_format_block_gen_compr - set up generic compress format params
  *
  * @ac: Client session handle
index a64cfa0..ec018c2 100644 (file)
@@ -108,8 +108,7 @@ static int parse_fwk_version_info(uint32_t *payload)
         */
        ver_size = sizeof(struct avcs_get_fwk_version) +
                   num_services * sizeof(struct avs_svc_api_info);
-       if (q6core_lcl.q6core_avcs_ver_info.ver_info != NULL)
-               pr_warn("%s: Version info is not NULL\n", __func__);
+
        q6core_lcl.q6core_avcs_ver_info.ver_info =
                kzalloc(ver_size, GFP_ATOMIC);
        if (q6core_lcl.q6core_avcs_ver_info.ver_info == NULL)
@@ -244,12 +243,16 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
                pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
                         __func__);
                payload1 = data->payload;
-               q6core_lcl.q6core_avcs_ver_info.status = VER_QUERY_SUPPORTED;
-               q6core_lcl.avcs_fwk_ver_resp_received = 1;
                ret = parse_fwk_version_info(payload1);
-               if (ret < 0)
+               if (ret < 0) {
+                       q6core_lcl.adsp_status = ret;
                        pr_err("%s: Failed to parse payload:%d\n",
                               __func__, ret);
+               } else {
+                       q6core_lcl.q6core_avcs_ver_info.status =
+                                               VER_QUERY_SUPPORTED;
+               }
+               q6core_lcl.avcs_fwk_ver_resp_received = 1;
                wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
                break;
        default:
@@ -449,8 +452,14 @@ size_t q6core_get_fwk_version_size(uint32_t service_id)
        if (ret)
                goto done;
 
-       num_services = q6core_lcl.q6core_avcs_ver_info.ver_info
-                              ->avcs_fwk_version.num_services;
+       if (q6core_lcl.q6core_avcs_ver_info.ver_info != NULL) {
+               num_services = q6core_lcl.q6core_avcs_ver_info.ver_info
+                                       ->avcs_fwk_version.num_services;
+       } else {
+               pr_err("%s: ver_info is NULL\n", __func__);
+               ret = -EINVAL;
+               goto done;
+       }
 
        ret = sizeof(struct avcs_get_fwk_version);
        if (service_id == AVCS_SERVICE_ID_ALL)