SoundWire 中的音訊流

音訊流是在以下兩者之間建立的邏輯或虛擬連線:

  1. 系統記憶體緩衝區與編解碼器

  2. DSP 記憶體緩衝區與編解碼器

  3. FIFO 與編解碼器

  4. 編解碼器與編解碼器

通常由一個或多個 DMA 通道透過資料鏈路驅動。音訊流包含一個或多個數據通道。流中的所有通道必須具有相同的取樣率和取樣大小。

假設使用 SoundWire 介面打開了一個包含兩個通道(左和右)的流。以下是流在 SoundWire 中表示的幾種方式。

記憶體中的流樣本(系統記憶體、DSP 記憶體或 FIFO)

-------------------------
| L | R | L | R | L | R |
-------------------------

示例 1:L 和 R 通道的立體聲流從主裝置渲染到從裝置。主裝置和從裝置都使用單個埠。

+---------------+                    Clock Signal  +---------------+
|    Master     +----------------------------------+     Slave     |
|   Interface   |                                  |   Interface   |
|               |                                  |       1       |
|               |                     Data Signal  |               |
|    L  +  R    +----------------------------------+    L  +  R    |
|     (Data)    |     Data Direction               |     (Data)    |
+---------------+  +----------------------->       +---------------+

示例 2:L 和 R 通道的立體聲流從從裝置捕獲到主裝置。主裝置和從裝置都使用單個埠。

+---------------+                    Clock Signal  +---------------+
|    Master     +----------------------------------+     Slave     |
|   Interface   |                                  |   Interface   |
|               |                                  |       1       |
|               |                     Data Signal  |               |
|    L  +  R    +----------------------------------+    L  +  R    |
|     (Data)    |     Data Direction               |     (Data)    |
+---------------+  <-----------------------+       +---------------+

示例 3:L 和 R 通道的立體聲流由主裝置渲染。L 和 R 通道分別由兩個不同的從裝置接收。主裝置和兩個從裝置都使用單個埠。

+---------------+                    Clock Signal  +---------------+
|    Master     +---------+------------------------+     Slave     |
|   Interface   |         |                        |   Interface   |
|               |         |                        |       1       |
|               |         |           Data Signal  |               |
|    L  +  R    +---+------------------------------+       L       |
|     (Data)    |   |     |    Data Direction      |     (Data)    |
+---------------+   |     |   +------------->      +---------------+
                    |     |
                    |     |
                    |     |                        +---------------+
                    |     +----------------------> |     Slave     |
                    |                              |   Interface   |
                    |                              |       2       |
                    |                              |               |
                    +----------------------------> |       R       |
                                                   |     (Data)    |
                                                   +---------------+

示例 4:L 和 R 通道的立體聲流由主裝置渲染。L 和 R 通道都由兩個不同的從裝置接收。主裝置和兩個從裝置都使用處理 L+R 的單個埠。每個從裝置在本地處理 L + R 資料,通常基於靜態配置或動態方向,並可能驅動一個或多個揚聲器。

+---------------+                    Clock Signal  +---------------+
|    Master     +---------+------------------------+     Slave     |
|   Interface   |         |                        |   Interface   |
|               |         |                        |       1       |
|               |         |           Data Signal  |               |
|    L  +  R    +---+------------------------------+     L + R     |
|     (Data)    |   |     |    Data Direction      |     (Data)    |
+---------------+   |     |   +------------->      +---------------+
                    |     |
                    |     |
                    |     |                        +---------------+
                    |     +----------------------> |     Slave     |
                    |                              |   Interface   |
                    |                              |       2       |
                    |                              |               |
                    +----------------------------> |     L + R     |
                                                   |     (Data)    |
                                                   +---------------+

示例 5:L 和 R 通道的立體聲流由主裝置的兩個不同埠渲染,並僅由從介面的單個埠接收。

+--------------------+
|                    |
|     +--------------+                             +----------------+
|     |             ||                             |                |
|     |  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)    |
+--------------------+                             |                |
                                                   +----------------+

示例 6:L 和 R 通道的立體聲流由 2 個主裝置渲染,每個主裝置渲染一個通道,並由兩個不同的從裝置接收,每個從裝置接收一個通道。兩個主裝置和兩個從裝置都使用單個埠。

+---------------+                    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)    |
+---------------+  +----------------------->       +---------------+

示例 7:L 和 R 通道的立體聲流由 2 個主裝置渲染,每個主裝置都渲染兩個通道。每個從裝置接收 L + R。這與示例 4 是相同的應用,但從裝置放置在獨立的鏈路上。

+---------------+                    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)    |
+---------------+  +----------------------->       +---------------+

示例 8:4 通道流由 2 個主裝置渲染,每個主裝置渲染 2 個通道。每個從裝置接收 2 個通道。

+---------------+                    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)    |
+---------------+  +----------------------->       +---------------+

注 1:在上述多鏈路情況下,要進行鎖定,通常會先獲取全域性鎖,然後再鎖定匯流排例項。但是,在這種情況下,呼叫者框架 (ASoC DPCM) 保證對卡上的流操作總是序列化的。因此,不存在競爭條件,也就不需要全域性鎖。

注 2:從裝置可以配置為接收給定流在鏈路上傳送的所有通道(示例 4),或僅接收資料的一個子集(示例 3)。從裝置的配置不由 SoundWire 子系統 API 處理,而是由 snd_soc_dai_set_tdm_slot() API 處理。平臺或機器驅動程式通常會配置使用哪些時隙。對於示例 4,所有裝置都將使用相同的時隙,而對於示例 3,從裝置 1 將使用例如時隙 0,從裝置 2 將使用時隙 1。

注 3:多個 Sink 埠可以從 SoundWire 幀中相同的 bitSlots 提取相同的資訊,但是多個 Source 埠應配置不同的 bitSlot 配置。這與 I2S/PCM TDM 用法具有相同的限制。

SoundWire 流管理流程

流定義

  1. 當前流:指需要執行操作的流,如準備、啟用、停用、去準備等。

  2. 活動流:指除當前流之外,已在總線上處於活動狀態的流。總線上可以有多個活動流。

SoundWire 匯流排管理 SoundWire 總線上每個渲染/捕獲流的流操作。本節解釋了匯流排為總線上分配/釋放的每個流執行的匯流排操作。以下是匯流排為每個音訊流維護的流狀態。

SoundWire 流狀態

下圖顯示了 SoundWire 流狀態和狀態轉換圖。

+-----------+     +------------+     +----------+     +----------+
| ALLOCATED +---->| CONFIGURED +---->| PREPARED +---->| ENABLED  |
|   STATE   |     |    STATE   |     |  STATE   |     |  STATE   |
+-----------+     +------------+     +---+--+---+     +----+-----+
                                         ^  ^              ^
                                         |  |              |
                                       __|  |___________   |
                                      |                 |  |
                                      v                 |  v
         +----------+           +-----+------+        +-+--+-----+
         | RELEASED |<----------+ DEPREPARED |<-------+ DISABLED |
         |  STATE   |           |   STATE    |        |  STATE   |
         +----------+           +------------+        +----------+

注意:SDW_STREAM_ENABLEDSDW_STREAM_DISABLED 之間的狀態轉換僅在 ALSA/ASoC 級別支援 INFO_PAUSE 標誌時才相關。同樣,SDW_DISABLED_STATESDW_PREPARED_STATE 之間的轉換取決於 INFO_RESUME 標誌。

注 2:該框架實現了基本的狀態轉換檢查,但例如不檢查從 DISABLED 到 ENABLED 的轉換在特定平臺上是否有效。此類測試需要在 ALSA/ASoC 級別新增。

流狀態操作

以下部分解釋了匯流排在流狀態轉換過程中對主裝置和從裝置執行的操作。

SDW_STREAM_ALLOCATED

流的分配狀態。這是流的進入狀態。在此狀態之前執行的操作:

  1. 為流分配了一個流執行時。該流執行時用作對流執行的所有操作的參考。

  2. 分配並初始化了儲存流執行時資訊所需的資源。這包含了所有流相關資訊,如流型別 (PCM/PDM) 及其引數、與流關聯的主從介面、流狀態等。

所有上述操作成功後,流狀態設定為 SDW_STREAM_ALLOCATED

匯流排實現了用於分配流的以下 API,每個流需要呼叫一次。從 ASoC DPCM 框架來看,此流狀態可能與 .startup() 操作相關聯。

int sdw_alloc_stream(char * stream_name, enum sdw_stream_type type);

SoundWire 核心提供了一個 sdw_startup_stream() 輔助函式,通常在 dailink .startup() 回撥期間呼叫,它執行流分配併為連線到流的所有 DAI 設定流指標。

SDW_STREAM_CONFIGURED

流的配置狀態。在此狀態之前執行的操作:

  1. 在此更新 SDW_STREAM_ALLOCATED 狀態中為流資訊分配的資源。這包括流引數、與當前流關聯的主裝置和從裝置執行時資訊。

  2. 與當前流關聯的所有主裝置和從裝置都向匯流排提供埠資訊,其中包括主裝置和從裝置為當前流分配的埠號及其通道掩碼。

所有上述操作成功後,流狀態設定為 SDW_STREAM_CONFIGURED

匯流排實現了用於 CONFIG 狀態的以下 API,這些 API 需要由與流關聯的相應主裝置和從裝置呼叫。這些 API 只能由相應的主裝置和從裝置呼叫一次。從 ASoC DPCM 框架來看,此流狀態與 .hw_params() 操作相關聯。

int sdw_stream_add_master(struct sdw_bus * bus,
              struct sdw_stream_config * stream_config,
              const 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,
              const struct sdw_ports_config * ports_config,
              struct sdw_stream_runtime * stream);

SDW_STREAM_PREPARED

流的準備狀態。在此狀態之前執行的操作:

  1. 在恢復操作的情況下,步驟 1 和 2 被省略,因為匯流排頻寬是已知的。

  2. 匯流排引數,如頻寬、幀形狀、時鐘頻率,是根據當前流以及總線上已有的活動流計算的。需要重新計算以適應總線上的當前流。

  3. 根據步驟 1 中計算的幀形狀和時鐘頻率,計算所有主裝置和從裝置埠的傳輸和埠引數,包括當前流和已有的活動流。

  4. 計算出的匯流排和傳輸引數被程式設計到主裝置和從裝置的暫存器中。 banked 暫存器程式設計在備用 bank(當前未使用的 bank)上進行。已有的活動流的埠在備用 bank(當前未使用的 bank)上啟用。這樣做是為了不中斷已有的活動流。

  5. 一旦所有值都程式設計完畢,匯流排將啟動切換到備用 bank,所有新程式設計的值將在此生效。

  6. 透過程式設計 PrepareCtrl 暫存器來準備當前流的主裝置和從裝置的埠。

所有上述操作成功後,流狀態設定為 SDW_STREAM_PREPARED

匯流排實現了用於 PREPARE 狀態的以下 API,每個流需要呼叫一次。從 ASoC DPCM 框架來看,此流狀態與 .prepare() 操作相關聯。由於 .trigger() 操作可能不會緊隨 .prepare(),因此允許從 SDW_STREAM_PREPARED 直接轉換到 SDW_STREAM_DEPREPARED

int sdw_prepare_stream(struct sdw_stream_runtime * stream);

SDW_STREAM_ENABLED

流的啟用狀態。進入此狀態後,資料埠將被啟用。在此狀態之前執行的操作:

  1. 在 SDW_STREAM_PREPARED 狀態中計算出的所有值都被程式設計到備用 bank(當前未使用的 bank)中。這也包括已有的活動流的程式設計。

  2. 透過程式設計 ChannelEn 暫存器,在備用 bank(當前未使用的 bank)上啟用當前流的所有主裝置和從裝置埠。

  3. 一旦所有值都程式設計完畢,匯流排將啟動切換到備用 bank,所有新程式設計的值將在此生效,並且與當前流關聯的埠將被啟用。

所有上述操作成功後,流狀態設定為 SDW_STREAM_ENABLED

匯流排實現了用於 ENABLE 狀態的以下 API,每個流需要呼叫一次。從 ASoC DPCM 框架來看,此流狀態與 .trigger() 啟動操作相關聯。

int sdw_enable_stream(struct sdw_stream_runtime * stream);

SDW_STREAM_DISABLED

流的停用狀態。退出此狀態後,資料埠將被停用。在此狀態之前執行的操作:

  1. 透過程式設計 ChannelEn 暫存器,在備用 bank(當前未使用的 bank)上停用當前流的所有主裝置和從裝置埠。

  2. 匯流排和活動流的所有當前配置都被程式設計到備用 bank(當前未使用的 bank)中。

  3. 一旦所有值都程式設計完畢,匯流排將啟動切換到備用 bank,所有新程式設計的值將在此生效,並且與當前流關聯的埠將被停用。

所有上述操作成功後,流狀態設定為 SDW_STREAM_DISABLED

匯流排實現了用於 DISABLED 狀態的以下 API,每個流需要呼叫一次。從 ASoC DPCM 框架來看,此流狀態與 .trigger() 停止操作相關聯。

當支援 INFO_PAUSE 標誌時,允許直接轉換到 SDW_STREAM_ENABLED

對於 ASoC 將使用 .prepare() 回撥的恢復操作,流可以從 SDW_STREAM_DISABLED 轉換到 SDW_STREAM_PREPARED,所有必需的設定都已恢復,但未更新頻寬和位分配。

int sdw_disable_stream(struct sdw_stream_runtime * stream);

SDW_STREAM_DEPREPARED

流的去準備狀態。在此狀態之前執行的操作:

  1. 透過程式設計 PrepareCtrl 暫存器,解除準備當前流的所有主裝置和從裝置埠。

  2. 透過執行 bank 切換等操作,當前流的有效負載頻寬從匯流排總頻寬需求中減少,並計算和應用新引數。

所有上述操作成功後,流狀態設定為 SDW_STREAM_DEPREPARED

匯流排實現了用於 DEPREPARED 狀態的以下 API,每個流需要呼叫一次。ALSA/ASoC 沒有“去準備”的概念,因此此流狀態到 ALSA/ASoC 操作的對映可能是實現特定的。

當支援 INFO_PAUSE 標誌時,流狀態與 .hw_free() 操作相關聯——流在 TRIGGER_STOP 時不會被去準備。

如果其他實現需要透過 SDW_STREAM_PREPARED 狀態進行轉換,則它們可能在 TRIGGER_STOP 時轉換到 SDW_STREAM_DEPREPARED 狀態。

int sdw_deprepare_stream(struct sdw_stream_runtime * stream);

SDW_STREAM_RELEASED

流的釋放狀態。在此狀態之前執行的操作:

  1. 釋放與當前流關聯的所有主裝置和從裝置埠的埠資源。

  2. 釋放與當前流關聯的主裝置和從裝置執行時資源。

  3. 釋放與當前流關聯的流執行時資源。

所有上述操作成功後,流狀態設定為 SDW_STREAM_RELEASED

匯流排實現了用於 RELEASE 狀態的以下 API,這些 API 需要由與流關聯的所有主裝置和從裝置呼叫。從 ASoC DPCM 框架來看,此流狀態與 .hw_free() 操作相關聯。

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);

.shutdown() ASoC DPCM 操作呼叫以下匯流排 API 以釋放作為 ALLOCATED 狀態一部分分配的流。

在 .shutdown() 中,維護流狀態的資料結構被釋放。

void sdw_release_stream(struct sdw_stream_runtime * stream);

SoundWire 核心提供了一個 sdw_shutdown_stream() 輔助函式,通常在 dailink .shutdown() 回撥期間呼叫,它清除連線到流的所有 DAI 的流指標並釋放為流分配的記憶體。

不支援

  1. 不支援在兩個流之間或跨流使用具有多個通道的單個埠。例如,一個具有 4 個通道的埠不能用於處理 2 個獨立的立體聲流,即使這在 SoundWire 中理論上是可能的。