Rafał Miłecki ─ Zajec

Multichannel audio problem with AMD GPUs (over HDMI)

From time to time that question reappears: what about multichannel audio with AMD/ATI GPU? I wanted to share that short summary on the current state and the lacking parts.

First of all, alsa driver needs to know audio-related capabilites of a receiver. That includes supported formats, channels and frequencies, all of that is available in CEA extension of an EDID (CEA is just a part of EDID). The problem is that the EDID is received by GPU, and it is GPU driver that has access to it, not the audio one.

So how it's usually solved? It's handled with the special connection between GPU and audio. That way GPU driver can pass some data to the audio card and audio driver can read it. There are 2 important formats:
1) SAD (Short Audio Descriptor) is a 3 bytes struct used in CEA. It carries info about format, channels, frequencies and bitrate. CEA usually has many SAD blocks.
2) ELD (EDID-Like Data) is a bigger struct containing name, information about speakrs and SADs.

Usually GPU driver's role is to read EDID, extract audio related info from it, build ELD struct and write it to the GPU. Thanks to the GPU←→audio connection that becomes available for in the audio card. It's nicely implemented in i915: they read EDID, use drm_edid_to_eld to construct ELD, and write it to the GPU in intel_write_eld function.

In case of Radeon hardware it seems slightly different. Driver doesn't build ELD struct, but it just fills proper registers with SADs data (see AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0 up to AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13). It doesn't sound like a big difference, but it causes some implementation/RE problems actually. My first idea was that it's firmware that builds ELD from the passed values and audio driver can just reads the ELD in a standard way. Unfortunately it doesn't seem to be so easy. When using fglrx I can clearly see that the registers are correctly filled, but alsa driver still complains with all that:
ALSA hda_eld.c:337 HDMI: ELD buf size is 0, force 128
ALSA hda_eld.c:356 HDMI: invalid ELD data byte 0

As I don't suspect bugs in fglrx regarding that part of audio support, I believe we are doing something wrong in audio driver. As reading ELD in a standard way doesn't seem to work, I think we should look for something else. The problem is I'm not sure if AMD uses ELD format at all. I got an idea that maybe we should look for the SADs in a vendor-specific verbs (on the audio side). I've installed "hda-verb" and wrote a trivial PHP script to read all possible vendor-specific verbs (starting from 0xF70 to 0xFFF and params from 0 to 0xFFFF). Unfortunately I didn't get anything interesting.

I don't really have any other ideas how to read SADs/ELD in the audio driver at this point. Kind of workaround would be to pass that info in a software way (just export a simple function in the alsa driver). However I don't think this hack would be accepted in a kernel. So right now I'm out of ideas and until someone figures it out, we won't really have a multichannel audio support in the alsa driver :(

One more extra problem is that "radeon" driver currently doesn't fill that AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0 ... AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13 registers at all. It blocks multichannel audio support, however there is no rush in implementing this, as alsa driver can read that anyway.

I've mailed some summary to alsa-devel as well, to see if someone has any idea: hda: sink info in case of AMD Radeon GPU card (no ELD?)