ASoC: Intel: Make ADSP memory block allocation more generic

Current block allocation is tied to block type and requestor type. Make the
allocation more generic by removing the struct module parameter and adding
a generic block allocator structure. Also pass in the list that the blocks
have to be added too in order to remove dependence on block requestor type.

ASoC: Intel: update scratch allocator to use generic block allocator

Update the scratch allocator to use the generic block allocator and calculate
total scratch buffer size.

ASoC: Intel: Add call to calculate offsets internally within the DSP.

A call to calculate internal DSP memory addresses used to allocate persistent
and scartch buffers.

ASoC: Intel: Add runtime module support.

Add support for runtime module objects that can be created for every FW
module that is parsed from the FW file. This gives a 1:N mapping between
the FW module from file and the runtime instantiations of that module.

We also need to make sure we remove every module and runtime module when
we unload the FW.

ASoC: Intel: Add DMA firmware loading support

Add support for DMA to load firmware modules to the DSP memory blocks.
Two DMA engines are supported, DesignWare and Intel MID.

ASoC: Intel: Add runtime module lookup API call

Add an API to allow quick lookup of runtime modules based on ID.

ASoC: Intel: Provide streams with dynamic module information

Remove the hard coded module paramaters and provide each module with
dynamically generated buffer information for scratch and persistent
buffers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Liam Girdwood 2014-10-28 17:37:12 +00:00 committed by Mark Brown
parent 9a80e8f597
commit e9600bc166
9 changed files with 1023 additions and 339 deletions

View File

@ -67,17 +67,12 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
{
struct dma_block_info *block;
struct sst_module *mod;
struct sst_module_data block_data;
struct sst_module_template template;
int count;
memset(&template, 0, sizeof(template));
template.id = module->type;
template.entry = module->entry_point;
template.p.type = SST_MEM_DRAM;
template.p.data_type = SST_DATA_P;
template.s.type = SST_MEM_DRAM;
template.s.data_type = SST_DATA_S;
mod = sst_module_new(fw, &template, NULL);
if (mod == NULL)
@ -94,19 +89,19 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
switch (block->type) {
case SST_BYT_IRAM:
block_data.offset = block->ram_offset +
mod->offset = block->ram_offset +
dsp->addr.iram_offset;
block_data.type = SST_MEM_IRAM;
mod->type = SST_MEM_IRAM;
break;
case SST_BYT_DRAM:
block_data.offset = block->ram_offset +
mod->offset = block->ram_offset +
dsp->addr.dram_offset;
block_data.type = SST_MEM_DRAM;
mod->type = SST_MEM_DRAM;
break;
case SST_BYT_CACHE:
block_data.offset = block->ram_offset +
mod->offset = block->ram_offset +
(dsp->addr.fw_ext - dsp->addr.lpe);
block_data.type = SST_MEM_CACHE;
mod->type = SST_MEM_CACHE;
break;
default:
dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
@ -114,11 +109,10 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
return -EINVAL;
}
block_data.size = block->size;
block_data.data_type = SST_DATA_M;
block_data.data = (void *)block + sizeof(*block);
mod->size = block->size;
mod->data = (void *)block + sizeof(*block);
sst_module_insert_fixed_block(mod, &block_data);
sst_module_alloc_blocks(mod);
block = (void *)block + sizeof(*block) + block->size;
}

View File

@ -26,6 +26,9 @@ struct sst_mem_block;
struct sst_module;
struct sst_fw;
/* do we need to remove or keep */
#define DSP_DRAM_ADDR_OFFSET 0x400000
/*
* DSP Operations exported by platform Audio DSP driver.
*/
@ -67,6 +70,8 @@ struct sst_addr {
u32 shim_offset;
u32 iram_offset;
u32 dram_offset;
u32 dsp_iram_offset;
u32 dsp_dram_offset;
void __iomem *lpe;
void __iomem *shim;
void __iomem *pci_cfg;
@ -83,15 +88,6 @@ struct sst_mailbox {
size_t out_size;
};
/*
* Audio DSP Firmware data types.
*/
enum sst_data_type {
SST_DATA_M = 0, /* module block data */
SST_DATA_P = 1, /* peristant data (text, data) */
SST_DATA_S = 2, /* scratch data (usually buffers) */
};
/*
* Audio DSP memory block types.
*/
@ -124,23 +120,6 @@ struct sst_fw {
void *private; /* core doesn't touch this */
};
/*
* Audio DSP Generic Module data.
*
* This is used to dsecribe any sections of persistent (text and data) and
* scratch (buffers) of module data in ADSP memory space.
*/
struct sst_module_data {
enum sst_mem_type type; /* destination memory type */
enum sst_data_type data_type; /* type of module data */
u32 size; /* size in bytes */
int32_t offset; /* offset in FW file */
u32 data_offset; /* offset in ADSP memory space */
void *data; /* module data */
};
/*
* Audio DSP Generic Module Template.
*
@ -150,15 +129,52 @@ struct sst_module_data {
struct sst_module_template {
u32 id;
u32 entry; /* entry point */
struct sst_module_data s; /* scratch data */
struct sst_module_data p; /* peristant data */
u32 scratch_size;
u32 persistent_size;
};
/*
* Block Allocator - Used to allocate blocks of DSP memory.
*/
struct sst_block_allocator {
u32 id;
u32 offset;
int size;
enum sst_mem_type type;
};
/*
* Runtime Module Instance - A module object can be instanciated multiple
* times within the DSP FW.
*/
struct sst_module_runtime {
struct sst_dsp *dsp;
int id;
struct sst_module *module; /* parent module we belong too */
u32 persistent_offset; /* private memory offset */
void *private;
struct list_head list;
struct list_head block_list; /* list of blocks used */
};
/*
* Runtime Module Context - The runtime context must be manually stored by the
* driver prior to enter S3 and restored after leaving S3. This should really be
* part of the memory context saved by the enter D3 message IPC ???
*/
struct sst_module_runtime_context {
dma_addr_t dma_buffer;
u32 *buffer;
};
/*
* Audio DSP Generic Module.
*
* Each Firmware file can consist of 1..N modules. A module can span multiple
* ADSP memory blocks. The simplest FW will be a file with 1 module.
* ADSP memory blocks. The simplest FW will be a file with 1 module. A module
* can be instanciated multiple times in the DSP.
*/
struct sst_module {
struct sst_dsp *dsp;
@ -167,10 +183,13 @@ struct sst_module {
/* module configuration */
u32 id;
u32 entry; /* module entry point */
u32 offset; /* module offset in firmware file */
s32 offset; /* module offset in firmware file */
u32 size; /* module size */
struct sst_module_data s; /* scratch data */
struct sst_module_data p; /* peristant data */
u32 scratch_size; /* global scratch memory required */
u32 persistent_size; /* private memory required */
enum sst_mem_type type; /* destination memory type */
u32 data_offset; /* offset in ADSP memory space */
void *data; /* module data */
/* runtime */
u32 usage_count; /* can be unloaded if count == 0 */
@ -180,6 +199,7 @@ struct sst_module {
struct list_head block_list; /* Module list of blocks in use */
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*/
};
/*
@ -208,7 +228,6 @@ struct sst_mem_block {
struct sst_block_ops *ops; /* block operations, if any */
/* block status */
enum sst_data_type data_type; /* data type held in this block */
u32 bytes_used; /* bytes in use by modules */
void *private; /* generic core does not touch this */
int users; /* number of modules using this block */
@ -253,6 +272,11 @@ struct sst_dsp {
struct list_head module_list;
struct list_head fw_list;
/* scratch buffer */
struct list_head scratch_block_list;
u32 scratch_offset;
u32 scratch_size;
/* platform data */
struct sst_pdata *pdata;
@ -290,18 +314,33 @@ void sst_fw_unload(struct sst_fw *sst_fw);
/* Create/Free firmware modules */
struct sst_module *sst_module_new(struct sst_fw *sst_fw,
struct sst_module_template *template, void *private);
void sst_module_free(struct sst_module *sst_module);
int sst_module_insert(struct sst_module *sst_module);
int sst_module_remove(struct sst_module *sst_module);
int sst_module_insert_fixed_block(struct sst_module *module,
struct sst_module_data *data);
void sst_module_free(struct sst_module *module);
struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
int sst_module_alloc_blocks(struct sst_module *module);
int sst_module_free_blocks(struct sst_module *module);
/* allocate/free pesistent/scratch memory regions managed by drv */
struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
void sst_mem_block_free_scratch(struct sst_dsp *dsp,
struct sst_module *scratch);
int sst_block_module_remove(struct sst_module *module);
/* Create/Free firmware module runtime instances */
struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
int id, void *private);
void sst_module_runtime_free(struct sst_module_runtime *runtime);
struct sst_module_runtime *sst_module_runtime_get_from_id(
struct sst_module *module, u32 id);
int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
int offset);
int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime);
int sst_module_runtime_save(struct sst_module_runtime *runtime,
struct sst_module_runtime_context *context);
int sst_module_runtime_restore(struct sst_module_runtime *runtime,
struct sst_module_runtime_context *context);
/* generic block allocation */
int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
struct list_head *block_list);
int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list);
/* scratch allocation */
int sst_block_alloc_scratch(struct sst_dsp *dsp);
void sst_block_free_scratch(struct sst_dsp *dsp);
/* Register the DSPs memory blocks - would be nice to read from ACPI */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
@ -309,4 +348,10 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
void *private);
void sst_mem_block_unregister_all(struct sst_dsp *dsp);
/* Create/Free DMA resources */
int sst_dma_new(struct sst_dsp *sst);
void sst_dma_free(struct sst_dma *dma);
u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
enum sst_mem_type type);
#endif

View File

@ -352,6 +352,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
INIT_LIST_HEAD(&sst->free_block_list);
INIT_LIST_HEAD(&sst->module_list);
INIT_LIST_HEAD(&sst->fw_list);
INIT_LIST_HEAD(&sst->scratch_block_list);
/* Initialise SST Audio DSP */
if (sst->ops->init) {
@ -366,6 +367,10 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
if (err)
goto irq_err;
err = sst_dma_new(sst);
if (err)
dev_warn(dev, "sst_dma_new failed %d\n", err);
return sst;
irq_err:
@ -381,6 +386,9 @@ void sst_dsp_free(struct sst_dsp *sst)
free_irq(sst->irq, sst);
if (sst->ops->free)
sst->ops->free(sst);
if (sst->dma)
sst_dma_free(sst->dma);
}
EXPORT_SYMBOL_GPL(sst_dsp_free);

View File

@ -245,6 +245,13 @@ void sst_memcpy_fromio_32(struct sst_dsp *sst,
/* DSP reset & boot */
void sst_dsp_reset(struct sst_dsp *sst);
int sst_dsp_boot(struct sst_dsp *sst);
/* DMA */
int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id);
void sst_dsp_dma_put_channel(struct sst_dsp *dsp);
int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
dma_addr_t src_addr, size_t size);
int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
dma_addr_t src_addr, size_t size);
/* Msg IO */
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,10 @@
#define SST_LP_SHIM_OFFSET 0xE7000
#define SST_WPT_IRAM_OFFSET 0xA0000
#define SST_LP_IRAM_OFFSET 0x80000
#define SST_WPT_DSP_DRAM_OFFSET 0x400000
#define SST_WPT_DSP_IRAM_OFFSET 0x00000
#define SST_LPT_DSP_DRAM_OFFSET 0x400000
#define SST_LPT_DSP_IRAM_OFFSET 0x00000
#define SST_SHIM_PM_REG 0x84
@ -86,9 +90,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
{
struct dma_block_info *block;
struct sst_module *mod;
struct sst_module_data block_data;
struct sst_module_template template;
int count;
int count, ret;
void __iomem *ram;
/* TODO: allowed module types need to be configurable */
@ -109,13 +112,9 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
memset(&template, 0, sizeof(template));
template.id = module->type;
template.entry = module->entry_point;
template.p.size = module->info.persistent_size;
template.p.type = SST_MEM_DRAM;
template.p.data_type = SST_DATA_P;
template.s.size = module->info.scratch_size;
template.s.type = SST_MEM_DRAM;
template.s.data_type = SST_DATA_S;
template.entry = module->entry_point - 4;
template.persistent_size = module->info.persistent_size;
template.scratch_size = module->info.scratch_size;
mod = sst_module_new(fw, &template, NULL);
if (mod == NULL)
@ -135,14 +134,14 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
switch (block->type) {
case SST_HSW_IRAM:
ram = dsp->addr.lpe;
block_data.offset =
mod->offset =
block->ram_offset + dsp->addr.iram_offset;
block_data.type = SST_MEM_IRAM;
mod->type = SST_MEM_IRAM;
break;
case SST_HSW_DRAM:
ram = dsp->addr.lpe;
block_data.offset = block->ram_offset;
block_data.type = SST_MEM_DRAM;
mod->offset = block->ram_offset;
mod->type = SST_MEM_DRAM;
break;
default:
dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
@ -151,30 +150,34 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
return -EINVAL;
}
block_data.size = block->size;
block_data.data_type = SST_DATA_M;
block_data.data = (void *)block + sizeof(*block);
block_data.data_offset = block_data.data - fw->dma_buf;
mod->size = block->size;
mod->data = (void *)block + sizeof(*block);
mod->data_offset = mod->data - fw->dma_buf;
dev_dbg(dsp->dev, "copy firmware block %d type 0x%x "
dev_dbg(dsp->dev, "module block %d type 0x%x "
"size 0x%x ==> ram %p offset 0x%x\n",
count, block->type, block->size, ram,
count, mod->type, block->size, ram,
block->ram_offset);
sst_module_insert_fixed_block(mod, &block_data);
ret = sst_module_alloc_blocks(mod);
if (ret < 0) {
dev_err(dsp->dev, "error: could not allocate blocks for module %d\n",
count);
sst_module_free(mod);
return ret;
}
block = (void *)block + sizeof(*block) + block->size;
}
return 0;
}
static int hsw_parse_fw_image(struct sst_fw *sst_fw)
{
struct fw_header *header;
struct sst_module *scratch;
struct fw_module_header *module;
struct sst_dsp *dsp = sst_fw->dsp;
struct sst_hsw *hsw = sst_fw->private;
int ret, count;
/* Read the header information from the data pointer */
@ -204,12 +207,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
module = (void *)module + sizeof(*module) + module->mod_size;
}
/* allocate persistent/scratch mem regions */
scratch = sst_mem_block_alloc_scratch(dsp);
if (scratch == NULL)
return -ENOMEM;
sst_hsw_set_scratch_module(hsw, scratch);
/* allocate scratch mem regions */
sst_block_alloc_scratch(dsp);
return 0;
}
@ -467,12 +466,16 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
region = lp_region;
region_count = ARRAY_SIZE(lp_region);
sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET;
sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET;
sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
break;
case SST_DEV_ID_WILDCAT_POINT:
region = wpt_region;
region_count = ARRAY_SIZE(wpt_region);
sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET;
sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET;
sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
break;
default:

View File

@ -1351,10 +1351,11 @@ int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
}
int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
u32 entry_point)
struct sst_hsw_stream *stream, struct sst_module_runtime *runtime)
{
struct sst_hsw_module_map *map = &stream->request.map;
struct sst_dsp *dsp = sst_hsw_get_dsp(hsw);
struct sst_module *module = runtime->module;
if (stream->commited) {
dev_err(hsw->dev, "error: stream committed for set module\n");
@ -1363,36 +1364,25 @@ int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
/* only support initial module atm */
map->module_entries_count = 1;
map->module_entries[0].module_id = module_id;
map->module_entries[0].entry_point = entry_point;
map->module_entries[0].module_id = module->id;
map->module_entries[0].entry_point = module->entry;
return 0;
}
stream->request.persistent_mem.offset =
sst_dsp_get_offset(dsp, runtime->persistent_offset, SST_MEM_DRAM);
stream->request.persistent_mem.size = module->persistent_size;
int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 offset, u32 size)
{
if (stream->commited) {
dev_err(hsw->dev, "error: stream committed for set pmem\n");
return -EINVAL;
}
stream->request.scratch_mem.offset =
sst_dsp_get_offset(dsp, dsp->scratch_offset, SST_MEM_DRAM);
stream->request.scratch_mem.size = dsp->scratch_size;
stream->request.persistent_mem.offset = offset;
stream->request.persistent_mem.size = size;
return 0;
}
int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 offset, u32 size)
{
if (stream->commited) {
dev_err(hsw->dev, "error: stream committed for set smem\n");
return -EINVAL;
}
stream->request.scratch_mem.offset = offset;
stream->request.scratch_mem.size = size;
dev_dbg(hsw->dev, "module %d runtime %d using:\n", module->id,
runtime->id);
dev_dbg(hsw->dev, " persistent offset 0x%x bytes 0x%x\n",
stream->request.persistent_mem.offset,
stream->request.persistent_mem.size);
dev_dbg(hsw->dev, " scratch offset 0x%x bytes 0x%x\n",
stream->request.scratch_mem.offset,
stream->request.scratch_mem.size);
return 0;
}
@ -1673,32 +1663,48 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw,
dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
dx->entries_no, state);
memcpy(&hsw->dx, dx, sizeof(*dx));
return 0;
return ret;
}
/* Used to save state into hsw->dx_reply */
int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
u32 *offset, u32 *size, u32 *source)
struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
int mod_id, int offset)
{
struct sst_hsw_ipc_dx_memory_item *dx_mem;
struct sst_hsw_ipc_dx_reply *dx_reply;
int entry_no;
struct sst_dsp *dsp = hsw->dsp;
struct sst_module *module;
struct sst_module_runtime *runtime;
int err;
dx_reply = &hsw->dx;
entry_no = dx_reply->entries_no;
module = sst_module_get_from_id(dsp, mod_id);
if (module == NULL) {
dev_err(dsp->dev, "error: failed to get module %d for pcm\n",
mod_id);
return NULL;
}
trace_ipc_request("PM get Dx state", entry_no);
runtime = sst_module_runtime_new(module, mod_id, NULL);
if (runtime == NULL) {
dev_err(dsp->dev, "error: failed to create module %d runtime\n",
mod_id);
return NULL;
}
if (item >= entry_no)
return -EINVAL;
err = sst_module_runtime_alloc_blocks(runtime, offset);
if (err < 0) {
dev_err(dsp->dev, "error: failed to alloc blocks for module %d runtime\n",
mod_id);
sst_module_runtime_free(runtime);
return NULL;
}
dx_mem = &dx_reply->mem_info[item];
*offset = dx_mem->offset;
*size = dx_mem->size;
*source = dx_mem->source;
dev_dbg(dsp->dev, "runtime id %d created for module %d\n", runtime->id,
mod_id);
return runtime;
}
return 0;
void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime)
{
sst_module_runtime_free_blocks(runtime);
sst_module_runtime_free(runtime);
}
static int msg_empty_list_init(struct sst_hsw *hsw)
@ -1718,12 +1724,6 @@ static int msg_empty_list_init(struct sst_hsw *hsw)
return 0;
}
void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
struct sst_module *scratch)
{
hsw->scratch = scratch;
}
struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
{
return hsw->dsp;

View File

@ -40,6 +40,7 @@ struct sst_hsw_stream;
struct sst_hsw_log_stream;
struct sst_pdata;
struct sst_module;
struct sst_module_runtime;
extern struct sst_ops haswell_ops;
/* Stream Allocate Path ID */
@ -432,8 +433,7 @@ int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
enum sst_hsw_interleaving style);
int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
u32 entry_point);
struct sst_hsw_stream *stream, struct sst_module_runtime *runtime);
int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 offset, u32 size);
int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
@ -486,7 +486,10 @@ int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
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);
void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
struct sst_module *scratch);
/* runtime module management */
struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
int mod_id, int offset);
void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime);
#endif

View File

@ -89,16 +89,23 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = {
.buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
};
struct hsw_pcm_module_map {
int dai_id;
enum sst_hsw_module_id mod_id;
};
/* private data for each PCM DSP stream */
struct hsw_pcm_data {
int dai_id;
struct sst_hsw_stream *stream;
struct sst_module_runtime *runtime;
u32 volume[2];
struct snd_pcm_substream *substream;
struct snd_compr_stream *cstream;
unsigned int wpos;
struct mutex mutex;
bool allocated;
int persistent_offset;
};
/* private data for the driver */
@ -472,28 +479,8 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
/* we use hardcoded memory offsets atm, will be updated for new FW */
if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
0x449400, 0x4000);
sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
0x400000, 0);
} else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);
sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
module_data->offset, module_data->size);
sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
0x44d400, 0x3800);
sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
module_data->offset, module_data->size);
sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
0x400000, 0);
}
sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
pcm_data->runtime);
ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
if (ret < 0) {
@ -654,6 +641,55 @@ static struct snd_pcm_ops hsw_pcm_ops = {
.page = snd_pcm_sgbuf_ops_page,
};
/* static mappings between PCMs and modules - may be dynamic in future */
static struct hsw_pcm_module_map mod_map[] = {
{0, SST_HSW_MODULE_PCM_SYSTEM}, /* "System Pin" */
{1, SST_HSW_MODULE_PCM}, /* "Offload0 Pin" */
{2, SST_HSW_MODULE_PCM}, /* "Offload1 Pin" */
{3, SST_HSW_MODULE_PCM_REFERENCE}, /* "Loopback Pin" */
{4, SST_HSW_MODULE_PCM_CAPTURE}, /* "Capture Pin" */
};
static int hsw_pcm_create_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[i];
pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
mod_map[i].mod_id, pcm_data->persistent_offset);
if (pcm_data->runtime == NULL)
goto err;
pcm_data->persistent_offset =
pcm_data->runtime->persistent_offset;
}
return 0;
err:
for (--i; i >= 0; i--) {
pcm_data = &pdata->pcm[i];
sst_hsw_runtime_module_free(pcm_data->runtime);
}
return -ENODEV;
}
static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
{
struct hsw_pcm_data *pcm_data;
int i;
for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
pcm_data = &pdata->pcm[i];
sst_hsw_runtime_module_free(pcm_data->runtime);
}
}
static void hsw_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
@ -797,6 +833,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
}
}
/* allocate runtime modules */
hsw_pcm_create_modules(priv_data);
return 0;
err: