diff options
Diffstat (limited to 'sound/soc/intel/skylake')
-rw-r--r-- | sound/soc/intel/skylake/skl-messages.c | 6 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-pcm.c | 57 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.c | 15 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.h | 5 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 78 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl.c | 67 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl.h | 4 |
7 files changed, 189 insertions, 43 deletions
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index de6dac496a0d..4629372d7c8e 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -688,14 +688,14 @@ int skl_unbind_modules(struct skl_sst *ctx, /* get src queue index */ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); if (src_index < 0) - return -EINVAL; + return 0; msg.src_queue = src_index; /* get dst queue index */ dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); if (dst_index < 0) - return -EINVAL; + return 0; msg.dst_queue = dst_index; @@ -747,7 +747,7 @@ int skl_bind_modules(struct skl_sst *ctx, skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); - if (src_mcfg->m_state < SKL_MODULE_INIT_DONE && + if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || dst_mcfg->m_state < SKL_MODULE_INIT_DONE) return 0; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index b89ae6f7c096..b6e6b61d10ec 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -25,6 +25,8 @@ #include <sound/soc.h> #include "skl.h" #include "skl-topology.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" #define HDA_MONO 1 #define HDA_STEREO 2 @@ -36,6 +38,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ SNDRV_PCM_INFO_HAS_LINK_ATIME | @@ -272,6 +275,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; + struct skl *skl = ebus_to_skl(ebus); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -285,6 +289,16 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, NULL); skl_set_suspend_active(substream, dai, false); + /* + * check if close is for "Reference Pin" and set back the + * CGCTL.MISCBDCGE if disabled by driver + */ + if (!strncmp(dai->name, "Reference Pin", 13) && + skl->skl_sst->miscbdcg_disabled) { + skl->skl_sst->enable_miscbdcge(dai->dev, true); + skl->skl_sst->miscbdcg_disabled = false; + } + kfree(dma_params); } @@ -380,6 +394,15 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: skl_pcm_prepare(substream, dai); + /* + * enable DMA Resume enable bit for the stream, set the dpib + * & lpib position to resune before starting the DMA + */ + snd_hdac_ext_stream_drsm_enable(ebus, true, + hdac_stream(stream)->index); + snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); + snd_hdac_ext_stream_set_lpib(stream, stream->lpib); + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* @@ -408,8 +431,17 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, return ret; ret = skl_decoupled_trigger(substream, cmd); - if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) { + /* save the dpib and lpib positions */ + stream->dpib = readl(ebus->bus.remap_addr + + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(stream)->index)); + + stream->lpib = snd_hdac_stream_get_pos_lpib( + hdac_stream(stream)); snd_hdac_ext_stream_decouple(ebus, stream, false); + } break; default: @@ -465,11 +497,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct hdac_ext_link *link; - if (link_dev->link_prepared) { - dev_dbg(dai->dev, "already stream is prepared - returning\n"); - return 0; - } - dma_params = (struct skl_dma_params *) snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) @@ -477,14 +504,15 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - snd_hdac_ext_link_stream_reset(link_dev); - - snd_hdac_ext_link_stream_setup(link_dev, format_val); - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); if (!link) return -EINVAL; + snd_hdac_ext_bus_link_power_up(link); + snd_hdac_ext_link_stream_reset(link_dev); + + snd_hdac_ext_link_stream_setup(link_dev, format_val); + snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); link_dev->link_prepared = 1; @@ -496,12 +524,16 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: + snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; @@ -509,6 +541,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(ebus, stream, false); break; default: @@ -829,6 +863,7 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, else delay += hstream->bufsize; } + delay = (hstream->bufsize == delay) ? 0 : delay; if (delay >= hstream->period_bytes) { dev_info(bus->dev, diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 62e665a3b8f7..543460293b00 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -16,8 +16,10 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" +#include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#include "sound/hdaudio_ext.h" #define IPC_IXC_STATUS_BITS 24 @@ -322,6 +324,19 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, wake_up(&skl->boot_wait); break; + case IPC_GLB_NOTIFY_PHRASE_DETECTED: + dev_dbg(ipc->dev, "***** Phrase Detected **********\n"); + + /* + * Per HW recomendation, After phrase detection, + * clear the CGCTL.MISCBDCGE. + * + * This will be set back on stream closure + */ + skl->enable_miscbdcge(ipc->dev, false); + skl->miscbdcg_disabled = true; + break; + default: dev_err(ipc->dev, "ipc: Unhandled error msg=%x", header.primary); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 1bbcdb471cf2..d59d1ba62a43 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -55,6 +55,11 @@ struct skl_sst { /* IPC messaging */ struct sst_generic_ipc ipc; + + /* callback for miscbdge */ + void (*enable_miscbdcge)(struct device *dev, bool enable); + /*Is CGCTL.MISCBDCGE disabled*/ + bool miscbdcg_disabled; }; struct skl_ipc_init_instance_msg { diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 5315b7422b98..a294fee431f0 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -54,12 +54,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) /* * Each pipelines needs memory to be allocated. Check if we have free memory - * from available pool. Then only add this to pool - * This is freed when pipe is deleted - * Note: DSP does actual memory management we only keep track for complete - * pool + * from available pool. */ -static bool skl_tplg_alloc_pipe_mem(struct skl *skl, +static bool skl_is_pipe_mem_avail(struct skl *skl, struct skl_module_cfg *mconfig) { struct skl_sst *ctx = skl->skl_sst; @@ -74,10 +71,20 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl, "exceeds ppl memory available %d mem %d\n", skl->resource.max_mem, skl->resource.mem); return false; + } else { + return true; } +} +/* + * Add the mem to the mem pool. This is freed when pipe is deleted. + * Note: DSP does actual memory management we only keep track for complete + * pool + */ +static void skl_tplg_alloc_pipe_mem(struct skl *skl, + struct skl_module_cfg *mconfig) +{ skl->resource.mem += mconfig->pipe->memory_pages; - return true; } /* @@ -85,10 +92,10 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl, * quantified in MCPS (Million Clocks Per Second) required for module/pipe * * Each pipelines needs mcps to be allocated. Check if we have mcps for this - * pipe. This adds the mcps to driver counter - * This is removed on pipeline delete + * pipe. */ -static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, + +static bool skl_is_pipe_mcps_avail(struct skl *skl, struct skl_module_cfg *mconfig) { struct skl_sst *ctx = skl->skl_sst; @@ -98,13 +105,18 @@ static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, "%s: module_id %d instance %d\n", __func__, mconfig->id.module_id, mconfig->id.instance_id); dev_err(ctx->dev, - "exceeds ppl memory available %d > mem %d\n", + "exceeds ppl mcps available %d > mem %d\n", skl->resource.max_mcps, skl->resource.mcps); return false; + } else { + return true; } +} +static void skl_tplg_alloc_pipe_mcps(struct skl *skl, + struct skl_module_cfg *mconfig) +{ skl->resource.mcps += mconfig->mcps; - return true; } /* @@ -411,7 +423,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) mconfig = w->priv; /* check resource available */ - if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) + if (!skl_is_pipe_mcps_avail(skl, mconfig)) return -ENOMEM; if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { @@ -435,6 +447,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) ret = skl_tplg_set_module_params(w, ctx); if (ret < 0) return ret; + skl_tplg_alloc_pipe_mcps(skl, mconfig); } return 0; @@ -477,10 +490,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, struct skl_sst *ctx = skl->skl_sst; /* check resource available */ - if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) + if (!skl_is_pipe_mcps_avail(skl, mconfig)) return -EBUSY; - if (!skl_tplg_alloc_pipe_mem(skl, mconfig)) + if (!skl_is_pipe_mem_avail(skl, mconfig)) return -ENOMEM; /* @@ -526,11 +539,15 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, src_module = dst_module; } + skl_tplg_alloc_pipe_mem(skl, mconfig); + skl_tplg_alloc_pipe_mcps(skl, mconfig); + return 0; } static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, struct skl *skl, + struct snd_soc_dapm_widget *src_w, struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; @@ -547,6 +564,10 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); next_sink = p->sink; + + if (!is_skl_dsp_widget_type(p->sink)) + return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); + /* * here we will check widgets in sink pipelines, so that * can be any widgets type and we are only interested if @@ -576,7 +597,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, } if (!sink) - return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); + return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); return 0; } @@ -605,7 +626,7 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, * if sink is not started, start sink pipe first, then start * this pipe */ - ret = skl_tplg_bind_sinks(w, skl, src_mconfig); + ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); if (ret) return ret; @@ -773,10 +794,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, continue; } - ret = skl_unbind_modules(ctx, src_module, dst_module); - if (ret < 0) - return ret; - + skl_unbind_modules(ctx, src_module, dst_module); src_module = dst_module; } @@ -814,9 +832,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * This is a connecter and if path is found that means * unbind between source and sink has not happened yet */ - ret = skl_stop_pipe(ctx, sink_mconfig->pipe); - if (ret < 0) - return ret; ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); } @@ -842,6 +857,12 @@ static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); + case SND_SOC_DAPM_POST_PMU: + return skl_tplg_mixer_dapm_post_pmu_event(w, skl); + + case SND_SOC_DAPM_PRE_PMD: + return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); + case SND_SOC_DAPM_POST_PMD: return skl_tplg_mixer_dapm_post_pmd_event(w, skl); } @@ -916,6 +937,13 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, skl_get_module_params(skl->skl_sst, (u32 *)bc->params, bc->max, bc->param_id, mconfig); + /* decrement size for TLV header */ + size -= 2 * sizeof(u32); + + /* check size as we don't want to send kernel data */ + if (size > bc->max) + size = bc->max; + if (bc->params) { if (copy_to_user(data, &bc->param_id, sizeof(u32))) return -EFAULT; @@ -1508,14 +1536,16 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) */ ret = snd_soc_tplg_component_load(&platform->component, &skl_tplg_ops, fw, 0); - release_firmware(fw); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); + release_firmware(fw); return -EINVAL; } skl->resource.max_mcps = SKL_MAX_MCPS; skl->resource.max_mem = SKL_FW_MAX_MEM; + skl->tplg = fw; + return 0; } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index c38bf99ced10..092705e73db4 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -25,9 +25,12 @@ #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/platform_device.h> +#include <linux/firmware.h> #include <sound/pcm.h> #include "../common/sst-acpi.h" #include "skl.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" /* * initialize the PCI registers @@ -58,6 +61,49 @@ static void skl_init_pci(struct skl *skl) skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); } +static void update_pci_dword(struct pci_dev *pci, + unsigned int reg, u32 mask, u32 val) +{ + u32 data = 0; + + pci_read_config_dword(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_dword(pci, reg, data); +} + +/* + * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits + * + * @dev: device pointer + * @enable: enable/disable flag + */ +static void skl_enable_miscbdcge(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + u32 val; + + val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; + + update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val); +} + +/* + * While performing reset, controller may not come back properly causing + * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset + * (init chip) and then again set CGCTL.MISCBDCGE to 1 + */ +static int skl_init_chip(struct hdac_bus *bus, bool full_reset) +{ + int ret; + + skl_enable_miscbdcge(bus->dev, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + skl_enable_miscbdcge(bus->dev, true); + + return ret; +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { @@ -144,7 +190,9 @@ static int _skl_suspend(struct hdac_ext_bus *ebus) return ret; snd_hdac_bus_stop_chip(bus); + skl_enable_miscbdcge(bus->dev, false); snd_hdac_bus_enter_link_reset(bus); + skl_enable_miscbdcge(bus->dev, true); return 0; } @@ -155,7 +203,7 @@ static int _skl_resume(struct hdac_ext_bus *ebus) struct hdac_bus *bus = ebus_to_hbus(ebus); skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); return skl_resume_dsp(skl); } @@ -170,12 +218,15 @@ static int skl_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); /* * Do not suspend if streams which are marked ignore suspend are * running, we need to save the state for these and continue */ if (skl->supend_active) { + snd_hdac_ext_bus_link_power_down_all(ebus); + enable_irq_wake(bus->irq); pci_save_state(pci); pci_disable_device(pci); return 0; @@ -189,6 +240,7 @@ static int skl_resume(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); int ret; /* @@ -198,6 +250,8 @@ static int skl_resume(struct device *dev) if (skl->supend_active) { pci_restore_state(pci); ret = pci_enable_device(pci); + snd_hdac_ext_bus_link_power_up_all(ebus); + disable_irq_wake(bus->irq); } else { ret = _skl_resume(ebus); } @@ -379,7 +433,7 @@ static int skl_codec_create(struct hdac_ext_bus *ebus) * back to the sanity state. */ snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); } } } @@ -489,7 +543,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus) /* initialize chip */ skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); /* codec detection */ if (!bus->codec_mask) { @@ -538,6 +592,8 @@ static int skl_probe(struct pci_dev *pci, dev_dbg(bus->dev, "error failed to register dsp\n"); goto out_mach_free; } + skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; + } if (ebus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(ebus); @@ -558,8 +614,6 @@ static int skl_probe(struct pci_dev *pci, goto out_unregister; /*configure PM */ - pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY); - pm_runtime_use_autosuspend(bus->dev); pm_runtime_put_noidle(bus->dev); pm_runtime_allow(bus->dev); @@ -585,6 +639,9 @@ static void skl_remove(struct pci_dev *pci) struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct skl *skl = ebus_to_skl(ebus); + if (skl->tplg) + release_firmware(skl->tplg); + if (pci_dev_run_wake(pci)) pm_runtime_get_noresume(&pci->dev); pci_dev_put(pci); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 3d167eed0f59..4d18293b5537 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -48,6 +48,9 @@ #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 +#define AZX_PCIREG_CGCTL 0x48 +#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) + struct skl_dsp_resource { u32 max_mcps; u32 max_mem; @@ -70,6 +73,7 @@ struct skl { struct list_head ppl_list; const char *fw_name; + const struct firmware *tplg; int supend_active; }; |