clear-pkgs-linux-iot-lts2018/0366-ASoC-Intel-Skylake-Add...

346 lines
11 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Paul, Subhankar" <subhankar.paul@intel.com>
Date: Tue, 8 Aug 2017 22:46:45 +0530
Subject: [PATCH] ASoC: Intel: Skylake: Add support for module notifications
Firmware modules can send asynchronous notification to driver
with event data as payload. Add support for notifying user of such
asynchronous notifications from firmware modules by adding
kcontrols. These kcontrols have the module event data that needs to be
sent to user.
Change-Id: If204e275a9613c769cf00fe632e45b174bd2fa2f
Signed-off-by: Mohit Sinha <mohit.sinha@intel.com>
Reviewed-on:
Reviewed-by: Shaik, Kareem M <kareem.m.shaik@intel.com>
Reviewed-by: Kesapragada, Pardha Saradhi <pardha.saradhi.kesapragada@intel.com>
Reviewed-by: Paul, Subhankar <subhankar.paul@intel.com>
Reviewed-by: Koul, Vinod <vinod.koul@intel.com>
Reviewed-by: audio_build
Tested-by: Avati, Santosh Kumar <santosh.kumar.avati@intel.com>
---
sound/soc/intel/skylake/skl-messages.c | 2 +
sound/soc/intel/skylake/skl-sst-dsp.h | 1 +
sound/soc/intel/skylake/skl-sst-ipc.c | 58 +++++++++++++-
sound/soc/intel/skylake/skl-sst-ipc.h | 9 +++
sound/soc/intel/skylake/skl-topology.c | 107 +++++++++++++++++++++++++
sound/soc/intel/skylake/skl-topology.h | 8 ++
sound/soc/intel/skylake/skl.c | 2 +
7 files changed, 186 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 9d413b8..ea500be 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -1224,6 +1224,8 @@ int skl_init_dsp(struct skl *skl)
dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
+ INIT_LIST_HEAD(&skl->skl_sst->notify_kctls);
+
/* Set DMA clock controls */
ret = skl_dsp_set_dma_clk_controls(skl->skl_sst);
if (ret < 0)
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 6736c89..207bf3f 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -241,6 +241,7 @@ struct skl_notify_data {
u32 type;
u32 length;
struct skl_tcn_events tcn_data;
+ char data[0];
};
struct skl_dsp_notify_ops {
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index cfdf2ce..5a8766a 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -198,6 +198,8 @@
#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \
<< IPC_D0IX_STREAMING_SHIFT)
+/* Offset to get the event data for module notification */
+#define MOD_DATA_OFFSET 12
enum skl_ipc_msg_target {
IPC_FW_GEN_MSG = 0,
@@ -274,7 +276,8 @@ enum skl_ipc_notification_type {
IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7,
IPC_GLB_NOTIFY_FW_READY = 8,
IPC_GLB_NOTIFY_FW_AUD_CLASS_RESULT = 9,
- IPC_GLB_NOTIFY_EXCEPTION_CAUGHT = 10
+ IPC_GLB_NOTIFY_EXCEPTION_CAUGHT = 10,
+ IPC_GLB_MODULE_NOTIFICATION = 12
};
/* Module Message Types */
@@ -355,6 +358,51 @@ static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
}
+static int skl_process_module_notification(struct skl_sst *skl)
+{
+ struct skl_notify_data *notify_data;
+ struct skl_module_notify mod_notif;
+ u32 notify_data_sz;
+ char *module_data;
+
+ dev_dbg(skl->dev, "***** Module Notification ******\n");
+ /* read module notification structure from mailbox */
+ sst_dsp_inbox_read(skl->dsp, &mod_notif,
+ sizeof(struct skl_module_notify));
+
+ notify_data_sz = sizeof(mod_notif) + mod_notif.event_data_size;
+ notify_data = kzalloc((sizeof(*notify_data) + notify_data_sz),
+ GFP_KERNEL);
+
+ if (!notify_data)
+ return -ENOMEM;
+
+ /* read the complete notification message */
+ sst_dsp_inbox_read(skl->dsp, notify_data->data, notify_data_sz);
+
+ notify_data->length = notify_data_sz;
+ notify_data->type = 0xFF;
+
+ /* Module notification data to console */
+ dev_dbg(skl->dev, "Module Id = %#x\n",
+ (mod_notif.unique_id >> 16));
+ dev_dbg(skl->dev, "Instanse Id = %#x\n",
+ (mod_notif.unique_id & 0x0000FFFF));
+ dev_dbg(skl->dev, "Data Size = %d bytes\n",
+ mod_notif.event_data_size);
+
+ module_data = notify_data->data;
+
+ print_hex_dump(KERN_DEBUG, "DATA: ", MOD_DATA_OFFSET, 8, 4,
+ module_data, notify_data->length, false);
+
+ skl->notify_ops.notify_cb(skl, IPC_GLB_MODULE_NOTIFICATION,
+ notify_data);
+ kfree(notify_data);
+
+ return 0;
+}
+
static void
skl_process_log_buffer(struct sst_dsp *sst, struct skl_ipc_header header)
{
@@ -455,6 +503,14 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
}
break;
+ case IPC_GLB_MODULE_NOTIFICATION:
+ ret = skl_process_module_notification(skl);
+ if (ret < 0) {
+ dev_err(ipc->dev,
+ "Module Notification read fail:%d\n", ret);
+ return ret;
+ }
+ break;
default:
dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n",
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index bc083b0..5db66e2 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -29,6 +29,7 @@ struct sst_generic_ipc;
#define NO_OF_INJECTOR 6
#define NO_OF_EXTRACTOR 8
#define FW_REG_SZ 1024
+#define SKL_EVENT_GLB_MODULE_NOTIFICATION 12
#define SKL_TPLG_CHG_NOTIFY 3
enum skl_ipc_pipeline_state {
@@ -244,6 +245,12 @@ struct skl_hw_property_info {
u32 ebb_size_bytes;
};
+struct skl_notify_kctrl_info {
+ struct list_head list;
+ u32 notify_id;
+ struct snd_kcontrol *notify_kctl;
+};
+
struct skl_sst {
struct device *dev;
struct sst_dsp *dsp;
@@ -313,6 +320,8 @@ struct skl_sst {
struct skl_sysfs_tree *sysfs_tree;
struct snd_kcontrol *kcontrol;
+
+ struct list_head notify_kctls;
};
struct skl_ipc_init_instance_msg {
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index f1d3518..bf93980 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -2642,6 +2642,96 @@ int skl_tplg_be_update_params(struct snd_soc_dai *dai,
return 0;
}
+/*
+ * This function searches notification kcontrol list present in skl_sst
+ * context against unique notify_id and returns kcontrol pointer if match
+ * found.
+ */
+struct snd_kcontrol *skl_search_notify_kctl(struct skl_sst *skl,
+ u32 notify_id)
+{
+ struct skl_notify_kctrl_info *kctl_info;
+
+ list_for_each_entry(kctl_info, &skl->notify_kctls, list) {
+ if (notify_id == kctl_info->notify_id)
+ return kctl_info->notify_kctl;
+ }
+ return NULL;
+}
+
+/*
+ * This function creates notification kcontrol list by searching control
+ * list present in snd_card context. It compares kcontrol name with specific
+ * string "notify params" to get notification kcontrols and add it up to the
+ * notification list present in skl_sst context.
+ * NOTE: To use module notification feature, new kcontrol named "notify" should
+ * be added in topology XML for that particular module.
+ */
+int skl_create_notify_kctl_list(struct skl_sst *skl_sst,
+ struct snd_card *card)
+{
+ struct snd_kcontrol *kctl;
+ struct snd_soc_dapm_widget *w;
+ struct skl_module_cfg *mconfig;
+ struct skl_notify_kctrl_info *info;
+ u32 size = sizeof(*info);
+
+ list_for_each_entry(kctl, &card->controls, list) {
+ if (strnstr(kctl->id.name, "notify params",
+ strlen(kctl->id.name))) {
+ info = kzalloc(size, GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ w = snd_soc_dapm_kcontrol_widget(kctl);
+ mconfig = w->priv;
+
+ /* Module ID (MS word) + Module Instance ID (LS word) */
+ info->notify_id = ((mconfig->id.module_id << 16) |
+ (mconfig->id.instance_id));
+ info->notify_kctl = kctl;
+
+ list_add_tail(&info->list, &skl_sst->notify_kctls);
+ }
+ }
+ return 0;
+}
+
+/*
+ * This function deletes notification kcontrol list from skl_sst
+ * context.
+ */
+void skl_delete_notify_kctl_list(struct skl_sst *skl_sst)
+{
+ struct skl_notify_kctrl_info *info, *tmp;
+
+ list_for_each_entry_safe(info, tmp, &skl_sst->notify_kctls, list) {
+ list_del(&info->list);
+ kfree(info);
+ }
+}
+
+/*
+ * This function creates notification kcontrol list on first module
+ * notification from firmware. It also search notification kcontrol
+ * list against unique notify_id sent from firmware and returns the
+ * corresponding kcontrol pointer.
+ */
+struct snd_kcontrol *skl_get_notify_kcontrol(struct skl_sst *skl,
+ struct snd_card *card, u32 notify_id)
+{
+ struct snd_kcontrol *kctl = NULL;
+
+ if (list_empty(&skl->notify_kctls))
+ skl_create_notify_kctl_list(skl, card);
+
+ kctl = skl_search_notify_kctl(skl, notify_id);
+
+ return kctl;
+}
+
+
+
/*
* Get the events along with data stored in notify_data and pass
* to kcontrol private data.
@@ -2683,7 +2773,24 @@ int skl_dsp_cb_event(struct skl_sst *ctx, unsigned int event,
snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
&ctx->kcontrol->id);
break;
+ case SKL_EVENT_GLB_MODULE_NOTIFICATION:
+ m_notification = (struct skl_module_notify *)notify_data->data;
+ card = component->card;
+ ctx->kcontrol = skl_get_notify_kcontrol(ctx, card->snd_card,
+ m_notification->unique_id);
+ if (!ctx->kcontrol) {
+ dev_dbg(ctx->dev, "Module notify control not found\n");
+ return -EINVAL;
+ }
+ sb = (struct soc_bytes_ext *)ctx->kcontrol->private_value;
+ bc = (struct skl_algo_data *)sb->dobj.private;
+ param_length = sizeof(struct skl_notify_data)
+ + notify_data->length;
+ memcpy(bc->params, (char *)notify_data, param_length);
+ snd_ctl_notify(card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &ctx->kcontrol->id);
+ break;
default:
return -EINVAL;
}
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index ce40696..4c09a08 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -617,4 +617,12 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx);
int skl_tplg_change_notification_get(struct snd_kcontrol *kcontrol,
unsigned int __user *data, unsigned int size);
+struct snd_kcontrol *skl_search_notify_kctl(struct skl_sst *skl,
+ u32 notify_id);
+int skl_create_notify_kctl_list(struct skl_sst *skl_sst,
+ struct snd_card *card);
+void skl_delete_notify_kctl_list(struct skl_sst *skl_sst);
+struct snd_kcontrol *skl_get_notify_kcontrol(struct skl_sst *skl,
+ struct snd_card *card, u32 notify_id);
+
#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 4b18925..6897be8 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -37,6 +37,7 @@
#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
+#include "skl-topology.h"
/*
* initialize the PCI registers
@@ -1091,6 +1092,7 @@ static void skl_remove(struct pci_dev *pci)
struct hdac_bus *bus = pci_get_drvdata(pci);
struct skl *skl = bus_to_skl(bus);
+ skl_delete_notify_kctl_list(skl->skl_sst);
release_firmware(skl->tplg);
pm_runtime_get_noresume(&pci->dev);
--
https://clearlinux.org