diff options
author | Takashi Iwai <tiwai@suse.de> | 2023-02-16 16:32:04 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2023-02-16 16:32:04 +0300 |
commit | 1bdb78368f9448cf0de9b11eb1388e887d1b4849 (patch) | |
tree | 82a70b8d8502d5078dc36d67fbb7bc315e760d63 /sound/soc/sof/intel | |
parent | 5661706efa200252d0e9fea02421b0a5857808c3 (diff) | |
parent | 76f5aaabce492aa6991c28c96bb78b00b05d06c5 (diff) | |
download | linux-1bdb78368f9448cf0de9b11eb1388e887d1b4849.tar.xz |
Merge tag 'asoc-v6.3' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: Updates for v6.3
There's been quite a lot of activity this release, but not really
one big feature - lots of new devices, plus a lot of cleanup and
modernisation work spread throughout the subsystem:
- More factoring out of common operations into helper functions
by Morimoto-san.
- DT schema conversons and stylistic nits.
- Continued work on building out the new SOF IPC4 scheme.
- Support for Awinc AT88395, Infineon PEB2466, Iron Device
SMA1303, Mediatek MT8188, Realtek RT712, Renesas IDT821034,
Samsung/Tesla FSD SoC I2S, and TI TAS5720A-Q1.
Diffstat (limited to 'sound/soc/sof/intel')
-rw-r--r-- | sound/soc/sof/intel/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/sof/intel/cnl.c | 2 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-dai.c | 92 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-dsp.c | 46 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-ipc.c | 36 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda.h | 6 | ||||
-rw-r--r-- | sound/soc/sof/intel/mtl.c | 16 | ||||
-rw-r--r-- | sound/soc/sof/intel/mtl.h | 6 |
8 files changed, 115 insertions, 93 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 36a0e2bf30ff..715ba8a7f2f8 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -322,8 +322,8 @@ config SND_SOC_SOF_HDA_PROBES config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE tristate - select SOUNDWIRE_INTEL if SND_SOC_SOF_INTEL_SOUNDWIRE - select SND_INTEL_SOUNDWIRE_ACPI if SND_SOC_SOF_INTEL_SOUNDWIRE + select SOUNDWIRE_INTEL if SND_SOC_SOF_INTEL_SOUNDWIRE != n + select SND_INTEL_SOUNDWIRE_ACPI if SND_SOC_SOF_INTEL_SOUNDWIRE != n config SND_SOC_SOF_INTEL_SOUNDWIRE tristate "SOF support for SoundWire" diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 6b075bbe5bfb..a08a77fa946b 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -280,6 +280,8 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, msg_data->primary | CNL_DSP_REG_HIPCIDR_BUSY); + hda_dsp_ipc4_schedule_d0i3_work(hdev, msg); + return 0; } diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 1c3d4887aa30..193b3e74820a 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -450,6 +450,8 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; struct snd_soc_pcm_runtime *rtd; struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; @@ -466,18 +468,30 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, w = snd_soc_dai_get_widget(dai, substream->stream); swidget = w->dobj.private; + pipe_widget = swidget->spipe->pipe_widget; + pipeline = pipe_widget->private; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_hdac_ext_stream_start(hext_stream); + if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_PAUSED; + } + + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_RUNNING); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_RUNNING; break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: { - struct snd_sof_widget *pipe_widget = swidget->pipe_widget; - struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) @@ -503,9 +517,6 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, } case SNDRV_PCM_TRIGGER_PAUSE_PUSH: { - struct snd_sof_widget *pipe_widget = swidget->pipe_widget; - struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) @@ -703,64 +714,6 @@ static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = { .shutdown = ssp_dai_shutdown, }; -static int ipc4_be_dai_common_trigger(struct snd_soc_dai *dai, int cmd, int stream) -{ - struct snd_sof_widget *pipe_widget; - struct sof_ipc4_pipeline *pipeline; - struct snd_sof_widget *swidget; - struct snd_soc_dapm_widget *w; - struct snd_sof_dev *sdev; - int ret; - - w = snd_soc_dai_get_widget(dai, stream); - swidget = w->dobj.private; - pipe_widget = swidget->pipe_widget; - pipeline = pipe_widget->private; - sdev = snd_soc_component_get_drvdata(swidget->scomp); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_PAUSED); - if (ret < 0) - return ret; - pipeline->state = SOF_IPC4_PIPE_PAUSED; - - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_RESET); - if (ret < 0) - return ret; - pipeline->state = SOF_IPC4_PIPE_RESET; - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_PAUSED); - if (ret < 0) - return ret; - pipeline->state = SOF_IPC4_PIPE_PAUSED; - break; - default: - break; - } - - return 0; -} - -static int ipc4_be_dai_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - return ipc4_be_dai_common_trigger(dai, cmd, substream->stream); -} - -static const struct snd_soc_dai_ops ipc4_dmic_dai_ops = { - .trigger = ipc4_be_dai_trigger, -}; - -static const struct snd_soc_dai_ops ipc4_ssp_dai_ops = { - .trigger = ipc4_be_dai_trigger, -}; - void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { int i; @@ -785,14 +738,6 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) struct sof_ipc4_fw_data *ipc4_data = sdev->private; for (i = 0; i < ops->num_drv; i++) { - if (strstr(ops->drv[i].name, "DMIC")) { - ops->drv[i].ops = &ipc4_dmic_dai_ops; - continue; - } - if (strstr(ops->drv[i].name, "SSP")) { - ops->drv[i].ops = &ipc4_ssp_dai_ops; - continue; - } #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) if (strstr(ops->drv[i].name, "iDisp") || strstr(ops->drv[i].name, "Analog") || @@ -804,9 +749,6 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) if (!hda_use_tplg_nhlt) ipc4_data->nhlt = intel_nhlt_init(sdev->dev); - if (IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)) - sdw_callback.trigger = ipc4_be_dai_common_trigger; - break; } default: diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index b4eacae8564c..68eb06f13a1f 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -364,19 +364,12 @@ static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev) static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags) { - struct sof_ipc_pm_gate pm_gate; - struct sof_ipc_reply reply; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); - memset(&pm_gate, 0, sizeof(pm_gate)); + if (pm_ops && pm_ops->set_pm_gate) + return pm_ops->set_pm_gate(sdev, flags); - /* configure pm_gate ipc message */ - pm_gate.hdr.size = sizeof(pm_gate); - pm_gate.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE; - pm_gate.flags = flags; - - /* send pm_gate ipc to dsp */ - return sof_ipc_tx_message_no_pm(sdev->ipc, &pm_gate, sizeof(pm_gate), - &reply, sizeof(reply)); + return 0; } static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) @@ -412,6 +405,34 @@ static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) return 0; } +/* + * d0i3 streaming is enabled if all the active streams can + * work in d0i3 state and playback is enabled + */ +static bool hda_dsp_d0i3_streaming_applicable(struct snd_sof_dev *sdev) +{ + struct snd_pcm_substream *substream; + struct snd_sof_pcm *spcm; + bool playback_active = false; + int dir; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_pcm_streams(dir) { + substream = spcm->stream[dir].substream; + if (!substream || !substream->runtime) + continue; + + if (!spcm->stream[dir].d0i3_compatible) + return false; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + playback_active = true; + } + } + + return playback_active; +} + static int hda_dsp_set_D0_state(struct snd_sof_dev *sdev, const struct sof_dsp_power_state *target_state) { @@ -453,6 +474,9 @@ static int hda_dsp_set_D0_state(struct snd_sof_dev *sdev, !hda_enable_trace_D0I3_S0 || sdev->system_suspend_target != SOF_SUSPEND_NONE) flags = HDA_PM_NO_DMA_TRACE; + + if (hda_dsp_d0i3_streaming_applicable(sdev)) + flags |= HDA_PM_PG_STREAMING; } else { /* prevent power gating in D0I0 */ flags = HDA_PM_PPG; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index a7c454e03952..df541b22b2d2 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -67,6 +67,32 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } +static inline bool hda_dsp_ipc4_pm_msg(u32 primary) +{ + /* pm setting is only supported by module msg */ + if (SOF_IPC4_MSG_IS_MODULE_MSG(primary) != SOF_IPC4_MODULE_MSG) + return false; + + if (SOF_IPC4_MSG_TYPE_GET(primary) == SOF_IPC4_MOD_SET_DX || + SOF_IPC4_MSG_TYPE_GET(primary) == SOF_IPC4_MOD_SET_D0IX) + return true; + + return false; +} + +void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev, + struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc4_msg *msg_data = msg->msg_data; + + /* Schedule a delayed work for d0i3 entry after sending non-pm ipc msg */ + if (hda_dsp_ipc4_pm_msg(msg_data->primary)) + return; + + mod_delayed_work(system_wq, &hdev->d0i3_work, + msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS)); +} + int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; @@ -88,6 +114,8 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, msg_data->primary | HDA_DSP_REG_HIPCI_BUSY); + hda_dsp_ipc4_schedule_d0i3_work(hdev, msg); + return 0; } @@ -361,12 +389,13 @@ int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) } int hda_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, void *p, size_t sz) { - if (!substream || !sdev->stream_box.size) { + if (!sps || !sdev->stream_box.size) { sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); } else { + struct snd_pcm_substream *substream = sps->substream; struct hdac_stream *hstream = substream->runtime->private_data; struct sof_intel_hda_stream *hda_stream; @@ -385,9 +414,10 @@ int hda_ipc_msg_data(struct snd_sof_dev *sdev, } int hda_set_stream_data_offset(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, size_t posn_offset) { + struct snd_pcm_substream *substream = sps->substream; struct hdac_stream *hstream = substream->runtime->private_data; struct sof_intel_hda_stream *hda_stream; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index caccaf8fba9c..45f9d4248f14 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -656,10 +656,10 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, int enable, u32 size); int hda_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, void *p, size_t sz); int hda_set_stream_data_offset(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, size_t posn_offset); /* @@ -919,6 +919,8 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context); int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context); bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev); +void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev, + struct snd_sof_ipc_msg *msg); int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void hda_ipc4_dump(struct snd_sof_dev *sdev); extern struct sdw_intel_ops sdw_callback; diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 904ae42534e1..307faad2ecf4 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -110,6 +110,8 @@ static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *ms snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR, msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY); + hda_dsp_ipc4_schedule_d0i3_work(hdev, msg); + return 0; } @@ -581,6 +583,18 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } +static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + u32 llp_l, llp_u; + + llp_l = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPL(hstream->index)); + llp_u = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPU(hstream->index)); + return ((u64)llp_u << 32) | llp_l; +} + /* Meteorlake ops */ struct snd_sof_dsp_ops sof_mtl_ops; EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -619,6 +633,8 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) /* dsp core get/put */ /* TODO: add core_get and core_put */ + sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; + sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 0fd4e6fe09b8..26418fb08807 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -6,6 +6,12 @@ * Copyright(c) 2020-2022 Intel Corporation. All rights reserved. */ +/* HDA Registers */ +#define MTL_PPLCLLPL_BASE 0x948 +#define MTL_PPLCLLPU_STRIDE 0x10 +#define MTL_PPLCLLPL(x) (MTL_PPLCLLPL_BASE + (x) * MTL_PPLCLLPU_STRIDE) +#define MTL_PPLCLLPU(x) (MTL_PPLCLLPL_BASE + 0x4 + (x) * MTL_PPLCLLPU_STRIDE) + /* DSP Registers */ #define MTL_HFDSSCS 0x1000 #define MTL_HFDSSCS_SPA_MASK BIT(16) |