mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 01:04:19 +08:00
ASoC: SOF: Intel: hda: Add support for DSPless mode
Via the SOF_DBG_DSPLESS_MODE sof_debug flag the SOF stack can be asked to not use the DSP for audio. The use of DSPless mode is governed by the sdev->dspless_mode_selected flag which is only going to be set if the user sets sof_debug=0x8000 and the platform advertises that the DSPless mode is supported on them. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Link: https://lore.kernel.org/r/20230404092115.27949-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
4a3b1433a8
commit
1f7b5d52be
@ -319,13 +319,44 @@ static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
|
||||
.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
|
||||
|
||||
const struct hda_dai_widget_dma_ops *
|
||||
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)
|
||||
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) {
|
||||
case SOF_IPC:
|
||||
|
@ -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_widget *swidget = w->dobj.private;
|
||||
struct snd_soc_component *component = swidget->scomp;
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
|
||||
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
||||
const struct sof_ipc_tplg_ops *tplg_ops;
|
||||
struct snd_soc_component *component;
|
||||
struct snd_sof_dev *sdev;
|
||||
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) {
|
||||
ret = tplg_ops->dai_config(sdev, swidget, flags, data);
|
||||
if (ret < 0) {
|
||||
@ -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_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
|
||||
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 */
|
||||
if (!sdai->platform_private) {
|
||||
const struct hda_dai_widget_dma_ops *ops =
|
||||
hda_select_dai_widget_ops(sdev, swidget);
|
||||
|
||||
if (!ops)
|
||||
return NULL;
|
||||
|
||||
|
@ -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 snd_dma_buffer *dmab;
|
||||
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;
|
||||
|
||||
dmab = substream->runtime->dma_buffer_p;
|
||||
|
||||
hstream->format_val = rate | bits | (params_channels(params) - 1);
|
||||
hstream->bufsize = size;
|
||||
/*
|
||||
* 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->bufsize = params_buffer_bytes(params);
|
||||
hstream->period_bytes = params_period_bytes(params);
|
||||
hstream->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,
|
||||
snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
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 */
|
||||
substream->runtime->private_data = &dsp_stream->hstream;
|
||||
return 0;
|
||||
|
@ -503,11 +503,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
|
||||
|
||||
hstream = &hext_stream->hstream;
|
||||
sd_offset = SOF_STREAM_SD_OFFSET(hstream);
|
||||
mask = BIT(hstream->index);
|
||||
|
||||
/* decouple host and link DMA */
|
||||
mask = 0x1 << hstream->index;
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
mask, mask);
|
||||
/* 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,
|
||||
mask, mask);
|
||||
|
||||
/* clear stream status */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
|
||||
@ -608,11 +609,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
|
||||
* 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 */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
mask, 0);
|
||||
}
|
||||
|
||||
/* program stream format */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
@ -620,11 +620,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
|
||||
SOF_HDA_ADSP_REG_SD_FORMAT,
|
||||
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 */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
mask, mask);
|
||||
}
|
||||
|
||||
/* program last valid index */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
@ -677,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,
|
||||
hstream);
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
u32 mask = 0x1 << hstream->index;
|
||||
int ret;
|
||||
|
||||
ret = hda_dsp_stream_reset(sdev, hstream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
/* couple host and link DMA if link DMA channel is idle */
|
||||
if (!hext_stream->link_locked)
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
|
||||
SOF_HDA_REG_PP_PPCTL, mask, 0);
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
u32 mask = BIT(hstream->index);
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
/* couple host and link DMA if link DMA channel is idle */
|
||||
if (!hext_stream->link_locked)
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
|
||||
SOF_HDA_REG_PP_PPCTL, mask, 0);
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
}
|
||||
|
||||
hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
|
||||
|
||||
|
@ -47,32 +47,34 @@
|
||||
static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
|
||||
{
|
||||
const struct sof_intel_dsp_desc *chip;
|
||||
u32 interface_mask = 0;
|
||||
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 = BIT(SOF_DAI_INTEL_SSP);
|
||||
interface_mask[0] = BIT(SOF_DAI_INTEL_SSP);
|
||||
break;
|
||||
case SOF_INTEL_CAVS_1_5:
|
||||
case SOF_INTEL_CAVS_1_5_PLUS:
|
||||
interface_mask = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
|
||||
BIT(SOF_DAI_INTEL_HDA);
|
||||
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 = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
|
||||
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
|
||||
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;
|
||||
return interface_mask[sdev->dspless_mode_selected];
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
|
||||
@ -1058,6 +1060,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0;
|
||||
#endif
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
hdev->no_ipc_position = 1;
|
||||
|
||||
/* set up HDA base */
|
||||
bus = sof_to_bus(sdev);
|
||||
ret = hda_init(sdev);
|
||||
|
Loading…
Reference in New Issue
Block a user