Let's talk about one reason why Asahi Linux doesn't have DisplayPort Alt Mode support yet.
I just spent the past 2 days trying to get the Apple Type-C PHY to work properly in the various alternate modes, including DisplayPort and USB3 host and device.
It's a painful mess. If you touch one part of the code, another part of the code breaks.
Here's the thing: Linux likes to abstract out hardware interfaces. Sometimes this works well, with stuff like I²C and SPI controllers.
Sometimes this doesn't work well, like the Linux mailbox subsystem, which is a poor excuse for abstracting out the concept of a hardware mailbox. Hardware mailboxes are not standards like I²C and SPI, it's a vague concept of similarly-designed hardware. There is no "cross-compatibility" between mailbox "controllers" and consumers. The subsystem exists only because someone decided to abstract out some common code (like queuing and polling/waiting for completion), but got the approach all wrong. When you want to abstract out common code, you want to do it as pluggable functions. The DRM subsystem does this well with its multiple components. What mailbox did is try to define a common interface around the hardware, abstracting out all possible variations through one common interface. That doesn't work.
We tried using mailbox for Asahi Linux, and after a bunch of time wasted in attempts to hack on the code and mailing list reviews, we gave up. I made the executive decision to drop mailbox. We now have an internal interface for Apple mailboxes, which only have Apple-specific consumer drivers anyway. It works much better, is overall less code than trying to work around the impedance mismatches of the mailbox subsystem, is more maintainable, and won't break when someone else touches the common code.
The story now repeats, but it's much, much worse. The players are the Linux Type-C subsystem, the PHY subsystem, DRM, USB, and more. This time there are actually semi-common drivers like dwc3 (the driver for the DesignWare USB3 host/device controller that Apple licensed) and tipd (the driver for the Texas Instruments Type-C port controller that Apple modified and commissioned a variant of), plus our own display/DCP drivers and Apple Type-C PHY drivers.
And the challenge is getting all these drivers to work together and drive the hardware in the right sequence to work, including complex/sudden hotplug cycles, mode switches, data role changes, live changes between USB and USB3+DP mode, the list goes on.
Here's how I spent the past hour:
usb3phy->power_on()
, which is too early to know if we're device or host modeusb3phy->set_mode()
usb3phy->set_mode()
twice with different but equivalent arguments for some bizarre reasonusb3phy->set_mode()
happens too late, after host controller soft-reset, and that's too late to work well.usb3phy->power_on()
is too early to know the mode, we're screwedusb2phy->set_mode()
is early enough for some reasonSo now I have PIPEHANDLER setup (a USB3-relevant configuration) happening in the "USB2" PHY callback (which goes to the same shared Apple Type-C PHY driver anyway), just to make it work.
This is just the last debugging mess. It's all like this. Yesterday I found out a previous version of the code was only working due to a race between "mux configuration" and dwc3 initialization in a workqueue, synchronized by an accidentally load-bearing msleep(20) in dwc3. Yes, really. The fix for that is changing the tipd driver to do the mux set before setting up the Type-C data role (which is what triggers dwc3 init). tipd is its own hacky mess, since the hardware is too high-level for the Linux Type-C subsystem's design.
What makes this worse is that this setup is all reverse-engineered, so we have no documentation on what is supposed to work and what isn't. All we have is register traces from how macOS does it. But it's actually completely impractical to replicate them 1:1 in Linux, because the Linux cross-driver sync points are nowhere near enough for that. So we're left guessing and trying different interleaving orders and hoping that if something works, it's reliable, even though it's different to what macOS does.
(continued)
The Linux modular subsystem approach falls flat on its face here. The Type-C, USB, PHY, etc. drivers are too loosely coupled. Even if we get this to work, it's liable to break any time anyone changes common code and subtly changes the order of operations. It is not practically possible to build an overarching, top-down, abstracted environment for tying drivers together like this when the underlying hardware has much more tightly coupled requirements for how it is driven. And don't get me started on adding in PCIe into the mix once we need to get Thunderbolt to work...
The "PHY" concept is the most egregious offender. PHY hardware is as diverse as mailbox hardware, yet Linux thinks it's reasonable to abstract it behind a bunch of rigid operations like "init", "power_on", "set_mode", "set_media", "set_speed", "validate", "calibrate". Then you end up with unions like PHY configuration operations for MIPI DPHY, DP, LVDS, .... And all this starts becoming an intractable mess when you have stuff like a Type-C phy that talks USB2, USB3, DisplayPort, and Thunderbolt on one side, and has interfaces for a USB2+USB3 host/device controller (talking to the USB2 side and either nothing, the USB3 side, or a USB4 tunnel on its SuperSpeed side), a PCIe controller, and a bridge to a DisplayPort mux that then connects to an array of display controllers, and which has fun dependencies like having the USB3 controller hard-reset register as part of the PHY, and init sequences that are tightly coupled to how the other peripherals are driven, and if you get it wrong everything just breaks.
When there is no universal hardware spec for what interface a given type of PHY (never mind all types of PHYs) should have, in terms of operations and state machines, trying to abstract it out under such an interface in software is a path doomed to failure. It might work for simple PHYs for simple protocols of a decade or two ago, but vendors are shipping "do everything USB Type C can do including multiple protocols in parallel and tunneling all in one PHY" now and good luck with that.
What we really need is a bottom-up approach where a vendor-specific driver ties everything together. But Linux hates that approach with a passion, because it's what hacky vendor kernel forks do all the time. And yes, when done poorly, as they do, it sucks. But sometimes it's the only way to get anything sane. Linux does support this concept in at least some places: the ALSA ASoC subsystem supports machine drivers into which different codec/DMA/PCM drivers plug in, and that's how we tie together all the audio hardware for Asahi Linux.
But there's nothing like a "Type C top-level port management driver", nor are the underlying driver interfaces structured to allow this, nor fine-grained enough to compose properly. It would be a major new undertaking.
And then we come to the final problem: We don't have time to fight for a huge refactoring of kernel subsystems. If the kernel community were in general friendlier, discussion and patch submission weren't saddled with a ton of friction, etc., we could entertain the notion. But given past experiences with LKML threads... sorry, I'm not going there.
End result, this is highly annoying and demotivating to work on. That's why the person who started working on it mostly lost interest. Even the USB3 support we've shipped so far partially worked by accident (it has the 5-second delay bug and other issues), we just didn't dare touch it for fear of breaking it. And now we need to get all the other features to work without regressing anything.
Best I can hope right now is I make this barely work with the existing approach and a bunch of hacks, that upstream won't block any of it, and that nobody will touch the code and break it. Wish me luck.
And if you think you can help and are willing to fight the bureaucracy to make this less insane in Linux, please get in touch.
@marcan after reading Catherine's talks about thunderbolt I'm not surprised that displayport is also a mess of an interface to deal with. lol
@crobisaur It's not DisplayPort. It's USB3, DisplayPort, and Thunderbolt, all at once, in the same hardware driver.
@marcan friendship ended with everything is a file, only everything is a PHY matters now
@marcan Would a multi-function driver (drivers/mfd) help?
For a certain SoC our team are working on at Renesas there are muxes, common configuration registers and ordering dependencies between different Ethernet subsystems. This can be handled by an MFD driver which has functions that can be called by the subsystem-specific drivers.
@marcan Even the USB3 support we ship broke already at least twice due to upstream changes and we had to fix it.
@marcan the 5 second USB device enumeration delay exists in the current kernel and was as far as I’m aware always there
@janne Right, because it's always been broken. The new atcphy code fixes it and I'm trying not to break it again.
@pbarker As far as I know mfd is mostly just a convenient way to have subdevices. We actually already had a fight with that maintainer because the SMC driver we have is a good fit for that subsystem, but he kept saying it wasn't because SMC doesn't "look" like most register-based drivers and he didn't understand why it made sense to use it. Still haven't had a chance to refactor and resubmit all that into what we finally agreed on (after a long mailing list discussion and a further IRC discussion).
But I don't think it fits here since in this case it's not even register-based devices involved only (e.g. tipd is on an I²C bus). We can't realistically nest all the dependencies under a parent driver. In fact for stuff like DCP which is behind a mux, that doesn't work at all since the mapping isn't 1:1.
And then the issue is getting things like the existing dwc3 driver to talk to us the way we need. No matter how you organize the device tree, that's still going to be a point of contention because it's a shared driver used by many other systems with different requirements.
@marcan ah, I noticed yesterday with $SOME wip phy state that the 5s delay was still there. Good if it is fixed
@marcan I'm planning to share this on the Linux subreddit, but I'm struggling coming up with a good title. Would "Marcan's Rant on the Current State of Linux Type-C Subsystem" be an okay title?
@marcan just curious, is there a reason why you can't just throw xnu+kexts into the IDA woodchipper? i thought that if someone else did it, made documentation about what it does, and someone else implements, it would maintain clean room?
@cb This has nothing to do with the RE approach or clean room. You can't reverse engineer documentation for PHY hardware by decompiling drivers. The drivers themselves are just a bunch of magic register pokes.
We actually already have way more info than usual from the Apple drivers because they have surprisingly verbose debug logs, down to register and field names. There's nothing else to be gained by using a decompiler.
The hard part isn't figuring out what macOS does, it's 1) figuring out what the hardware actually requires, and what invariants have to be maintained, and 2) making it all work in the Linux model.
@curioustommy It's not really a rant about the Type C subsystem itself. The problem isn't one subsystem, it's getting multiple subsystems to work together in ways they weren't designed to.
Maybe "When simple Linux subsystems collide with complex hardware, nothing works"?
@marcan Kind of curious, how do other laptops' USB-C ports work on Linux?
@TellowKrinkle I'm not even sure if a full unified PHY for all protocols including USB4 like Apple's exists for any other vendor, and if it does (recent AMD stuff maybe?), it's all managed by firmware/ACPI and built to work with less tightly coupled drivers on the OS side.
Simpler implementations that just do USB3 and nothing else have the PHY managed by the xHCI controller and there is no mode switching or PHY driver. A basic DP/USB3 implementation as might exist in many non-Thunderbolt laptops and some recent embedded platforms would just use a dumb external mux to switch the data lines (which is what the simplistic Linux model is designed to work with, if it isn't just managed by ACPI). Again no PHY drivers, just a trivial mux driver. Intel Thunderbolt stuff is managed by external Thunderbolt controllers with piles of firmware and ACPI glue on the OS side, and again just looks like discrete controllers to the OS.
We are certainly the first platform trying to shove full OS-managed Type-C USB4 PHY support into Linux. Also I'm pretty sure Apple is the only vendor in existence that does full USB4+TBT3+DP+dual-role USB2/3 (including device role / gadget mode). Don't think any other laptop can do that (plug in a Mac into another non-TBT/USB4 host and the Mac enumerates as a SuperSpeed ethernet interface and exposes network services like SMB).
It doesn't help that Apple is using DesignWare USB3 controllers which are one of the worst in terms of quirks and hacks required. The list of special case hack toggles and properties in the devicetree bindings for dwc3 is ridiculous.
@marcan I'm sure this is pure naivety on my part, but is "embrace out of tree until they come to their senses" reasonable at this point? I know that's an easy way to piss off some maintainers, but I can't imagine the people who _would_ take offense haven't already over something else
@sawyerbergeron Major refactors are not viable out-of-tree. It would increase our rebase workload significantly. The only things viable to carry out-of-tree for longer periods of time are small fixes and whole new drivers, not major subsystem changes.
@marcan High level abstractions starting to leak -- nothing new there. Only few companies actually make drives for Linux (like Intel), so no wonder that you have a lot to improve and implement.
@spyke Yeah, because ~all the downstream embedded (non-x86) vendors suck and nobody else tries to upstream anything or attempt to engineer anything to be upstreamed...
@marcan oh yeah, I don't mean dragging the entire subsystem and all of the leaves along, I meant treating this all as one big driver and pulling in what you need from those subsystems. Guessing still too big a lift?
@sawyerbergeron I'm leaning towards that option if the current approach ends up completely nonviable, but it would still require at least a pretty horrible patchset to a few other drivers to make them play nicely. E.g. we will probably have to add some kind of ugly hooks to dwc3 so it can call into the PHY driver in more, fine-grained places. And also get rid of its workqueue nonsense for role-switch actions, since running stuff in other threads is a recipe for disaster. The only way this is going to work and be robust is if all the mode changes and init/shutdown logic runs within a single (logical) thread (per Type C port/controller). And then we need to do something about tipd, though I'm starting to lean towards "fork/rewrite it", given how much Apple's variant is already diverging from upstream tipd, and how the non-Apple tipd driver is very barebones and has no altmode support at all anyway.
But then the question remains, is this ever going to be upstreamable. Because if it isn't, we lose long term.
@crobisaur @marcan Where is that talk ? That sound's like something I'd be interested in watching.
@whitequark @wilson Would it be possible to write a rant about the subtly horrific things ?
@whitequark @wilson Do such NDAs have expiration dates ? Is this in the range of a few years, or decades ?
@marcan In my unhelpful opinion, this sounds like it needs a "usb-c port" driver of some sort which is (initially) implementation-specific and covers the coordination: modes, timing, coordination, etc. With all the existing drivers being cored out to become "dumb" hardware abstractions which just do their "one" thing only and tell this coordinator when things change. It sounds like the "design" of the current subsystem assumes that the "MUX" thing _is_ the coordinator which works for simple cases and everything else is ACPI or "invisible" firmware.
I've spent a long time thinking about how to build a "tiny" laptop thing with a USB-C port and every time I've tried to come up with a way to do something more complicated than a hardwired host or device port, I can't see any way to communicate which mode to use to the driver for the device-capable USB controller. This assumes I've got a separate microcontroller to manage the USB-C port and are limited to USB2 only.
@juliancalaby Right, the problem is the existing interface isn't even consistent, because it evolved from simpler hardware and is now a mess for more complex hardware.
There's a "USB Role Switch" interface which is part of the USB subsystem, and is called by both drivers in the "extcon" subsystem and the "usb/typec" subsystem. But that is just host/device, it doesn't cover any TypeC shenanigans (this started in the miniUSB/microUSB days). This is what actually triggers the USB controller to switch modes between host/device.
Then there is the TypeC mux interface, which is intended to just change modes for the TypeC pins. But it doesn't know anything about host/device roles, that is assumed to be independent.
Then there is the TypeC USB-PD stuff, which is intended to handle USB-PD interface details for chips which are basically USB-PD PHYs.
Then there's the reset subsystem, which provides out-of-band control over reset lines for peripherals.
And then there is the PHY interface, which just deals, in principle, with a single PHY for a single protocol in front of a single controller.
So this whole thing was designed for a system where you have discrete components:
USB/DP/etc controllers, which each interact (potentially) with their own PHY, completely under their control
A TypeC USB-PD PHY with the PD protocol managed in software
A dumb mux (and/or possibly retimer) chip to switch the data lines between backing PHYs
Some unrelated reset control, if necessary
And then the mess we have right now is:
The tipd driver handles the USB-PD controller chip, which is not just a PD PHY but actually autonomously does everything the TypeC subsystem wants to do manually, which doesn't work well with the subsystem. It also manages the retimer chips autonomously (but they are just retimers, not muxes). So it skips all those layers and calls into the mux and role switch layers directly.
The dwc3 driver handles the role switching and calls into the phy drivers for USB2/USB3, but only to an extent.
Our display controller driver delegates its stuff to DCP firmware, but DCP firmware calls back into the display controller driver for PHY management, so it has to forward that to the (DP) PHY subsystem.
Our atcphy driver tries to be all of a reset controller, all the PHYs, and USB-C mux, all at once, to tie everything together. But since the mux side doesn't know about host/device roles, and since the PHY side is split up into different logical PHYs, and since the order everything is called is not consistent, and since dwc3 insists on doing role switching in a workqueue asynchronously, and since it's actually tipd doing the calls to both the role switch and mux sides, it's a giant mess.
The ultimate problem here is there is a fixed hierarchy of calls. The design of the subsystems assumes the PD stuff will call into roleswitch and mux. But what we really need is a top-level management driver that just receives status notifications from the PD driver, and then drives the PHY config as needed, coordinating the roleswitch and DisplayPort HPD calls exactly when needed.
@marcan My perspective on this is mostly USB2, but the same problem exists there too: some drivers do everything in-house, some have external PHY drivers that do ... something maybe involving a MUX thing, etc.
IMHO you should go further than just a "top-level management" driver coordinating things for the PD device and build something more like a "port" driver: status flows up from every device (driver) involved and control flows down to the various components and _nothing_ does anything without the go-ahead of this driver.
The problem then becomes that this would probably require significant refactoring of just about every driver involved, and worse, would probably require coring out most of the "logic" from the dwc3 driver, which is probably just hacked together "port" drivers for other SoCs.
Sent an email to lkml & friends about this, but I'm not holding my breath that it's going to lead to a clear solution...
https://lore.kernel.org/lkml/fda8b831-1ffc-4087-8e7b-d97779b3ecc5@marcan.st/
@marcan just write the new subsystem in rust for more shits and giggels
@marcan not sure if the term "braindead" earns you any sympathies, if you aren't named Linus Torvalds
@marcan reading through the DP-parts of this, I feel the dread of the DRM interface again.
Ideally you could just assign any empty display controller (as long as they are available) to a new display on a type-c port and the compositor could figure out, that it needs to swap CRTCs to drive a high-spec display with an appropriate display controller.
But like with so many parts of the api there is absolutely no way to know, why something failed. So best a compositor could do is try every combination of CRTCs and connectors and see which one enables the most displays. Which might not even be, what the user wants.
(And yes, I know this completely ignores the problem of DRM expecting to be able to still read connector properties like the EDID, even when no controllers are still free...)
@drakulix @marcan for the probe issue the kms uapi solution for that is the "unknown" connector status. we've already had that for way back when CRT/VGA load testing required a real crtc, and if all where in use you couldn't probe the output
also as long as you still have a crtc you can steal during probe, we've fixed the locking so that you can do that properly. as long as there's still a free crtc you can steal
"unknown" will probably confuse most compositors to no end, but it's a thing
@drakulix @marcan for the issue of picking the right crtc it's either down to the kernel virtualizes them all, and picks the least capable one that works for an output at modeset time. or we add some max_clock property to crtc and offload this to userspace
combinatorial search doesn't work, because it doesn't scale once you apply this to all problems. we just had an irc chat on that for other reasons
@sima @marcan
> "unknown" will probably confuse most compositors to no end, but it's a thing
Which is the reason why asahi iirc doesn't even expose it's cursor plane, because those don't support overlapping with screen edges. And some (most?) compositor don't handle the resulting failed commit well...
Good to know there is a mechanism for this, but if that is documented somewhere, I have never seen it.
So just to be clear, if I see a connector with an "unknown" state during hotplug, I should make sure to force a probe? (Which would give the driver an opportunity to temporarily lock resources it needs to read out and cache properties?)
@drakulix @marcan it's more the other way round: a norma drmGetConnector forces a full probe, and if it's a platform that needs something really expensive then drmGetConnectorCurrent is maybe more what you want
so unless your hotplug handler uses drmGetConnectorCurrent you can't do more forcing
sysfs iirc is a bit different, and doesn't force by default because some old pm deamons abused that to no end
@sima Yeah I know. I am running into this problem a lot with bandwidth requirements, color formats and modifiers, ever since cosmic started to utilize overlay planes.
I've been meaning to write a blog post about this *some* day.
On the CRTCs I wouldn't mind either approach, but we should probably document what the compositors can expect here. I just recently stumbled upon a mutter issue, where apparently compositors are expected to just try other CRTCs, when the first compatible one didn't work, because i915 and xe don't fully virtualize and a pipe might be blocked due to bandwidth requirements...
@drakulix yeah that crtc virtualization discussing is exactly what came up again
and other drivers very much do virtualize, my personal take is that this is an i915/xe bug. but since there's no docs and no agreed upon contract that's not decided yet, perhaps those will start to materialize though
@sima I am not using libdrm. ;)
https://docs.rs/drm/latest/drm/control/trait.Device.html#method.get_connector
@drakulix yeah you might want to force probe again after you've disabled a crtc or connector, just to be sure
also the unknown status is documented, but only if you know where to look for it unfortuantely
https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#c.drm_connector_status
@sima @drakulix @marcan my plan was to map a free crtc/dcp in probe mode to the connector to read the EDID.
I don’t know if “unknown” is the correct state. We know via DP altmode that a display is there the driver just can’t provide any information. kms docs say connectors with “unknown” status shall be only light up when there’s no “connected” connector. That would need to be adjusted
@janne @drakulix @marcan unknown would only be for the case where you cannot get a free crtc/dcp to read out all the stuff. and with the fixed locking you should be able to race-free do this for all ports, as long as there's still one dcp available
if there's no dcp available then at that point userspace can't light up the thing anyway, so I think the semantics of "unknown" fit
@mxk The USB-IF's terrible standards have been inflicting pain on the embedded and OS community for over three decades, and I've been dealing with them with over 20 years of my own life. I consider them the single worst, most broadly negatively impactful offender on the mental health of systems developers and engineers all over the world.
There is no excuse for, in this decade, designing a level-shifted USB2 standard that has a state machine that can just wedge up if both sides fall out of sync with no possible recovery short of a full reset of both sides. That's just downright negligent.
I think these standards have earned having a few expletives thrown their way by now.
@marcan I think at least the phy subsystem authors would agree. From their docs:
"This framework will be of use only to devices that use external PHY (PHY functionality is not embedded within the controller)."
The intention of the phy layer seems to be a way to avoid code duplication where it makes sense but it not supposed to be home to absolutely all phy code. The trouble seems to come from other code that assumed otherwise.
@dvogel The problem is how you define "external". "External" can mean a physically external PHY chip, but it can also mean a discrete, separate silicon block (possibly designed by someone else) within the same chip, which is our case. You need *some* interface to handle that case generically (e.g. dwc3 is embedded into many SoCs with different PHYs). Perhaps the PHY subsystem wasn't designed with that in mind, but it definitely is being used for these cases now, just perhaps nothing as complex as ours yet.
@marcan @janne @sima I don’t think “no way to provide a good UX” is true here.
The driver *could* signal a hotplug with “unknown” state and user-space *should* then trigger a probe. Probes are allowed to flicker, so the driver is allowed to temporarily steal a dpc, read what it needs and cache the results. Then user-space could enumerate all connected displays but disallow enabling them all at once (which is already a thing).
Though I won’t argue with you on whether that is actually worth the effort. Given the low display count supported by the entry level devices, it would certainly be nice to have though.
@marcan @mxk The USB-IF has seriously screwed up both the spec and the branding of the standard. The other day, @dcavalca showed me a mainboard panel that had over a dozen USB ports, but no two ports had the same feature set or scope. It was mind-boggling and made me wish for the days before USB. At least then the ports were clear about what they were for...
Not happy with the pile-of-hacks approach, but it does seem to mostly work for now. I've concluded at this point that I'm going to fork tipd, since if we're putting critical hotplug sequencing behavior in there, I don't want to be coordinating with the non-Apple users of that driver (which use different, related chips anyway, and seem to be in use on vastly simpler platforms with no alt mode support at all). I'll just split it into common helpers and separate top-level drivers for cd321x and tps6598x. Besides, we need an entire new spmi backend for M3+ anyway.
Putting debouncing/event coalescing and asynchronous queuing into tipd, and getting rid of the dwc3 workqueue stuff in turn, seems to have fixed most of the hotplug horribleness.
I also had to make one single subsystem change, adding a data_role member to the TypeC mux config structure. That's arguably useful for "real" muxes anyway since you could hypothetically have to mux between a USB host controller and a USB device controller anyway (instead of them being combined). It's only implemented in tipd and atcphy, all other existing drivers ignore it. Hope upstream doesn't push back on this.
Still really not happy with how interdependent dwc3, tipd, and atcphy have become, but this is the only realistic way to move forward in the short term.
@Sobex Different interface, mostly the same chip otherwise.
https://en.wikipedia.org/wiki/System_Power_Management_Interface
TL;DR MIPI's proprietary version of I2C, because the MIPI Alliance is hellbent on replacing every basic digital interface with a proprietary members-only standard. They also have I3C, which is yet another thing which is only half-proprietary (a cut-down spec is public), because of course they do.
@alwayscurious @marcan well yes, but because rust currently depends on llvm this is sadly not that easy. There will for now always be platforms that Linux support but rust for Linux cannot yet. So drivers yes. Subsystems in rust, even though I would love it, are sadly rather a problem to not forget platforms
@alwayscurious @kloenk FWIW the only driver (not subsystem) involved in this stack that would arguably benefit from Rust is DCP and we do plan on rewriting that one in Rust in the near future. Everything else has minimal complexity of the kind that is likely to cause security issues and that Rust can help with (it has other kinds of complexity, though).
(That's not counting the generic xHCI driver and USB stack/subsystem, which damn well should be rewritten in Rust, but that's not a job we are signing up for.)
@marcan @alwayscurious I will try to help with the DCP stuff if I can
(currently writing abstractions for the LED subsystem (and a driver for a Lenovo hardware) in rust, and also got a Mac mini m4, and currently trying to figure out m1n1 on it, but not yet enough understanding to make myself known in the IRC)