mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 17:23:55 +08:00
5952880771
The state machine and notes don't accurately explain or allow transitions from STREAM_DEPREPARED and STREAM_DISABLED. Add more explanations and allow for more transitions as a result of a trigger_stop(), trigger_suspend() and prepare(), depending on the ALSA/ASoC layer behavior defined by the INFO_RESUME and INFO_PAUSE flags. Also add basic checks to help debug inconsistent states and illegal state machine transitions. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20200114235227.14502-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
436 lines
18 KiB
ReStructuredText
436 lines
18 KiB
ReStructuredText
=========================
|
|
Audio Stream in SoundWire
|
|
=========================
|
|
|
|
An audio stream is a logical or virtual connection created between
|
|
|
|
(1) System memory buffer(s) and Codec(s)
|
|
|
|
(2) DSP memory buffer(s) and Codec(s)
|
|
|
|
(3) FIFO(s) and Codec(s)
|
|
|
|
(4) Codec(s) and Codec(s)
|
|
|
|
which is typically driven by a DMA(s) channel through the data link. An
|
|
audio stream contains one or more channels of data. All channels within
|
|
stream must have same sample rate and same sample size.
|
|
|
|
Assume a stream with two channels (Left & Right) is opened using SoundWire
|
|
interface. Below are some ways a stream can be represented in SoundWire.
|
|
|
|
Stream Sample in memory (System memory, DSP memory or FIFOs) ::
|
|
|
|
-------------------------
|
|
| L | R | L | R | L | R |
|
|
-------------------------
|
|
|
|
Example 1: Stereo Stream with L and R channels is rendered from Master to
|
|
Slave. Both Master and Slave is using single port. ::
|
|
|
|
+---------------+ Clock Signal +---------------+
|
|
| Master +----------------------------------+ Slave |
|
|
| Interface | | Interface |
|
|
| | | 1 |
|
|
| | Data Signal | |
|
|
| L + R +----------------------------------+ L + R |
|
|
| (Data) | Data Direction | (Data) |
|
|
+---------------+ +-----------------------> +---------------+
|
|
|
|
|
|
Example 2: Stereo Stream with L and R channels is captured from Slave to
|
|
Master. Both Master and Slave is using single port. ::
|
|
|
|
|
|
+---------------+ Clock Signal +---------------+
|
|
| Master +----------------------------------+ Slave |
|
|
| Interface | | Interface |
|
|
| | | 1 |
|
|
| | Data Signal | |
|
|
| L + R +----------------------------------+ L + R |
|
|
| (Data) | Data Direction | (Data) |
|
|
+---------------+ <-----------------------+ +---------------+
|
|
|
|
|
|
Example 3: Stereo Stream with L and R channels is rendered by Master. Each
|
|
of the L and R channel is received by two different Slaves. Master and both
|
|
Slaves are using single port. ::
|
|
|
|
+---------------+ Clock Signal +---------------+
|
|
| Master +---------+------------------------+ Slave |
|
|
| Interface | | | Interface |
|
|
| | | | 1 |
|
|
| | | Data Signal | |
|
|
| L + R +---+------------------------------+ L |
|
|
| (Data) | | | Data Direction | (Data) |
|
|
+---------------+ | | +-------------> +---------------+
|
|
| |
|
|
| |
|
|
| | +---------------+
|
|
| +----------------------> | Slave |
|
|
| | Interface |
|
|
| | 2 |
|
|
| | |
|
|
+----------------------------> | R |
|
|
| (Data) |
|
|
+---------------+
|
|
|
|
|
|
Example 4: Stereo Stream with L and R channel is rendered by two different
|
|
Ports of the Master and is received by only single Port of the Slave
|
|
interface. ::
|
|
|
|
+--------------------+
|
|
| |
|
|
| +--------------+ +----------------+
|
|
| | || | |
|
|
| | Data Port || L Channel | |
|
|
| | 1 |------------+ | |
|
|
| | L Channel || | +-----+----+ |
|
|
| | (Data) || | L + R Channel || Data | |
|
|
| Master +----------+ | +---+---------> || Port | |
|
|
| Interface | | || 1 | |
|
|
| +--------------+ | || | |
|
|
| | || | +----------+ |
|
|
| | Data Port |------------+ | |
|
|
| | 2 || R Channel | Slave |
|
|
| | R Channel || | Interface |
|
|
| | (Data) || | 1 |
|
|
| +--------------+ Clock Signal | L + R |
|
|
| +---------------------------> | (Data) |
|
|
+--------------------+ | |
|
|
+----------------+
|
|
|
|
Example 5: Stereo Stream with L and R channel is rendered by 2 Masters, each
|
|
rendering one channel, and is received by two different Slaves, each
|
|
receiving one channel. Both Masters and both Slaves are using single port. ::
|
|
|
|
+---------------+ Clock Signal +---------------+
|
|
| Master +----------------------------------+ Slave |
|
|
| Interface | | Interface |
|
|
| 1 | | 1 |
|
|
| | Data Signal | |
|
|
| L +----------------------------------+ L |
|
|
| (Data) | Data Direction | (Data) |
|
|
+---------------+ +-----------------------> +---------------+
|
|
|
|
+---------------+ Clock Signal +---------------+
|
|
| Master +----------------------------------+ Slave |
|
|
| Interface | | Interface |
|
|
| 2 | | 2 |
|
|
| | Data Signal | |
|
|
| R +----------------------------------+ R |
|
|
| (Data) | Data Direction | (Data) |
|
|
+---------------+ +-----------------------> +---------------+
|
|
|
|
Note: In multi-link cases like above, to lock, one would acquire a global
|
|
lock and then go on locking bus instances. But, in this case the caller
|
|
framework(ASoC DPCM) guarantees that stream operations on a card are
|
|
always serialized. So, there is no race condition and hence no need for
|
|
global lock.
|
|
|
|
SoundWire Stream Management flow
|
|
================================
|
|
|
|
Stream definitions
|
|
------------------
|
|
|
|
(1) Current stream: This is classified as the stream on which operation has
|
|
to be performed like prepare, enable, disable, de-prepare etc.
|
|
|
|
(2) Active stream: This is classified as the stream which is already active
|
|
on Bus other than current stream. There can be multiple active streams
|
|
on the Bus.
|
|
|
|
SoundWire Bus manages stream operations for each stream getting
|
|
rendered/captured on the SoundWire Bus. This section explains Bus operations
|
|
done for each of the stream allocated/released on Bus. Following are the
|
|
stream states maintained by the Bus for each of the audio stream.
|
|
|
|
|
|
SoundWire stream states
|
|
-----------------------
|
|
|
|
Below shows the SoundWire stream states and state transition diagram. ::
|
|
|
|
+-----------+ +------------+ +----------+ +----------+
|
|
| ALLOCATED +---->| CONFIGURED +---->| PREPARED +---->| ENABLED |
|
|
| STATE | | STATE | | STATE | | STATE |
|
|
+-----------+ +------------+ +---+--+---+ +----+-----+
|
|
^ ^ ^
|
|
| | |
|
|
__| |___________ |
|
|
| | |
|
|
v | v
|
|
+----------+ +-----+------+ +-+--+-----+
|
|
| RELEASED |<----------+ DEPREPARED |<-------+ DISABLED |
|
|
| STATE | | STATE | | STATE |
|
|
+----------+ +------------+ +----------+
|
|
|
|
NOTE: State transitions between ``SDW_STREAM_ENABLED`` and
|
|
``SDW_STREAM_DISABLED`` are only relevant when then INFO_PAUSE flag is
|
|
supported at the ALSA/ASoC level. Likewise the transition between
|
|
``SDW_DISABLED_STATE`` and ``SDW_PREPARED_STATE`` depends on the
|
|
INFO_RESUME flag.
|
|
|
|
NOTE2: The framework implements basic state transition checks, but
|
|
does not e.g. check if a transition from DISABLED to ENABLED is valid
|
|
on a specific platform. Such tests need to be added at the ALSA/ASoC
|
|
level.
|
|
|
|
Stream State Operations
|
|
-----------------------
|
|
|
|
Below section explains the operations done by the Bus on Master(s) and
|
|
Slave(s) as part of stream state transitions.
|
|
|
|
SDW_STREAM_ALLOCATED
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Allocation state for stream. This is the entry state
|
|
of the stream. Operations performed before entering in this state:
|
|
|
|
(1) A stream runtime is allocated for the stream. This stream
|
|
runtime is used as a reference for all the operations performed
|
|
on the stream.
|
|
|
|
(2) The resources required for holding stream runtime information are
|
|
allocated and initialized. This holds all stream related information
|
|
such as stream type (PCM/PDM) and parameters, Master and Slave
|
|
interface associated with the stream, stream state etc.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_ALLOCATED``.
|
|
|
|
Bus implements below API for allocate a stream which needs to be called once
|
|
per stream. From ASoC DPCM framework, this stream state maybe linked to
|
|
.startup() operation.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_alloc_stream(char * stream_name);
|
|
|
|
|
|
SDW_STREAM_CONFIGURED
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Configuration state of stream. Operations performed before entering in
|
|
this state:
|
|
|
|
(1) The resources allocated for stream information in SDW_STREAM_ALLOCATED
|
|
state are updated here. This includes stream parameters, Master(s)
|
|
and Slave(s) runtime information associated with current stream.
|
|
|
|
(2) All the Master(s) and Slave(s) associated with current stream provide
|
|
the port information to Bus which includes port numbers allocated by
|
|
Master(s) and Slave(s) for current stream and their channel mask.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_CONFIGURED``.
|
|
|
|
Bus implements below APIs for CONFIG state which needs to be called by
|
|
the respective Master(s) and Slave(s) associated with stream. These APIs can
|
|
only be invoked once by respective Master(s) and Slave(s). From ASoC DPCM
|
|
framework, this stream state is linked to .hw_params() operation.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_stream_add_master(struct sdw_bus * bus,
|
|
struct sdw_stream_config * stream_config,
|
|
struct sdw_ports_config * ports_config,
|
|
struct sdw_stream_runtime * stream);
|
|
|
|
int sdw_stream_add_slave(struct sdw_slave * slave,
|
|
struct sdw_stream_config * stream_config,
|
|
struct sdw_ports_config * ports_config,
|
|
struct sdw_stream_runtime * stream);
|
|
|
|
|
|
SDW_STREAM_PREPARED
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
Prepare state of stream. Operations performed before entering in this state:
|
|
|
|
(0) Steps 1 and 2 are omitted in the case of a resume operation,
|
|
where the bus bandwidth is known.
|
|
|
|
(1) Bus parameters such as bandwidth, frame shape, clock frequency,
|
|
are computed based on current stream as well as already active
|
|
stream(s) on Bus. Re-computation is required to accommodate current
|
|
stream on the Bus.
|
|
|
|
(2) Transport and port parameters of all Master(s) and Slave(s) port(s) are
|
|
computed for the current as well as already active stream based on frame
|
|
shape and clock frequency computed in step 1.
|
|
|
|
(3) Computed Bus and transport parameters are programmed in Master(s) and
|
|
Slave(s) registers. The banked registers programming is done on the
|
|
alternate bank (bank currently unused). Port(s) are enabled for the
|
|
already active stream(s) on the alternate bank (bank currently unused).
|
|
This is done in order to not disrupt already active stream(s).
|
|
|
|
(4) Once all the values are programmed, Bus initiates switch to alternate
|
|
bank where all new values programmed gets into effect.
|
|
|
|
(5) Ports of Master(s) and Slave(s) for current stream are prepared by
|
|
programming PrepareCtrl register.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_PREPARED``.
|
|
|
|
Bus implements below API for PREPARE state which needs to be called
|
|
once per stream. From ASoC DPCM framework, this stream state is linked
|
|
to .prepare() operation. Since the .trigger() operations may not
|
|
follow the .prepare(), a direct transition from
|
|
``SDW_STREAM_PREPARED`` to ``SDW_STREAM_DEPREPARED`` is allowed.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_prepare_stream(struct sdw_stream_runtime * stream);
|
|
|
|
|
|
SDW_STREAM_ENABLED
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
Enable state of stream. The data port(s) are enabled upon entering this state.
|
|
Operations performed before entering in this state:
|
|
|
|
(1) All the values computed in SDW_STREAM_PREPARED state are programmed
|
|
in alternate bank (bank currently unused). It includes programming of
|
|
already active stream(s) as well.
|
|
|
|
(2) All the Master(s) and Slave(s) port(s) for the current stream are
|
|
enabled on alternate bank (bank currently unused) by programming
|
|
ChannelEn register.
|
|
|
|
(3) Once all the values are programmed, Bus initiates switch to alternate
|
|
bank where all new values programmed gets into effect and port(s)
|
|
associated with current stream are enabled.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_ENABLED``.
|
|
|
|
Bus implements below API for ENABLE state which needs to be called once per
|
|
stream. From ASoC DPCM framework, this stream state is linked to
|
|
.trigger() start operation.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_enable_stream(struct sdw_stream_runtime * stream);
|
|
|
|
SDW_STREAM_DISABLED
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
Disable state of stream. The data port(s) are disabled upon exiting this state.
|
|
Operations performed before entering in this state:
|
|
|
|
(1) All the Master(s) and Slave(s) port(s) for the current stream are
|
|
disabled on alternate bank (bank currently unused) by programming
|
|
ChannelEn register.
|
|
|
|
(2) All the current configuration of Bus and active stream(s) are programmed
|
|
into alternate bank (bank currently unused).
|
|
|
|
(3) Once all the values are programmed, Bus initiates switch to alternate
|
|
bank where all new values programmed gets into effect and port(s) associated
|
|
with current stream are disabled.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_DISABLED``.
|
|
|
|
Bus implements below API for DISABLED state which needs to be called once
|
|
per stream. From ASoC DPCM framework, this stream state is linked to
|
|
.trigger() stop operation.
|
|
|
|
When the INFO_PAUSE flag is supported, a direct transition to
|
|
``SDW_STREAM_ENABLED`` is allowed.
|
|
|
|
For resume operations where ASoC will use the .prepare() callback, the
|
|
stream can transition from ``SDW_STREAM_DISABLED`` to
|
|
``SDW_STREAM_PREPARED``, with all required settings restored but
|
|
without updating the bandwidth and bit allocation.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_disable_stream(struct sdw_stream_runtime * stream);
|
|
|
|
|
|
SDW_STREAM_DEPREPARED
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
De-prepare state of stream. Operations performed before entering in this
|
|
state:
|
|
|
|
(1) All the port(s) of Master(s) and Slave(s) for current stream are
|
|
de-prepared by programming PrepareCtrl register.
|
|
|
|
(2) The payload bandwidth of current stream is reduced from the total
|
|
bandwidth requirement of bus and new parameters calculated and
|
|
applied by performing bank switch etc.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_DEPREPARED``.
|
|
|
|
Bus implements below API for DEPREPARED state which needs to be called
|
|
once per stream. ALSA/ASoC do not have a concept of 'deprepare', and
|
|
the mapping from this stream state to ALSA/ASoC operation may be
|
|
implementation specific.
|
|
|
|
When the INFO_PAUSE flag is supported, the stream state is linked to
|
|
the .hw_free() operation - the stream is not deprepared on a
|
|
TRIGGER_STOP.
|
|
|
|
Other implementations may transition to the ``SDW_STREAM_DEPREPARED``
|
|
state on TRIGGER_STOP, should they require a transition through the
|
|
``SDW_STREAM_PREPARED`` state.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_deprepare_stream(struct sdw_stream_runtime * stream);
|
|
|
|
|
|
SDW_STREAM_RELEASED
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
Release state of stream. Operations performed before entering in this state:
|
|
|
|
(1) Release port resources for all Master(s) and Slave(s) port(s)
|
|
associated with current stream.
|
|
|
|
(2) Release Master(s) and Slave(s) runtime resources associated with
|
|
current stream.
|
|
|
|
(3) Release stream runtime resources associated with current stream.
|
|
|
|
After all above operations are successful, stream state is set to
|
|
``SDW_STREAM_RELEASED``.
|
|
|
|
Bus implements below APIs for RELEASE state which needs to be called by
|
|
all the Master(s) and Slave(s) associated with stream. From ASoC DPCM
|
|
framework, this stream state is linked to .hw_free() operation.
|
|
|
|
.. code-block:: c
|
|
|
|
int sdw_stream_remove_master(struct sdw_bus * bus,
|
|
struct sdw_stream_runtime * stream);
|
|
int sdw_stream_remove_slave(struct sdw_slave * slave,
|
|
struct sdw_stream_runtime * stream);
|
|
|
|
|
|
The .shutdown() ASoC DPCM operation calls below Bus API to release
|
|
stream assigned as part of ALLOCATED state.
|
|
|
|
In .shutdown() the data structure maintaining stream state are freed up.
|
|
|
|
.. code-block:: c
|
|
|
|
void sdw_release_stream(struct sdw_stream_runtime * stream);
|
|
|
|
Not Supported
|
|
=============
|
|
|
|
1. A single port with multiple channels supported cannot be used between two
|
|
streams or across stream. For example a port with 4 channels cannot be used
|
|
to handle 2 independent stereo streams even though it's possible in theory
|
|
in SoundWire.
|