Commit 2775f88b authored by Mark Brown's avatar Mark Brown

ASoC: SOF: Extend ChainDMA and DSPless mode to LNL+

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

For both ChainDMA and DSPless mode the requirement is that the link must
be serviced by HD-DMA.
On pre Lunar Lake platforms this was only valid for HDAudio links but with
Lunar Lake all link types now serviced by HD-DMA.

This allows us to enable ChainDMA and DSPless mode for SoundWire links as
well.
parents fd236653 2065610b
......@@ -83,6 +83,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
.is_chain_dma_supported = hda_is_chain_dma_supported,
/* PM */
.suspend = hda_dsp_suspend,
......
......@@ -522,6 +522,17 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.get_hlink = hda_get_hlink,
};
static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
.get_hext_stream = hda_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
.release_hext_stream = hda_release_hext_stream,
.setup_hext_stream = hda_setup_hext_stream,
.reset_hext_stream = hda_reset_hext_stream,
.trigger = hda_trigger,
.calc_stream_format = generic_calc_stream_format,
.get_hlink = sdw_get_hlink,
};
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
......@@ -596,6 +607,13 @@ static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
.get_hlink = hda_get_hlink,
};
static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
.get_hext_stream = hda_dspless_get_hext_stream,
.setup_hext_stream = hda_dspless_setup_hext_stream,
.calc_stream_format = generic_calc_stream_format,
.get_hlink = sdw_get_hlink,
};
#endif
const struct hda_dai_widget_dma_ops *
......@@ -603,12 +621,24 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
struct snd_sof_dai *sdai;
const struct sof_intel_dsp_desc *chip;
if (sdev->dspless_mode_selected)
return &hda_dspless_dma_ops;
chip = get_chip_info(sdev->pdata);
sdai = swidget->private;
if (sdev->dspless_mode_selected) {
switch (sdai->type) {
case SOF_DAI_INTEL_HDA:
return &hda_dspless_dma_ops;
case SOF_DAI_INTEL_ALH:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
return &sdw_dspless_dma_ops;
default:
return NULL;
}
}
switch (sdev->pdata->ipc_type) {
case SOF_IPC_TYPE_3:
{
......@@ -620,22 +650,15 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
}
case SOF_IPC_TYPE_4:
{
struct sof_ipc4_copier *ipc4_copier = sdai->private;
const struct sof_intel_dsp_desc *chip;
chip = get_chip_info(sdev->pdata);
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
switch (ipc4_copier->dai_type) {
switch (sdai->type) {
case SOF_DAI_INTEL_HDA:
{
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
if (pipeline->use_chain_dma)
return &hda_ipc4_chain_dma_ops;
return &hda_ipc4_dma_ops;
}
case SOF_DAI_INTEL_SSP:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
......@@ -647,6 +670,8 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
case SOF_DAI_INTEL_ALH:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
if (pipeline->use_chain_dma)
return &sdw_ipc4_chain_dma_ops;
return &sdw_ipc4_dma_ops;
default:
......
......@@ -83,12 +83,13 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
sdev = widget_to_sdev(w);
/*
* The swidget parameter of hda_select_dai_widget_ops() is ignored in
* case of DSPless mode
*/
if (!swidget) {
dev_err(sdev->dev, "%s: swidget is NULL\n", __func__);
return NULL;
}
if (sdev->dspless_mode_selected)
return hda_select_dai_widget_ops(sdev, NULL);
return hda_select_dai_widget_ops(sdev, swidget);
sdai = swidget->private;
......@@ -368,8 +369,11 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
/* get stream_id */
sdev = widget_to_sdev(w);
if (sdev->dspless_mode_selected)
goto skip_tlv;
/* get stream_id */
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
if (!hext_stream) {
......@@ -402,6 +406,7 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
dma_config->dma_priv_config_size = 0;
skip_tlv:
return 0;
}
......
......@@ -748,6 +748,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
{
const struct sof_intel_dsp_desc *chip;
int ret;
/* display codec must be powered before link reset */
......@@ -780,6 +781,10 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
}
chip = get_chip_info(sdev->pdata);
if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0)
hda_sdw_int_enable(sdev, true);
cleanup:
/* display codec can powered off after controller init */
hda_codec_i915_display_power(sdev, false);
......
......@@ -21,6 +21,7 @@
#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "../sof-audio.h"
#include "../ipc4-priv.h"
#include "hda.h"
#define HDA_LTRP_GB_VALUE_US 95
......@@ -937,6 +938,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
/* store total stream count (playback + capture) from GCAP */
sof_hda->stream_max = num_total;
/* store stream count from GCAP required for CHAIN_DMA */
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
ipc4_data->num_playback_streams = num_playback;
ipc4_data->num_capture_streams = num_capture;
}
return 0;
}
......
......@@ -46,44 +46,83 @@
#define EXCEPT_MAX_HDR_SIZE 0x400
#define HDA_EXT_ROM_STATUS_SIZE 8
static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
static void hda_get_interfaces(struct snd_sof_dev *sdev, u32 *interface_mask)
{
const struct sof_intel_dsp_desc *chip;
u32 interface_mask[2] = { 0 };
chip = get_chip_info(sdev->pdata);
switch (chip->hw_ip_version) {
case SOF_INTEL_TANGIER:
case SOF_INTEL_BAYTRAIL:
case SOF_INTEL_BROADWELL:
interface_mask[0] = BIT(SOF_DAI_INTEL_SSP);
interface_mask[SOF_DAI_DSP_ACCESS] = BIT(SOF_DAI_INTEL_SSP);
break;
case SOF_INTEL_CAVS_1_5:
case SOF_INTEL_CAVS_1_5_PLUS:
interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
BIT(SOF_DAI_INTEL_HDA);
interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
interface_mask[SOF_DAI_DSP_ACCESS] =
BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | BIT(SOF_DAI_INTEL_HDA);
interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
break;
case SOF_INTEL_CAVS_1_8:
case SOF_INTEL_CAVS_2_0:
case SOF_INTEL_CAVS_2_5:
case SOF_INTEL_ACE_1_0:
interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
interface_mask[SOF_DAI_DSP_ACCESS] =
BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
break;
case SOF_INTEL_ACE_2_0:
interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */
interface_mask[SOF_DAI_DSP_ACCESS] =
BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
/* all interfaces accessible without DSP */
interface_mask[SOF_DAI_HOST_ACCESS] =
interface_mask[SOF_DAI_DSP_ACCESS];
break;
default:
break;
}
}
static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
{
u32 interface_mask[SOF_DAI_ACCESS_NUM] = { 0 };
hda_get_interfaces(sdev, interface_mask);
return interface_mask[sdev->dspless_mode_selected];
}
bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type)
{
u32 interface_mask[SOF_DAI_ACCESS_NUM] = { 0 };
const struct sof_intel_dsp_desc *chip;
if (sdev->dspless_mode_selected)
return false;
hda_get_interfaces(sdev, interface_mask);
if (!(interface_mask[SOF_DAI_DSP_ACCESS] & BIT(dai_type)))
return false;
if (dai_type == SOF_DAI_INTEL_HDA)
return true;
switch (dai_type) {
case SOF_DAI_INTEL_SSP:
case SOF_DAI_INTEL_DMIC:
case SOF_DAI_INTEL_ALH:
chip = get_chip_info(sdev->pdata);
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return false;
return true;
default:
return false;
}
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
/*
......@@ -1192,6 +1231,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip;
int ret = 0;
hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
......@@ -1305,12 +1345,28 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
}
chip = get_chip_info(sdev->pdata);
if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
ret = hda_sdw_startup(sdev);
if (ret < 0) {
dev_err(sdev->dev, "could not startup SoundWire links\n");
goto disable_pp_cap;
}
hda_sdw_int_enable(sdev, true);
}
init_waitqueue_head(&hdev->waitq);
hdev->nhlt = intel_nhlt_init(sdev->dev);
return 0;
disable_pp_cap:
if (!sdev->dspless_mode_selected) {
hda_dsp_ctrl_ppcap_int_enable(sdev, false);
hda_dsp_ctrl_ppcap_enable(sdev, false);
}
free_ipc_irq:
free_irq(sdev->ipc_irq, sdev);
free_irq_vector:
......
......@@ -573,6 +573,11 @@ struct sof_intel_hda_stream {
#define SOF_STREAM_SD_OFFSET_CRST 0x1
/*
* DAI support
*/
bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type);
/*
* DSP Core services.
*/
......
......@@ -77,6 +77,19 @@ static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
}
static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
if (sdev->first_boot) {
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
/* Check if IMR boot is usable */
if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT))
hda->imrboot_supported = true;
}
return 0;
}
int sof_lnl_ops_init(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data;
......@@ -85,7 +98,8 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* probe */
sof_lnl_ops.probe = lnl_hda_dsp_probe;
if (!sdev->dspless_mode_selected)
sof_lnl_ops.probe = lnl_hda_dsp_probe;
/* shutdown */
sof_lnl_ops.shutdown = hda_dsp_shutdown;
......@@ -106,7 +120,7 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
/* pre/post fw run */
sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run;
sof_lnl_ops.post_fw_run = lnl_dsp_post_fw_run;
/* parse platform specific extended manifest */
sof_lnl_ops.parse_platform_ext_manifest = NULL;
......@@ -115,8 +129,10 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
/* TODO: add core_get and core_put */
/* PM */
sof_lnl_ops.resume = lnl_hda_dsp_resume;
sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
if (!sdev->dspless_mode_selected) {
sof_lnl_ops.resume = lnl_hda_dsp_resume;
sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
}
sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
......
......@@ -231,9 +231,11 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
*/
static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
int direction,
struct snd_sof_pcm_stream_pipeline_list *pipeline_list,
int state, int cmd)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
bool allocate, enable, set_fifo_size;
struct sof_ipc4_msg msg = {{ 0 }};
int i;
......@@ -294,6 +296,20 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
msg.extension |= pipeline->msg.extension;
}
if (direction == SNDRV_PCM_STREAM_CAPTURE) {
/*
* For ChainDMA the DMA ids are unique with the following mapping:
* playback: 0 - (num_playback_streams - 1)
* capture: num_playback_streams - (num_playback_streams +
* num_capture_streams - 1)
*
* Add the num_playback_streams offset to the DMA ids stored in
* msg.primary in case capture
*/
msg.primary += SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(ipc4_data->num_playback_streams);
msg.primary += SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(ipc4_data->num_playback_streams);
}
if (allocate)
msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK;
......@@ -340,7 +356,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
* trigger function that handles the rest for the substream.
*/
if (pipeline->use_chain_dma)
return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
return sof_ipc4_chain_dma_trigger(sdev, substream->stream,
pipeline_list, state, cmd);
/* allocate memory for the pipeline data */
trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
......
......@@ -66,6 +66,8 @@ struct sof_ipc4_fw_library {
* @nhlt: NHLT table either from the BIOS or the topology manifest
* @mtrace_type: mtrace type supported on the booted platform
* @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply
* @num_playback_streams: max number of playback DMAs, needed for CHAIN_DMA offset
* @num_capture_streams: max number of capture DMAs
* @max_num_pipelines: max number of pipelines
* @max_libs_count: Maximum number of libraries support by the FW including the
* base firmware
......@@ -79,6 +81,8 @@ struct sof_ipc4_fw_data {
void *nhlt;
enum sof_ipc4_mtrace_type mtrace_type;
u32 mtrace_log_bytes;
int num_playback_streams;
int num_capture_streams;
int max_num_pipelines;
u32 max_libs_count;
bool fw_context_save;
......
......@@ -509,6 +509,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
{
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_copier *ipc4_copier;
struct snd_sof_widget *pipe_widget;
......@@ -548,14 +549,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
dai->type = ipc4_copier->dai_type;
ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) {
dev_err(scomp->dev,
"Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n",
ipc4_copier->dai_type, SOF_DAI_INTEL_HDA);
if (pipeline->use_chain_dma &&
!snd_sof_is_chain_dma_supported(sdev, ipc4_copier->dai_type)) {
dev_err(scomp->dev, "Bad DAI type '%d', Chain DMA is not supported\n",
ipc4_copier->dai_type);
ret = -ENODEV;
goto free_available_fmt;
}
......@@ -2800,13 +2803,14 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
if (!data)
return 0;
if (pipeline->use_chain_dma) {
pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
return 0;
}
switch (ipc4_copier->dai_type) {
case SOF_DAI_INTEL_HDA:
if (pipeline->use_chain_dma) {
pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
break;
}
gtw_attr = ipc4_copier->gtw_attr;
gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
fallthrough;
......
......@@ -567,6 +567,15 @@ snd_sof_set_mach_params(struct snd_soc_acpi_mach *mach,
sof_ops(sdev)->set_mach_params(mach, sdev);
}
static inline bool
snd_sof_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type)
{
if (sof_ops(sdev) && sof_ops(sdev)->is_chain_dma_supported)
return sof_ops(sdev)->is_chain_dma_supported(sdev, dai_type);
return false;
}
/**
* snd_sof_dsp_register_poll_timeout - Periodically poll an address
* until a condition is met or a timeout occurs
......
......@@ -46,7 +46,6 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
{
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_pipeline *spipe = swidget->spipe;
struct snd_sof_widget *pipe_widget;
int err = 0;
int ret;
......@@ -59,8 +58,6 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
if (--swidget->use_count)
return 0;
pipe_widget = swidget->spipe->pipe_widget;
/* reset route setup status for all routes that contain this widget */
sof_reset_route_setup_status(sdev, swidget);
......@@ -109,8 +106,9 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
* free the scheduler widget (same as pipe_widget) associated with the current swidget.
* skip for static pipelines
*/
if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
ret = sof_widget_free_unlocked(sdev, pipe_widget);
if (swidget->spipe && swidget->dynamic_pipeline_widget &&
swidget->id != snd_soc_dapm_scheduler) {
ret = sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
if (ret < 0 && !err)
err = ret;
}
......
......@@ -514,6 +514,7 @@ struct snd_sof_route {
struct snd_sof_dai {
struct snd_soc_component *scomp;
const char *name;
u32 type;
int number_configs;
int current_config;
......
......@@ -157,6 +157,13 @@ struct sof_firmware {
u32 payload_offset;
};
enum sof_dai_access {
SOF_DAI_DSP_ACCESS, /* access from DSP only */
SOF_DAI_HOST_ACCESS, /* access from host only */
SOF_DAI_ACCESS_NUM
};
/*
* SOF DSP HW abstraction operations.
* Used to abstract DSP HW architecture and any IO busses between host CPU
......@@ -338,6 +345,8 @@ struct snd_sof_dsp_ops {
struct snd_soc_dai_driver *drv;
int num_drv;
bool (*is_chain_dma_supported)(struct snd_sof_dev *sdev, u32 dai_type); /* optional */
/* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */
u32 hw_info;
......
......@@ -2354,25 +2354,43 @@ static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_dapm_widget *tw)
{
if (WIDGET_IS_DAI(w->id)) {
static const struct sof_topology_token dai_tokens[] = {
{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 0}};
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *priv = &tw->priv;
struct snd_sof_widget *swidget;
struct snd_sof_dai dai;
struct snd_sof_dai *sdai;
int ret;
swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
if (!swidget)
return -ENOMEM;
memset(&dai, 0, sizeof(dai));
sdai = kzalloc(sizeof(*sdai), GFP_KERNEL);
if (!sdai) {
kfree(swidget);
return -ENOMEM;
}
ret = sof_parse_tokens(scomp, &sdai->type, dai_tokens, ARRAY_SIZE(dai_tokens),
priv->array, le32_to_cpu(priv->size));
if (ret < 0) {
dev_err(scomp->dev, "Failed to parse DAI tokens for %s\n", tw->name);
kfree(swidget);
kfree(sdai);
return ret;
}
ret = sof_connect_dai_widget(scomp, w, tw, &dai);
ret = sof_connect_dai_widget(scomp, w, tw, sdai);
if (ret) {
kfree(swidget);
kfree(sdai);
return ret;
}
swidget->scomp = scomp;
swidget->widget = w;
swidget->private = sdai;
mutex_init(&swidget->setup_mutex);
w->dobj.private = swidget;
list_add(&swidget->list, &sdev->widget_list);
......@@ -2396,6 +2414,7 @@ static int sof_dspless_widget_unload(struct snd_soc_component *scomp,
/* remove and free swidget object */
list_del(&swidget->list);
kfree(swidget->private);
kfree(swidget);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment