Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/sound/sof.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct snd_sof_dev;
/**
* enum sof_fw_state - DSP firmware state definitions
* @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_IN_PROGRESS: firmware boot is in progress
* @SOF_FW_BOOT_FAILED: firmware boot failed
Expand All @@ -31,6 +32,7 @@ struct snd_sof_dev;
*/
enum sof_fw_state {
SOF_FW_BOOT_NOT_STARTED = 0,
SOF_DSPLESS_MODE,
SOF_FW_BOOT_PREPARE,
SOF_FW_BOOT_IN_PROGRESS,
SOF_FW_BOOT_FAILED,
Expand Down Expand Up @@ -130,6 +132,9 @@ struct sof_dev_desc {
unsigned int ipc_supported_mask;
enum sof_ipc_type ipc_default;

/* The platform supports DSPless mode */
bool dspless_mode_supported;

/* defaults paths for firmware, library and topology files */
const char *default_fw_path[SOF_IPC_TYPE_COUNT];
const char *default_lib_path[SOF_IPC_TYPE_COUNT];
Expand Down
31 changes: 26 additions & 5 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
/* set up platform component driver */
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 */
ret = snd_sof_dbg_init(sdev);
if (ret < 0) {
Expand Down Expand Up @@ -266,6 +271,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
}

skip_dsp_init:
/* hereafter all FW boot flows are for PM reasons */
sdev->first_boot = false;

Expand Down Expand Up @@ -365,6 +371,15 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
if (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 */
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",
Expand All @@ -378,12 +393,18 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
return ret;

/* check all mandatory ops */
if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !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) {
if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
sof_ops_free(sdev);
dev_err(dev, "missing mandatory ops\n");
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);
dev_err(dev, "error: missing mandatory ops\n");
dev_err(dev, "missing mandatory DSP ops\n");
return -EINVAL;
}

Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ static const struct soc_fw_state_info {
const char *name;
} fw_state_dbg[] = {
{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_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"},
{SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"},
Expand Down
33 changes: 32 additions & 1 deletion sound/soc/sof/intel/hda-dai-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
27 changes: 21 additions & 6 deletions sound/soc/sof/intel/hda-dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,19 @@ 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 (tplg_ops && tplg_ops->dai_config) {
if (!swidget)
return 0;

component = swidget->scomp;
sdev = snd_soc_component_get_drvdata(component);
tplg_ops = sof_ipc_get_ops(sdev, tplg);

if (swidget && tplg_ops && tplg_ops->dai_config) {
ret = tplg_ops->dai_config(sdev, swidget, flags, data);
if (ret < 0) {
dev_err(sdev->dev, "DAI config with flags %x failed for widget %s\n",
Expand All @@ -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;

Expand Down
13 changes: 12 additions & 1 deletion sound/soc/sof/intel/hda-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,13 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,

dmab = substream->runtime->dma_buffer_p;

hstream->format_val = rate | bits | (params_channels(params) - 1);
/*
* Use the codec required format val (which is link_bps adjusted) when
* the DSP is not in use
*/
if (!sdev->dspless_mode_selected)
hstream->format_val = rate | bits | (params_channels(params) - 1);

hstream->bufsize = size;
hstream->period_bytes = params_period_bytes(params);
hstream->no_period_wakeup =
Expand Down Expand Up @@ -249,6 +255,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;
Expand Down
42 changes: 23 additions & 19 deletions sound/soc/sof/intel/hda-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
struct hdac_bus *bus = sof_to_bus(sdev);
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret;
struct hdac_stream *hstream;
int sd_offset, ret;
u32 dma_start = SOF_HDA_SD_CTL_DMA_START;
u32 mask;
u32 run;
Expand All @@ -502,10 +501,14 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return -ENODEV;
}

/* 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);
hstream = &hext_stream->hstream;
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,
mask, mask);

/* clear stream status */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
Expand Down Expand Up @@ -606,23 +609,21 @@ 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,
sd_offset +
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,
Expand Down Expand Up @@ -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,
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);

Expand Down
Loading