OSDev.org
https://forum.osdev.org/

How to play sound Intel HD Audio?
https://forum.osdev.org/viewtopic.php?f=1&t=34525
Page 4 of 4

Author:  Ethin [ Wed Oct 30, 2019 6:41 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Apologies for bumping this topic, but I've got the CORB and RIRB set up and all works (I think, anyway). This is what I do:
1) I reset the controller by setting the CRST bit and waiting for that to show as set. I do not clear this bit (the specification does not say I need to do so).
2) I sleep for an additional 10 RTC ticks, which on my OS is about 1.221 µs (to allow all codecs -- even slow ones -- to initialize). The specification only says that 521 Us is required, but I wait a bit longer just in case.
3) I set bits 14:0 on WAKEEN and post that to the controller.
4) I clear bits 1:0 on corbctl and post that.
5) I set corbsize to 0100 to allow 256 entries (thank you, Linux) and post that.
6) I generate a random 64-bit address for the CORB and align it on a 128-byte boundry as the specification indicates. I double-verify this alignment before submitting it, and if bits 63:48 are set, I clear them to avoid a processor exception. I write bits 31:0 of the address to Corblbase and bits 63:32 to corbubase. A similar process occurs with the RIRB.
7) Before I set up the RIRB, I set Corbwp to 0 and reset Corbrp.
8) I set up the RIRB following an identical address and size setting process as above. When setting Rirbctl, I clear bits 2:0.
9) I set bit 1 in Corbctl and Rirbctl to start both engines.
10) I perform a final check by verifying that bit 0 of Corbsts is clear. If its set, I know I've hit a CMEI and panic.
At this point I think I've got everything initialized and ready to go. The only issue is exactly how to send a command to a node. Bits 31:28 are the codec address; is there a way I can determine this? Similar question for the node index.

Author:  DavidCooper [ Thu Oct 31, 2019 2:12 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Good to see that you've got so far with it. You should know the codec number from STATESTS. From the top of page 61 we have:-

Code:
4.3 Codec Discovery
When the link is enabled by the assertion of CRST, the codecs will detect the de-assertion of the RESET# signal and request a status change and enumeration by the controller.  As the controller hardware detects these requests, it will provide the codecs with their unique addresses and set the controller STATESTS bits to indicate that a Status Change event was detected on the appropriate SDATA_INx signals.  Software can use these bits to determine the addresses of the codecs attached to the link.  A 1 in a given bit position indicates that a codec at that associated address is present.  For instance, a value of 05h means that there are codecs with addresses 0 and 2 attached to the link.


And the offset for that is 0Eh:-

Code:
3.3.9  Offset 0Eh:  STATESTS – State Change Status Length: 2 bytes
Table 10. Wake Status

Bit: 15
Type: RsvdZ
Reset: 0‟s
Description: Reserved

Bits: 14:0
Type: RW1CS, RSM
Reset: 0‟s
Description: SDIN State Change Status Flags (SDIWAKE):  Flag bits that indicate which SDIN signal(s) received a “State Change” event.  The bits are cleared by writing 1‟s to them.  The SDATA_IN[0] line corresponds to bit 0, etc. These bits are only cleared by a power-on reset.

The SDIWAKE bits are used to indicate that a “Status Change” event has occurred on the link, which usually indicates that either the codec has just come out of reset and is requesting an address, or that a codec is signaling a wake event.  The controller hardware will perform the resulting address cycle on the bus, and set this bit to inform the software that the event has occurred.  The setting of this bit may cause a processor interrupt to occur if the appropriate WAKEEN bits (Section 3.3.8) are set.


The node index (NID) is 0 for the root node, so you start with that set to zero and use it with verb F00h and paramater 04h to return the range of NIDs representing function groups. You then change the NID to that of a function group to ask it if it's an AFG (using F00h again but with parameter 05h), and once you've found the AFG group (the response will have the lowest byte = 1 for the AFG group) you can use parameter 04h with that NID to get it to return the range of NIDs that are HDA widgets. When interpreting the response for parameter 04h, the byte using bits 23-16 are the first NID in the range of relevant NIDs, and the byte using bits 7-0 holds the number of nodes (the range of relevant NIDs, including the first one). When you use this with the root node, you'll likely only find one group and it will be the AFG group. When you use it with the AFG group node, you should find a range covering two to three dozen widgets.

Author:  Ethin [ Thu Oct 31, 2019 6:10 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

DavidCooper wrote:
Good to see that you've got so far with it. You should know the codec number from STATESTS. From the top of page 61 we have:-

Code:
4.3 Codec Discovery
When the link is enabled by the assertion of CRST, the codecs will detect the de-assertion of the RESET# signal and request a status change and enumeration by the controller.  As the controller hardware detects these requests, it will provide the codecs with their unique addresses and set the controller STATESTS bits to indicate that a Status Change event was detected on the appropriate SDATA_INx signals.  Software can use these bits to determine the addresses of the codecs attached to the link.  A 1 in a given bit position indicates that a codec at that associated address is present.  For instance, a value of 05h means that there are codecs with addresses 0 and 2 attached to the link.


And the offset for that is 0Eh:-

Code:
3.3.9  Offset 0Eh:  STATESTS – State Change Status Length: 2 bytes
Table 10. Wake Status

Bit: 15
Type: RsvdZ
Reset: 0‟s
Description: Reserved

Bits: 14:0
Type: RW1CS, RSM
Reset: 0‟s
Description: SDIN State Change Status Flags (SDIWAKE):  Flag bits that indicate which SDIN signal(s) received a “State Change” event.  The bits are cleared by writing 1‟s to them.  The SDATA_IN[0] line corresponds to bit 0, etc. These bits are only cleared by a power-on reset.

The SDIWAKE bits are used to indicate that a “Status Change” event has occurred on the link, which usually indicates that either the codec has just come out of reset and is requesting an address, or that a codec is signaling a wake event.  The controller hardware will perform the resulting address cycle on the bus, and set this bit to inform the software that the event has occurred.  The setting of this bit may cause a processor interrupt to occur if the appropriate WAKEEN bits (Section 3.3.8) are set.


The node index (NID) is 0 for the root node, so you start with that set to zero and use it with verb F00h and paramater 04h to return the range of NIDs representing function groups. You then change the NID to that of a function group to ask it if it's an AFG (using F00h again but with parameter 05h), and once you've found the AFG group (the response will have the lowest byte = 1 for the AFG group) you can use parameter 04h with that NID to get it to return the range of NIDs that are HDA widgets. When interpreting the response for parameter 04h, the byte using bits 23-16 are the first NID in the range of relevant NIDs, and the byte using bits 7-0 holds the number of nodes (the range of relevant NIDs, including the first one). When you use this with the root node, you'll likely only find one group and it will be the AFG group. When you use it with the AFG group node, you should find a range covering two to three dozen widgets.

Thanks! Just one last question: is the interrupt for HDA always interrupt Bh, as my system indicates on the PCI bus for the interrupt line, which corresponds to interrupt 2Bh on my PIC (I haven't transitioned to using ACPI/APIC yet)? I ask this because I'm not really sure how to dynamically update my IDT. I was thinking about having a driver submit an add interrupt request to my interrupts handler subsystem, but I don't know if I can do that.

Author:  DavidCooper [ Fri Nov 01, 2019 1:33 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

I haven't attempted to use interrupts with HDA because there's so little to gain from doing so. If you want them though and are using the PIC, I think it's just a matter of changing the value in offset 3Ch in the HDA configuration space (its a four byte register, and you want to set bits 7-0). This is from the wiki's PCI page:-

Code:
Interrupt handling:-

If you're using the old PIC, your life is really easy. You have the Interrupt Line field of the header, which is read/write (you can change it's value!) and it says which interrupt will the PCI device fire when it needs attention.

If you plan to use the I/O APIC, your life will be a nightmare. You have 4 new IRQs called INTA#, INTB#, INTC# and INTD#. You can find which IRQ the device will use in the Interrupt Line field. In the ACPI AML Tables you will find (using ACPICA) that INTA# is connected to a specified interrupt line, INTB# to another, etc...

So far so good. You have, say, 20 devices. 10 of those are using INTA#, 5 for INTB#, 5 for INTC#, and none for INTD#. So when the IRQ number related to #INTC you have to scan the 5 devices to understand who was the interested one. So there is a LOT of IRQ sharing, expecially for INTA#.

With time manufacturers started to use mainly INTA#, forgetting the existence of other pins. So you will likely have 18 devices on INTA# and 2 on INTB#. Motherboard manufacturers decided take the situation in control. So at boot the INTx# are remapped, so that you will have 5 devices for INTA#, 5 for INTB#, 5 for INTC#, and 5 for INTD# (in the best case). That's great! IRQs are balanced and IRQ sharing is reduced. The only problem is that you don't know what devices where mapped. If you read the Interrupt Pin you still get INTA#. You now need to parse the MP Tables or the ACPI ones to solve the mess. Good luck.

Author:  Ethin [ Fri Nov 01, 2019 3:56 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

I don't mind asking my PIC timer interrupt to do all the handling and requests for polling to the HDA driver. That can easily be done. Thank you for all the help -- I'll try and implement what you said! :)

Author:  johnsa [ Mon Nov 04, 2019 8:17 am ]
Post subject:  Re: How to play sound Intel HD Audio?

Some more feedback on progress from my side with regards to the mac, the reason the DMA was still not running is that on these machines there is an IO-MMU. The IO-MMU had been configured by the firmware to remap DMA!
So the buffers I thought I was pointing my DMA at were in fact not in the right place. After writing a small io-mmu driver and switching off dma remapping, I now have pio and dma modes working on all machines.

Author:  DavidCooper [ Mon Nov 04, 2019 11:54 am ]
Post subject:  Re: How to play sound Intel HD Audio?

Well done. It's good to see perseverance rewarded. I admire your patience.

Page 4 of 4 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/