mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
527 lines
23 KiB
527 lines
23 KiB
========================= |
|
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 channels is rendered by |
|
Master. Both of the L and R channels are received by two different |
|
Slaves. Master and both Slaves are using single port handling |
|
L+R. Each Slave device processes the L + R data locally, typically |
|
based on static configuration or dynamic orientation, and may drive |
|
one or more speakers. :: |
|
|
|
+---------------+ Clock Signal +---------------+ |
|
| Master +---------+------------------------+ Slave | |
|
| Interface | | | Interface | |
|
| | | | 1 | |
|
| | | Data Signal | | |
|
| L + R +---+------------------------------+ L + R | |
|
| (Data) | | | Data Direction | (Data) | |
|
+---------------+ | | +-------------> +---------------+ |
|
| | |
|
| | |
|
| | +---------------+ |
|
| +----------------------> | Slave | |
|
| | Interface | |
|
| | 2 | |
|
| | | |
|
+----------------------------> | L + R | |
|
| (Data) | |
|
+---------------+ |
|
|
|
Example 5: 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 6: 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) | |
|
+---------------+ +-----------------------> +---------------+ |
|
|
|
Example 7: Stereo Stream with L and R channel is rendered by 2 |
|
Masters, each rendering both channels. Each Slave receives L + R. This |
|
is the same application as Example 4 but with Slaves placed on |
|
separate links. :: |
|
|
|
+---------------+ Clock Signal +---------------+ |
|
| Master +----------------------------------+ Slave | |
|
| Interface | | Interface | |
|
| 1 | | 1 | |
|
| | Data Signal | | |
|
| L + R +----------------------------------+ L + R | |
|
| (Data) | Data Direction | (Data) | |
|
+---------------+ +-----------------------> +---------------+ |
|
|
|
+---------------+ Clock Signal +---------------+ |
|
| Master +----------------------------------+ Slave | |
|
| Interface | | Interface | |
|
| 2 | | 2 | |
|
| | Data Signal | | |
|
| L + R +----------------------------------+ L + R | |
|
| (Data) | Data Direction | (Data) | |
|
+---------------+ +-----------------------> +---------------+ |
|
|
|
Example 8: 4-channel Stream is rendered by 2 Masters, each rendering a |
|
2 channels. Each Slave receives 2 channels. :: |
|
|
|
+---------------+ Clock Signal +---------------+ |
|
| Master +----------------------------------+ Slave | |
|
| Interface | | Interface | |
|
| 1 | | 1 | |
|
| | Data Signal | | |
|
| L1 + R1 +----------------------------------+ L1 + R1 | |
|
| (Data) | Data Direction | (Data) | |
|
+---------------+ +-----------------------> +---------------+ |
|
|
|
+---------------+ Clock Signal +---------------+ |
|
| Master +----------------------------------+ Slave | |
|
| Interface | | Interface | |
|
| 2 | | 2 | |
|
| | Data Signal | | |
|
| L2 + R2 +----------------------------------+ L2 + R2 | |
|
| (Data) | Data Direction | (Data) | |
|
+---------------+ +-----------------------> +---------------+ |
|
|
|
Note1: 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. |
|
|
|
Note2: A Slave device may be configured to receive all channels |
|
transmitted on a link for a given Stream (Example 4) or just a subset |
|
of the data (Example 3). The configuration of the Slave device is not |
|
handled by a SoundWire subsystem API, but instead by the |
|
snd_soc_dai_set_tdm_slot() API. The platform or machine driver will |
|
typically configure which of the slots are used. For Example 4, the |
|
same slots would be used by all Devices, while for Example 3 the Slave |
|
Device1 would use e.g. Slot 0 and Slave device2 slot 1. |
|
|
|
Note3: Multiple Sink ports can extract the same information for the |
|
same bitSlots in the SoundWire frame, however multiple Source ports |
|
shall be configured with different bitSlot configurations. This is the |
|
same limitation as with I2S/PCM TDM usages. |
|
|
|
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); |
|
|
|
The SoundWire core provides a sdw_startup_stream() helper function, |
|
typically called during a dailink .startup() callback, which performs |
|
stream allocation and sets the stream pointer for all DAIs |
|
connected to a stream. |
|
|
|
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); |
|
|
|
The SoundWire core provides a sdw_shutdown_stream() helper function, |
|
typically called during a dailink .shutdown() callback, which clears |
|
the stream pointer for all DAIS connected to a stream and releases the |
|
memory allocated for the 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.
|
|
|