# Overview * Feature Name: SndwFeaturePkg - The SoundWire (Sndw) Manager IP is a soft controller IP with configurable parameters that can be tailored to support audio streaming applications over the SoundWire interface on Intel platforms. * PI Phase(s) Supported: DXE * SMM Required: No ## Purpose This feature allows to initialize built-in SoundWire controllers on Intel platforms and enumerate/control connected codecs to each SoundWire controller over the SoundWire interface. For more information about SoundWire interface, see [SoundWire specification](https://www.mipi.org/specifications/soundwire). Currently supported use cases: * Driver strength selection * Multiple codecs support, up to 11 codecs on each SoundWire link (single Manager interface handles up to 11 codecs according to SoundWire specification) * Installing SndwAccess protocol which allows communication with all connected codecs * Installing SndwBeep protocol which allows short tones generation by supported codecs Currently supported codecs: * Realtek ALC1308 ## High-Level Theory of Operation Feature package contains: * Protocols * **SndwAccess** * This protocol contains all functions needed to operate on attached SoundWire codecs. Enable/disable functions allow to enable and disable access to SoundWire codecs. User before any operation on codecs should use **Enable** function. In other cases access will not be ready. After the user is done using codecs, **Disable** function should be called. In other cases SoundWire OS driver may work incorrectly. * **SndwBeep** * This protocol contains functions which allow to generate short tones e.g. for diagnostic purpose. This protocol for correct working require SndwAccess protocol. * Drivers * **SndwInitDxe** (*DxeSndwInit.inf*) * This driver is responsible for installing the **SndwAccess** protocol on *SndwInitDxe* entry point. *SndwAccess* protocol allows to prepare SoundWire controllers for codecs enumeration process. During enumeration *SndwInitDxe* driver checks and initializes all of the connected codecs and reads all identification information from them. Based on this data *SndwInitDxe* driver creates codecs list. The *SndwInitDxe.inf* entry point has to be executed before drivers start binding to the hardware. It is board responsibility to place them in flash in a way that meets this requirement. * **SndwBeepRltkAlc1308** (*SndwBeepRltkAlc1308.inf*) * This driver is responsible for installing the **SndwBeep** protocol. It implements all of the *SndwBeep* protocol functions for Realtek ALC1308 codec. This driver requires *SndwAccess* protocol to work. ### SoundWire Access Protocol EFI Guid Name | Guid Value ----------------------- | ---------- gSndwAccessProtocolGuid | ```0x0DA23D05-425B-4A21-83EE-D3546E2CD4C3``` Function Name | Parameters | Comments ------------- | ---------- | -------- ```Send``` | **CONST SNDW_ACCESS** *```*This```*
**SNDW_CODEC_INFO** *```SndwCodecInfo```*
**SNDW_COMMAND** *```*TxCommand```*
**UINTN** *```TxSize```* | Function operating on Sndw Fifo buffer for sending messages to codecs. ```SendWithAck``` | **CONST SNDW_ACCESS** *```*This```*
**SNDW_CODEC_INFO** *```SndwCodecInfo```*
**SNDW_COMMAND** *```TxCommand```*
**SNDW_COMMAND** *```RxCommand```* (OPTIONAL) | Function sends one message through the Sndw interface and waits for the corresponding ACK message. ```Receive``` | **CONST SNDW_ACCESS** *```*This```*
**SNDW_CODEC_INFO** *```SndwCodecInfo```*
**SNDW_COMMAND** *```**RxCommand```*
**UINTN** *```RxSize```* | Function operating on Sndw Fifo for receiving messages from codecs. ```GetFirstCodec``` | **CONST SNDW_ACCESS** *```*This```*
**SNDW_CODEC_INFO** *```**SndwCodecInfo```* | Function return first codec saved in codecs list. If it does not exist, function sets *CodecInfo to ```NULL```. ```GetNextCodec``` | **CONST SNDW_ACCESS** *```*This```*
**SNDW_CODEC_INFO** *```*SndwCodecInfo```*
**SNDW_CODEC_INFO** *```**NextCodecInfo```* | Function retrieves the next codec saved in codecs list that follows the given one. If it does not exist, function sets *NextCodecInfo to ```NULL```. ```Enable``` | **CONST SNDW_ACCESS** *```*This```* | Function enables Soundwire interface and enumerates attached codecs. ```Disable``` | **CONST SNDW_ACCESS** *```*This```* | Function disables Soundwire interface. ### SoundWire CodecInfo structure (SNDW_CODEC_INFO) Field Name | Comments ------------- | -------- ```SndwLinkIndex``` | Number of SoundWire link from 1 to max SoundWire link number (Defined by silicon). Check board design. ```CodecId``` | Structure specifying the address of SoundWire codec. This address should be unique on link, where codec is connected. ### SoundWire CodecId structure Register Address | Field Name | Comments ---------------- | -------------- | -------- ```0x50``` | Version | Indicates compliance with a specific SoundWire specification version.
b```0011``` => SoundWire v1.2
b```0010``` => SoundWire v1.1
b```0001``` => SoundWire v1.0 ```0x51```, ```0x52``` | ManufacturerID | MIPI standard manufacturer code, see [http://mid.mipi.org](http://mid.mipi.org/). ```0x53```, ```0x54``` | PartID | Fields implemented and defined by manufacturer. ```0x55``` | Class | Field reserved for MIPI-defined class encoding. ### SoundWire MIPI Tx/Rx Commands structure Bits | Field Name | Read | Write | Comments ----- | ------------- | --------------------- | -------------------- | -------- ```31``` | SspTag | SSPOINT_TAG | SSPOINT_TAG | This bit is used to inform hardware that this command should be delayed until the next SSP occurs. ```30:28``` | Opcode | SndwCmdRead | SndwCmdWrite | Type of the command. ```27:24``` | DeviceAddress | Device Address (0-11) | DeviceAddress (0-11) | Do not edit this field. It is overriden by driver based on enumeration process. ```23:8``` | RegAddress | Register Address | Register Address | It is an address of the register in codec memory. Check codec specification. ```7:0``` | RegData | Reserved | Register Data | New value of register ### SoundWire MIPI Rx Responses structure Bits | Field Name | Read | Write | Comments ----- | ---------- | ----------- | ------------- | -------- ```31:16``` | Reserved2 | Reserved | Reserved | Reserved. ```15:8``` | Data | RegData | Response Data | Response from Read Tx Command. ```7``` | Reserved1 | Reserved | Reserved | Reserved. ```6:4``` | Opcode | SndwCmdRead | SndwCmdWrite | Type of command. ```3:2``` | Reserved0 | Reserved | Reserved | Reserved. ```1``` | Nak | NAK | NAK | If this value is equal to b```1```, command is aborted. ```0``` | Ack | ACK | ACK | Informs whether command has been accepted. If this value is equal to b```1``` then command has been accepted. ### Opcode Value in Opcode field | Command Name --------------------- | ------------ b```000``` | Ping b```010``` | Read b```011``` | Write ### SoundWire Beep Protocol EFI Guid Name | Guid Value ----------------------- | ---------- gSndwBeepProtocolGuid | ```0x5D2A7CCF-33BE-444D-BAA6-D6B597F5668B``` Function Name | Parameters | Comments ------------- | ---------- | -------- ```BeepOff``` | **CONST SNDW_BEEP** *```*This```* | Function send command which disables sine tone generator. ```BeepOn``` | **CONST SNDW_BEEP** *```*This```*
**UINTN** *```Frequency```*
**INTN** *```Amplitude```* | Function sends command which enables sine tone generator. ```Beep``` | **CONST SNDW_BEEP** *```*This```*
**UINTN** *```Frequency```*
**INTN** *```Amplitude```*
**UINTN** *```NumOfBeeps```*
**UINTN** *```BeepDuration```*
**UINTN** *```PauseDuration```* | Function send command which enables sine tone generator. It allows to customize parameters like duration, number of beeps and pause between beeps. ```Enable``` | **CONST SNDW_BEEP** *```*This```* | Function calls **Enable** function from SoundWire Access protocol. ```Disable``` | **CONST SNDW_BEEP** *```*This```* | Function calls **Disable** function from SoundWire Access protocol. ## Modules * DxeSndwInit.inf * SndwBeepRltkAlc1308.inf * SndwBeepExample.inf ## Configuration Set ```gSndwFeatureModuleTokenSpaceGuid.PcdSndwFeatureEnable``` to ```TRUE``` to enable SoundWire feature.
SndwBeepDriver is configured by PCDs: PcdSndwBeepLinkNumber and PcdSndwBeepCodecId. PcdSndwBeepLinkNumber is used to select the number of SoundWire link. SoundWire links are numbered from 1. PcdSndwBeepCodecId contains information about codec IDs.
### Settings example gSndwFeatureModuleTokenSpaceGuid.PcdSndwBeepLinkNumber|```0x01```
gSndwFeatureModuleTokenSpaceGuid.PcdSndwBeepCodecId|{```0x20```, ```0x02```, ```0x5D```, ```0x13```, ```0x08```, ```0x00```} ## Data flows ### SoundWire Access Protocol SndwAccess Protocol can be used in all DXE phases after protocol installation. Before calling any function for communication with codecs user should use ```Enable``` function. After that user can call any function provided by SndwAccess Protocol. After all operations user should use ```Disable``` function. This step is important for further SoundWire components like OS drivers. Example: ```C Status = gBS->LocateProtocol ( &gSndwAccessProtocolGuid, NULL, (VOID **) &SndwAccess ); ASSERT_EFI_ERROR (Status); Status = SndwAccess->Enable (SndwAccess); ... Status = SndwAccess->Disable (SndwAccess); ``` After ```SndwAccess->Enable``` call user can send and receive MCP messages from codecs. Function ```Send``` is able to send multiple messages. Parameters for ```Send``` function are pointer to SndwAccess Protocol, codec informations (SNDW_CODEC_INFO), pointer to array of MCP messages (SNDW_COMMAND) and number of messages. Refer to SoundWire [CodecId structure](#soundWire-CodecId-structure), SoundWire MIPI [Tx](#soundWire-MIPI-Tx/Rx-Commands-structure)/[Rx](#soundWire-MIPI-Rx-Responses-structure) Commands structure and [Opcode](#opcode). Example: ```C SNDW_CODEC_INFO CodecInfo; SNDW_COMMAND Command[1]; CodecInfo.SndwLinkIndex = 1; // Sndw Link index CodecInfo.CodecId.Encoding.Version = 0x20; CodecInfo.CodecId.Encoding.ManufacturerID[0] = 0x02; CodecInfo.CodecId.Encoding.ManufacturerID[1] = 0x5D; CodecInfo.CodecId.Encoding.PartId[0] = 0x13; CodecInfo.CodecId.Encoding.PartId[1] = 0x08; CodecInfo.CodecId.Encoding.Class = 0x00; Command[0].TxWrite.OpCode = SndwCmdWrite; // write data to codec Command[0].TxWrite.RegAddr = 0x42; // address of register in codec memory Command[0].TxWrite.RegData = 0x21; // new register value Status = SndwAccess->Send (SndwAccess, CodecInfo, &Command, 1); ``` All messages sent to codecs have responses. Response contains data from codec if OpCode of command was SndwRead, Ack and Nak. Refer to [SoundWire MIPI Rx Responses structure](#soundWire-MIPI-Rx-Responses-structure). Function for getting responses is ```Receive```. Parameters for ```Receive``` function are pointer to *SndwAccess* protocol, codec information structure (*SNDW_CODEC_INFO*), pointer to received MCP messages (*SNDW_COMMAND*) and number of received messages. ```Receive``` function allocates memory and user should free up this memory with ```FreePool```; Example: ```C SNDW_CODEC_INFO CodecInfo; SNDW_COMMAND *CommandResponse; UINTN ResponseSize; CodecInfo.SndwLinkIndex = 1; // Sndw Link index CodecInfo.CodecId.Encoding.Version = 0x20; CodecInfo.CodecId.Encoding.ManufacturerID[0] = 0x02; CodecInfo.CodecId.Encoding.ManufacturerID[1] = 0x5D; CodecInfo.CodecId.Encoding.PartId[0] = 0x13; CodecInfo.CodecId.Encoding.PartId[1] = 0x08; CodecInfo.CodecId.Encoding.Class = 0x00; Status = SndwAccess->Receive (SndwAccess, CodecInfo, &CommandResponse, &ResponseSize); if (!EFI_ERROR (Status) && CommandResponse[0].Rx.Ack == 1) { // command success } FreePool (CommandResponse); ``` SndwAccess Protocol allows to send and receive one MCP message at a time by ```SendWithAck``` function. Parameters are pointer to *SndwAccess* protocol, codec information structure (*SNDW_CODEC_INFO*), MCP messages to send (*SNDW_COMMAND*) and pointer to received MCP message. Example: ```C SNDW_CODEC_INFO CodecInfo; SNDW_COMMAND Command; SNDW_COMMAND *CommandRespons; CodecInfo.SndwLinkIndex = 1; // Sndw Link index CodecInfo.CodecId.Encoding.Version = 0x20; CodecInfo.CodecId.Encoding.ManufacturerID[0] = 0x02; CodecInfo.CodecId.Encoding.ManufacturerID[1] = 0x5D; CodecInfo.CodecId.Encoding.PartId[0] = 0x13; CodecInfo.CodecId.Encoding.PartId[1] = 0x08; CodecInfo.CodecId.Encoding.Class = 0x00; Command.TxWrite.OpCode = SndwCmdWrite; // write data to codec Command.TxWrite.RegAddr = 0x42; // address of regioster in codec Command.TxWrite.RegData = 0x21; // new register value SndwAccess->SendWithAck (SndwAccess, CodecInfo, Command, CommandRespons); if (!EFI_ERROR (Status) && CommandRespons->Rx.Ack == 1) { // command success } ``` During the codecs enumeration process codecs list is created. From this list user can retrieve information about any found codec. ```GetFirstCodec``` function allows to get information about first codec discovered during codecs enumeration. Parameters for this function are pointer to *SndwAccess* protocol and pointer to pointer to codec information structure (```SNDW_CODEC_INFO **CodecInfo```). ```GetFirstCodec``` allocates memory for codec information structure and user should free up this memory with ```FreePool```.
```GetNextCodec``` retrieves codec information about codec that follows the given one. Parameters for this function are are pointer to *SndwAccess* protocol, pointer to codec information structure (```SNDW_CODEC_INFO *CodecInfo```) preceding the one that user wants to get and pointer to pointer to codec information structure (```SNDW_CODEC_INFO **NextCodecInfo```). ```GetNextCodec``` allocates memory for codec information structure and user should free up this memory with ```FreePool```. If there is no codec in codecs list following the given one, value pointed out by ```NextCodecInfo``` will be set to ```NULL```. Example: ```C SNDW_CODEC_INFO *CodecInfo; SNDW_CODEC_INFO *NextCodecInfo; SndwAccess->GetFirstCodec (SndwAccess, &NextCodecInfo); while (NextCodecInfo != NULL) { DEBUG ((DEBUG_INFO, "------- SNDW CODEC -------\n")); DEBUG ((DEBUG_INFO, "SndwLinkIndex: %d\n", NextCodecInfo->SndwLinkIndex)); DEBUG ((DEBUG_INFO, "Codec ID:\n")); DEBUG ((DEBUG_INFO, " Version: 0x%02x\n", NextCodecInfo->CodecId.Encoding.Version)); DEBUG ((DEBUG_INFO, " ManufacturerID[0]: 0x%02x\n", NextCodecInfo->CodecId.Encoding.ManufacturerID[0])); DEBUG ((DEBUG_INFO, " ManufacturerID[1]: 0x%02x\n", NextCodecInfo->CodecId.Encoding.ManufacturerID[1])); DEBUG ((DEBUG_INFO, " PartId[0]: 0x%02x\n", NextCodecInfo->CodecId.Encoding.PartId[0])); DEBUG ((DEBUG_INFO, " PartId[1]: 0x%02x\n", NextCodecInfo->CodecId.Encoding.PartId[1])); DEBUG ((DEBUG_INFO, " Class: 0x%02x\n", NextCodecInfo->CodecId.Encoding.Class)); DEBUG ((DEBUG_INFO, "----------------------\n")); CodecInfo = NextCodecInfo; NextCodecInfo = NULL; SndwAccess->GetNextCodec (SndwAccess, CodecInfo, &NextCodecInfo); FreePool (CodecInfo); } ``` ### SoundWire Beep Protocol SndwBeep Protocol can be used in all DXE phases after protocol installation. Before using functions for generating beep sound user should use ```Enable``` function, after that user can use ```Beep``` function. Parameters for ```Beep``` are pointer to SndwBeep Protocol, frequency in Hz, amplitude in dB, number of beep sound, duration of beep in milliseconds and pause between beeps in milliseconds. ```Beep``` function is blocking function. It means that user cannot do anything before end of this function. SndwBeep Protocol contains also function for non blocking beep sounds. ```BeepOn``` function alows to turn on tone generator. Parameters for ```BeepOn``` are pointer to SndwBeep Protocol, frequency in Hz, amplitude in dB. ```BeepOff``` allow to turn off tone generator. Parameter for ```BeepOff``` is pointer to SndwBeep Protocol. After all operations user should use ```Disable``` function. This step is important for further SoundWire components like OS drivers. Example of generating beep: ```C Status = gBS->LocateProtocol ( &gSndwBeepProtocolGuid, NULL, (VOID **) &SndwBeep ); ASSERT_EFI_ERROR (Status); Status = SndwBeep->Enable (SndwBeep); Status = SndwBeep->Beep (SndwBeep, 250, 0, 2, 1000, 500); Status = SndwBeep->Disable (SndwBeep); ``` ## Build flows No special tools are required to build this feature. ## Feature Enabling Checklist 1. Add *SndwFeaturePkg.dsc* entry, check if all required packages and libraries are available. 1. Add *SndwFeaturePostMemory.fdf* to flash map file. 1. *SndwBeepExample.c* shows an example of use.