summaryrefslogtreecommitdiff
path: root/sound/soc/intel/sst-haswell-ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/sst-haswell-ipc.c')
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c83
1 files changed, 77 insertions, 6 deletions
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index 863a9ca34b8e..ec688f598320 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);