// SPDX-License-Identifier: GPL-2.0-only /* * HD-audio stream operations */ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/clocksource.h> #include <sound/compress_driver.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/hdaudio.h> #include <sound/hda_register.h> #include "trace.h" /* * the hdac_stream library is intended to be used with the following * transitions. The states are not formally defined in the code but loosely * inspired by boolean variables. Note that the 'prepared' field is not used * in this library but by the callers during the hw_params/prepare transitions * * | * stream_init() | * v * +--+-------+ * | unused | * +--+----+--+ * | ^ * stream_assign() | | stream_release() * v | * +--+----+--+ * | opened | * +--+----+--+ * | ^ * stream_reset() | | * stream_setup() | | stream_cleanup() * v | * +--+----+--+ * | prepared | * +--+----+--+ * | ^ * stream_start() | | stream_stop() * v | * +--+----+--+ * | running | * +----------+ */ /** * snd_hdac_get_stream_stripe_ctl - get stripe control value * @bus: HD-audio core bus * @substream: PCM substream */ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, struct snd_pcm_substream *substream) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_init - initialize each stream (aka device) * @bus: HD-audio core bus * @azx_dev: HD-audio core stream object to initialize * @idx: stream index number * @direction: stream direction (SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE) * @tag: the tag id to assign * * Assign the starting bdl address to each stream (device) and initialize. */ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, int idx, int direction, int tag) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_start - start a stream * @azx_dev: HD-audio core stream to start * * Start a stream, set start_wallclk and set the running flag. */ void snd_hdac_stream_start(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_clear - helper to clear stream registers and stop DMA transfers * @azx_dev: HD-audio core stream to stop */ static void snd_hdac_stream_clear(struct hdac_stream *azx_dev) { … } /** * snd_hdac_stream_stop - stop a stream * @azx_dev: HD-audio core stream to stop * * Stop a stream DMA and disable stream interrupt */ void snd_hdac_stream_stop(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stop_streams - stop all streams * @bus: HD-audio core bus */ void snd_hdac_stop_streams(struct hdac_bus *bus) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stop_streams_and_chip - stop all streams and chip if running * @bus: HD-audio core bus */ void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_reset - reset a stream * @azx_dev: HD-audio core stream to reset */ void snd_hdac_stream_reset(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_setup - set up the SD for streaming * @azx_dev: HD-audio core stream to set up * @code_loading: Whether the stream is for PCM or code-loading. */ int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_cleanup - cleanup a stream * @azx_dev: HD-audio core stream to clean up */ void snd_hdac_stream_cleanup(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_assign - assign a stream for the PCM * @bus: HD-audio core bus * @substream: PCM substream to assign * * Look for an unused stream for the given PCM substream, assign it * and return the stream object. If no stream is free, returns NULL. * The function tries to keep using the same stream object when it's used * beforehand. Also, when bus->reverse_assign flag is set, the last free * or matching entry is returned. This is needed for some strange codecs. */ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_release_locked - release the assigned stream * @azx_dev: HD-audio core stream to release * * Release the stream that has been assigned by snd_hdac_stream_assign(). * The bus->reg_lock needs to be taken at a higher level */ void snd_hdac_stream_release_locked(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_release - release the assigned stream * @azx_dev: HD-audio core stream to release * * Release the stream that has been assigned by snd_hdac_stream_assign(). */ void snd_hdac_stream_release(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_get_stream - return hdac_stream based on stream_tag and * direction * * @bus: HD-audio core bus * @dir: direction for the stream to be found * @stream_tag: stream tag for stream to be found */ struct hdac_stream *snd_hdac_get_stream(struct hdac_bus *bus, int dir, int stream_tag) { … } EXPORT_SYMBOL_GPL(…); /* * set up a BDL entry */ static int setup_bdle(struct hdac_bus *bus, struct snd_dma_buffer *dmab, struct hdac_stream *azx_dev, __le32 **bdlp, int ofs, int size, int with_ioc) { … } /** * snd_hdac_stream_setup_periods - set up BDL entries * @azx_dev: HD-audio core stream to set up * * Set up the buffer descriptor table of the given stream based on the * period and buffer sizes of the assigned PCM substream. */ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_set_params - set stream parameters * @azx_dev: HD-audio core stream for which parameters are to be set * @format_val: format value parameter * * Setup the HD-audio core stream parameters from substream of the stream * and passed format value */ int snd_hdac_stream_set_params(struct hdac_stream *azx_dev, unsigned int format_val) { … } EXPORT_SYMBOL_GPL(…); static u64 azx_cc_read(const struct cyclecounter *cc) { … } static void azx_timecounter_init(struct hdac_stream *azx_dev, bool force, u64 last) { … } /** * snd_hdac_stream_timecounter_init - initialize time counter * @azx_dev: HD-audio core stream (master stream) * @streams: bit flags of streams to set up * * Initializes the time counter of streams marked by the bit flags (each * bit corresponds to the stream index). * The trigger timestamp of PCM substream assigned to the given stream is * updated accordingly, too. */ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, unsigned int streams) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_sync_trigger - turn on/off stream sync register * @azx_dev: HD-audio core stream (master stream) * @set: true = set, false = clear * @streams: bit flags of streams to sync * @reg: the stream sync register address */ void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, unsigned int streams, unsigned int reg) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_sync - sync with start/stop trigger operation * @azx_dev: HD-audio core stream (master stream) * @start: true = start, false = stop * @streams: bit flags of streams to sync * * For @start = true, wait until all FIFOs get ready. * For @start = false, wait until all RUN bits are cleared. */ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, unsigned int streams) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_spbcap_enable - enable SPIB for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable SPIB * @index: stream index for which SPIB need to be enabled */ void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_set_spib - sets the spib value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * @value: spib value to set */ int snd_hdac_stream_set_spib(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * * Return maxfifo for the stream */ int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM * @index: stream index for which DRSM need to be enabled */ void snd_hdac_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { … } EXPORT_SYMBOL_GPL(…); /* * snd_hdac_stream_wait_drsm - wait for HW to clear RSM for a stream * @azx_dev: HD-audio core stream to await RSM for * * Returns 0 on success and -ETIMEDOUT upon a timeout. */ int snd_hdac_stream_wait_drsm(struct hdac_stream *azx_dev) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * @value: dpib value to set */ int snd_hdac_stream_set_dpibr(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_set_lpib - sets the lpib value of a stream * @azx_dev: hdac_stream * @value: lpib value to set */ int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value) { … } EXPORT_SYMBOL_GPL(…); #ifdef CONFIG_SND_HDA_DSP_LOADER /** * snd_hdac_dsp_prepare - prepare for DSP loading * @azx_dev: HD-audio core stream used for DSP loading * @format: HD-audio stream format * @byte_size: data chunk byte size * @bufp: allocated buffer * * Allocate the buffer for the given size and set up the given stream for * DSP loading. Returns the stream tag (>= 0), or a negative error code. */ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, unsigned int byte_size, struct snd_dma_buffer *bufp) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_dsp_trigger - start / stop DSP loading * @azx_dev: HD-audio core stream used for DSP loading * @start: trigger start or stop */ void snd_hdac_dsp_trigger(struct hdac_stream *azx_dev, bool start) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_dsp_cleanup - clean up the stream from DSP loading to normal * @azx_dev: HD-audio core stream used for DSP loading * @dmab: buffer used by DSP loading */ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, struct snd_dma_buffer *dmab) { … } EXPORT_SYMBOL_GPL(…); #endif /* CONFIG_SND_HDA_DSP_LOADER */