Commit 750e1a22 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: core/Intel: Introduce DSPless mode

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

This series will add support for SOF Linux stack to run without using the DSP.

DSPless mode provides a good tool for verification that the hardware itself
works correctly by taking the DSP use out from the picture.
It can only work with interfaces which supports this mode: Intel HDA at the
moment but with LNL it could be possible to support other audio interfaces.

The main driver for this mode is to be able to test programming sequences,
low-level code and for low-level verification of a platform.

The feature is not targetted for end-users and it will not make the SOF stack
to work on hardware without DSP, but it is giving us a tool to debug and enable
platforms earlier (when for example t he firmware is not mature enough).
parents 194f8692 5962c2a5
...@@ -21,6 +21,7 @@ struct snd_sof_dev; ...@@ -21,6 +21,7 @@ struct snd_sof_dev;
/** /**
* enum sof_fw_state - DSP firmware state definitions * enum sof_fw_state - DSP firmware state definitions
* @SOF_FW_BOOT_NOT_STARTED: firmware boot is not yet started * @SOF_FW_BOOT_NOT_STARTED: firmware boot is not yet started
* @SOF_DSPLESS_MODE: DSP is not used
* @SOF_FW_BOOT_PREPARE: preparing for boot (firmware loading for exaqmple) * @SOF_FW_BOOT_PREPARE: preparing for boot (firmware loading for exaqmple)
* @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress * @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress
* @SOF_FW_BOOT_FAILED: firmware boot failed * @SOF_FW_BOOT_FAILED: firmware boot failed
...@@ -31,6 +32,7 @@ struct snd_sof_dev; ...@@ -31,6 +32,7 @@ struct snd_sof_dev;
*/ */
enum sof_fw_state { enum sof_fw_state {
SOF_FW_BOOT_NOT_STARTED = 0, SOF_FW_BOOT_NOT_STARTED = 0,
SOF_DSPLESS_MODE,
SOF_FW_BOOT_PREPARE, SOF_FW_BOOT_PREPARE,
SOF_FW_BOOT_IN_PROGRESS, SOF_FW_BOOT_IN_PROGRESS,
SOF_FW_BOOT_FAILED, SOF_FW_BOOT_FAILED,
...@@ -130,6 +132,9 @@ struct sof_dev_desc { ...@@ -130,6 +132,9 @@ struct sof_dev_desc {
unsigned int ipc_supported_mask; unsigned int ipc_supported_mask;
enum sof_ipc_type ipc_default; enum sof_ipc_type ipc_default;
/* The platform supports DSPless mode */
bool dspless_mode_supported;
/* defaults paths for firmware, library and topology files */ /* defaults paths for firmware, library and topology files */
const char *default_fw_path[SOF_IPC_TYPE_COUNT]; const char *default_fw_path[SOF_IPC_TYPE_COUNT];
const char *default_lib_path[SOF_IPC_TYPE_COUNT]; const char *default_lib_path[SOF_IPC_TYPE_COUNT];
......
...@@ -208,6 +208,11 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -208,6 +208,11 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
/* set up platform component driver */ /* set up platform component driver */
snd_sof_new_platform_drv(sdev); snd_sof_new_platform_drv(sdev);
if (sdev->dspless_mode_selected) {
sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
goto skip_dsp_init;
}
/* register any debug/trace capabilities */ /* register any debug/trace capabilities */
ret = snd_sof_dbg_init(sdev); ret = snd_sof_dbg_init(sdev);
if (ret < 0) { if (ret < 0) {
...@@ -266,6 +271,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -266,6 +271,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "SOF firmware trace disabled\n"); dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
} }
skip_dsp_init:
/* hereafter all FW boot flows are for PM reasons */ /* hereafter all FW boot flows are for PM reasons */
sdev->first_boot = false; sdev->first_boot = false;
...@@ -365,6 +371,15 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) ...@@ -365,6 +371,15 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
if (sof_core_debug) if (sof_core_debug)
dev_info(dev, "sof_debug value: %#x\n", sof_core_debug); dev_info(dev, "sof_debug value: %#x\n", sof_core_debug);
if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) {
if (plat_data->desc->dspless_mode_supported) {
dev_info(dev, "Switching to DSPless mode\n");
sdev->dspless_mode_selected = true;
} else {
dev_info(dev, "DSPless mode is not supported by the platform\n");
}
}
/* check IPC support */ /* check IPC support */
if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) { if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) {
dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n", dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n",
...@@ -378,12 +393,18 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) ...@@ -378,12 +393,18 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
return ret; return ret;
/* check all mandatory ops */ /* check all mandatory ops */
if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
!sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || sof_ops_free(sdev);
!sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || dev_err(dev, "missing mandatory ops\n");
!sof_ops(sdev)->ipc_msg_data) { return -EINVAL;
}
if (!sdev->dspless_mode_selected &&
(!sof_ops(sdev)->run || !sof_ops(sdev)->block_read ||
!sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg ||
!sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) {
sof_ops_free(sdev); sof_ops_free(sdev);
dev_err(dev, "error: missing mandatory ops\n"); dev_err(dev, "missing mandatory DSP ops\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -370,6 +370,7 @@ static const struct soc_fw_state_info { ...@@ -370,6 +370,7 @@ static const struct soc_fw_state_info {
const char *name; const char *name;
} fw_state_dbg[] = { } fw_state_dbg[] = {
{SOF_FW_BOOT_NOT_STARTED, "SOF_FW_BOOT_NOT_STARTED"}, {SOF_FW_BOOT_NOT_STARTED, "SOF_FW_BOOT_NOT_STARTED"},
{SOF_DSPLESS_MODE, "SOF_DSPLESS_MODE"},
{SOF_FW_BOOT_PREPARE, "SOF_FW_BOOT_PREPARE"}, {SOF_FW_BOOT_PREPARE, "SOF_FW_BOOT_PREPARE"},
{SOF_FW_BOOT_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"}, {SOF_FW_BOOT_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"},
{SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"}, {SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"},
......
...@@ -319,13 +319,44 @@ static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = { ...@@ -319,13 +319,44 @@ static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
.post_trigger = hda_ipc3_post_trigger, .post_trigger = hda_ipc3_post_trigger,
}; };
static struct hdac_ext_stream *
hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
return stream_to_hdac_ext_stream(hstream);
}
static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
struct hdac_ext_stream *hext_stream,
unsigned int format_val)
{
/*
* Save the format_val which was adjusted by the maxbps of the codec.
* This information is not available on the FE side since there we are
* using dummy_codec.
*/
hext_stream->hstream.format_val = format_val;
}
static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
.get_hext_stream = hda_dspless_get_hext_stream,
.setup_hext_stream = hda_dspless_setup_hext_stream,
};
#endif #endif
const struct hda_dai_widget_dma_ops * const struct hda_dai_widget_dma_ops *
hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{ {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
struct snd_sof_dai *sdai = swidget->private; struct snd_sof_dai *sdai;
if (sdev->dspless_mode_selected)
return &hda_dspless_dma_ops;
sdai = swidget->private;
switch (sdev->pdata->ipc_type) { switch (sdev->pdata->ipc_type) {
case SOF_IPC: case SOF_IPC:
......
...@@ -31,11 +31,18 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, ...@@ -31,11 +31,18 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
struct snd_sof_dai_config_data *data) struct snd_sof_dai_config_data *data)
{ {
struct snd_sof_widget *swidget = w->dobj.private; struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp; const struct sof_ipc_tplg_ops *tplg_ops;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_component *component;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_dev *sdev;
int ret; int ret;
if (!swidget)
return 0;
component = swidget->scomp;
sdev = snd_soc_component_get_drvdata(component);
tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops && tplg_ops->dai_config) { if (tplg_ops && tplg_ops->dai_config) {
ret = tplg_ops->dai_config(sdev, swidget, flags, data); ret = tplg_ops->dai_config(sdev, swidget, flags, data);
if (ret < 0) { if (ret < 0) {
...@@ -56,13 +63,21 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai ...@@ -56,13 +63,21 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
struct snd_sof_widget *swidget = w->dobj.private; struct snd_sof_widget *swidget = w->dobj.private;
struct snd_sof_dai *sdai = swidget->private; struct snd_sof_dai *sdai;
/*
* The swidget parameter of hda_select_dai_widget_ops() is ignored in
* case of DSPless mode
*/
if (sdev->dspless_mode_selected)
return hda_select_dai_widget_ops(sdev, NULL);
sdai = swidget->private;
/* select and set the DAI widget ops if not set already */ /* select and set the DAI widget ops if not set already */
if (!sdai->platform_private) { if (!sdai->platform_private) {
const struct hda_dai_widget_dma_ops *ops = const struct hda_dai_widget_dma_ops *ops =
hda_select_dai_widget_ops(sdev, swidget); hda_select_dai_widget_ops(sdev, swidget);
if (!ops) if (!ops)
return NULL; return NULL;
......
...@@ -321,6 +321,9 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) ...@@ -321,6 +321,9 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc; const struct sof_intel_dsp_desc *chip = hda->desc;
if (sdev->dspless_mode_selected)
return;
/* enable IPC DONE and BUSY interrupts */ /* enable IPC DONE and BUSY interrupts */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY, HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY,
...@@ -336,6 +339,9 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) ...@@ -336,6 +339,9 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc; const struct sof_intel_dsp_desc *chip = hda->desc;
if (sdev->dspless_mode_selected)
return;
/* disable IPC interrupt */ /* disable IPC interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_IPC, 0); HDA_DSP_ADSPIC_IPC, 0);
...@@ -681,6 +687,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) ...@@ -681,6 +687,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
/* power down all hda links */ /* power down all hda links */
hda_bus_ml_suspend(bus); hda_bus_ml_suspend(bus);
if (sdev->dspless_mode_selected)
goto skip_dsp;
ret = chip->power_down_dsp(sdev); ret = chip->power_down_dsp(sdev);
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, "failed to power down DSP during suspend\n"); dev_err(sdev->dev, "failed to power down DSP during suspend\n");
...@@ -694,6 +703,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) ...@@ -694,6 +703,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
/* disable ppcap interrupt */ /* disable ppcap interrupt */
hda_dsp_ctrl_ppcap_enable(sdev, false); hda_dsp_ctrl_ppcap_enable(sdev, false);
hda_dsp_ctrl_ppcap_int_enable(sdev, false); hda_dsp_ctrl_ppcap_int_enable(sdev, false);
skip_dsp:
/* disable hda bus irq and streams */ /* disable hda bus irq and streams */
hda_dsp_ctrl_stop_chip(sdev); hda_dsp_ctrl_stop_chip(sdev);
...@@ -744,9 +754,11 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) ...@@ -744,9 +754,11 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
hda_codec_jack_check(sdev); hda_codec_jack_check(sdev);
} }
if (!sdev->dspless_mode_selected) {
/* enable ppcap interrupt */ /* enable ppcap interrupt */
hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_enable(sdev, true);
hda_dsp_ctrl_ppcap_int_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true);
}
cleanup: cleanup:
/* display codec can powered off after controller init */ /* display codec can powered off after controller init */
...@@ -843,8 +855,10 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) ...@@ -843,8 +855,10 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
}; };
int ret; int ret;
if (!sdev->dspless_mode_selected) {
/* cancel any attempt for DSP D0I3 */ /* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work); cancel_delayed_work_sync(&hda->d0i3_work);
}
/* stop hda controller and power dsp off */ /* stop hda controller and power dsp off */
ret = hda_suspend(sdev, true); ret = hda_suspend(sdev, true);
...@@ -866,8 +880,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) ...@@ -866,8 +880,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
}; };
int ret; int ret;
if (!sdev->dspless_mode_selected) {
/* cancel any attempt for DSP D0I3 */ /* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work); cancel_delayed_work_sync(&hda->d0i3_work);
}
if (target_state == SOF_DSP_PM_D0) { if (target_state == SOF_DSP_PM_D0) {
/* Set DSP power state */ /* Set DSP power state */
......
...@@ -355,6 +355,9 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) ...@@ -355,6 +355,9 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
bool ret = false; bool ret = false;
u32 irq_status; u32 irq_status;
if (sdev->dspless_mode_selected)
return false;
/* store status */ /* store status */
irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
trace_sof_intel_hda_irq_ipc_check(sdev, irq_status); trace_sof_intel_hda_irq_ipc_check(sdev, irq_status);
......
...@@ -101,18 +101,23 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, ...@@ -101,18 +101,23 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct snd_dma_buffer *dmab; struct snd_dma_buffer *dmab;
int ret; int ret;
u32 size, rate, bits;
size = params_buffer_bytes(params);
rate = hda_dsp_get_mult_div(sdev, params_rate(params));
bits = hda_dsp_get_bits(sdev, params_width(params));
hstream->substream = substream; hstream->substream = substream;
dmab = substream->runtime->dma_buffer_p; dmab = substream->runtime->dma_buffer_p;
/*
* Use the codec required format val (which is link_bps adjusted) when
* the DSP is not in use
*/
if (!sdev->dspless_mode_selected) {
u32 rate = hda_dsp_get_mult_div(sdev, params_rate(params));
u32 bits = hda_dsp_get_bits(sdev, params_width(params));
hstream->format_val = rate | bits | (params_channels(params) - 1); hstream->format_val = rate | bits | (params_channels(params) - 1);
hstream->bufsize = size; }
hstream->bufsize = params_buffer_bytes(params);
hstream->period_bytes = params_period_bytes(params); hstream->period_bytes = params_period_bytes(params);
hstream->no_period_wakeup = hstream->no_period_wakeup =
(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
...@@ -249,6 +254,11 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, ...@@ -249,6 +254,11 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
snd_pcm_hw_constraint_integer(substream->runtime, snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS); SNDRV_PCM_HW_PARAM_PERIODS);
/* Only S16 and S32 supported by HDA hardware when used without DSP */
if (sdev->dspless_mode_selected)
snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32);
/* binding pcm substream to hda stream */ /* binding pcm substream to hda stream */
substream->runtime->private_data = &dsp_stream->hstream; substream->runtime->private_data = &dsp_stream->hstream;
return 0; return 0;
......
...@@ -485,9 +485,8 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, ...@@ -485,9 +485,8 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
{ {
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
struct hdac_stream *hstream = &hext_stream->hstream; struct hdac_stream *hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int sd_offset, ret;
int ret;
u32 dma_start = SOF_HDA_SD_CTL_DMA_START; u32 dma_start = SOF_HDA_SD_CTL_DMA_START;
u32 mask; u32 mask;
u32 run; u32 run;
...@@ -502,8 +501,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, ...@@ -502,8 +501,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return -ENODEV; return -ENODEV;
} }
/* decouple host and link DMA */ hstream = &hext_stream->hstream;
mask = 0x1 << hstream->index; sd_offset = SOF_STREAM_SD_OFFSET(hstream);
mask = BIT(hstream->index);
/* decouple host and link DMA if the DSP is used */
if (!sdev->dspless_mode_selected)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, mask); mask, mask);
...@@ -606,11 +609,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, ...@@ -606,11 +609,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
* enable decoupled mode * enable decoupled mode
*/ */
if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { if (!sdev->dspless_mode_selected && (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK))
/* couple host and link DMA, disable DSP features */ /* couple host and link DMA, disable DSP features */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, 0); mask, 0);
}
/* program stream format */ /* program stream format */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
...@@ -618,11 +620,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, ...@@ -618,11 +620,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
SOF_HDA_ADSP_REG_SD_FORMAT, SOF_HDA_ADSP_REG_SD_FORMAT,
0xffff, hstream->format_val); 0xffff, hstream->format_val);
if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { if (!sdev->dspless_mode_selected && (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK))
/* decouple host and link DMA, enable DSP features */ /* decouple host and link DMA, enable DSP features */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, mask); mask, mask);
}
/* program last valid index */ /* program last valid index */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
...@@ -675,20 +676,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, ...@@ -675,20 +676,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
struct hdac_ext_stream *hext_stream = container_of(hstream, struct hdac_ext_stream *hext_stream = container_of(hstream,
struct hdac_ext_stream, struct hdac_ext_stream,
hstream); hstream);
struct hdac_bus *bus = sof_to_bus(sdev);
u32 mask = 0x1 << hstream->index;
int ret; int ret;
ret = hda_dsp_stream_reset(sdev, hstream); ret = hda_dsp_stream_reset(sdev, hstream);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!sdev->dspless_mode_selected) {
struct hdac_bus *bus = sof_to_bus(sdev);
u32 mask = BIT(hstream->index);
spin_lock_irq(&bus->reg_lock); spin_lock_irq(&bus->reg_lock);
/* couple host and link DMA if link DMA channel is idle */ /* couple host and link DMA if link DMA channel is idle */
if (!hext_stream->link_locked) if (!hext_stream->link_locked)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
SOF_HDA_REG_PP_PPCTL, mask, 0); SOF_HDA_REG_PP_PPCTL, mask, 0);
spin_unlock_irq(&bus->reg_lock); spin_unlock_irq(&bus->reg_lock);
}
hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0); hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
...@@ -870,12 +874,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) ...@@ -870,12 +874,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
hext_stream = &hda_stream->hext_stream; hext_stream = &hda_stream->hext_stream;
if (sdev->bar[HDA_DSP_PP_BAR]) {
hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
SOF_HDA_PPLC_INTERVAL * i; SOF_HDA_PPLC_INTERVAL * i;
}
hstream = &hext_stream->hstream; hstream = &hext_stream->hstream;
...@@ -926,13 +932,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) ...@@ -926,13 +932,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
hext_stream = &hda_stream->hext_stream; hext_stream = &hda_stream->hext_stream;
/* we always have DSP support */ if (sdev->bar[HDA_DSP_PP_BAR]) {
hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
SOF_HDA_PPLC_INTERVAL * i; SOF_HDA_PPLC_INTERVAL * i;
}
hstream = &hext_stream->hstream; hstream = &hext_stream->hstream;
......
...@@ -44,6 +44,39 @@ ...@@ -44,6 +44,39 @@
#define EXCEPT_MAX_HDR_SIZE 0x400 #define EXCEPT_MAX_HDR_SIZE 0x400
#define HDA_EXT_ROM_STATUS_SIZE 8 #define HDA_EXT_ROM_STATUS_SIZE 8
static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
{
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);
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);
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);
break;
default:
break;
}
return interface_mask[sdev->dspless_mode_selected];
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
/* /*
...@@ -89,8 +122,12 @@ void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) ...@@ -89,8 +122,12 @@ void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
const struct sof_intel_dsp_desc *chip; const struct sof_intel_dsp_desc *chip;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return;
chip = get_chip_info(sdev->pdata); chip = get_chip_info(sdev->pdata);
if (chip && chip->enable_sdw_irq) if (chip && chip->enable_sdw_irq)
chip->enable_sdw_irq(sdev, enable); chip->enable_sdw_irq(sdev, enable);
...@@ -98,10 +135,14 @@ void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) ...@@ -98,10 +135,14 @@ void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev; struct sof_intel_hda_dev *hdev;
acpi_handle handle; acpi_handle handle;
int ret; int ret;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return -EINVAL;
handle = ACPI_HANDLE(sdev->dev); handle = ACPI_HANDLE(sdev->dev);
/* save ACPI info for the probe step */ /* save ACPI info for the probe step */
...@@ -255,8 +296,12 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev) ...@@ -255,8 +296,12 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev) static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
const struct sof_intel_dsp_desc *chip; const struct sof_intel_dsp_desc *chip;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return false;
chip = get_chip_info(sdev->pdata); chip = get_chip_info(sdev->pdata);
if (chip && chip->check_sdw_irq) if (chip && chip->check_sdw_irq)
return chip->check_sdw_irq(sdev); return chip->check_sdw_irq(sdev);
...@@ -271,8 +316,12 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) ...@@ -271,8 +316,12 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev; struct sof_intel_hda_dev *hdev;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return false;
hdev = sdev->pdata->hw_pdata; hdev = sdev->pdata->hw_pdata;
if (hdev->sdw && if (hdev->sdw &&
snd_sof_dsp_read(sdev, HDA_DSP_BAR, snd_sof_dsp_read(sdev, HDA_DSP_BAR,
...@@ -284,8 +333,12 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) ...@@ -284,8 +333,12 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev; struct sof_intel_hda_dev *hdev;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return;
hdev = sdev->pdata->hw_pdata; hdev = sdev->pdata->hw_pdata;
if (!hdev->sdw) if (!hdev->sdw)
return; return;
...@@ -845,6 +898,7 @@ static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev, ...@@ -845,6 +898,7 @@ static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
static int hda_init_caps(struct snd_sof_dev *sdev) static int hda_init_caps(struct snd_sof_dev *sdev)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_sof_pdata *pdata = sdev->pdata; struct snd_sof_pdata *pdata = sdev->pdata;
struct sof_intel_hda_dev *hdev = pdata->hw_pdata; struct sof_intel_hda_dev *hdev = pdata->hw_pdata;
...@@ -865,6 +919,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ...@@ -865,6 +919,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
hda_bus_ml_get_capabilities(bus); hda_bus_ml_get_capabilities(bus);
/* Skip SoundWire if it is not supported */
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
/* scan SoundWire capabilities exposed by DSDT */ /* scan SoundWire capabilities exposed by DSDT */
ret = hda_sdw_acpi_scan(sdev); ret = hda_sdw_acpi_scan(sdev);
if (ret < 0) { if (ret < 0) {
...@@ -972,6 +1030,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -972,6 +1030,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
const struct sof_intel_dsp_desc *chip; const struct sof_intel_dsp_desc *chip;
int ret = 0; int ret = 0;
if (!sdev->dspless_mode_selected) {
/* /*
* detect DSP by checking class/subclass/prog-id information * detect DSP by checking class/subclass/prog-id information
* class=04 subclass 03 prog-if 00: no DSP, legacy driver is required * class=04 subclass 03 prog-if 00: no DSP, legacy driver is required
...@@ -980,13 +1039,16 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -980,13 +1039,16 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
* class=04 subclass 03 prog-if 80: either of DSP or legacy mode works * class=04 subclass 03 prog-if 80: either of DSP or legacy mode works
*/ */
if (pci->class == 0x040300) { if (pci->class == 0x040300) {
dev_err(sdev->dev, "error: the DSP is not enabled on this platform, aborting probe\n"); dev_err(sdev->dev, "the DSP is not enabled on this platform, aborting probe\n");
return -ENODEV; return -ENODEV;
} else if (pci->class != 0x040100 && pci->class != 0x040380) { } else if (pci->class != 0x040100 && pci->class != 0x040380) {
dev_err(sdev->dev, "error: unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class); dev_err(sdev->dev, "unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n",
pci->class);
return -ENODEV; return -ENODEV;
} }
dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class); dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
pci->class);
}
chip = get_chip_info(sdev->pdata); chip = get_chip_info(sdev->pdata);
if (!chip) { if (!chip) {
...@@ -1022,12 +1084,18 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -1022,12 +1084,18 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0; hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0;
#endif #endif
if (sdev->dspless_mode_selected)
hdev->no_ipc_position = 1;
/* set up HDA base */ /* set up HDA base */
bus = sof_to_bus(sdev); bus = sof_to_bus(sdev);
ret = hda_init(sdev); ret = hda_init(sdev);
if (ret < 0) if (ret < 0)
goto hdac_bus_unmap; goto hdac_bus_unmap;
if (sdev->dspless_mode_selected)
goto skip_dsp_setup;
/* DSP base */ /* DSP base */
sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR);
if (!sdev->bar[HDA_DSP_BAR]) { if (!sdev->bar[HDA_DSP_BAR]) {
...@@ -1038,6 +1106,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -1038,6 +1106,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
sdev->mmio_bar = HDA_DSP_BAR; sdev->mmio_bar = HDA_DSP_BAR;
sdev->mailbox_bar = HDA_DSP_BAR; sdev->mailbox_bar = HDA_DSP_BAR;
skip_dsp_setup:
/* allow 64bit DMA address if supported by H/W */ /* allow 64bit DMA address if supported by H/W */
if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) { if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) {
...@@ -1103,6 +1172,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -1103,6 +1172,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
if (ret < 0) if (ret < 0)
goto free_ipc_irq; goto free_ipc_irq;
if (!sdev->dspless_mode_selected) {
/* enable ppcap interrupt */ /* enable ppcap interrupt */
hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_enable(sdev, true);
hda_dsp_ctrl_ppcap_int_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true);
...@@ -1111,6 +1181,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -1111,6 +1181,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET; sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET;
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work); INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
}
init_waitqueue_head(&hdev->waitq); init_waitqueue_head(&hdev->waitq);
...@@ -1126,6 +1197,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -1126,6 +1197,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
free_streams: free_streams:
hda_dsp_stream_free(sdev); hda_dsp_stream_free(sdev);
/* dsp_unmap: not currently used */ /* dsp_unmap: not currently used */
if (!sdev->dspless_mode_selected)
iounmap(sdev->bar[HDA_DSP_BAR]); iounmap(sdev->bar[HDA_DSP_BAR]);
hdac_bus_unmap: hdac_bus_unmap:
platform_device_unregister(hdev->dmic_dev); platform_device_unregister(hdev->dmic_dev);
...@@ -1146,6 +1218,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) ...@@ -1146,6 +1218,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
if (nhlt) if (nhlt)
intel_nhlt_free(nhlt); intel_nhlt_free(nhlt);
if (!sdev->dspless_mode_selected)
/* cancel any attempt for DSP D0I3 */ /* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work); cancel_delayed_work_sync(&hda->d0i3_work);
...@@ -1156,14 +1229,19 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) ...@@ -1156,14 +1229,19 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
if (!IS_ERR_OR_NULL(hda->dmic_dev)) if (!IS_ERR_OR_NULL(hda->dmic_dev))
platform_device_unregister(hda->dmic_dev); platform_device_unregister(hda->dmic_dev);
if (!sdev->dspless_mode_selected) {
/* disable DSP IRQ */ /* disable DSP IRQ */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_PIE, 0); SOF_HDA_PPCTL_PIE, 0);
}
/* disable CIE and GIE interrupts */ /* disable CIE and GIE interrupts */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0); SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0);
if (sdev->dspless_mode_selected)
goto skip_disable_dsp;
/* no need to check for error as the DSP will be disabled anyway */ /* no need to check for error as the DSP will be disabled anyway */
if (chip && chip->power_down_dsp) if (chip && chip->power_down_dsp)
chip->power_down_dsp(sdev); chip->power_down_dsp(sdev);
...@@ -1172,6 +1250,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) ...@@ -1172,6 +1250,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_GPROCEN, 0); SOF_HDA_PPCTL_GPROCEN, 0);
skip_disable_dsp:
free_irq(sdev->ipc_irq, sdev); free_irq(sdev->ipc_irq, sdev);
if (sdev->msi_enabled) if (sdev->msi_enabled)
pci_free_irq_vectors(pci); pci_free_irq_vectors(pci);
...@@ -1180,7 +1259,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) ...@@ -1180,7 +1259,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
hda_bus_ml_free(sof_to_bus(sdev)); hda_bus_ml_free(sof_to_bus(sdev));
if (!sdev->dspless_mode_selected)
iounmap(sdev->bar[HDA_DSP_BAR]); iounmap(sdev->bar[HDA_DSP_BAR]);
iounmap(bus->remap_addr); iounmap(bus->remap_addr);
sof_hda_bus_exit(sdev); sof_hda_bus_exit(sdev);
...@@ -1486,12 +1567,16 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach, ...@@ -1486,12 +1567,16 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach,
struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
{ {
u32 interface_mask = hda_get_interface_mask(sdev);
struct snd_sof_pdata *sof_pdata = sdev->pdata; struct snd_sof_pdata *sof_pdata = sdev->pdata;
const struct sof_dev_desc *desc = sof_pdata->desc; const struct sof_dev_desc *desc = sof_pdata->desc;
struct snd_soc_acpi_mach *mach; struct snd_soc_acpi_mach *mach = NULL;
const char *tplg_filename; const char *tplg_filename;
/* Try I2S or DMIC if it is supported */
if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC)))
mach = snd_soc_acpi_find_machine(desc->machines); mach = snd_soc_acpi_find_machine(desc->machines);
if (mach) { if (mach) {
bool add_extension = false; bool add_extension = false;
bool tplg_fixup = false; bool tplg_fixup = false;
...@@ -1598,10 +1683,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) ...@@ -1598,10 +1683,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
} }
} }
/* /* If I2S fails, try SoundWire if it is supported */
* If I2S fails, try SoundWire if (!mach && (interface_mask & BIT(SOF_DAI_INTEL_ALH)))
*/
if (!mach)
mach = hda_sdw_machine_select(sdev); mach = hda_sdw_machine_select(sdev);
/* /*
......
...@@ -29,6 +29,7 @@ static const struct sof_dev_desc bxt_desc = { ...@@ -29,6 +29,7 @@ static const struct sof_dev_desc bxt_desc = {
.chip_info = &apl_chip_info, .chip_info = &apl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/apl", [SOF_INTEL_IPC4] = "intel/avs/apl",
...@@ -60,6 +61,7 @@ static const struct sof_dev_desc glk_desc = { ...@@ -60,6 +61,7 @@ static const struct sof_dev_desc glk_desc = {
.chip_info = &apl_chip_info, .chip_info = &apl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/glk", [SOF_INTEL_IPC4] = "intel/avs/glk",
......
...@@ -30,6 +30,7 @@ static const struct sof_dev_desc cnl_desc = { ...@@ -30,6 +30,7 @@ static const struct sof_dev_desc cnl_desc = {
.chip_info = &cnl_chip_info, .chip_info = &cnl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl", [SOF_INTEL_IPC4] = "intel/avs/cnl",
...@@ -62,6 +63,7 @@ static const struct sof_dev_desc cfl_desc = { ...@@ -62,6 +63,7 @@ static const struct sof_dev_desc cfl_desc = {
.chip_info = &cnl_chip_info, .chip_info = &cnl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl", [SOF_INTEL_IPC4] = "intel/avs/cnl",
...@@ -94,6 +96,7 @@ static const struct sof_dev_desc cml_desc = { ...@@ -94,6 +96,7 @@ static const struct sof_dev_desc cml_desc = {
.chip_info = &cnl_chip_info, .chip_info = &cnl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl", [SOF_INTEL_IPC4] = "intel/avs/cnl",
......
...@@ -30,6 +30,7 @@ static const struct sof_dev_desc icl_desc = { ...@@ -30,6 +30,7 @@ static const struct sof_dev_desc icl_desc = {
.chip_info = &icl_chip_info, .chip_info = &icl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/icl", [SOF_INTEL_IPC4] = "intel/avs/icl",
...@@ -61,6 +62,7 @@ static const struct sof_dev_desc jsl_desc = { ...@@ -61,6 +62,7 @@ static const struct sof_dev_desc jsl_desc = {
.chip_info = &jsl_chip_info, .chip_info = &jsl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/jsl", [SOF_INTEL_IPC4] = "intel/avs/jsl",
......
...@@ -31,6 +31,7 @@ static const struct sof_dev_desc mtl_desc = { ...@@ -31,6 +31,7 @@ static const struct sof_dev_desc mtl_desc = {
.chip_info = &mtl_chip_info, .chip_info = &mtl_chip_info,
.ipc_supported_mask = BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_INTEL_IPC4, .ipc_default = SOF_INTEL_IPC4,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl", [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl",
}, },
......
...@@ -26,6 +26,7 @@ static struct sof_dev_desc skl_desc = { ...@@ -26,6 +26,7 @@ static struct sof_dev_desc skl_desc = {
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.ipc_supported_mask = BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_INTEL_IPC4, .ipc_default = SOF_INTEL_IPC4,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_INTEL_IPC4] = "intel/avs/skl", [SOF_INTEL_IPC4] = "intel/avs/skl",
}, },
...@@ -50,6 +51,7 @@ static struct sof_dev_desc kbl_desc = { ...@@ -50,6 +51,7 @@ static struct sof_dev_desc kbl_desc = {
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.ipc_supported_mask = BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_INTEL_IPC4, .ipc_default = SOF_INTEL_IPC4,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_INTEL_IPC4] = "intel/avs/kbl", [SOF_INTEL_IPC4] = "intel/avs/kbl",
}, },
......
...@@ -30,6 +30,7 @@ static const struct sof_dev_desc tgl_desc = { ...@@ -30,6 +30,7 @@ static const struct sof_dev_desc tgl_desc = {
.chip_info = &tgl_chip_info, .chip_info = &tgl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl", [SOF_INTEL_IPC4] = "intel/avs/tgl",
...@@ -62,6 +63,7 @@ static const struct sof_dev_desc tglh_desc = { ...@@ -62,6 +63,7 @@ static const struct sof_dev_desc tglh_desc = {
.chip_info = &tglh_chip_info, .chip_info = &tglh_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl-h", [SOF_INTEL_IPC4] = "intel/avs/tgl-h",
...@@ -93,6 +95,7 @@ static const struct sof_dev_desc ehl_desc = { ...@@ -93,6 +95,7 @@ static const struct sof_dev_desc ehl_desc = {
.chip_info = &ehl_chip_info, .chip_info = &ehl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/ehl", [SOF_INTEL_IPC4] = "intel/avs/ehl",
...@@ -125,6 +128,7 @@ static const struct sof_dev_desc adls_desc = { ...@@ -125,6 +128,7 @@ static const struct sof_dev_desc adls_desc = {
.chip_info = &adls_chip_info, .chip_info = &adls_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl-s", [SOF_INTEL_IPC4] = "intel/avs/adl-s",
...@@ -157,6 +161,7 @@ static const struct sof_dev_desc adl_desc = { ...@@ -157,6 +161,7 @@ static const struct sof_dev_desc adl_desc = {
.chip_info = &tgl_chip_info, .chip_info = &tgl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl", [SOF_INTEL_IPC4] = "intel/avs/adl",
...@@ -189,6 +194,7 @@ static const struct sof_dev_desc adl_n_desc = { ...@@ -189,6 +194,7 @@ static const struct sof_dev_desc adl_n_desc = {
.chip_info = &tgl_chip_info, .chip_info = &tgl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl-n", [SOF_INTEL_IPC4] = "intel/avs/adl-n",
...@@ -221,6 +227,7 @@ static const struct sof_dev_desc rpls_desc = { ...@@ -221,6 +227,7 @@ static const struct sof_dev_desc rpls_desc = {
.chip_info = &adls_chip_info, .chip_info = &adls_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/rpl-s", [SOF_INTEL_IPC4] = "intel/avs/rpl-s",
...@@ -253,6 +260,7 @@ static const struct sof_dev_desc rpl_desc = { ...@@ -253,6 +260,7 @@ static const struct sof_dev_desc rpl_desc = {
.chip_info = &tgl_chip_info, .chip_info = &tgl_chip_info,
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC, .ipc_default = SOF_IPC,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = { .default_fw_path = {
[SOF_IPC] = "intel/sof", [SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/rpl", [SOF_INTEL_IPC4] = "intel/avs/rpl",
......
...@@ -330,6 +330,11 @@ static int sof_pcm_trigger(struct snd_soc_component *component, ...@@ -330,6 +330,11 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
spcm->stream[substream->stream].suspend_ignored = true; spcm->stream[substream->stream].suspend_ignored = true;
return 0; return 0;
} }
/* On suspend the DMA must be stopped in DSPless mode */
if (sdev->dspless_mode_selected)
reset_hw_params = true;
fallthrough; fallthrough;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
ipc_first = true; ipc_first = true;
...@@ -705,7 +710,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) ...@@ -705,7 +710,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
pd->pcm_construct = sof_pcm_new; pd->pcm_construct = sof_pcm_new;
pd->ignore_machine = drv_name; pd->ignore_machine = drv_name;
pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
pd->be_pcm_base = SOF_BE_PCM_BASE; pd->be_pcm_base = SOF_BE_PCM_BASE;
pd->use_dai_pcm_id = true; pd->use_dai_pcm_id = true;
pd->topology_name_prefix = "sof"; pd->topology_name_prefix = "sof";
...@@ -714,4 +718,11 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) ...@@ -714,4 +718,11 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
pd->module_get_upon_open = 1; pd->module_get_upon_open = 1;
pd->legacy_dai_naming = 1; pd->legacy_dai_naming = 1;
/*
* The fixup is only needed when the DSP is in use as with the DSPless
* mode we are directly using the audio interface
*/
if (!sdev->dspless_mode_selected)
pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
} }
...@@ -103,6 +103,11 @@ static int sof_resume(struct device *dev, bool runtime_resume) ...@@ -103,6 +103,11 @@ static int sof_resume(struct device *dev, bool runtime_resume)
return ret; return ret;
} }
if (sdev->dspless_mode_selected) {
sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
return 0;
}
/* /*
* Nothing further to be done for platforms that support the low power * Nothing further to be done for platforms that support the low power
* D0 substate. Resume trace and return when resuming from * D0 substate. Resume trace and return when resuming from
......
...@@ -688,7 +688,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, ...@@ -688,7 +688,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
struct snd_sof_widget *pipe_widget; struct snd_sof_widget *pipe_widget;
struct snd_sof_pipeline *spipe; struct snd_sof_pipeline *spipe;
if (!swidget) if (!swidget || sdev->dspless_mode_selected)
continue; continue;
spipe = swidget->spipe; spipe = swidget->spipe;
......
...@@ -130,6 +130,9 @@ int sof_register_clients(struct snd_sof_dev *sdev) ...@@ -130,6 +130,9 @@ int sof_register_clients(struct snd_sof_dev *sdev)
{ {
int ret; int ret;
if (sdev->dspless_mode_selected)
return 0;
/* Register platform independent client devices */ /* Register platform independent client devices */
ret = sof_register_ipc_flood_test(sdev); ret = sof_register_ipc_flood_test(sdev);
if (ret) { if (ret) {
......
...@@ -48,6 +48,7 @@ struct snd_sof_pcm_stream; ...@@ -48,6 +48,7 @@ struct snd_sof_pcm_stream;
#define SOF_DBG_FORCE_NOCODEC BIT(10) /* ignore all codec-related #define SOF_DBG_FORCE_NOCODEC BIT(10) /* ignore all codec-related
* configurations * configurations
*/ */
#define SOF_DBG_DSPLESS_MODE BIT(15) /* Do not initialize and use the DSP */
/* Flag definitions used for controlling the DSP dump behavior */ /* Flag definitions used for controlling the DSP dump behavior */
#define SOF_DBG_DUMP_REGS BIT(0) #define SOF_DBG_DUMP_REGS BIT(0)
...@@ -528,6 +529,16 @@ struct snd_sof_dev { ...@@ -528,6 +529,16 @@ struct snd_sof_dev {
spinlock_t ipc_lock; /* lock for IPC users */ spinlock_t ipc_lock; /* lock for IPC users */
spinlock_t hw_lock; /* lock for HW IO access */ spinlock_t hw_lock; /* lock for HW IO access */
/*
* When true the DSP is not used.
* It is set under the following condition:
* User sets the SOF_DBG_DSPLESS_MODE flag in sof_debug module parameter
* and
* the platform advertises that it can support such mode
* pdata->desc->dspless_mode_supported is true.
*/
bool dspless_mode_selected;
/* Main, Base firmware image */ /* Main, Base firmware image */
struct sof_firmware basefw; struct sof_firmware basefw;
......
...@@ -1144,8 +1144,12 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, ...@@ -1144,8 +1144,12 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
int dir) int dir)
{ {
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_widget *host_widget; struct snd_sof_widget *host_widget;
if (sdev->dspless_mode_selected)
return 0;
host_widget = snd_sof_find_swidget_sname(scomp, host_widget = snd_sof_find_swidget_sname(scomp,
spcm->pcm.caps[dir].name, spcm->pcm.caps[dir].name,
dir); dir);
...@@ -2270,6 +2274,126 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { ...@@ -2270,6 +2274,126 @@ static struct snd_soc_tplg_ops sof_tplg_ops = {
.bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops), .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops),
}; };
static int snd_sof_dspless_kcontrol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return 0;
}
static const struct snd_soc_tplg_kcontrol_ops sof_dspless_io_ops[] = {
{SOF_TPLG_KCTL_VOL_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
{SOF_TPLG_KCTL_BYTES_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
{SOF_TPLG_KCTL_ENUM_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
{SOF_TPLG_KCTL_SWITCH_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
};
static int snd_sof_dspless_bytes_ext_get(struct snd_kcontrol *kcontrol,
unsigned int __user *binary_data,
unsigned int size)
{
return 0;
}
static int snd_sof_dspless_bytes_ext_put(struct snd_kcontrol *kcontrol,
const unsigned int __user *binary_data,
unsigned int size)
{
return 0;
}
static const struct snd_soc_tplg_bytes_ext_ops sof_dspless_bytes_ext_ops[] = {
{SOF_TPLG_KCTL_BYTES_ID, snd_sof_dspless_bytes_ext_get, snd_sof_dspless_bytes_ext_put},
{SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_dspless_bytes_ext_get},
};
/* external widget init - used for any driver specific init */
static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_widget *w,
struct snd_soc_tplg_dapm_widget *tw)
{
if (WIDGET_IS_DAI(w->id)) {
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_widget *swidget;
struct snd_sof_dai dai;
int ret;
swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
if (!swidget)
return -ENOMEM;
memset(&dai, 0, sizeof(dai));
ret = sof_connect_dai_widget(scomp, w, tw, &dai);
if (ret) {
kfree(swidget);
return ret;
}
swidget->scomp = scomp;
swidget->widget = w;
mutex_init(&swidget->setup_mutex);
w->dobj.private = swidget;
list_add(&swidget->list, &sdev->widget_list);
}
return 0;
}
static int sof_dspless_widget_unload(struct snd_soc_component *scomp,
struct snd_soc_dobj *dobj)
{
struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
if (WIDGET_IS_DAI(w->id)) {
struct snd_sof_widget *swidget = dobj->private;
sof_disconnect_dai_widget(scomp, w);
if (!swidget)
return 0;
/* remove and free swidget object */
list_del(&swidget->list);
kfree(swidget);
}
return 0;
}
static int sof_dspless_link_load(struct snd_soc_component *scomp, int index,
struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg)
{
link->platforms->name = dev_name(scomp->dev);
/* Set nonatomic property for FE dai links for FE-BE compatibility */
if (!link->no_pcm)
link->nonatomic = true;
return 0;
}
static struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
/* external widget init - used for any driver specific init */
.widget_ready = sof_dspless_widget_ready,
.widget_unload = sof_dspless_widget_unload,
/* FE DAI - used for any driver specific init */
.dai_load = sof_dai_load,
.dai_unload = sof_dai_unload,
/* DAI link - used for any driver specific init */
.link_load = sof_dspless_link_load,
/* vendor specific kcontrol handlers available for binding */
.io_ops = sof_dspless_io_ops,
.io_ops_count = ARRAY_SIZE(sof_dspless_io_ops),
/* vendor specific bytes ext handlers available for binding */
.bytes_ext_ops = sof_dspless_bytes_ext_ops,
.bytes_ext_ops_count = ARRAY_SIZE(sof_dspless_bytes_ext_ops),
};
int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
{ {
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
...@@ -2287,7 +2411,11 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) ...@@ -2287,7 +2411,11 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
return ret; return ret;
} }
if (sdev->dspless_mode_selected)
ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw);
else
ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
if (ret < 0) { if (ret < 0) {
dev_err(scomp->dev, "error: tplg component load failed %d\n", dev_err(scomp->dev, "error: tplg component load failed %d\n",
ret); ret);
......
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