Obtaining data from the DSP by reading the mailbox is Intel-specific, move them from the SOF core to Intel-specific drivers.
Signed-off-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com ---
This is just an RFC, it only supports APL at the moment, but has been tested on it. Adding all other platforms should be simple. Please, suggest better names.
sound/soc/sof/intel/apl.c | 4 ++++ sound/soc/sof/intel/hda-pcm.c | 40 +++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-stream.c | 18 +++++++++----- sound/soc/sof/intel/hda.h | 16 ++++++++++++- sound/soc/sof/intel/shim.h | 6 +++++ sound/soc/sof/ipc.c | 51 +++++++++++++++++----------------------- sound/soc/sof/ops.h | 28 ++++++++++++++++++++++ sound/soc/sof/pcm.c | 30 +++++++++++++---------- sound/soc/sof/sof-priv.h | 13 ++++++++++ 9 files changed, 156 insertions(+), 50 deletions(-)
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 654d741..d7fa884 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -64,6 +64,10 @@ .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer,
+ .pcm_read_dev = hda_pcm_read_dev, + .pcm_read_stream = hda_pcm_read_stream, + .pcm_params = hda_pcm_params, + /* firmware loading */ .load_firmware = snd_sof_load_firmware_raw,
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index bbcef74..fcbf64d 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -240,3 +240,43 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev, substream->runtime->private_data = NULL; return 0; } + +void hda_pcm_read_dev(struct snd_sof_dev *sdev, void *p, size_t sz) +{ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); +} + +void hda_pcm_read_stream(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream = container_of(hstream, + struct sof_intel_hda_stream, hda_stream.hstream); + + snd_sof_dsp_mailbox_read(sdev, hda_stream->stream.posn_offset, + p, sz); + + dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", + hda_stream->stream.posn_offset); +} + +int hda_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream = container_of(hstream, + struct sof_intel_hda_stream, hda_stream.hstream); + /* validate offset */ + size_t posn_offset = reply->posn_offset; + + /* check if offset is overflow or it is not aligned */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) + return -EINVAL; + + hda_stream->stream.posn_offset = sdev->stream_box.offset + posn_offset; + + return 0; +} diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 5b8e589..6f1530d 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -552,11 +552,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
/* create capture streams */ for (i = 0; i < num_capture; i++) { - - stream = devm_kzalloc(sdev->dev, sizeof(*stream), GFP_KERNEL); - if (!stream) + struct sof_intel_hda_stream *hda_stream = devm_kzalloc(sdev->dev, + sizeof(*hda_stream), GFP_KERNEL); + if (!hda_stream) return -ENOMEM;
+ stream = &hda_stream->hda_stream; + hda_stream->stream.hw_stream_priv = stream; + stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
@@ -601,11 +604,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
/* create playback streams */ for (i = num_capture; i < num_total; i++) { - - stream = devm_kzalloc(sdev->dev, sizeof(*stream), GFP_KERNEL); - if (!stream) + struct sof_intel_hda_stream *hda_stream = devm_kzalloc(sdev->dev, + sizeof(*hda_stream), GFP_KERNEL); + if (!hda_stream) return -ENOMEM;
+ stream = &hda_stream->hda_stream; + hda_stream->stream.hw_stream_priv = stream; + /* we always have DSP support */ stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index f9c055a..fc14c01 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -12,6 +12,7 @@ #define __SOF_INTEL_HDA_H
#include <sound/hda_codec.h> +#include <sound/hdaudio_ext.h> #include "shim.h"
/* PCI registers */ @@ -360,7 +361,7 @@ struct sof_intel_hda_dev { /* hw config */ const struct sof_intel_dsp_desc *desc;
- /*trace */ + /* trace */ struct hdac_ext_stream *dtrace_stream;
/* if position update IPC needed */ @@ -386,6 +387,11 @@ static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) return &hda->hbus; }
+struct sof_intel_hda_stream { + struct hdac_ext_stream hda_stream; + struct sof_intel_stream stream; +}; + #define bus_to_sof_hda(bus) \ container_of(bus, struct sof_intel_hda_dev, hbus.core)
@@ -462,6 +468,14 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int enable, u32 size);
+void hda_pcm_read_dev(struct snd_sof_dev *sdev, void *p, size_t sz); +void hda_pcm_read_stream(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); +int hda_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); + /* * DSP IPC Operations. */ diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 617da2d..16e4a34 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -176,4 +176,10 @@ struct sof_intel_dsp_desc { extern const struct sof_intel_dsp_desc hsw_chip_info; extern const struct sof_intel_dsp_desc tng_chip_info;
+struct sof_intel_stream { + int posn_offset; + + void *hw_stream_priv; +}; + #endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 63f9e96..01e9576 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -343,7 +343,7 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) int err = 0;
/* read back header */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr)); + snd_sof_pcm_read_dev(sdev, &hdr, sizeof(hdr)); ipc_log_header(sdev->dev, "ipc rx", hdr.cmd);
cmd = hdr.cmd & SOF_GLB_TYPE_MASK; @@ -406,8 +406,7 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) switch (msg_id) { case SOF_IPC_TRACE_DMA_POSITION: /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); + snd_sof_pcm_read_dev(sdev, &posn, sizeof(posn)); snd_sof_trace_update_pos(sdev, &posn); break; default: @@ -424,15 +423,14 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_stream_posn posn; + struct snd_sof_pcm_stream *stream; struct snd_sof_pcm *spcm; - u32 posn_offset; int direction;
/* check if we have stream box */ if (sdev->stream_box.size == 0) { /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); + snd_sof_pcm_read_dev(sdev, &posn, sizeof(posn));
spcm = snd_sof_find_spcm_comp(sdev, posn.comp_id, &direction); } else { @@ -446,39 +444,35 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) return; }
- /* have stream box read from stream box */ - if (sdev->stream_box.size != 0) { - posn_offset = spcm->posn_offset[direction]; - snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, - sizeof(posn)); + stream = &spcm->stream[direction];
- dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", - posn_offset); - } + /* have stream box read from stream box */ + if (sdev->stream_box.size != 0) + snd_sof_pcm_read_stream(sdev, stream->substream, + &posn, sizeof(posn));
dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", posn.host_posn, posn.dai_posn, posn.wallclock);
- memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); + memcpy(&stream->posn, &posn, sizeof(posn));
/* only inform ALSA for period_wakeup mode */ - if (!spcm->stream[direction].substream->runtime->no_period_wakeup) - snd_pcm_period_elapsed(spcm->stream[direction].substream); + if (!stream->substream->runtime->no_period_wakeup) + snd_pcm_period_elapsed(stream->substream); }
/* DSP notifies host of an XRUN within FW */ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_stream_posn posn; + struct snd_sof_pcm_stream *stream; struct snd_sof_pcm *spcm; - u32 posn_offset; int direction;
/* check if we have stream MMIO on this platform */ if (sdev->stream_box.size == 0) { /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); + snd_sof_pcm_read_dev(sdev, &posn, sizeof(posn));
spcm = snd_sof_find_spcm_comp(sdev, posn.comp_id, &direction); } else { @@ -491,23 +485,20 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) return; }
- /* have stream box read from stream box */ - if (sdev->stream_box.size != 0) { - posn_offset = spcm->posn_offset[direction]; - snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, - sizeof(posn)); + stream = &spcm->stream[direction];
- dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", - posn_offset); - } + /* have stream box read from stream box */ + if (sdev->stream_box.size != 0) + snd_sof_pcm_read_stream(sdev, stream->substream, + &posn, sizeof(posn));
dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP) /* stop PCM on XRUN - used for pipeline debug */ - memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); - snd_pcm_stop_xrun(spcm->stream[direction].substream); + memcpy(&stream->posn, &posn, sizeof(posn)); + snd_pcm_stop_xrun(stream->substream); #endif }
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index cba2d16..54a6c6e 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -330,6 +330,34 @@ static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) return 0; }
+/* host read DSP device data */ +static inline void snd_sof_pcm_read_dev(struct snd_sof_dev *sdev, + void *p, size_t sz) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_read_dev) + sof_ops(sdev)->pcm_read_dev(sdev, p, sz); +} + +/* host read DSP stream data */ +static inline void snd_sof_pcm_read_stream(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_read_stream) + sof_ops(sdev)->pcm_read_stream(sdev, substream, p, sz); +} + +/* host configure DSP HW parameters */ +static inline int snd_sof_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_params) + return sof_ops(sdev)->pcm_params(sdev, substream, reply); + + return 0; +} + /* host stream pointer */ static inline snd_pcm_uframes_t snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 545eed4..a7c6b63 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -38,6 +38,20 @@ static int create_page_table(struct snd_pcm_substream *substream, spcm->stream[stream].page_table.area, size); }
+static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct snd_sof_dev *sdev = spcm->sdev; + /* validate offset */ + int ret = snd_sof_pcm_params(sdev, substream, reply); + + if (ret < 0) + dev_err(sdev->dev, "error: got wrong reply for PCM %d\n", + spcm->pcm.pcm_id); + + return ret; +} + /* this may get called several times by oss emulation */ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -50,7 +64,6 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm; struct sof_ipc_pcm_params pcm; struct sof_ipc_pcm_params_reply ipc_params_reply; - int posn_offset; int ret;
/* nothing todo for BE */ @@ -158,18 +171,9 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; }
- /* validate offset */ - posn_offset = ipc_params_reply.posn_offset; - - /* check if offset is overflow or it is not aligned */ - if (posn_offset > sdev->stream_box.size || - posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) { - dev_err(sdev->dev, "error: got wrong posn offset 0x%x for PCM %d\n", - posn_offset, spcm->pcm.pcm_id); - return -EINVAL; - } - spcm->posn_offset[substream->stream] = - sdev->stream_box.offset + posn_offset; + ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply); + if (ret < 0) + return ret;
/* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index c4465b2d..1ab4d5b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -148,6 +148,19 @@ struct snd_sof_dsp_ops { snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */
+ /* host read DSP device data */ + void (*pcm_read_dev)(struct snd_sof_dev *sdev, void *p, size_t sz); + + /* host read DSP stream data */ + void (*pcm_read_stream)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); + + /* host configure DSP HW parameters */ + int (*pcm_params)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); + /* pre/post firmware run */ int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */