Jump to content

Fairphone 5 (fairphone-fp5)/Audio

From postmarketOS Wiki

Current status

Speaker output and microphone input is currently broken on Fairphone 5 (fairphone-fp5). This issue attempts to summarise the current state of progress, pull together necessary resources into one place and hopefully help people get involved more easily.

Currently, all relevant drivers for audio are in the mainline kernel. Each one of them is known to work on different hardware (and in different combinations), but the sound does not work on the FP5 yet.

Speaker playback through AW88261 causes a kernel crash. It is likely that the device tree is not entirely correct yet. It is also possible that the combination of needed drivers is triggering some new bug in one of the drivers.

Microphone input through the WCD9385 codec does not currently work (on any device, to my knowledge). WCD also handles analogue headphones, which does work.

What works

Bluetooth and USB-C audio work fine out of the box.

DP/HDMI sound output works fine but currently requires restarting pulseaudio after connecting the display (killall pulseaudio). After restarting pulseaudio, sound should be routed through HDMI/DP without problems. This appears to be a known wider problem (not device-specific).

Analogue headphones (though a USB adapter) can be made to work, but this is currently in a development branch and not in the main kernel package.

Hardware

FP5 uses Qualcomm QCM6490 SoC (yupik). This is closely related to SM7325 and SC7280 (see wiki entry linked below).

Sound is handled by two separate codec chips. The on-board Qualcomm WCD9385 handles the four microphones and the analogue headphones (through USB dongle). The speaker output is handled by the awinic AW88261 digital amp and codec.

AW88261 receives digital audio via the I2S bus, decodes it, amplifies it and drives the onboard speakers. WCD is not involved in this process. I2S can carry multiple signals (primary, secondary, etc.). On the FP5, the QCM6490 connects to the AW88261 via quinary I2S (see schematics below).

WCD9385 communicates to mics via SoundWire (AMIC1, AMIC3, AMIC4). It communicates with headphones (WCD_HPH) and AMIC2 via Type-C audio. There is also AUX, but I'm not sure if that's relevant for us, likely not a priority.

Qualcomm chips have a complex routing infrastructure that allows different parts of the SoC to communicate. This is handled by the mainline qcom drivers and (AFAIK) works fine.

Resources

Driver support

All relevant drivers are in mainline at the moment. QCM6490 is supported in Luca's sc7280 kernel fork (close to mainline). This includes all the complex code to enable audio routing inside the SoC. AW88261 has a mainline driver. This driver is thought to work because there are devices where this chip reported to work (xiaomi-pipa).

There is a downstream android driver for awinic sound chips. I have not experimented with this, but it was reported to not work reliably on mainline (very quiet sound) which could be due to differences between mainline and downstream qcom driver implementation. It is also hellish in terms of code quality and will probably never be mainlined. Because of this, most of the effort has gone into the existing mainline driver.

WCD9385 also has a mainline driver that reportedly works on other hardware.

Firmware

AW88261 requires firmware file aw882xx_acf.bin (MD5sum: 47e2e868a18b13bb3c43ab24ea4d7a4a). This can be extracted from the FP5 Android image and placed under /lib/firmware

In the longer term, we probably want to add this to the firmware-fairphone-fp5 package (any reason not to do this now?)

Relevant devices

  • Shiftphone 8 (shift-otter) uses the same SoC (QCM6490) but uses a different digital amp (no sound yet)
  • Nothing Phone 1 (nothing-spacewar) uses essentially the same SoC (SM7325-AE) but uses a different digital amp (Goodix TFA9873)
  • Xiaomi Pad 6 (xiaomi-pipa) uses a different SoC (SM8250-AC) but same digital amp (AW88261) and has working audio on mainline

In-kernel device tree

Device tree is a structured description of the hardware. It is used by the kernel to load and initialise drivers. It is a key part of embedded/ARM kernel development and can be very confusing to those of us coming from the x86 world.

The Fairphone 5 dts (device tree source) file contains most of the work needed to get sound working. It supplies information about connectivity, clocks, voltages, compatible drivers and similar detail that the kernel cannot discover on its own. FP5 device tree is defined in arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts and includes a lot of information from related files (especially the sc7280 SoC) which means it takes time to understand how everything fits together.

The relevant values for clocks and voltage regulators are mostly based on the reference SC7280 implementation and available schematics. Relevant sections for FP5 sound include (there are probably others):

  • sound: for specifying sound driver and how to route signals
  • wcd9385: for wcd-related voltages and pinctrls
  • i2c2: for aw88261 codec connections via i2c
  • q6afedai: for specifying registers corresponding to I2S, displayport etc.

Resources

Kernel WIP for AW88261

There are three branches I'm aware of that contain work in progress on AW88261 on FP5:

All of these branches are in a similar state as far as I'm aware. The relevant work is in the device tree: arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts. This makes it easy to port changes to later kernels, so working on older kernel versions is OK.

AW88261 starts up, a correct audio path can be set up (using amixer), but on attempting playback there is a crash (null dereference) in the kernel which (eventually) requires a reboot.

The crash does not happen in the AW88261 driver but the qcom driver. Interestingly, it appears to be related to Soundwire (which should not be used here, to my knowledge). I have done some debugging and could not find any null pointers being passed around but more investigation is needed. I suspect that something is not connected correctly (dts) so the driver gets invalid data.

Kernel sources have useful documentation:

  • Reference implementation (yupik): sc7280-idp.dtsi
  • QCom documentation: Documentation/devicetree/bindings/sound

Kernel WIP for WCD9385

I have done very little on this, but it probably makes sense to discuss WCD9385 in the same issue because it is possible that there are routing/qcom-related issues that affect all sound work.

There were timing issues reported when trying to mainline WCD9385 on the FP5, not sure whether this ever got resolved: https://patches.linaro.org/project/linux-arm-msm/patch/CXCXIAY8RBVK.2Y9W66THN9QH2@fairphone.com/

There has been progress on this on nothing-spacewar (closely related SoC, same WCD codec). I don't think mics work on spacewar yet, and once they do, FP5 will probably need changes (due to individual mic biases and how they connect). The relevant commits from Mar 25 are linked below, I can't find the original branch anymore to see whether there was follow-up work on this (it was probably removed at some point).

Resources

ALSA WIP

In order to test the sound, valid audio routes first need to be set. ALSA uses DAPM (dynamic audio power management) which is essential even if one is not interested in power management. This is because the kernel will only power up specific hardware (such as audio amp or speaker) if it is part of a valid audio path. Everything that is not part of a valid audio path (for example, headphone amp when headphones are not plugged in) is not powered up and will not produce sound. So to test whether sound works one will need to establish an audio path from a source to a sink (in this case it will terminate with AW88261 and then the speakers).

This is normally handled via UCM profiles. These will need to be set up once kernel stuff works. At the moment, there is a profile for DP/HDMI sound and nothing else.

In the meantime, one can establish routes manually using the amixer tool (see postmarketOS wiki linked below) in order to test if sound works. A valid route will be visible in several ways:

  • it should show up in pavucontrol
  • it can be plotted graphically
  • it can be inspected in /sys/kernel/debug/asoc

Resources

Some open questions

  • how to enable stereo on AW88261 (driver complains that the driver was already loaded)
  • is there a good overview of Qualcomm adsp stuff (afedai, asmdai, routing, etc.)?
  • correct mapping of amic ports to swr ports for mics over WCD9835

How to get involved

You will probably want to do this on edge (for envkernel support).

You'll need a kernel with a WIP device tree (envkernel is useful for this):

  • Clone a repository from one of the links above.
  • Use envkernel to create a build environment (source pmbootstrap/helpers/envkernel.sh)
  • Copy the sc7280 kernel config (config-postmarketos-qcom-sc7280.aarch64) from pmaports to arch/arm64/configs/sc7280_defconfig
  • Edit the config to make sure the AW88261 driver is built if needed (CONFIG_SND_SOC_AW88261=y)
  • Configure the kernel (make sc7280_defconfig)
  • Build the kernel (make)
  • Package the kernel (pmbootstrap build --envkernel linux-postmarketos-qcom-sc7280)
  • Install the kernel and reboot (pmbootstrap sideload --host myhost --user myuser linux-postmarketos-qcom-sc7280)

Check dmesg to see that aw88261 powers up correctly (my branch has debug output added in). You can easily restore the original kernel (apk upgrade -a)

Resources