// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // // Copyright(c) 2025 Intel Corporation. //
/* * Hardware interface for SoundWire BPT support with HDA DMA
*/
#define BPT_FREQUENCY 192000 /* The max rate defined in rate_bits[] hdac_device.c */ #define BPT_MULTIPLIER ((BPT_FREQUENCY / 48000) - 1) #define BPT_CHAIN_DMA_FIFO_MS 10 /* * This routine is directly inspired by sof_ipc4_chain_dma_trigger(), * with major simplifications since there are no pipelines defined * and no dependency on ALSA hw_params
*/ staticint chain_dma_trigger(struct snd_sof_dev *sdev, unsignedint stream_tag, int direction, int state)
{ struct sof_ipc4_fw_data *ipc4_data = sdev->private; bool allocate, enable, set_fifo_size; struct sof_ipc4_msg msg = {{ 0 }}; int dma_id;
if (sdev->pdata->ipc_type != SOF_IPC_TYPE_4) return -EOPNOTSUPP;
switch (state) { case SOF_IPC4_PIPE_RUNNING: /* Allocate and start the chain */
allocate = true;
enable = true;
set_fifo_size = true; break; case SOF_IPC4_PIPE_PAUSED: /* Stop the chain */
allocate = true;
enable = false;
set_fifo_size = false; break; case SOF_IPC4_PIPE_RESET: /* Deallocate chain resources and remove the chain */
allocate = false;
enable = false;
set_fifo_size = false; break; default:
dev_err(sdev->dev, "Unexpected state %d", state); return -EINVAL;
}
/* for BPT/BRA we can use the same stream tag for host and link */
dma_id = stream_tag - 1; if (direction == SNDRV_PCM_STREAM_CAPTURE)
dma_id += ipc4_data->num_playback_streams;
/* * the baseline format needs to be adjusted to * bandwidth requirements
*/
format |= (num_channels - 1);
format |= BPT_MULTIPLIER << AC_FMT_MULT_SHIFT;
time_tx_left = wait_for_completion_timeout(&hda_tx_stream->ioc,
msecs_to_jiffies(HDA_BPT_IOC_TIMEOUT_MS)); if (!time_tx_left) {
tx_position = hda_dsp_stream_get_position(hdac_stream(bpt_tx_stream),
SNDRV_PCM_STREAM_PLAYBACK, false);
dev_err(dev, "%s: SDW BPT TX DMA did not complete: %ld\n",
__func__, tx_position);
ret = -ETIMEDOUT; goto dma_disable;
}
/* Make sure the DMA is flushed */
i = 0; do {
tx_position = hda_dsp_stream_get_position(hdac_stream(bpt_tx_stream),
SNDRV_PCM_STREAM_PLAYBACK, false);
usleep_range(1000, 1010);
i++;
} while (tx_position && i < HDA_BPT_IOC_TIMEOUT_MS); if (tx_position) {
dev_err(dev, "%s: SDW BPT TX DMA position %ld was not cleared\n",
__func__, tx_position);
ret = -ETIMEDOUT; goto dma_disable;
}
/* the wait should be minimal here */
time_rx_left = wait_for_completion_timeout(&hda_rx_stream->ioc,
msecs_to_jiffies(HDA_BPT_IOC_TIMEOUT_MS)); if (!time_rx_left) {
rx_position = hda_dsp_stream_get_position(hdac_stream(bpt_rx_stream),
SNDRV_PCM_STREAM_CAPTURE, false);
dev_err(dev, "%s: SDW BPT RX DMA did not complete: %ld\n",
__func__, rx_position);
ret = -ETIMEDOUT; goto dma_disable;
}
/* Make sure the DMA is flushed */
i = 0; do {
rx_position = hda_dsp_stream_get_position(hdac_stream(bpt_rx_stream),
SNDRV_PCM_STREAM_CAPTURE, false);
usleep_range(1000, 1010);
i++;
} while (rx_position && i < HDA_BPT_IOC_TIMEOUT_MS); if (rx_position) {
dev_err(dev, "%s: SDW BPT RX DMA position %ld was not cleared\n",
__func__, rx_position);
ret = -ETIMEDOUT; goto dma_disable;
}
dma_disable:
ret1 = hda_sdw_bpt_dma_disable(dev, bpt_rx_stream); if (!ret)
ret = ret1;
ret1 = hda_sdw_bpt_dma_disable(dev, bpt_tx_stream); if (!ret)
ret = ret1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.