Progress Report: Linux 7.0

After almost three years of 6.x series kernels, Linux 7.0 is finally here. That means it’s also time for another Asahi progress report!

Automate Everything

Users of alternate distros and keen-eyed individuals may have noticed some changes to the Asahi Installer. After almost two years, we finally got around to pushing an updated version of the installer to the CDN! Two years is a long time to go between updates, so what took so long?

Our upstream installer package is a little bit of a Rube-Goldberg machine. The bulk of the installer is written in Python, with some small Bash scripts to bootstrap it. When you run curl | sh, you’re actually downloading the boostrap script, which then fetches the actual installer bundle from our CDN. This bundle consists of a Python interpreter and very stripped down standard library, a built m1n1 stage 1 binary, and the installer itself.

Until recently, cutting an installer release meant:

  1. Tagging the installer repo
  2. Downloading a macOS Python build
  3. Building m1n1 from a blessed commit
  4. Bundling Python, m1n1 and the installer
  5. Uploading the installer bundle to the CDN
  6. Updating the CDN’s version flag file

This process was time-consuming and required administrative access to the CDN. As a result, we neglected to push installer updated for quite some time; the previous installer tag was from June 2024! As upstreaming work has progressed and Devicetree bindings churned, this became rather problematic for our friends maintaining distros.

The Asahi Installer offers a UEFI-only installation option. This option shrinks macOS and only installs what is necessary to boot a UEFI executable, meaning m1n1 stage 1, the Devicetrees, and U-Boot. This allows users to boot from live media with Asahi support, such as specialised Gentoo Asahi LiveCD images.

Since the Devicetrees on a fresh UEFI-only install come from the installer bundle itself, a kernel will only successfully boot when the installer-bundled Devicetrees match what that kernel expects to see. The two have gotten rather out of sync as time has gone on due to Devicetree bindings changing as a result of the upstreaming process. This situation finally came to a head with kernel 6.18, which required numerous changes to both m1n1 and the Devicetree bindings for the Apple USB subsystem. This made booting kernel 6.18 and above from live media impossible. Oops.

Rather than go through the trouble of manually pushing out another update, we took the opportunity to build some automation and solve this problem permanently.

We moved the manifest of installable images into the asahi-installer-data repo, allowing us to update it independently of the installer codebase. On top of this, we also now deploy the installer using GitHub workflows. Going forward, every push to the main branch of asahi-installer will automatically build the installer and upload it to https://alx.sh/dev. Every tag pushed to GitHub will do the same for https://alx.sh.

The latest version, 0.8.0, bumps the bundled m1n1 stage 1 binary to version 1.5.2, introduces installer support for the Mac Pro, and adds a firmware update mode which ties in nicely with…

How do you overengineer a light sensor?

Basically everything with a screen now comes with some sort of light sensor. This is usually to enable automatic brightness adjustment based on ambient conditions. It’s a very convenient feature in devices like smartphones, where a user may walk outside and find their display too dim to see. The cheapest versions of this use a simple photoresistor. This is fine if the goal is just to change brightness, but brightness is not the only thing affected by ambient lighting conditions. What about colour rendering?

Apple’s devices have had the True Tone display feature for quite some time. This works by measuring both the brightness and the colour characteristics of the environment’s ambient lighting. This data is then used to apply brightness and colour transformations to the display to ensure that it is always displaying content as accurately as possible. This is most noticeable in environments with lighting fixtures that have a low Colour Rendering Index, such as fluorescent tubes or cheap cool white LEDs. The devices that enable this, ambient light sensors, are usually little ICs that connect to the system over I2C or other industry-standard bus. This is fine for basic applications, but this is Apple. There are some other considerations to be had:

  • The light sensor is doing stuff whenever the screen is on, so processing its output should be as efficient as possible
  • The light sensor should be able to be calibrated for maximum accuracy
  • There are multiple models of light sensor in use, and the OS should not have to care too much about that
  • The light sensor has to have a three letter acronym like every other piece of hardware on this platform (ALS)

Naturally, this sounds like a job for the Always-On Processor1 (AOP)!

We’ve had a working AOP+ALS driver set for a while thanks to chaos_princess, however the raw data AOP reports back from ALS is rather inaccurate without calibration. That calibration is a binary blob that must be uploaded to the AOP at runtime. It is essentially firmware. Since we cannot redistribute Apple’s binaries, it must be retrieved from macOS at install time and then stored somewhere the driver knows to look for it.

To achieve this, the Asahi Installer gathers up all the firmware it knows we will need in Linux and stores it on the EFI System Partition it creates. A Dracut module then mounts this to a subdirectory of /lib/firmware/, where drivers can find it. However, issues arise when we need to retrieve more firmware from macOS after Asahi Linux has already been installed. To avoid a repeat of the webcam situation, where users were required to manually do surgery on their EFI System Partition, chaos_princess added the ability for the Asahi Installer to automatically update the firmware package. Starting with ALS, any required firmware updates will be a simple matter of booting into macOS or macOS Recovery, re-running the Asahi Installer, and following the prompts.

To enable ALS support (and to do firmware upgrades in the future), follow these steps:

  1. Ensure you are running version 6.19 or above of the Asahi kernel
  2. Ensure your distro ships iio-sensor-proxy as a dependency of your DE (Fedora Asahi Remix does this)
  3. Shut down your Mac
  4. Hold the power button until “Loading startup options” appears on the display for MacBooks, or for 5-7 seconds on the desktop machines
  5. Select Options from the Apple boot menu
  6. Log in with your macOS credentials, then do Command + Shift + T to open a terminal
  7. Invoke the Asahi Installer by running curl https://alx.sh | sh
  8. Choose the “Rebuild vendor firmware package” option when prompted
  9. Quit the installer and reboot once this is done

Solving the energy crisis

Idle energy consumption has been an ongoing issue, especially on devices with Pro/Max/Ultra SoCs. The power management architecture on this platform is incredibly complex, and there are a lot of moving parts involved in making it all work. There is Power Manager (PMGR), which is responsible for the SoC’s power domains, but there is also the Power Management Processor (PMP), which does… stuff?

The actual low-level details of how power is managed across the SoC are quite opaque. PMGR is responsible for powering SoC regions up or down and is runtime-configurable. This is necessary to power up parts of the SoC on boot, and to power them up or down on suspend and resume. PMP, however, has a more interesting job. Many SoC blocks communicate their power states to PMP directly in a region of shared memory. PMP also takes reports from the application cores when PMGR power domains are powered up or down. PMP will not read these reports if it is not booted, and certain power management functionality will not work. We are not sure exactly what it does with this information, but it likely involves controlling Apple Fabric power and clocking, among other things.

To support PMP, chaos_princess wrote drivers enabling it to accept reports from the SoC blocks and PMGR. This alone is enough to save around half a Watt on a 14" M1 Pro MacBook Pro when idle. That is around a 20% decrease in idle power consumption! There is obviously still work to be done to reach macOS levels of idle and suspend time, but this is a significant step forward.

Machines with the base M1 SoC have an older variant of PMP, which is not compatible with the variant found on the M1 Pro and later SoCs. dd-dreams is working on enabling PMP support on these machines, so stay tuned!

PMP support has not yet been validated on every machine we support, and we do not plan to ship it enabled by default until it is merged upstream. Users comfortable with making Devicetree changes may define APPLE_USE_PMP in their device’s Devicetree (e.g. t8112-j415.dts) to enable it.

Bluetooth fixes!

Bluetooth and WiFi have a long history of contention and interference. Both operate around the same 2.4 GHz frequencies and are typically both present in a given device. If not dealt with, this can cause packet loss and dropouts. There are a number of strategies to deal with this. In modern systems, WiFi and Bluetooth are typically integrated into the same controller. This allows the controller to monitor active 2.4 GHz WiFi and Bluetooth connections at the same time. By default, each connection is allocated a “fair” share of the available airtime, however this can cause issues when latency is important, or when some connections require minimal interruption. A connection that is actively streaming audio must be given priority over a keyboard, or a scan for 2.4 GHz WiFi broadcasts.

Unfortunately nothing is ever simple with Broadcom, and coexistence configuration is done using vendor-specific extensions to the Bluetooth Host Controller Interface (HCI). These were previously not supported in the upstream Linux kernel, causing our Bluetooth controllers to drop audio packets when, for example, KDE Connect would trigger a Bluetooth scan. chaos_princess recently added support for these commands to the kernel Bluetooth stack, and since BlueZ, the userspace Bluetooth daemon, marks all audio streams as high priority, these commands can be triggered whenever a connection is streaming audio. Bluetooth audio dropouts are now a thing of the past!

Hiding in plain sight

Our struggles with the display controller (DCP) have been well documented at this point. The firmware interface is enormous, unstable between versions, and frustratingly limited in weird ways that make no sense. Once we had enough of it working to get basic display support, attention turned to other pieces of hardware and no one really had the time to invest in further DCP work. It is still missing a bunch of features though, and one we constantly get questions about is Variable Refresh Rate (VRR).

VRR is a bit of a complicated thing to support. The display controller and display must communicate using special packets, which are different between HDMI and DisplayPort. The display controller must also be configured to “stretch” vertical blanking intervals based on the actual presentation of frames, not the set timing mode’s nominal refresh rate. The display must also advertise VRR as a capability, and this all needs to be wired up to the KMS API so that userspace knows about it.

DCP’s firmware interface is very layered. Like almost every other Apple coprocessor it runs RTKit, but sitting atop RTKit is the Endpoint Interface Client (EPIC). EPIC exposes “services” that each expose their own API surface, comprised of functions and callbacks. Each service also has “parameters” which are essentially a key-value store of knobs that control various runtime behaviours. These are changed by making a call to a “set parameter” API.

When initial DCP bringup work was being done, it was noticed that one such parameter was being set to 0 when a DCP was powered up for an external display. This was assumed to be part of some power on sequence. The Linux driver probe sequence was written to set this parameter on every power on accordingly.

While toggling VRR on and off during tracing, I noticed that same parameter being flipped between 0x300000 and 0x0. This was followed by a modeset, after which VRR would be either enabled or disabled. The display I was testing with has a minimum refresh rate of 48 Hz. In the fixed-point decimal format DCP uses to represent refresh rates, 48 is 0x300000. What if…

After hacking some code into the Linux DCP driver to set this parameter and trigger a modeset, I saw exactly what I wanted to see!

RTKit: syslog message: FramebufferDCP.cpp:5931: IOMFBParameter_adaptive_sync Req minRR = 0x300000, mediaTargetRate = 0x0, Fractional Rate = 0
...
RTKit: syslog message: PPipeDCP_H13P.cpp:12251: IOMFB: AdaptiveSync Range [48Hz, 165Hz]

The parameter we had been setting this entire time had nothing to do with power sequencing, it was the minimum refresh rate toggle for VRR. Setting it to 0 before a modeset simply tells DCP to disable VRR. Turning what is usually hundreds of lines of driver code into effectively two function calls is one benefit of having a firmware blob as enormous as DCP’s.

I also tested this on a MacBook Pro with a ProMotion display, and found that it is activated in the same way. This was surprising since MacBook internal displays do not advertise an EDID/DisplayID for DCP to parse, which is the normal way we retrieve and set the display’s VRR capabilities. While DCP’s firmware is not fully understood, we suspect that the laptop displays receive special treatment, and DCP simply knows how to drive them. To work around this, the Linux driver determines if the connected display is an internal MacBook Pro LCD and statically sets the necessary properties accordingly rather than trying to pull them from a nonexistent EDID.

Productionising all of this proved to be a bit of a challenge. Both VESA DisplayPort specification for Adaptive Sync, and the KMS API contract expressly forbid needing a modeset to transition between VRR states. Unfortunately for us, Apple either don’t care about the VESA spec or could not make DCP transition VRR states without a modeset. As such, we cannot expose VRR to userspace, and even if we did, compositors such as Kwin would simply ignore it as it requires a modeset. For now, users will be able to force VRR unconditionally on by setting the appledrm.force_vrr kernel module parameter once the pull request is merged. If your display supports VRR, DCP will enable and use it without telling KMS or the compositor. Kwin handles this fine, however your experience with other compositors may differ. Please do not raise bugs about this either with us or with your compositor’s developers as it is a hack that compositors are not required to tolerate gracefully.

However, that may soon change. The HDMI specification does not forbid modesetting between VRR transitions, and other display controllers (e.g. Intel’s) behave similarly to DCP in this regard. Discussions are ongoing upstream on how best to deal with this; either drivers will be expected to enable VRR modes unconditionally or modesetting between transitions will be allowed. Once the way forward is clear upstream, we will expose VRR in the expected way so that compositors can decide when to enable it.

More embedded audio quirks

Work is progressing on getting the entirety of the audio stack upstream. We have already merged changes to Cirrus Logic and Texas Instruments drivers for the headphone jack and speaker amp chips used on this platform, as well as drivers for the I2S peripheral and Apple DMA controller.

One of the things that makes this platform special is the way in which the speakers are prevented from destroying themselves. The Texas Instruments amps used by Apple can communicate the voltage and current across the connected speaker back to the SoC over I2S. These values can then be used along with a set of documented characteristics of the connected speaker (Thiele/Small Parameters) to work out the temperature of the voice coil at any given moment. On macOS, CoreAudio does this. On Linux, this is speakersafetyd’s job. No other desktop-class platform does this. This is usually either not done at all, handled entirely in hardware, or mostly hidden from the OS by Sound Open Firmware.

But that’s not all! Each amp chip’s data transmit pin is connected in series with other amps. All of the “left” speaker amps are grouped, and so too are the “right” amps. Each of these lines must be combined at the receiver into one data stream, so the lines are ORed. This only works if the amps on one side are guaranteed to be logic low when the other side is trying to transmit data. This is not uncommon, and the amp chips Apple use include bus keepers to assist with this. These are small circuits designed to guarantee that a bus will be in a specific state at any given time, usually tied to ground.

We originally had these configured entirely in the amp chip’s driver, with specific Devicetree bindings to specify the bus keeper configuration. This was too limited and inflexible for upstream, however. Instead, we created a generic API that allows any ASoC component to expose that it has a configurable bus keeper, allowing the consuming drivers (usually the “platform” driver, which ties all of the physical audio components into a coherent “sound card”) to configure the bus keeper as required at runtime. Bus keepers are not uncommon, and it is possible that this functionality will be useful on other embedded-style platforms. The patch set implementing this has been merged for 7.1.

Going beyond macOS

One of the challenges with bringing up a completely undocumented platform is that we have no frame of reference for the hardware’s capabilities. As far as we can possibly know, the hardware is capable of exactly what macOS does to it and nothing more. Almost all of our m1n1 and Linux driver code is based on observing the commands macOS sends to a given hardware block and effectively replaying them. But that is not always the case…

Apple are not afraid to use their buying power to get exactly what they want out of third party chip vendors. Followers of certain board-level repair and Right to Repair Internet personalities will be aware of how Apple gets CD321x series chips from Texas Instruments. These are incompatible variants of other TI USB-C mux chips with no publicly available datasheet, and sold exclusively to Apple in bulk. Apple has similar arrangements for the speaker amp chips they use, which are variants of TI’s TAS2764 and TAS2770. The same is true of CS42L84, an Apple-specific variant of the Cirrus Logic CS42L42 headphone jack chip. The vendors often won’t even acknowledge the existence of these variants. Connections to their publicly available counterparts can only be deduced through leaks and Internet sleuthing.

These variants are often similar enough to their publicly available counterparts that information on their datasheets and drivers can be useful reference material. Any incompatibilities are often limited to slightly different register layouts or discrete features that do not affect the rest of the chip’s operation. In the case of the TI speaker amps, we were able to add support for the Apple variants to the upstream TAS2764 and TAS2770 drivers with minimal fuss.

That said, it is always beneficial to begin by tracing macOS, and to treat those traces as the sole source of truth. CS42L84 ended up being different enough from CS42L42 that it requires its own Linux driver, which has since been upstreamed. As mentioned, this approach has the limitation of only allowing us to expose the functionality macOS makes use of. Since macOS only ever programs CS42L84 to operate at either 48 or 96 kHz, we could only add support for those two sample rates to the Linux driver. This is quite limiting, as it forces PipeWire to waste CPU cycles (and therefore battery life) on resampling audio streams that are not either 48 or 96 kHz. Doing so also degrades the quality of the audio. However, CS42L42 supports all the other common sample rates, and while the register layout and programming sequence is different, the actual values programmed in for 48 and 96 kHz are the same across both chips. What would happen if we simply took the values for all other sample rates from the CS42L42 datasheet and added those to the CS42L84 driver? As it turns out, you get support for those sample rates!

The patch to enable hardware support for 44.1, 88.2, 176.4 and 192 kHz sample rates on both the input and output of the headphone jack was submitted directly upstream, and has been merged for 7.1. We also backported this to Asahi kernel 6.19.9, allowing users to take advantage of this immediately.

More M3!

Also finding their way into the Asahi kernel tree are patches to enable more hardware on M3 machines. This includes support for PCIe, MacBook keyboards and trackpads support, the SMC-based RTC and reboot controller, and the NVMe controller, courtesy once again of Michael Reeves and Alyssa Milburn. This brings Linux support for the M3 up to roughly the same level as the first Asahi Linux alpha for M1!

While we aren’t quite ready to enable installation on M3 machines via the Asahi Installer, progress is being made. Stay tuned for more!

Fedora Asahi Remix 44

Despite the delays in getting Fedora Asahi Remix 43 to you all, we are still on track to release Fedora Asahi Remix 44 either on or within a few days of Fedora Linux 44 on 28 April! Going forward, new KDE Plasma based installs will take advantage of a number of new features that shipped with Plasma 6.6.

Plasma Setup replaces the previous Calamares-based setup wizard, providing a Plasma-native experience for user account creation and system setup. Additionally, Plasma Login Manager is now the default greeter and session manager, replacing SDDM. This applies to new installs only; users upgrading from previous versions of Fedora Asahi Remix will not have their configuration changed.

Fedora Asahi Remix 44 also retires our vendored Mesa and virglrenderer packages. Users who have not already manually done so will be automatically transitioned to the upstream Mesa and virglrenderer packages provided by the upstream Fedora repositories.

Until next time!

As always, we would like to extend our gratitude to everyone who continues to support our work on OpenCollective and GitHub Sponsors. We would also like to thank Bunny, who have supported us with free CDN and hosting services since the project’s first days.


  1. We cannot stress enough just how misleading this name is; the Processor is not Always-On ↩︎

James Calligeros · 2026-04-26