aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h14
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c53
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h6
-rw-r--r--sound/soc/intel/skylake/skl-sst.c175
-rw-r--r--sound/soc/intel/skylake/skl-topology.c29
5 files changed, 276 insertions, 1 deletions
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index f2a69d9e56b3..5d0947935e2b 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -114,6 +114,9 @@ struct skl_dsp_fw_ops {
114 int (*set_state_D0)(struct sst_dsp *ctx); 114 int (*set_state_D0)(struct sst_dsp *ctx);
115 int (*set_state_D3)(struct sst_dsp *ctx); 115 int (*set_state_D3)(struct sst_dsp *ctx);
116 unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); 116 unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
117 int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name);
118 int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
119
117}; 120};
118 121
119struct skl_dsp_loader_ops { 122struct skl_dsp_loader_ops {
@@ -123,6 +126,17 @@ struct skl_dsp_loader_ops {
123 struct snd_dma_buffer *dmab); 126 struct snd_dma_buffer *dmab);
124}; 127};
125 128
129struct skl_load_module_info {
130 u16 mod_id;
131 const struct firmware *fw;
132};
133
134struct skl_module_table {
135 struct skl_load_module_info *mod_info;
136 unsigned int usage_cnt;
137 struct list_head list;
138};
139
126void skl_cldma_process_intr(struct sst_dsp *ctx); 140void skl_cldma_process_intr(struct sst_dsp *ctx);
127void skl_cldma_int_disable(struct sst_dsp *ctx); 141void skl_cldma_int_disable(struct sst_dsp *ctx);
128int skl_cldma_prepare(struct sst_dsp *ctx); 142int skl_cldma_prepare(struct sst_dsp *ctx);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 95679c02c6ee..33860d2311c4 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -130,6 +130,11 @@
130#define IPC_SRC_QUEUE_MASK 0x7 130#define IPC_SRC_QUEUE_MASK 0x7
131#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ 131#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \
132 << IPC_SRC_QUEUE_SHIFT) 132 << IPC_SRC_QUEUE_SHIFT)
133/* Load Module count */
134#define IPC_LOAD_MODULE_SHIFT 0
135#define IPC_LOAD_MODULE_MASK 0xFF
136#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \
137 << IPC_LOAD_MODULE_SHIFT)
133 138
134/* Save pipeline messgae extension register */ 139/* Save pipeline messgae extension register */
135#define IPC_DMA_ID_SHIFT 0 140#define IPC_DMA_ID_SHIFT 0
@@ -728,6 +733,54 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
728} 733}
729EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); 734EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
730 735
736/*
737 * In order to load a module we need to send IPC to initiate that. DMA will
738 * performed to load the module memory. The FW supports multiple module load
739 * at single shot, so we can send IPC with N modules represented by
740 * module_cnt
741 */
742int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
743 u8 module_cnt, void *data)
744{
745 struct skl_ipc_header header = {0};
746 u64 *ipc_header = (u64 *)(&header);
747 int ret;
748
749 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
750 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
751 header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
752 header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
753
754 ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
755 (sizeof(u16) * module_cnt), NULL, 0);
756 if (ret < 0)
757 dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
758
759 return ret;
760}
761EXPORT_SYMBOL_GPL(skl_ipc_load_modules);
762
763int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt,
764 void *data)
765{
766 struct skl_ipc_header header = {0};
767 u64 *ipc_header = (u64 *)(&header);
768 int ret;
769
770 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
771 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
772 header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS);
773 header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
774
775 ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
776 (sizeof(u16) * module_cnt), NULL, 0);
777 if (ret < 0)
778 dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret);
779
780 return ret;
781}
782EXPORT_SYMBOL_GPL(skl_ipc_unload_modules);
783
731int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, 784int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
732 struct skl_ipc_large_config_msg *msg, u32 *param) 785 struct skl_ipc_large_config_msg *msg, u32 *param)
733{ 786{
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index f1a154e45dc3..e17012778560 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -108,6 +108,12 @@ int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc,
108int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc, 108int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc,
109 struct skl_ipc_bind_unbind_msg *msg); 109 struct skl_ipc_bind_unbind_msg *msg);
110 110
111int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
112 u8 module_cnt, void *data);
113
114int skl_ipc_unload_modules(struct sst_generic_ipc *ipc,
115 u8 module_cnt, void *data);
116
111int skl_ipc_set_dx(struct sst_generic_ipc *ipc, 117int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
112 u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); 118 u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
113 119
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index e1d34d5c3f9a..8cd5cdb21fd5 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -38,6 +38,8 @@
38#define SKL_INSTANCE_ID 0 38#define SKL_INSTANCE_ID 0
39#define SKL_BASE_FW_MODULE_ID 0 39#define SKL_BASE_FW_MODULE_ID 0
40 40
41#define SKL_NUM_MODULES 1
42
41static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) 43static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
42{ 44{
43 u32 cur_sts; 45 u32 cur_sts;
@@ -202,11 +204,182 @@ static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
202 return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); 204 return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
203} 205}
204 206
207/*
208 * since get/set_module are called from DAPM context,
209 * we don't need lock for usage count
210 */
211static unsigned int skl_get_module(struct sst_dsp *ctx, u16 mod_id)
212{
213 struct skl_module_table *module;
214
215 list_for_each_entry(module, &ctx->module_list, list) {
216 if (module->mod_info->mod_id == mod_id)
217 return ++module->usage_cnt;
218 }
219
220 return -EINVAL;
221}
222
223static unsigned int skl_put_module(struct sst_dsp *ctx, u16 mod_id)
224{
225 struct skl_module_table *module;
226
227 list_for_each_entry(module, &ctx->module_list, list) {
228 if (module->mod_info->mod_id == mod_id)
229 return --module->usage_cnt;
230 }
231
232 return -EINVAL;
233}
234
235static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx,
236 char *mod_name, int mod_id)
237{
238 const struct firmware *fw;
239 struct skl_module_table *skl_module;
240 unsigned int size;
241 int ret;
242
243 ret = request_firmware(&fw, mod_name, ctx->dev);
244 if (ret < 0) {
245 dev_err(ctx->dev, "Request Module %s failed :%d\n",
246 mod_name, ret);
247 return NULL;
248 }
249
250 skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL);
251 if (skl_module == NULL) {
252 release_firmware(fw);
253 return NULL;
254 }
255
256 size = sizeof(*skl_module->mod_info);
257 skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
258 if (skl_module->mod_info == NULL) {
259 release_firmware(fw);
260 return NULL;
261 }
262
263 skl_module->mod_info->mod_id = mod_id;
264 skl_module->mod_info->fw = fw;
265 list_add(&skl_module->list, &ctx->module_list);
266
267 return skl_module;
268}
269
270/* get a module from it's unique ID */
271static struct skl_module_table *skl_module_get_from_id(
272 struct sst_dsp *ctx, u16 mod_id)
273{
274 struct skl_module_table *module;
275
276 if (list_empty(&ctx->module_list)) {
277 dev_err(ctx->dev, "Module list is empty\n");
278 return NULL;
279 }
280
281 list_for_each_entry(module, &ctx->module_list, list) {
282 if (module->mod_info->mod_id == mod_id)
283 return module;
284 }
285
286 return NULL;
287}
288
289static int skl_transfer_module(struct sst_dsp *ctx,
290 struct skl_load_module_info *module)
291{
292 int ret;
293 struct skl_sst *skl = ctx->thread_context;
294
295 ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data,
296 module->fw->size);
297 if (ret < 0)
298 return ret;
299
300 ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES,
301 (void *)&module->mod_id);
302 if (ret < 0)
303 dev_err(ctx->dev, "Failed to Load module: %d\n", ret);
304
305 ctx->cl_dev.ops.cl_stop_dma(ctx);
306
307 return ret;
308}
309
310static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid)
311{
312 struct skl_module_table *module_entry = NULL;
313 int ret = 0;
314 char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
315
316 snprintf(mod_name, sizeof(mod_name), "%s%s%s",
317 "intel/dsp_fw_", guid, ".bin");
318
319 module_entry = skl_module_get_from_id(ctx, mod_id);
320 if (module_entry == NULL) {
321 module_entry = skl_fill_module_table(ctx, mod_name, mod_id);
322 if (module_entry == NULL) {
323 dev_err(ctx->dev, "Failed to Load module\n");
324 return -EINVAL;
325 }
326 }
327
328 if (!module_entry->usage_cnt) {
329 ret = skl_transfer_module(ctx, module_entry->mod_info);
330 if (ret < 0) {
331 dev_err(ctx->dev, "Failed to Load module\n");
332 return ret;
333 }
334 }
335
336 ret = skl_get_module(ctx, mod_id);
337
338 return ret;
339}
340
341static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
342{
343 unsigned int usage_cnt;
344 struct skl_sst *skl = ctx->thread_context;
345 int ret = 0;
346
347 usage_cnt = skl_put_module(ctx, mod_id);
348 if (usage_cnt < 0) {
349 dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
350 return -EIO;
351 }
352 ret = skl_ipc_unload_modules(&skl->ipc,
353 SKL_NUM_MODULES, &mod_id);
354 if (ret < 0) {
355 dev_err(ctx->dev, "Failed to UnLoad module\n");
356 skl_get_module(ctx, mod_id);
357 return ret;
358 }
359
360 return ret;
361}
362
363static void skl_clear_module_table(struct sst_dsp *ctx)
364{
365 struct skl_module_table *module, *tmp;
366
367 if (list_empty(&ctx->module_list))
368 return;
369
370 list_for_each_entry_safe(module, tmp, &ctx->module_list, list) {
371 list_del(&module->list);
372 release_firmware(module->mod_info->fw);
373 }
374}
375
205static struct skl_dsp_fw_ops skl_fw_ops = { 376static struct skl_dsp_fw_ops skl_fw_ops = {
206 .set_state_D0 = skl_set_dsp_D0, 377 .set_state_D0 = skl_set_dsp_D0,
207 .set_state_D3 = skl_set_dsp_D3, 378 .set_state_D3 = skl_set_dsp_D3,
208 .load_fw = skl_load_base_firmware, 379 .load_fw = skl_load_base_firmware,
209 .get_fw_errcode = skl_get_errorcode, 380 .get_fw_errcode = skl_get_errorcode,
381 .load_mod = skl_load_module,
382 .unload_mod = skl_unload_module,
210}; 383};
211 384
212static struct sst_ops skl_ops = { 385static struct sst_ops skl_ops = {
@@ -251,6 +424,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
251 sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), 424 sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
252 SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); 425 SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
253 426
427 INIT_LIST_HEAD(&sst->module_list);
254 sst->dsp_ops = dsp_ops; 428 sst->dsp_ops = dsp_ops;
255 sst->fw_ops = skl_fw_ops; 429 sst->fw_ops = skl_fw_ops;
256 430
@@ -277,6 +451,7 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
277 451
278void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) 452void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
279{ 453{
454 skl_clear_module_table(ctx->dsp);
280 skl_ipc_free(&ctx->ipc); 455 skl_ipc_free(&ctx->ipc);
281 ctx->dsp->ops->free(ctx->dsp); 456 ctx->dsp->ops->free(ctx->dsp);
282} 457}
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 622f7430e100..32735eff386c 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -26,6 +26,8 @@
26#include "skl-topology.h" 26#include "skl-topology.h"
27#include "skl.h" 27#include "skl.h"
28#include "skl-tplg-interface.h" 28#include "skl-tplg-interface.h"
29#include "../common/sst-dsp.h"
30#include "../common/sst-dsp-priv.h"
29 31
30#define SKL_CH_FIXUP_MASK (1 << 0) 32#define SKL_CH_FIXUP_MASK (1 << 0)
31#define SKL_RATE_FIXUP_MASK (1 << 1) 33#define SKL_RATE_FIXUP_MASK (1 << 1)
@@ -412,6 +414,13 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
412 if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) 414 if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
413 return -ENOMEM; 415 return -ENOMEM;
414 416
417 if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
418 ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
419 mconfig->id.module_id, mconfig->guid);
420 if (ret < 0)
421 return ret;
422 }
423
415 /* 424 /*
416 * apply fix/conversion to module params based on 425 * apply fix/conversion to module params based on
417 * FE/BE params 426 * FE/BE params
@@ -431,6 +440,24 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
431 return 0; 440 return 0;
432} 441}
433 442
443static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
444 struct skl_pipe *pipe)
445{
446 struct skl_pipe_module *w_module = NULL;
447 struct skl_module_cfg *mconfig = NULL;
448
449 list_for_each_entry(w_module, &pipe->w_list, node) {
450 mconfig = w_module->w->priv;
451
452 if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod)
453 return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
454 mconfig->id.module_id);
455 }
456
457 /* no modules to unload in this path, so return */
458 return 0;
459}
460
434/* 461/*
435 * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 462 * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
436 * need create the pipeline. So we do following: 463 * need create the pipeline. So we do following:
@@ -755,7 +782,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
755 782
756 ret = skl_delete_pipe(ctx, mconfig->pipe); 783 ret = skl_delete_pipe(ctx, mconfig->pipe);
757 784
758 return ret; 785 return skl_tplg_unload_pipe_modules(ctx, s_pipe);
759} 786}
760 787
761/* 788/*