346 lines
11 KiB
Diff
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
|
|
|