All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/8] ASoC: Intel: add function to load firmware image
@ 2015-03-10  2:41 han.lu
  2015-03-10  2:41 ` [PATCH v2 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Add a general method to load firmware image, and apply to base firmware
image loading. With the method, the driver will support loading multiple
different modules in order to support different features.

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
index b9da030..396d545 100644
--- a/sound/soc/intel/sst-dsp-priv.h
+++ b/sound/soc/intel/sst-dsp-priv.h
@@ -173,6 +173,16 @@ struct sst_module_runtime_context {
 };
 
 /*
+ * Audio DSP Module State
+ */
+enum sst_module_state {
+	SST_MODULE_STATE_UNLOADED = 0,	/* default state */
+	SST_MODULE_STATE_LOADED,
+	SST_MODULE_STATE_INITIALIZED,	/* and inactive */
+	SST_MODULE_STATE_ACTIVE,
+};
+
+/*
  * Audio DSP Generic Module.
  *
  * Each Firmware file can consist of 1..N modules. A module can span multiple
@@ -203,6 +213,9 @@ struct sst_module {
 	struct list_head list;		/* DSP list of modules */
 	struct list_head list_fw;	/* FW list of modules */
 	struct list_head runtime_list;	/* list of runtime module objects*/
+
+	/* state */
+	enum sst_module_state state;
 };
 
 /*
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
index 5f71ef6..5e58008 100644
--- a/sound/soc/intel/sst-firmware.c
+++ b/sound/soc/intel/sst-firmware.c
@@ -498,6 +498,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw,
 	sst_module->scratch_size = template->scratch_size;
 	sst_module->persistent_size = template->persistent_size;
 	sst_module->entry = template->entry;
+	sst_module->state = SST_MODULE_STATE_UNLOADED;
 
 	INIT_LIST_HEAD(&sst_module->block_list);
 	INIT_LIST_HEAD(&sst_module->runtime_list);
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
index 402b728..8ad733b 100644
--- a/sound/soc/intel/sst-haswell-dsp.c
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -169,6 +169,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
 
 		block = (void *)block + sizeof(*block) + block->size;
 	}
+	mod->state = SST_MODULE_STATE_LOADED;
 
 	return 0;
 }
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index 863a9ca..ec688f5 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -1844,6 +1844,8 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw)
 	if (ret < 0)
 		dev_err(dev, "error: audio DSP boot failure\n");
 
+	sst_hsw_init_module_state(hsw);
+
 	ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
 		msecs_to_jiffies(IPC_BOOT_MSECS));
 	if (ret == 0) {
@@ -1886,6 +1888,74 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
 	return hsw->dsp;
 }
 
+void sst_hsw_init_module_state(struct sst_hsw *hsw)
+{
+	struct sst_module *module;
+	enum sst_hsw_module_id id;
+
+	/* the base fw contains several modules */
+	for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) {
+		module = sst_module_get_from_id(hsw->dsp, id);
+		if (module)
+			module->state = SST_MODULE_STATE_ACTIVE;
+	}
+}
+
+int sst_hsw_module_load(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id, char *name)
+{
+	int ret = 0;
+	const struct firmware *fw = NULL;
+	struct sst_fw *hsw_sst_fw;
+	struct sst_module *module;
+	struct device *dev = hsw->dev;
+	struct sst_dsp *dsp = hsw->dsp;
+
+	dev_dbg(dev, "sst_hsw_module_load id=%d, name='%s'", module_id, name);
+
+	module = sst_module_get_from_id(dsp, module_id);
+	if (module == NULL) {
+		/* loading for the first time */
+		if (module_id == SST_HSW_MODULE_BASE_FW) {
+			/* for base module: use fw requested in acpi probe */
+			fw = dsp->pdata->fw;
+			if (!fw) {
+				dev_err(dev, "request Base fw failed\n");
+				return -ENODEV;
+			}
+		} else {
+			/* try and load any other optional modules if they are
+			 * available. Use dev_info instead of dev_err in case
+			 * request firmware failed */
+			ret = request_firmware(&fw, name, dev);
+			if (ret) {
+				dev_info(dev, "fw image %s not available(%d)\n",
+						name, ret);
+				return ret;
+			}
+		}
+		hsw_sst_fw = sst_fw_new(dsp, fw, hsw);
+		if (hsw_sst_fw  == NULL) {
+			dev_err(dev, "error: failed to load firmware\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+		module = sst_module_get_from_id(dsp, module_id);
+		if (module == NULL) {
+			dev_err(dev, "error: no module %d in firmware %s\n",
+					module_id, name);
+		}
+	} else
+		dev_info(dev, "module %d (%s) already loaded\n",
+				module_id, name);
+out:
+	/* release fw, but base fw should be released by acpi driver */
+	if (fw && module_id != SST_HSW_MODULE_BASE_FW)
+		release_firmware(fw);
+
+	return ret;
+}
+
 static struct sst_dsp_device hsw_dev = {
 	.thread = hsw_irq_thread,
 	.ops = &haswell_ops,
@@ -1947,12 +2017,10 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
 	/* keep the DSP in reset state for base FW loading */
 	sst_dsp_reset(hsw->dsp);
 
-	hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
-	if (hsw->sst_fw == NULL) {
-		ret = -ENODEV;
-		dev_err(dev, "error: failed to load firmware\n");
+	/* load base module and other modules in base firmware image */
+	ret = sst_hsw_module_load(hsw, SST_HSW_MODULE_BASE_FW, 0, "Base");
+	if (ret < 0)
 		goto fw_err;
-	}
 
 	/* allocate scratch mem regions */
 	ret = sst_block_alloc_scratch(hsw->dsp);
@@ -1971,6 +2039,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
 		goto boot_err;
 	}
 
+	/* init module state after boot */
+	sst_hsw_init_module_state(hsw);
+
 	/* get the FW version */
 	sst_hsw_fw_get_version(hsw, &version);
 
@@ -1986,7 +2057,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
 
 boot_err:
 	sst_dsp_reset(hsw->dsp);
-	sst_fw_free(hsw->sst_fw);
+	sst_fw_free_all(hsw->dsp);
 fw_err:
 	dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
 			hsw->dx_context, hsw->dx_context_paddr);
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 8580960..e071b3a 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -467,6 +467,12 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
 void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
 struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
 
+/* fw module function */
+void sst_hsw_init_module_state(struct sst_hsw *hsw);
+
+int sst_hsw_module_load(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id, char *name);
+
 /* runtime module management */
 struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
 	int mod_id, int offset);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/8] ASoC: Intel: add function to load sound effect module waves
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10  2:41 ` [PATCH v2 3/8] ASoC: Intel: add function to enable/disable " han.lu
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Try to load module waves and allocate runtime blocks for it if the firmware
image of module waves exists.

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
index 8ad733b..b3e957d 100644
--- a/sound/soc/intel/sst-haswell-dsp.c
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -100,6 +100,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
 		&& module->type != SST_HSW_MODULE_PCM
 		&& module->type != SST_HSW_MODULE_PCM_REFERENCE
 		&& module->type != SST_HSW_MODULE_PCM_CAPTURE
+		&& module->type != SST_HSW_MODULE_WAVES
 		&& module->type != SST_HSW_MODULE_LPAL)
 		return 0;
 
@@ -139,6 +140,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
 			mod->type = SST_MEM_IRAM;
 			break;
 		case SST_HSW_DRAM:
+		case SST_HSW_REGS:
 			ram = dsp->addr.lpe;
 			mod->offset = block->ram_offset;
 			mod->type = SST_MEM_DRAM;
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index ec688f5..63740e3 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -1896,11 +1896,27 @@ void sst_hsw_init_module_state(struct sst_hsw *hsw)
 	/* the base fw contains several modules */
 	for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) {
 		module = sst_module_get_from_id(hsw->dsp, id);
-		if (module)
-			module->state = SST_MODULE_STATE_ACTIVE;
+		if (module) {
+			/* module waves is active only after being enabled */
+			if (id == SST_HSW_MODULE_WAVES)
+				module->state = SST_MODULE_STATE_INITIALIZED;
+			else
+				module->state = SST_MODULE_STATE_ACTIVE;
+		}
 	}
 }
 
+bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id)
+{
+	struct sst_module *module;
+
+	module = sst_module_get_from_id(hsw->dsp, module_id);
+	if (module == NULL || module->state == SST_MODULE_STATE_UNLOADED)
+		return false;
+	else
+		return true;
+}
+
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name)
 {
@@ -2022,6 +2038,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
 	if (ret < 0)
 		goto fw_err;
 
+	/* try to load module waves */
+	sst_hsw_module_load(hsw, SST_HSW_MODULE_WAVES, 0, "intel/IntcPP01.bin");
+
 	/* allocate scratch mem regions */
 	ret = sst_block_alloc_scratch(hsw->dsp);
 	if (ret < 0)
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index e071b3a..208724b 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -469,6 +469,7 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
 
 /* fw module function */
 void sst_hsw_init_module_state(struct sst_hsw *hsw);
+bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id);
 
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name);
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 7e21e8f..a604cc4 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -807,6 +807,17 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
 			pcm_data->runtime->persistent_offset;
 	}
 
+	/* create runtime blocks for module waves */
+	if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) {
+		pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0];
+		pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
+			SST_HSW_MODULE_WAVES, pcm_data->persistent_offset);
+		if (pcm_data->runtime == NULL)
+			goto err;
+		pcm_data->persistent_offset =
+			pcm_data->runtime->persistent_offset;
+	}
+
 	return 0;
 
 err:
@@ -820,12 +831,16 @@ err:
 
 static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
 {
+	struct sst_hsw *hsw = pdata->hsw;
 	struct hsw_pcm_data *pcm_data;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
 		pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-
+		sst_hsw_runtime_module_free(pcm_data->runtime);
+	}
+	if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) {
+		pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0];
 		sst_hsw_runtime_module_free(pcm_data->runtime);
 	}
 }
@@ -984,7 +999,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 	}
 
 	/* allocate runtime modules */
-	hsw_pcm_create_modules(priv_data);
+	ret = hsw_pcm_create_modules(priv_data);
+	if (ret < 0)
+		goto err;
 
 	/* enable runtime PM with auto suspend */
 	pm_runtime_set_autosuspend_delay(platform->dev,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/8] ASoC: Intel: add function to enable/disable sound effect module waves
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
  2015-03-10  2:41 ` [PATCH v2 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10  2:41 ` [PATCH v2 4/8] ASoC: Intel: add kcontrol " han.lu
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index 63740e3..265d754 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -79,6 +79,15 @@
 #define IPC_LOG_ID_MASK		(0xf << IPC_LOG_ID_SHIFT)
 #define IPC_LOG_ID(x)		(x << IPC_LOG_ID_SHIFT)
 
+/* Module Message */
+#define IPC_MODULE_OPERATION_SHIFT	20
+#define IPC_MODULE_OPERATION_MASK	(0xf << IPC_MODULE_OPERATION_SHIFT)
+#define IPC_MODULE_OPERATION(x)	(x << IPC_MODULE_OPERATION_SHIFT)
+
+#define IPC_MODULE_ID_SHIFT	16
+#define IPC_MODULE_ID_MASK	(0xf << IPC_MODULE_ID_SHIFT)
+#define IPC_MODULE_ID(x)	(x << IPC_MODULE_ID_SHIFT)
+
 /* IPC message timeout (msecs) */
 #define IPC_TIMEOUT_MSECS	300
 #define IPC_BOOT_MSECS		200
@@ -115,6 +124,7 @@ enum ipc_glb_type {
 	IPC_GLB_ENTER_DX_STATE = 12,
 	IPC_GLB_GET_MIXER_STREAM_INFO = 13,	/* Request mixer stream params */
 	IPC_GLB_DEBUG_LOG_MESSAGE = 14,		/* Message to or from the debug logger. */
+	IPC_GLB_MODULE_OPERATION = 15,		/* Message to loadable fw module */
 	IPC_GLB_REQUEST_TRANSFER = 16, 		/* < Request Transfer for host */
 	IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17,	/* Maximum message number */
 };
@@ -133,6 +143,16 @@ enum ipc_glb_reply {
 	IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10,	/* Source was not started. */
 };
 
+enum ipc_module_operation {
+	IPC_MODULE_NOTIFICATION = 0,
+	IPC_MODULE_ENABLE = 1,
+	IPC_MODULE_DISABLE = 2,
+	IPC_MODULE_GET_PARAMETER = 3,
+	IPC_MODULE_SET_PARAMETER = 4,
+	IPC_MODULE_GET_INFO = 5,
+	IPC_MODULE_MAX_MESSAGE
+};
+
 /* Stream Message - Types */
 enum ipc_str_operation {
 	IPC_STR_RESET = 0,
@@ -352,6 +372,16 @@ static inline u32 msg_get_notify_reason(u32 msg)
 	return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
 }
 
+static inline u32 msg_get_module_operation(u32 msg)
+{
+	return (msg & IPC_MODULE_OPERATION_MASK) >> IPC_MODULE_OPERATION_SHIFT;
+}
+
+static inline u32 msg_get_module_id(u32 msg)
+{
+	return (msg & IPC_MODULE_ID_MASK) >> IPC_MODULE_ID_SHIFT;
+}
+
 u32 create_channel_map(enum sst_hsw_channel_config config)
 {
 	switch (config) {
@@ -795,6 +825,31 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header)
 	return 1;
 }
 
+static int hsw_module_message(struct sst_hsw *hsw, u32 header)
+{
+	u32 operation, module_id;
+	int handled = 0;
+
+	operation = msg_get_module_operation(header);
+	module_id = msg_get_module_id(header);
+	dev_dbg(hsw->dev, "received module message header: 0x%8.8x\n",
+			header);
+	dev_dbg(hsw->dev, "operation: 0x%8.8x module_id: 0x%8.8x\n",
+			operation, module_id);
+
+	switch (operation) {
+	case IPC_MODULE_NOTIFICATION:
+		dev_dbg(hsw->dev, "module notification received");
+		handled = 1;
+		break;
+	default:
+		handled = hsw_process_reply(hsw, header);
+		break;
+	}
+
+	return handled;
+}
+
 static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
 {
 	u32 stream_msg, stream_id, stage_type;
@@ -890,6 +945,9 @@ static int hsw_process_notification(struct sst_hsw *hsw)
 	case IPC_GLB_DEBUG_LOG_MESSAGE:
 		handled = hsw_log_message(hsw, header);
 		break;
+	case IPC_GLB_MODULE_OPERATION:
+		handled = hsw_module_message(hsw, header);
+		break;
 	default:
 		dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n",
 			type, header);
@@ -1917,6 +1975,17 @@ bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id)
 		return true;
 }
 
+bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id)
+{
+	struct sst_module *module;
+
+	module = sst_module_get_from_id(hsw->dsp, module_id);
+	if (module != NULL && module->state == SST_MODULE_STATE_ACTIVE)
+		return true;
+	else
+		return false;
+}
+
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name)
 {
@@ -1972,6 +2041,112 @@ out:
 	return ret;
 }
 
+int sst_hsw_module_enable(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id)
+{
+	int ret;
+	u32 header = 0;
+	struct sst_hsw_ipc_module_config config;
+	struct sst_module *module;
+	struct sst_module_runtime *runtime;
+	struct device *dev = hsw->dev;
+	struct sst_dsp *dsp = hsw->dsp;
+
+	if (!sst_hsw_is_module_loaded(hsw, module_id)) {
+		dev_dbg(dev, "module %d not loaded\n", module_id);
+		return 0;
+	}
+
+	if (sst_hsw_is_module_active(hsw, module_id)) {
+		dev_info(dev, "module %d already enabled\n", module_id);
+		return 0;
+	}
+
+	module = sst_module_get_from_id(dsp, module_id);
+	if (module == NULL) {
+		dev_err(dev, "module %d not valid\n", module_id);
+		return -ENXIO;
+	}
+
+	runtime = sst_module_runtime_get_from_id(module, module_id);
+	if (runtime == NULL) {
+		dev_err(dev, "runtime %d not valid", module_id);
+		return -ENXIO;
+	}
+
+	header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) |
+			IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) |
+			IPC_MODULE_ID(module_id);
+	dev_dbg(dev, "module enable header: %x\n", header);
+
+	config.map.module_entries_count = 1;
+	config.map.module_entries[0].module_id = module->id;
+	config.map.module_entries[0].entry_point = module->entry;
+
+	config.persistent_mem.offset =
+		sst_dsp_get_offset(dsp,
+			runtime->persistent_offset, SST_MEM_DRAM);
+	config.persistent_mem.size = module->persistent_size;
+
+	config.scratch_mem.offset =
+		sst_dsp_get_offset(dsp,
+			dsp->scratch_offset, SST_MEM_DRAM);
+	config.scratch_mem.size = module->scratch_size;
+	dev_dbg(dev, "mod %d enable p:%d @ %x, s:%d @ %x, ep: %x",
+		config.map.module_entries[0].module_id,
+		config.persistent_mem.size,
+		config.persistent_mem.offset,
+		config.scratch_mem.size, config.scratch_mem.offset,
+		config.map.module_entries[0].entry_point);
+
+	ret = ipc_tx_message_wait(hsw, header,
+			&config, sizeof(config), NULL, 0);
+	if (ret < 0)
+		dev_err(dev, "ipc: module enable failed - %d\n", ret);
+	else
+		module->state = SST_MODULE_STATE_ACTIVE;
+
+	return ret;
+}
+
+int sst_hsw_module_disable(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id)
+{
+	int ret;
+	u32 header;
+	struct sst_module *module;
+	struct device *dev = hsw->dev;
+	struct sst_dsp *dsp = hsw->dsp;
+
+	if (!sst_hsw_is_module_loaded(hsw, module_id)) {
+		dev_dbg(dev, "module %d not loaded\n", module_id);
+		return 0;
+	}
+
+	if (!sst_hsw_is_module_active(hsw, module_id)) {
+		dev_info(dev, "module %d already disabled\n", module_id);
+		return 0;
+	}
+
+	module = sst_module_get_from_id(dsp, module_id);
+	if (module == NULL) {
+		dev_err(dev, "module %d not valid\n", module_id);
+		return -ENXIO;
+	}
+
+	header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) |
+			IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) |
+			IPC_MODULE_ID(module_id);
+
+	ret = ipc_tx_message_wait(hsw, header,  NULL, 0, NULL, 0);
+	if (ret < 0)
+		dev_err(dev, "module disable failed - %d\n", ret);
+	else
+		module->state = SST_MODULE_STATE_INITIALIZED;
+
+	return ret;
+}
+
 static struct sst_dsp_device hsw_dev = {
 	.thread = hsw_irq_thread,
 	.ops = &haswell_ops,
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 208724b..30c65b2 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -215,6 +215,12 @@ struct sst_hsw_fx_enable {
 	struct sst_hsw_memory_info persistent_mem;
 } __attribute__((packed));
 
+struct sst_hsw_ipc_module_config {
+	struct sst_hsw_module_map map;
+	struct sst_hsw_memory_info persistent_mem;
+	struct sst_hsw_memory_info scratch_mem;
+} __attribute__((packed));
+
 struct sst_hsw_get_fx_param {
 	u32 parameter_id;
 	u32 param_size;
@@ -470,9 +476,14 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
 /* fw module function */
 void sst_hsw_init_module_state(struct sst_hsw *hsw);
 bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id);
+bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id);
 
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name);
+int sst_hsw_module_enable(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id);
+int sst_hsw_module_disable(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id);
 
 /* runtime module management */
 struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/8] ASoC: Intel: add kcontrol to enable/disable sound effect module waves
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
  2015-03-10  2:41 ` [PATCH v2 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
  2015-03-10  2:41 ` [PATCH v2 3/8] ASoC: Intel: add function to enable/disable " han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10 20:37   ` Mark Brown
  2015-03-10  2:41 ` [PATCH v2 5/8] ASoC: Intel: track module state on RTD3 han.lu
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Add kcontrol to enable/disable module waves. IPC is valid only when module
is loaded.

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index a604cc4..3d10acc 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -318,6 +318,42 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct sst_hsw *hsw = pdata->hsw;
+	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
+
+	ucontrol->value.integer.value[0] = sst_hsw_is_module_active(hsw, id);
+	return 0;
+}
+
+static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct sst_hsw *hsw = pdata->hsw;
+	int ret = 0;
+	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
+	bool switch_on = (bool)ucontrol->value.integer.value[0];
+
+	if (sst_hsw_is_module_loaded(hsw, id)) {
+		if (switch_on == sst_hsw_is_module_active(hsw, id))
+			return 0;
+
+		/* ipc is valid only when module is loaded */
+		if (switch_on)
+			ret = sst_hsw_module_enable(hsw, id, 0);
+		else
+			ret = sst_hsw_module_disable(hsw, id, 0);
+	}
+
+	return ret;
+}
+
 /* TLV used by both global and stream volumes */
 static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
 
@@ -339,6 +375,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
 	SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
 		ARRAY_SIZE(volume_map) - 1, 0,
 		hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+	/* enable/disable module waves */
+	SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
+		hsw_waves_switch_get, hsw_waves_switch_put),
 };
 
 /* Create DMA buffer page table for DSP */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/8] ASoC: Intel: track module state on RTD3
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (2 preceding siblings ...)
  2015-03-10  2:41 ` [PATCH v2 4/8] ASoC: Intel: add kcontrol " han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10  2:41 ` [PATCH v2 6/8] ASoC: Intel: add function to set parameter to sound effect module waves han.lu
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Track module state over suspend so it's state can be restored on resume.

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index 265d754..ebca903 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -337,6 +337,10 @@ struct sst_hsw {
 
 	/* FW log stream */
 	struct sst_hsw_log_stream log_stream;
+
+	/* flags bit field to track module state when resume from RTD3,
+	 * each bit represent state (enabled/disabled) of single module */
+	u32 enabled_modules_rtd3;
 };
 
 #define CREATE_TRACE_POINTS
@@ -1986,6 +1990,21 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id)
 		return false;
 }
 
+void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id)
+{
+	hsw->enabled_modules_rtd3 |= (1 << module_id);
+}
+
+void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id)
+{
+	hsw->enabled_modules_rtd3 &= ~(1 << module_id);
+}
+
+bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id)
+{
+	return hsw->enabled_modules_rtd3 & (1 << module_id);
+}
+
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name)
 {
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 30c65b2..48290a1 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -477,6 +477,9 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
 void sst_hsw_init_module_state(struct sst_hsw *hsw);
 bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id);
 bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id);
+void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id);
+void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id);
+bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id);
 
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name);
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 3d10acc..72e9e9a 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -326,7 +326,9 @@ static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol,
 	struct sst_hsw *hsw = pdata->hsw;
 	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
 
-	ucontrol->value.integer.value[0] = sst_hsw_is_module_active(hsw, id);
+	ucontrol->value.integer.value[0] =
+		(sst_hsw_is_module_active(hsw, id) ||
+		sst_hsw_is_module_enabled_rtd3(hsw, id));
 	return 0;
 }
 
@@ -349,6 +351,16 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
 			ret = sst_hsw_module_enable(hsw, id, 0);
 		else
 			ret = sst_hsw_module_disable(hsw, id, 0);
+	} else {
+		/* on RTD3, module is unloaded */
+		if (switch_on == sst_hsw_is_module_enabled_rtd3(hsw, id))
+			return 0;
+
+		/* set flag for track */
+		if (switch_on)
+			sst_hsw_set_module_enabled_rtd3(hsw, id);
+		else
+			sst_hsw_set_module_disabled_rtd3(hsw, id);
 	}
 
 	return ret;
@@ -1157,10 +1169,18 @@ static int hsw_pcm_runtime_suspend(struct device *dev)
 {
 	struct hsw_priv_data *pdata = dev_get_drvdata(dev);
 	struct sst_hsw *hsw = pdata->hsw;
+	int ret;
 
 	if (pdata->pm_state >= HSW_PM_STATE_RTD3)
 		return 0;
 
+	/* fw modules will be unloaded on RTD3, set flag to track */
+	if (sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) {
+		ret = sst_hsw_module_disable(hsw, SST_HSW_MODULE_WAVES, 0);
+		if (ret < 0)
+			return ret;
+		sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES);
+	}
 	sst_hsw_dsp_runtime_suspend(hsw);
 	sst_hsw_dsp_runtime_sleep(hsw);
 	pdata->pm_state = HSW_PM_STATE_RTD3;
@@ -1195,6 +1215,15 @@ static int hsw_pcm_runtime_resume(struct device *dev)
 	else if (ret == 1) /* no action required */
 		return 0;
 
+	/* check flag when resume */
+	if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) {
+		ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0);
+		if (ret < 0)
+			return ret;
+		/* unset flag */
+		sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES);
+	}
+
 	pdata->pm_state = HSW_PM_STATE_D0;
 	return ret;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 6/8] ASoC: Intel: add function to set parameter to sound effect module waves
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (3 preceding siblings ...)
  2015-03-10  2:41 ` [PATCH v2 5/8] ASoC: Intel: track module state on RTD3 han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10  2:41 ` [PATCH v2 7/8] ASoC: Intel: add kcontrol " han.lu
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index ebca903..a97324d 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -2166,6 +2166,65 @@ int sst_hsw_module_disable(struct sst_hsw *hsw,
 	return ret;
 }
 
+int sst_hsw_module_set_param(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id, u32 parameter_id,
+	u32 param_size, char *param)
+{
+	int ret;
+	unsigned char *data = NULL;
+	u32 header = 0;
+	u32 payload_size = 0, transfer_parameter_size = 0;
+	dma_addr_t dma_addr = 0;
+	struct sst_hsw_transfer_parameter *parameter;
+	struct device *dev = hsw->dev;
+
+	header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) |
+			IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) |
+			IPC_MODULE_ID(module_id);
+	dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header);
+
+	payload_size = param_size +
+		sizeof(struct sst_hsw_transfer_parameter) -
+		sizeof(struct sst_hsw_transfer_list);
+	dev_dbg(dev, "parameter size : %d\n", param_size);
+	dev_dbg(dev, "payload size   : %d\n", payload_size);
+
+	if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) {
+		/* short parameter, mailbox can contain data */
+		dev_dbg(dev, "transfer parameter size : %d\n",
+			transfer_parameter_size);
+
+		transfer_parameter_size = ALIGN(payload_size, 4);
+		dev_dbg(dev, "transfer parameter aligned size : %d\n",
+			transfer_parameter_size);
+
+		parameter = kzalloc(transfer_parameter_size, GFP_KERNEL);
+		if (parameter == NULL)
+			return -ENOMEM;
+
+		memcpy(parameter->data, param, param_size);
+	} else {
+		dev_warn(dev, "transfer parameter size too large!");
+		return 0;
+	}
+
+	parameter->parameter_id = parameter_id;
+	parameter->data_size = param_size;
+
+	ret = ipc_tx_message_wait(hsw, header,
+		parameter, transfer_parameter_size , NULL, 0);
+	if (ret < 0)
+		dev_err(dev, "ipc: module set parameter failed - %d\n", ret);
+
+	kfree(parameter);
+
+	if (data)
+		dma_free_coherent(hsw->dsp->dma_dev,
+			param_size, (void *)data, dma_addr);
+
+	return ret;
+}
+
 static struct sst_dsp_device hsw_dev = {
 	.thread = hsw_irq_thread,
 	.ops = &haswell_ops,
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 48290a1..16bec43 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -37,6 +37,7 @@
 #define SST_HSW_IPC_MAX_PAYLOAD_SIZE	400
 #define SST_HSW_MAX_INFO_SIZE		64
 #define SST_HSW_BUILD_HASH_LENGTH	40
+#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE	500
 
 struct sst_hsw;
 struct sst_hsw_stream;
@@ -187,6 +188,28 @@ enum sst_hsw_performance_action {
 	SST_HSW_PERF_STOP = 1,
 };
 
+struct sst_hsw_transfer_info {
+	uint32_t destination;       /* destination address */
+	uint32_t reverse:1;         /* if 1 data flows from destination */
+	uint32_t size:31;           /* transfer size in bytes.*/
+	uint16_t first_page_offset; /* offset to data in the first page. */
+	uint8_t  packed_pages;   /* page addresses. Each occupies 20 bits */
+} __attribute__((packed));
+
+struct sst_hsw_transfer_list {
+	uint32_t transfers_count;
+	struct sst_hsw_transfer_info transfers;
+} __attribute__((packed));
+
+struct sst_hsw_transfer_parameter {
+	uint32_t parameter_id;
+	uint32_t data_size;
+	union {
+		uint8_t data[1];
+		struct sst_hsw_transfer_list transfer_list;
+	};
+} __attribute__((packed));
+
 /* SST firmware module info */
 struct sst_hsw_module_info {
 	u8 name[SST_HSW_MAX_INFO_SIZE];
@@ -487,6 +510,9 @@ int sst_hsw_module_enable(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id);
 int sst_hsw_module_disable(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id);
+int sst_hsw_module_set_param(struct sst_hsw *hsw,
+	u32 module_id, u32 instance_id, u32 parameter_id,
+	u32 param_size, char *param);
 
 /* runtime module management */
 struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module waves
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (4 preceding siblings ...)
  2015-03-10  2:41 ` [PATCH v2 6/8] ASoC: Intel: add function to set parameter to sound effect module waves han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10  2:41 ` [PATCH v2 8/8] ASoC: Intel: enable parameter restore for " han.lu
  2015-03-10 20:38 ` [PATCH v2 1/8] ASoC: Intel: add function to load firmware image Mark Brown
  7 siblings, 0 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

Each kcontrol command includes a line of parameters up to 128 bytes.
kcontrol command to set param:
    cset "name='Waves Set Param' <0x01,0xff,...>"
or
    cset-bin-file "name='Waves Set Param' <path/to/binary/config/file>"
alsa-lib v1.0.29 or commit 6ea14c36 and f47480af are required to support the
kcontrol commands.

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 16bec43..737f206 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -38,6 +38,7 @@
 #define SST_HSW_MAX_INFO_SIZE		64
 #define SST_HSW_BUILD_HASH_LENGTH	40
 #define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE	500
+#define WAVES_PARAM_COUNT		128
 
 struct sst_hsw;
 struct sst_hsw_stream;
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 72e9e9a..470f206 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -366,6 +366,33 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
+static int hsw_waves_param_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	/* keep an empty function here to match alsa-lib calling */
+	return 0;
+}
+
+static int hsw_waves_param_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct sst_hsw *hsw = pdata->hsw;
+	int ret;
+	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
+	int param_id = ucontrol->value.bytes.data[0];
+	int param_size = WAVES_PARAM_COUNT;
+
+	if (sst_hsw_is_module_loaded(hsw, id)) {
+		if (!sst_hsw_is_module_active(hsw, id))
+			return 0;
+		ret = sst_hsw_module_set_param(hsw, id, 0, param_id,
+				param_size, ucontrol->value.bytes.data);
+	}
+	return ret;
+}
+
 /* TLV used by both global and stream volumes */
 static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
 
@@ -390,6 +417,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
 	/* enable/disable module waves */
 	SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
 		hsw_waves_switch_get, hsw_waves_switch_put),
+	/* set parameters to module waves */
+	SND_SOC_BYTES_EXT("Waves Set Param", WAVES_PARAM_COUNT,
+		hsw_waves_param_get, hsw_waves_param_put),
 };
 
 /* Create DMA buffer page table for DSP */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 8/8] ASoC: Intel: enable parameter restore for sound effect module waves
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (5 preceding siblings ...)
  2015-03-10  2:41 ` [PATCH v2 7/8] ASoC: Intel: add kcontrol " han.lu
@ 2015-03-10  2:41 ` han.lu
  2015-03-10 20:38 ` [PATCH v2 1/8] ASoC: Intel: add function to load firmware image Mark Brown
  7 siblings, 0 replies; 14+ messages in thread
From: han.lu @ 2015-03-10  2:41 UTC (permalink / raw)
  To: broonie, alsa-devel, liam.r.girdwood; +Cc: Lu, Han

From: "Lu, Han" <han.lu@intel.com>

There are 2 issues on waves firmware: 1. the parameters read from DSP do not
match parameters set to DSP. 2. the parameters in DSP will lost on RTD3.
The patch add a buffer array to store parameter lines, so parameters can be
read back from buffer, and be relaunched to DSP when resume from RTD3.
The size of buffer is 160 parameter lines.
Also add kcontrol command to reset the buffer:
    cset "name='Waves Set Param' 0xff"

Signed-off-by: Lu, Han <han.lu@intel.com>

diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index a97324d..ebc3f25 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -341,6 +341,11 @@ struct sst_hsw {
 	/* flags bit field to track module state when resume from RTD3,
 	 * each bit represent state (enabled/disabled) of single module */
 	u32 enabled_modules_rtd3;
+
+	/* buffer to store parameter lines */
+	u32 param_idx_w;	/* write index */
+	u32 param_idx_r;	/* read index */
+	u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT];
 };
 
 #define CREATE_TRACE_POINTS
@@ -2005,6 +2010,64 @@ bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id)
 	return hsw->enabled_modules_rtd3 & (1 << module_id);
 }
 
+void sst_hsw_reset_param_buf(struct sst_hsw *hsw)
+{
+	hsw->param_idx_w = 0;
+	hsw->param_idx_r = 0;
+	memset((void *)hsw->param_buf, 0, sizeof(hsw->param_buf));
+}
+
+int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf)
+{
+	if (hsw->param_idx_w > WAVES_PARAM_LINES - 1) {
+		dev_warn(hsw->dev, "warning: param buffer overflow!\n");
+		return -EPERM;
+	}
+	memcpy(hsw->param_buf[hsw->param_idx_w], buf, WAVES_PARAM_COUNT);
+	hsw->param_idx_w++;
+	return 0;
+}
+
+int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf)
+{
+	u8 id = 0;
+
+	/* iterate param buffer lines, return the first matching line */
+	while (hsw->param_idx_r < WAVES_PARAM_LINES) {
+		id = hsw->param_buf[hsw->param_idx_r][0];
+		hsw->param_idx_r++;
+		if (buf[0] == id) {
+			memcpy(buf, hsw->param_buf[hsw->param_idx_r],
+				WAVES_PARAM_COUNT);
+			break;
+		}
+	}
+	if (hsw->param_idx_r > WAVES_PARAM_LINES - 1) {
+		dev_dbg(hsw->dev, "end of buffer, roll to the beginning\n");
+		hsw->param_idx_r = 0;
+		return 0;
+	}
+	return 0;
+}
+
+int sst_hsw_launch_param_buf(struct sst_hsw *hsw)
+{
+	int ret, idx;
+
+	for (idx = 0; idx < hsw->param_idx_w; idx++) {
+		/* 0 is invalid parameter id */
+		if (0 == hsw->param_buf[idx][0])
+			continue;
+
+		ret = sst_hsw_module_set_param(hsw,
+			SST_HSW_MODULE_WAVES, 0, hsw->param_buf[idx][0],
+			WAVES_PARAM_COUNT, hsw->param_buf[idx]);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name)
 {
@@ -2299,6 +2362,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
 	if (ret < 0)
 		goto boot_err;
 
+	/* init param buffer */
+	sst_hsw_reset_param_buf(hsw);
+
 	/* wait for DSP boot completion */
 	sst_dsp_boot(hsw->dsp);
 	ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 737f206..06d71ae 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -39,6 +39,7 @@
 #define SST_HSW_BUILD_HASH_LENGTH	40
 #define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE	500
 #define WAVES_PARAM_COUNT		128
+#define WAVES_PARAM_LINES		160
 
 struct sst_hsw;
 struct sst_hsw_stream;
@@ -504,6 +505,10 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id);
 void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id);
 void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id);
 bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id);
+void sst_hsw_reset_param_buf(struct sst_hsw *hsw);
+int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf);
+int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf);
+int sst_hsw_launch_param_buf(struct sst_hsw *hsw);
 
 int sst_hsw_module_load(struct sst_hsw *hsw,
 	u32 module_id, u32 instance_id, char *name);
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 470f206..ada4b99 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -369,8 +369,12 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
 static int hsw_waves_param_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	/* keep an empty function here to match alsa-lib calling */
-	return 0;
+	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct sst_hsw *hsw = pdata->hsw;
+
+	/* return a matching line from param buffer */
+	return sst_hsw_load_param_line(hsw, ucontrol->value.bytes.data);
 }
 
 static int hsw_waves_param_put(struct snd_kcontrol *kcontrol,
@@ -384,9 +388,21 @@ static int hsw_waves_param_put(struct snd_kcontrol *kcontrol,
 	int param_id = ucontrol->value.bytes.data[0];
 	int param_size = WAVES_PARAM_COUNT;
 
+	/* clear param buffer and reset buffer index */
+	if (param_id == 0xFF) {
+		sst_hsw_reset_param_buf(hsw);
+		return 0;
+	}
+
+	/* store params into buffer */
+	ret = sst_hsw_store_param_line(hsw, ucontrol->value.bytes.data);
+	if (ret < 0)
+		return ret;
+
 	if (sst_hsw_is_module_loaded(hsw, id)) {
 		if (!sst_hsw_is_module_active(hsw, id))
 			return 0;
+
 		ret = sst_hsw_module_set_param(hsw, id, 0, param_id,
 				param_size, ucontrol->value.bytes.data);
 	}
@@ -1250,6 +1266,10 @@ static int hsw_pcm_runtime_resume(struct device *dev)
 		ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0);
 		if (ret < 0)
 			return ret;
+		/* put parameters from buffer to dsp */
+		ret = sst_hsw_launch_param_buf(hsw);
+		if (ret < 0)
+			return ret;
 		/* unset flag */
 		sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES);
 	}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 4/8] ASoC: Intel: add kcontrol to enable/disable sound effect module waves
  2015-03-10  2:41 ` [PATCH v2 4/8] ASoC: Intel: add kcontrol " han.lu
@ 2015-03-10 20:37   ` Mark Brown
  2015-03-11  7:07     ` Lu, Han
  0 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2015-03-10 20:37 UTC (permalink / raw)
  To: han.lu; +Cc: alsa-devel, liam.r.girdwood


[-- Attachment #1.1: Type: text/plain, Size: 1161 bytes --]

On Tue, Mar 10, 2015 at 10:41:23AM +0800, han.lu@intel.com wrote:

> +static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
> +				struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
> +	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
> +	struct sst_hsw *hsw = pdata->hsw;
> +	int ret = 0;
> +	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
> +	bool switch_on = (bool)ucontrol->value.integer.value[0];
> +
> +	if (sst_hsw_is_module_loaded(hsw, id)) {
> +		if (switch_on == sst_hsw_is_module_active(hsw, id))
> +			return 0;
> +
> +		/* ipc is valid only when module is loaded */
> +		if (switch_on)
> +			ret = sst_hsw_module_enable(hsw, id, 0);
> +		else
> +			ret = sst_hsw_module_disable(hsw, id, 0);
> +	}

I'm not clear how this setting is saved when the module is not in RAM on
the DSP.  If the module enable/disable calls do that that's fine but I'd
expect the function to return an error if the module isn't loaded (or
better yet for the control not to be made visible to userspace at all) -
we shouldn't be silently ignoring what the user is setting.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/8] ASoC: Intel: add function to load firmware image
  2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (6 preceding siblings ...)
  2015-03-10  2:41 ` [PATCH v2 8/8] ASoC: Intel: enable parameter restore for " han.lu
@ 2015-03-10 20:38 ` Mark Brown
  2015-03-11  6:48   ` Lu, Han
  7 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2015-03-10 20:38 UTC (permalink / raw)
  To: han.lu; +Cc: alsa-devel, liam.r.girdwood


[-- Attachment #1.1: Type: text/plain, Size: 450 bytes --]

On Tue, Mar 10, 2015 at 10:41:20AM +0800, han.lu@intel.com wrote:
> From: "Lu, Han" <han.lu@intel.com>
> 
> Add a general method to load firmware image, and apply to base firmware
> image loading. With the method, the driver will support loading multiple
> different modules in order to support different features.

This doesn't apply against current code - you should be sending things
against my git tree (or -next is often close enough).

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/8] ASoC: Intel: add function to load firmware image
  2015-03-10 20:38 ` [PATCH v2 1/8] ASoC: Intel: add function to load firmware image Mark Brown
@ 2015-03-11  6:48   ` Lu, Han
  2015-03-11 12:54     ` Mark Brown
  0 siblings, 1 reply; 14+ messages in thread
From: Lu, Han @ 2015-03-11  6:48 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Girdwood, Liam R

> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Wednesday, March 11, 2015 4:39 AM
> To: Lu, Han
> Cc: alsa-devel@alsa-project.org; Girdwood, Liam R
> Subject: Re: [PATCH v2 1/8] ASoC: Intel: add function to load firmware image
> 
> On Tue, Mar 10, 2015 at 10:41:20AM +0800, han.lu@intel.com wrote:
> > From: "Lu, Han" <han.lu@intel.com>
> >
> > Add a general method to load firmware image, and apply to base
> > firmware image loading. With the method, the driver will support
> > loading multiple different modules in order to support different features.
> 
> This doesn't apply against current code - you should be sending things against
> my git tree (or -next is often close enough).

[Han] sorry, I made patches against for-next branch, and I just run
	$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
	$ cd sound
	$ git checkout origin/for-next -b for-next
And apply the patches manually
	$ patch -p1 < 0001-ASoC-Intel-add-function-to-load-firmware-image.patch
	$ patch -p1 < 0002-ASoC-Intel-add-function-to-load-sound-effect-module-.patch
	...
	$ patch -p1 < 0008-ASoC-Intel-enable-parameter-restore-for-sound-effect.patch
But didn't find conflict. Is there any mistake in my operation, or could you please share the error log so I can correct my patch? Very sorry for inconvenient.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 4/8] ASoC: Intel: add kcontrol to enable/disable sound effect module waves
  2015-03-10 20:37   ` Mark Brown
@ 2015-03-11  7:07     ` Lu, Han
  2015-03-11 12:57       ` Mark Brown
  0 siblings, 1 reply; 14+ messages in thread
From: Lu, Han @ 2015-03-11  7:07 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Girdwood, Liam R

> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Wednesday, March 11, 2015 4:38 AM
> To: Lu, Han
> Cc: alsa-devel@alsa-project.org; Girdwood, Liam R
> Subject: Re: [PATCH v2 4/8] ASoC: Intel: add kcontrol to enable/disable
> sound effect module waves
> 
> On Tue, Mar 10, 2015 at 10:41:23AM +0800, han.lu@intel.com wrote:
> 
> > +static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
> > +				struct snd_ctl_elem_value *ucontrol) {
> > +	struct snd_soc_platform *platform =
> snd_soc_kcontrol_platform(kcontrol);
> > +	struct hsw_priv_data *pdata =
> snd_soc_platform_get_drvdata(platform);
> > +	struct sst_hsw *hsw = pdata->hsw;
> > +	int ret = 0;
> > +	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
> > +	bool switch_on = (bool)ucontrol->value.integer.value[0];
> > +
> > +	if (sst_hsw_is_module_loaded(hsw, id)) {
> > +		if (switch_on == sst_hsw_is_module_active(hsw, id))
> > +			return 0;
> > +
> > +		/* ipc is valid only when module is loaded */
> > +		if (switch_on)
> > +			ret = sst_hsw_module_enable(hsw, id, 0);
> > +		else
> > +			ret = sst_hsw_module_disable(hsw, id, 0);
> > +	}
> 
> I'm not clear how this setting is saved when the module is not in RAM on the
> DSP.  If the module enable/disable calls do that that's fine but I'd expect the
> function to return an error if the module isn't loaded (or better yet for the
> control not to be made visible to userspace at all) - we shouldn't be silently
> ignoring what the user is setting.

[Han] if module is not in RAM on the DSP, sst_hsw_is_module_loaded() will return false. Also sst_hsw_module_enable() and sst_hsw_module_disable() will check the module status in DSP before send IPC commands to DSP.
In case sst_hsw_is_module_loaded() return false, (eg. System go RTD3 and modules in DSP RAM be unloaded) the user setting will be stored in variant u32 enabled_modules_rtd3, which is implemented in patch 0005. So which is better for next version of patch, to add error return here, merge patch 0005 with 0004, or  do not change this part? Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/8] ASoC: Intel: add function to load firmware image
  2015-03-11  6:48   ` Lu, Han
@ 2015-03-11 12:54     ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2015-03-11 12:54 UTC (permalink / raw)
  To: Lu, Han; +Cc: alsa-devel, Girdwood, Liam R


[-- Attachment #1.1: Type: text/plain, Size: 417 bytes --]

On Wed, Mar 11, 2015 at 06:48:51AM +0000, Lu, Han wrote:

Please fix your mailer to word wrap within paragraphs, it makes your
e-mails easier to both read and respond to.

> But didn't find conflict. Is there any mistake in my operation, or
> could you please share the error log so I can correct my patch? Very
> sorry for inconvenient.

I've managed to find the dependencies and resolved this, applied patches
1-3.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 4/8] ASoC: Intel: add kcontrol to enable/disable sound effect module waves
  2015-03-11  7:07     ` Lu, Han
@ 2015-03-11 12:57       ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2015-03-11 12:57 UTC (permalink / raw)
  To: Lu, Han; +Cc: alsa-devel, Girdwood, Liam R


[-- Attachment #1.1: Type: text/plain, Size: 2315 bytes --]

On Wed, Mar 11, 2015 at 07:07:12AM +0000, Lu, Han wrote:

Again, please fix your mailer to word wrap within paragraphs - this mail
is very difficult to read.

> > On Tue, Mar 10, 2015 at 10:41:23AM +0800, han.lu@intel.com wrote:
> > 
> > > +static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
> > > +				struct snd_ctl_elem_value *ucontrol) {
> > > +	struct snd_soc_platform *platform =
> > snd_soc_kcontrol_platform(kcontrol);
> > > +	struct hsw_priv_data *pdata =
> > snd_soc_platform_get_drvdata(platform);
> > > +	struct sst_hsw *hsw = pdata->hsw;
> > > +	int ret = 0;
> > > +	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
> > > +	bool switch_on = (bool)ucontrol->value.integer.value[0];

> > > +	if (sst_hsw_is_module_loaded(hsw, id)) {
> > > +		if (switch_on == sst_hsw_is_module_active(hsw, id))
> > > +			return 0;
> > > +
> > > +		/* ipc is valid only when module is loaded */
> > > +		if (switch_on)
> > > +			ret = sst_hsw_module_enable(hsw, id, 0);
> > > +		else
> > > +			ret = sst_hsw_module_disable(hsw, id, 0);
> > > +	}

> > I'm not clear how this setting is saved when the module is not in RAM on the
> > DSP.  If the module enable/disable calls do that that's fine but I'd expect the
> > function to return an error if the module isn't loaded (or better yet for the
> > control not to be made visible to userspace at all) - we shouldn't be silently
> > ignoring what the user is setting.

> [Han] if module is not in RAM on the DSP, sst_hsw_is_module_loaded()
> will return false. Also sst_hsw_module_enable() and
> sst_hsw_module_disable() will check the module status in DSP before
> send IPC commands to DSP.  In case sst_hsw_is_module_loaded() return
> false, (eg. System go RTD3 and modules in DSP RAM be unloaded) the
> user setting will be stored in variant u32 enabled_modules_rtd3, which
> is implemented in patch 0005. So which is better for next version of
> patch, to add error return here, merge patch 0005 with 0004, or  do
> not change this part? Thanks.

It's better to merge the two patches so that it's clear that everything
is working fine - in general the idea is that things should work after
every patch and people shouldn't be finding problems in the patch series
which are fixed later on in the same series.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2015-03-11 12:57 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-10  2:41 [PATCH v2 1/8] ASoC: Intel: add function to load firmware image han.lu
2015-03-10  2:41 ` [PATCH v2 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
2015-03-10  2:41 ` [PATCH v2 3/8] ASoC: Intel: add function to enable/disable " han.lu
2015-03-10  2:41 ` [PATCH v2 4/8] ASoC: Intel: add kcontrol " han.lu
2015-03-10 20:37   ` Mark Brown
2015-03-11  7:07     ` Lu, Han
2015-03-11 12:57       ` Mark Brown
2015-03-10  2:41 ` [PATCH v2 5/8] ASoC: Intel: track module state on RTD3 han.lu
2015-03-10  2:41 ` [PATCH v2 6/8] ASoC: Intel: add function to set parameter to sound effect module waves han.lu
2015-03-10  2:41 ` [PATCH v2 7/8] ASoC: Intel: add kcontrol " han.lu
2015-03-10  2:41 ` [PATCH v2 8/8] ASoC: Intel: enable parameter restore for " han.lu
2015-03-10 20:38 ` [PATCH v2 1/8] ASoC: Intel: add function to load firmware image Mark Brown
2015-03-11  6:48   ` Lu, Han
2015-03-11 12:54     ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.