alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/8] ASoC: Intel: add function to load firmware image
@ 2015-03-02  7:36 han.lu
  2015-03-02  7:36 ` [PATCH 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: han.lu @ 2015-03-02  7:36 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..cbd8c00 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,75 @@ 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);
+		}
+		dev_info(dev, "firmware %s loaded successfuly\n", 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 +2018,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 +2040,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 +2058,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] 12+ messages in thread

* [PATCH 2/8] ASoC: Intel: add function to load sound effect module waves
  2015-03-02  7:36 [PATCH 1/8] ASoC: Intel: add function to load firmware image han.lu
@ 2015-03-02  7:36 ` han.lu
  2015-03-02  7:36 ` [PATCH 3/8] ASoC: Intel: add function to enable/disable " han.lu
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: han.lu @ 2015-03-02  7:36 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 cbd8c00..711439e 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)
 {
@@ -2023,6 +2039,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] 12+ messages in thread

* [PATCH 3/8] ASoC: Intel: add function to enable/disable sound effect module waves
  2015-03-02  7:36 [PATCH 1/8] ASoC: Intel: add function to load firmware image han.lu
  2015-03-02  7:36 ` [PATCH 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
@ 2015-03-02  7:36 ` han.lu
  2015-03-02  7:36 ` [PATCH 4/8] ASoC: Intel: add kcontrol " han.lu
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: han.lu @ 2015-03-02  7:36 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 711439e..2c15da2 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_info(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)
 {
@@ -1973,6 +2042,115 @@ 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 {
+		dev_info(dev, "ipc: module enable success\n");
+		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 {
+		dev_info(dev, "module %d is now disabled\n", module_id);
+		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] 12+ messages in thread

* [PATCH 4/8] ASoC: Intel: add kcontrol to enable/disable sound effect module waves
  2015-03-02  7:36 [PATCH 1/8] ASoC: Intel: add function to load firmware image han.lu
  2015-03-02  7:36 ` [PATCH 2/8] ASoC: Intel: add function to load sound effect module waves han.lu
  2015-03-02  7:36 ` [PATCH 3/8] ASoC: Intel: add function to enable/disable " han.lu
@ 2015-03-02  7:36 ` han.lu
  2015-03-02  7:36 ` [PATCH 5/8] ASoC: Intel: track module state on RTD3 han.lu
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: han.lu @ 2015-03-02  7:36 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] 12+ messages in thread

* [PATCH 5/8] ASoC: Intel: track module state on RTD3
  2015-03-02  7:36 [PATCH 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (2 preceding siblings ...)
  2015-03-02  7:36 ` [PATCH 4/8] ASoC: Intel: add kcontrol " han.lu
@ 2015-03-02  7:36 ` han.lu
  2015-03-02  7:36 ` [PATCH 6/8] ASoC: Intel: add function to set parameter to sound effect module waves han.lu
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: han.lu @ 2015-03-02  7:36 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 2c15da2..d6ccb46 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..f82560f 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 trace */
+	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] 12+ messages in thread

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

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

Add function to set parameters to module waves. The parameters can be set
only when module is enabled, and parameter size is limited to 500 Bytes.

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 d6ccb46..7dda402 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -2170,6 +2170,67 @@ 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);
+	else
+		dev_info(dev, "ipc: module set parameter success\n");
+
+	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] 12+ messages in thread

* [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module waves
  2015-03-02  7:36 [PATCH 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (4 preceding siblings ...)
  2015-03-02  7:36 ` [PATCH 6/8] ASoC: Intel: add function to set parameter to sound effect module waves han.lu
@ 2015-03-02  7:36 ` han.lu
  2015-03-06 11:35   ` Mark Brown
  2015-03-02  7:36 ` [PATCH 8/8] ASoC: Intel: enable parameter restore for " han.lu
  2015-03-06 11:36 ` [PATCH 1/8] ASoC: Intel: add function to load firmware image Mark Brown
  7 siblings, 1 reply; 12+ messages in thread
From: han.lu @ 2015-03-02  7:36 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 commit 6ea14c36 and f47480af are required for listed format.

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 f82560f..e69b364 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] 12+ messages in thread

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

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

The parameters in DSP will lost on RTD3. To fix this, store parameter lines
in a buffer, and put the buffer content to DSP when resume from RTD3. The
size of buffer is 160 parameter lines.
And 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 7dda402..df19d6c 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -341,6 +341,10 @@ 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;
+	u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT];
 };
 
 #define CREATE_TRACE_POINTS
@@ -2005,6 +2009,37 @@ 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 = 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 > WAVES_PARAM_LINES - 1) {
+		dev_warn(hsw->dev, "warning: param buffer overflow!\n");
+		return 0;
+	}
+	memcpy(hsw->param_buf[hsw->param_idx], buf, WAVES_PARAM_COUNT);
+	hsw->param_idx++;
+	return 0;
+}
+
+int sst_hsw_launch_param_buf(struct sst_hsw *hsw)
+{
+	int ret, idx;
+
+	for (idx = 0; idx < hsw->param_idx; idx++) {
+		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)
 {
@@ -2305,6 +2340,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..52fdea0 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,9 @@ 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_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 e69b364..4ba684b 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -384,6 +384,17 @@ 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;
@@ -1250,6 +1261,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] 12+ messages in thread

* Re: [PATCH 6/8] ASoC: Intel: add function to set parameter to sound effect module waves
  2015-03-02  7:36 ` [PATCH 6/8] ASoC: Intel: add function to set parameter to sound effect module waves han.lu
@ 2015-03-06 11:33   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2015-03-06 11:33 UTC (permalink / raw)
  To: han.lu; +Cc: alsa-devel, liam.r.girdwood


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

On Mon, Mar 02, 2015 at 03:36:16PM +0800, han.lu@intel.com wrote:

> +	if (ret < 0)
> +		dev_err(dev, "ipc: module set parameter failed - %d\n", ret);
> +	else
> +		dev_info(dev, "ipc: module set parameter success\n");

Logging on error is good but logging every time someone sets a control
is going to get too noisy, please remove the print there.

[-- 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] 12+ messages in thread

* Re: [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module waves
  2015-03-02  7:36 ` [PATCH 7/8] ASoC: Intel: add kcontrol " han.lu
@ 2015-03-06 11:35   ` Mark Brown
  2015-03-10  2:42     ` Lu, Han
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Brown @ 2015-03-06 11:35 UTC (permalink / raw)
  To: han.lu; +Cc: alsa-devel, liam.r.girdwood


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

On Mon, Mar 02, 2015 at 03:36:17PM +0800, han.lu@intel.com wrote:

> +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;
> +}

No, if it's valid to omit this we should be able to remove the function
- but I'd really expect to always be able to read the current state of
any control.  Applications should be able to do that and then write the
value back without changing anything.  Either we should actually read
things back or this should return an error (which is presumably what the
core does if the function is missing).

[-- 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] 12+ messages in thread

* Re: [PATCH 1/8] ASoC: Intel: add function to load firmware image
  2015-03-02  7:36 [PATCH 1/8] ASoC: Intel: add function to load firmware image han.lu
                   ` (6 preceding siblings ...)
  2015-03-02  7:36 ` [PATCH 8/8] ASoC: Intel: enable parameter restore for " han.lu
@ 2015-03-06 11:36 ` Mark Brown
  7 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2015-03-06 11:36 UTC (permalink / raw)
  To: han.lu; +Cc: alsa-devel, liam.r.girdwood


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

On Mon, Mar 02, 2015 at 03:36:11PM +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, please check and resend.

[-- 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] 12+ messages in thread

* Re: [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module waves
  2015-03-06 11:35   ` Mark Brown
@ 2015-03-10  2:42     ` Lu, Han
  0 siblings, 0 replies; 12+ messages in thread
From: Lu, Han @ 2015-03-10  2:42 UTC (permalink / raw)
  To: 'Mark Brown'; +Cc: alsa-devel, Girdwood, Liam R

> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Friday, March 6, 2015 7:35 PM
> To: Lu, Han
> Cc: alsa-devel@alsa-project.org; Girdwood, Liam R
> Subject: Re: [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound
> effect module waves
> 
> On Mon, Mar 02, 2015 at 03:36:17PM +0800, han.lu@intel.com wrote:
> 
> > +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;
> > +}
> 
> No, if it's valid to omit this we should be able to remove the function
> - but I'd really expect to always be able to read the current state of any
> control.  Applications should be able to do that and then write the value back
> without changing anything.  Either we should actually read things back or this
> should return an error (which is presumably what the core does if the
> function is missing).

[Han Lu] OK. I made patch v2 against current code, and remove unnecessary logs. For the read back kcontrol, I do not modify patch 7/8 but add actual read back code on patch 8/8, (merge patch 7 and 8 may make the patch too long and unclear?) please review. Thanks.

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

end of thread, other threads:[~2015-03-10  2:42 UTC | newest]

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).