Intel High Definition Audio: Difference between revisions

General improvement of article, added "In Progress"
[unchecked revision][unchecked revision]
(General improvement of article, added "In Progress")
 
(3 intermediate revisions by 2 users not shown)
Line 1:
{{In Progress}}
Intel High Definition Audio refers to the specification released by Intel for delivering high-definition audio that is capable of playing back more channels at higher quality than previous integrated audio codecs like [[AC97]].
 
Intel High Definition Audio refers to the specification released by Intel for delivering high-definition audio that is capable of playing back more channels at higher quality than previous integrated audio codecs like [[AC97]].
 
== Identifying HDA on a machine ==
 
All HDA devices appear on the PCI bus with a specific VendorID and DeviceID. Many HDA devices have a Vendor ID of 8086 (Intel), and a Device ID such as 2668 or 27D8, but other Vendor IDs are also in use, e.g. Vendor ID 1002 (AMD) and Device ID 4383. If you find any others, please add them into this page. The best way to identify HDA is probably just to look for the Class code (4h) and subclass (3h), but the HDA specification doesn't tell you to do this.
 
== Overview ==
Line 21 ⟶ 22:
 
== Device Registers ==
 
Base address of these registers can be found in BAR0 in PCI. Full description of these registers can be found in specification, descriptions below do not aim to explain every register or every single bit, only relevant ones.
 
==== 0x00 (4 bytes) Global Capabilities ====
 
{| {{wikitable}}
! Bits
! Offset (Hex)
! Name
! Description
! Notes
|-
| 15:12 || Number of Output streams
| 00 || GCAP || Global Capabilities || (includes number of DMA engines for input and output streams)
|-
| 0211:8 || VMINNumber ||of MinorInput Version ||streams
|-
| 037:3 || VMAJNumber ||of MajorBidirectional Version ||streams
|-
| 0 || 1 = 64 bit addressing is supported
| 04 || OUTPAY || Output Payload Capacity || (packet size limit for the/each output line)
|-
|}
| 06 || INPAY || Input Payload Capacity || (packet size limit for each input line)
 
==== 0x02 (1 byte) Minor Version / 0x03 (1 byte) Major Version ====
 
As names suggests, from these registers you can read version of High Definition Audio specification that is implemented by sound card.
 
==== 0x08 (2 bytes) Global Control ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 8 || 1 = Unsolicited responses from Codec are allowed
| 08 || GCTL || Global Control || (used to reset the link and codec)
|-
| 0 || 0 = Controller is in reset state 1 = Controller is in operational state
| 0C || WAKEEN || Wake Enable ||
|-
|}
| 0E || STATESTS || State Change Status ||
 
==== 0x20 (4 bytes) Interrupt Control ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 31 || 0 = All interrupts are disabled 1 = Interrupts are enabled
| 10 || GSTS || Global Status ||
|-
| 30 || 1 = Controller will generate interrupt due to Response interrupt, Response Buffer overrun and wake events
| 18 || OUTSTRMPAY || Output Stream Payload Capability ||
|-
| 29:0 || If is particular bit set, it mean that corresponding stream will be able to generate interrupts. Bits for streams are sorted in order: Input Streams, Output Streams, Bidirectional streams. So for example if there is one stream from each category, bit 0 will control Input Stream, bit 1 Output Stream and bit 2 Bidirectional Stream. Unused bits are reserved.
| 1A || INSTRMPAY || Input Stream Payload Capability ||
|-
|}
| 20 || INTCTL || Interrupt Control ||
 
==== 0x34 (4 bytes) Stream Synchronization ====
 
Note: The HD Audio specifications list this register at offset 0x38, but this appears to be incorrect.
 
This register allows to start or stop more streams at same time. You can do it by setting bits of these streams what will stop them, then start DMA engine on each of them and finally clear their bits to allow DMA engines to start working with data.
 
{| {{wikitable}}
! Bits
! Description
|-
| 29:0 || If is particular bit clear, it mean that corresponding stream will be able to sent or receive data. Bits for streams are sorted in same order as in register 0x20 Interrupt Control.
| 24 || INTSTS || Interrupt Status ||
|-
|}
| 30 || COUNTER || Wall Clock Counter ||
 
==== 0x40 (4 bytes) CORB Lower Base Address ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 31:7 || Lower Base Address of CORB ring
| 34 || SSYNC || Stream Synchronization || (set bits 0-29 to pause DMA streams 1-30)
Note: The HD Audio specifications list this register at offset 0x38, but this appears to be incorrect.
|-
| 6:0 || Reserved to force 1 KB alignment
| 40 || CORBLBASE || CORB Lower Base Address || (command output ring buffer address)
|-
|}
| 44 || CORBUBASE || CORB Upper Base Address ||
 
==== 0x44 (4 bytes) CORB Upper Base Address ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 4831:0 || CORBWPUpper ||Base CORBAddress Writeof PointerCORB ||ring
|-
|}
| 4a || CORBRP || CORB Read Pointer ||
 
==== 0x48 (2 bytes) CORB Write Pointer ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 4c7:0 || CORBCTLNumber ||of last valid CORB Control ||entry
|-
|}
| 4d || CORBSTS || CORB Status ||
 
==== 0x4A (2 bytes) CORB Read Pointer ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 15 || 1 = Reset CORB read pointer (this bit is not self-clearing, you have to wait for it to be set, then clear it and wait for it to be clear)
| 4e || CORBSIZE || CORB Size ||
|-
| 7:0 || Number of last CORB entry that controller processed
| 50 || RIRBLBASE || RIRB Lower Base Address || (response input ring buffer address)
|-
|}
| 54 || RIRBUBASE || RIRB Upper Base Address ||
 
==== 0x4C (1 byte) CORB Control ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 1 || 0 = CORB is stopped 1 = CORB is running
| 58 || RIRBWP || RIRB Write Pointer ||
|-
| 5a0 || RINTCNT1 || Response= Interrupt Countwill ||be generated if there is memory error
|-
|}
| 5c || RIRBCTL || RIRB Control ||
 
==== 0x4E (1 byte) CORB Size ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 6 || 1 = CORB ring can be programmed to have 256 entries
| 5d || RIRBSTS || RIRB Status ||
|-
| 5 || 1 = CORB ring can be programmed to have 16 entries
| 5e || RIRBSIZE || RIRB Size ||
|-
| 4 || 1 = CORB ring can be programmed to have 2 entries
| 60 || || Immediate Command Output Interface ||
|-
| 1:0 || Number of CORB ring entries. 0b00 = 2 entries 0b01 = 16 entries 0b10 = 256 entries 0b11 = Reserved
| 64 || || Immediate Response Input Interface ||
|-
|}
| 68 || || Immediate Command Status ||
 
==== 0x50 (4 bytes) RIRB Lower Base Address ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 7031:7 || DPLBASE || DMA Position Lower Base Address ||of RIRB ring
|-
| 6:0 || Reserved to force 1 KB alignment
| 74 || DPUBASE || DMA Position Upper Base Address ||
|-
|}
| 80 || || Stream Descriptors ||
 
==== 0x54 (4 bytes) RIRB Upper Base Address ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 31:0 || Upper Base Address of RIRB ring
|-
|}
 
==== 0x58 (2 bytes) RIRB Write Pointer ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 15 || 1 = Reset write pointer (note: this bit always reads as 0)
|-
| 7:0 || Number of last RIRB entry that was written by controller
|-
|}
 
==== 0x5A (2 bytes) RIRB Response Interrupt Count ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 7:0 || How many responses have to be written by RIRB to generate interrupt
|-
|}
 
==== 0x5C (1 byte) RIRB Control ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 0 || 1 = Interrupt will be generated if there is response overrun
|-
| 1 || 0 = RIRB is stopped 1 = RIRB is running
|-
| 0 || 1 = Interrupt will be generated if there is memory error
|-
|}
 
==== 0x5E (1 byte) RIRB Size ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 6 || 1 = RIRB ring can be programmed to have 256 entries
|-
| 5 || 1 = RIRB ring can be programmed to have 16 entries
|-
| 4 || 1 = RIRB ring can be programmed to have 2 entries
|-
| 1:0 || Number of RIRB ring entries. 0b00 = 2 entries 0b01 = 16 entries 0b10 = 256 entries 0b11 = Reserved
|-
|}
 
==== 0x70 (4 bytes) DMA Position Lower Base Address ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 31:7 || Lower Base Address of DMA position buffer
|-
| 6:1 || Reserved to force 1 KB alignment
|-
| 0 || 1 = DMA position buffer is enabled
|-
|}
 
==== 0x74 (4 bytes) DMA Position Upper Base Address ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 31:0 || Upper Base Address of DMA position buffer
|-
|}
 
=== 0x80+ Registers of Stream Descriptors ===
 
Sound card has as many Stream Descriptors as many streams it have. Registers of every Stream Control occupies 0x20 bytes. As first there are Stream Descriptors for Input Streams, then for Output Streams and then for Bidirectional Streams. Number of streams can be readed from 0x00 Global Capabilities register.
 
For example, if there are 4 Input Streams, 3 Output Streams and 1 Bidirectional Stream, base address for registers of first Stream Descriptor for Input Stream is at (mmio_base + 0x80), first Stream Descriptor for Output Stream is at (mmio_base + 0x80 + 0x20*4) and first Stream Descriptor for Bidirectional Stream is at (mmio_base + 0x80 + 0x20*4 + 0x20*3).
 
Offsets in table below should be added to particular Stream Descriptor base.
 
{| {{wikitable}}
! Offset
! Size
! Description
|-
| 0x00 || 1 byte || Stream Control byte 0
|-
| 0x02 || 1 byte || Stream Control byte 2
|-
| 0x03 || 1 byte || Stream Status
|-
| 0x04 || 4 bytes || Link position in buffer entry
|-
| 0x08 || 4 bytes || Cyclic Buffer Length (size of all entries in Buffer Descriptor List added together)
|-
| 0x0C || 2 bytes || Last Valid Index (number of entries in Buffer Descriptor List + 1)
|-
| 0x12 || 2 bytes || Stream Format
|-
| 0x18 || 4 bytes || Lower Base Address of Buffer Descriptor List
|-
| 0x1C || 4 bytes || Upper Base Address of Buffer Descriptor List
|-
|}
 
==== Stream Control byte 0 ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 4 || 1 = Generate interrupt if there is Descriptor error
|-
| 3 || 1 = Generate interrupt if there is FIFO error
|-
| 2 || 1 = Generate interrupt if was transferred buffer with IOC bit set
|-
| 1 || 1 = Stream is running (transferring data)
|-
| 0 || 1 = Reset all registers of Stream Descriptor, must not be set when Stream is running (this bit is not self-clearing, you have to wait for it to be set, then clear it and wait for it to be clear)
|-
|}
 
==== Stream Control byte 2 ====
 
{| {{wikitable}}
! Bits
! Description
|-
| 7:4 || Number of stream to which this Stream Descriptor will send data. Value 0 is reserved and indicate that this Stream Descriptor is unused.
|-
| 3 || Relevant only for Bidirectional streams to set their behaviour 0 = Select Input engine 1 = Select Output engine
|-
| 2 || This bit may be read-only. 0 = Stream will be handled on „best effort“ basis 1 = Stream will be transferred as preferred traffic
|-
|}
Line 103 ⟶ 322:
== CODECs and Nodes ==
 
Each HD Audio device contains one or more CODECs, and each CODEC contains a list of "nodes" that are connected together in a hierarchical structure. You can find the available CODECs in the STATESTS register, and you can find the node count for each CODEC by sending a GetParameter command to the codec's root node (node 0) using the CORB ring buffer (or the Immediate Command Output Interface, if available). If response is not 0x00000000, it mean that CODEC is present.
 
== Node Commands ==
 
Each entry in the CORB ring buffer has the following structure:
 
{| {{wikitable}}
! Bits
Line 122 ⟶ 342:
|}
 
The following commandslist cancontain besome sentuseful toverbs specificthat CODECcould nodesbe usingsend theto CORBCODEC ring buffernodes:
 
{| {{wikitable}}
Line 129 ⟶ 349:
! Notes
|-
| f00F00 || Get Parameter || Data is number of requested parameter
|-
| f01F02 || Get SelectedConnection InputList Entry ||
|-
| 701 || Set Selected Input ||
|-
| f06705 || GetSet StreamPower ChannelState || 0 in data mean full power
|-
| 706 || Set Converter Stream, Channel ||
|-
| f07 || Get Pin Widget Control ||
|-
| 707 || Set Pin Widget Control ||
|-
| F09 || Get Pin Widget Sense || Used to detect if headphone/microphone is plugged into Pin
| f0f || Get Volume Control ||
|-
| 70f70C || Set Volume ControlEAPD/BTL ||
|-
| f1cF1C || Get Pin Widget Configuration Default ||
|-
| f2d72D || GetSet Output Converter Channel Count ||
|-
| 7FF || Audio Function Node Reset || Reset all nodes in particular Audio Function Group
| 72d || Set Converter Channel Count ||
|-
| 7ff0x3 || FunctionSet ResetAmplifier Gain || (16-bit payload)
|-
| 0x30x2 || Set AmplifierStream GainConverter Format || 4(16-bit commandpayload) allowsData forhave asame 16-bitformat payloadas Stream Format register
|-
|}
Line 161 ⟶ 379:
== Node Parameters ==
 
The following parameters can be read using the GetParameterGet commandParameter verb above:
 
{| {{wikitable}}
Line 180 ⟶ 398:
| 09 || Audio Widget Capabilities ||
|-
| 0a0A || Supported PCM Rates ||
|-
| 0b0B || Supported Formats ||
|-
| 0c0C || Pin Capabilities ||
|-
| 0d0D || Input Amplifier Capabilities ||
|-
| 12 || Output Amplifier Capabilities ||
|-
| 0e0E || Connection List Length ||
|-
| 0f0F || Supported Power States ||
|-
| 10 || Processing Capabilities ||
Line 202 ⟶ 420:
|}
 
== SettingInitalizing upsound the AFG codeccard ==
 
TODO
 
== Initalizing CODEC ==
 
=== Setting up the AFG codec ===
 
Each programmer will likely have their own way of going about this, but the main aim will be to set out to identify which pin complexes are connected to actual speakers, headphone sockets, microphones and microphone sockets before following the trail of connections back to the most appropriate DAC or ADC to handle the stream. How you end up connecting things up will depend on what you want to do: you could, for example, use the same DAC for the speakers as for the headphone jack, but there might be occasions when you want to send different sound streams to each. Similarly, you might use the same ADC for the built-in microphone as for the microphone jack, but you could use a different ADC for each if you need to collect different inputs from different microphones (perhaps using one to collect background noise to subtract from the other input). You might also want to send sound out through the microphone socket so that two people can listen to the same music at the same time on headphones, or you might want to use the headphone socket as an extra microphone socket, perhaps to set up a pair of stereo microphones in a tetrahedron arrangement in order to calculate the direction a sound is coming from. Try to make your driver flexible enough to cover all those cases, or at least to make it easy to adapt it to cover them later.
 
Here's an suggestion as to how the initial task might be broken down, but use it only as a rough guide:-
 
 
(1) Use verb F00h with parameter 4 and NID 0 (the root node) to find the number of function groups in the codec, then check those nodes using their NID and with verb F00h and parameter 5 to hunt for an AFG function group.
Line 233 ⟶ 456:
After you've done all that, get the near end of the link set up to get the DMA engines to handle the streams (read the specification carefully and act on it) and with luck you'll soon have sound coming in and out. If it doesn't happen that easily, you can set up the DMA position buffer to see if the DMA engines are actually running and looping correctly through the cyclic stream buffers. If all is well there, you might find it useful to use the codec ID to find the datasheet for it just to make sure you aren't missing anything out in the way you're setting it up. Also, feel free to improve the instructions on this page so that others can gain from your solutions to any problems you encounter.
 
=== Finding all useful paths through the codec ===
 
The paths that are potentially useful are the ones that lead from pins with output devices connected to them back to a DAC, plus all the paths from those same pins back to all other pins with an input device connected to them (some codecs allow inputs to be mixed into outputs for such purposes as karaoke, so your device driver might as well make this option available if the codec supports it), plus all the paths from ADCs to all pins with an input device connected. A socket for a jack can be both an output and input device, but not at the same time.
Line 243 ⟶ 466:
== Playing Audio ==
 
If you successfully initalized all nodes that are in path, you can play audio by following steps:
The following steps must be performed to play audio on an HD Audio device:
 
==== Set Audio Output node ====
(1) Create a buffer list structure, and add at least two buffer entries to the list.
 
You have to set Audio Output node to format of your data by verb 0x2, and also set stream number and channel you will use to transfer data by verb 0x706. Node will remember these values, so you need to set them only when you want to change them.
(2) Setup an output stream descriptor, normally located at memory offset 0x100 in the register table above. This descriptor contains the address of the buffer table from step 1, the audio format (44.1k stereo 16-bit, etc.), the total buffer length, the current buffer position, the number of buffers in the buffer list, and most importantly, the RUN bit that will start streaming data to any DACs currently configured to play audio from this stream.
 
==== Create Buffer Descriptor List ====
(3) Find at least one speaker or headphone node in the CODEC that you want to use to play your audio, and turn it on by sending a SetPinWidgetControl command to it.
 
Buffer Descriptor List has to be 1 KB aligned, what mean that first seven bits must be zero. It has to contain at least 2 entries. Every entry is 16 bytes long and has following format:
(4) Use the speaker node's connection table to find out which DAC node it is connected to.
 
{| {{wikitable}}
(5) Configure the DAC to use the stream number that you configured above in step 2 by sending it a SetStreamChannel command.
! Offset
! Length
! Description
|-
| 0x00 || 8 bytes || Address of Audio Data
|-
| 0x08 || 4 bytes || Length of Audio Data in bytes
|-
| 0x0C || 4 bytes || Bit 0 = IOC (Interrupt On Completion), if set, interrupt will be generated after transferring this entry. Rest is reserved.
|-
|}
 
NOTE: Sound Card will read Buffer Descriptor List data directly from RAM memory, so you have to be sure, that you really wrote it into RAM memory and not only to processor cache. You can do it by flushing processor cache by assembly command „wbinvd“
(6) Make sure that the DAC is fully powered (in D0 state). The SetPowerState command is used for this.
 
==== Set Stream Descriptor ====
(7) By default, the DAC's output amplifier is muted. Clear the mute bit, and set the gain (volume) by sending the DAC node a SetAmplifierGain command. You can find the maximum gain value by reading the OutputAmplifierCapabilities property on the DAC node (or in some cases, its parent node). Do not be surprised if the maximum volume is the one with 0dB gain - the job of the amplifier at a DAC is to reduce the volume rather than to increase it, so all the other values will usually be negative.
 
Now you have to select Stream Descriptor that you do not already use and program it to transfer your Buffer Descriptor List.
(8) Enable the configured stream from step 1 by clearing its corresponding bit in the StreamSynchonization register.
 
(1) Stop Stream Descriptor (clear bit 1 in Control register)
The audio will play until the end of the last buffer in the buffer list, then it will begin playing the beginning of the first buffer again. You can enable the proper interrupt to be notified when a buffer has been played, so that you can refill the buffer with the next block of audio data.
 
(2) Reset Stream Descriptor (set bit 0 in Control register, wait until it is set, then clear it and wait for it to be cleared)
 
(3) Write Buffer Descriptor List physical address
 
(4) Add up length of all entries in Buffer Descriptor List and write it to register
 
(5) Set number of Buffer Descriptor List entries
 
(6) Set Stream Format register by same format you sended to Audio Output node
 
(7) Set number of stream you want to use for streaming data (in byte 2 of Control register)
 
(8) Start transfer (set bit 1 in Control register)
 
If you configured everything properly, DMA engine should start transfer your audio data and you should hear sound from PIN(s) you enabled and connected them to Audio Output(s) that are receiving data from your stream number. The audio will play until the end of the last buffer in the buffer list, then it will begin playing the beginning of the first buffer again. You can enable the proper interrupt to be notified when a buffer has been played, so that you can refill the buffer with the next block of audio data.
 
== External links ==
Line 267 ⟶ 517:
* [http://www.intel.co.uk/content/www/us/en/standards/high-definition-audio-specification.html Intel High Definition Audio Specification]
 
* [https://forum.osdev.org/viewtopic.php?f=1&t=34525 Thread about playing sound throughtthrough Intel HD Audio]
 
* https://forum.osdev.org/viewtopic.php?f=1&t=28944
 
 
Anonymous user