ASoC: Intel: add function to load firmware image

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>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Lu, Han 2015-03-10 10:41:20 +08:00 committed by Mark Brown
parent 357635ae01
commit 9449d39b99
5 changed files with 98 additions and 6 deletions

View File

@ -172,6 +172,16 @@ struct sst_module_runtime_context {
u32 *buffer;
};
/*
* 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.
*
@ -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;
};
/*

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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);