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(a)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 */
--
1.9.3