Repository navigation
M6 audio: DART owned streams, ADMAC apertures, CIO reset, AOP audio and macaudio for the T8152 Mac mini - #359
Open
joshuaswarren wants to merge 32 commits into
Open
joshuaswarren wants to merge 32 commits into
joshuaswarren wants to merge 32 commits into
Conversation
The T8152 GPIO block has the same layout as the T8140 one. Match "apple,t8152-pinctrl" with the T8140 hardware data. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
T8152 has a SART with a new register layout: the per-entry config, physical address and size registers sit at 0x00, 0x60 and 0xc0. Add the operations for it and match "apple,t8152-sart". The binding lists the new compatible as a stand-alone entry. Measured on an M6 Mac mini with an earlier form of this change: the machine boots and runs its root file system from NVMe, which uses this SART. This version is compile-checked only. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
On T8152 the queue setup registers (admin queue, IO queues, the linear submission queue control) live at different offsets, and a few of them accept writes but read back zero. Add a register translation for that layout, skip the read-back checks that cannot work, and describe the controller with a new hardware data block matched by "apple,t8152-nvme-ans2". The ANS is a virtual PMGR device on this SoC and has no reset line, so the hardware data block carries a no_reset_control flag. Only T8152 skips the reset lookup. Every other SoC still requires a reset control and fails the probe without one, as before. The binding gets the new compatible. On T8152 the resets, power-domains and power-domain-names properties are not required, and the controller has two register regions (the NVMMU registers live in the first one). Measured on an M6 Mac mini with an earlier form of this change: the machine boots and runs its root file system from NVMe. This version is compile-checked only. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
On T8152 the ATC USB blocks (and the GPU) are behind a per-slot service request in the power state director, on top of the normal PMGR power states. Expose each slot, or a group of slots that must come up together, as a generic power domain. Power-on writes the slot request and waits for the acknowledge; power-off requests state 6 in reverse order. Add the devicetree binding. When a power-on request times out, the slot that timed out is put back to idle with the slots before it, because its acknowledge was not seen but it may still start. When a group power-off fails, every slot is put back to its active state, including a slot whose off request timed out and may still finish stopping, because genpd keeps the domain marked on after a failed power-off and would skip power_on at the next resume. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The fixed host ports on T8152 need only the USB2 part of the PHY. Add a driver that applies the bootloader-supplied calibration, handles host and device mode, and leaves the USB3 and USB4 lanes alone. Add the devicetree binding. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
A hub with the Apple ID 05ac:800f sits behind the front ports of the M6 Mac mini. Add that ID to the hub quirk table with HUB_QUIRK_DISABLE_AUTOSUSPEND so the kernel keeps it powered. The match is on the vendor and product ID alone. Every hub with this ID loses autosuspend, not only the one on this machine. The constant is named after the ID, USB_PRODUCT_APPLE_HUB_800F, because the ID is Apple's and the part behind it was not identified from the descriptor. This quirk was not measured on its own: it only keeps the hub awake. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Add a peripherals fragment to the M6 Mac mini board file: the always-on GPIO controller with the reset hog for the front-port USB hub, and the four PSD service slots for the USB ports. The NVMe controller, its mailbox and its address filter are not described here. The NVMe node needs a mailbox driver change that is not in this tree yet. The fragment holds only addresses, interrupt numbers and wiring. The boot loader adds the register tunables that some blocks need. The PMGR power domains are not described yet, so nodes that need them are left out. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Add the DART of the Apple M6 (T8152), a third-generation DART whose topology is fixed by the hardware. Its streams are described by static parameters instead of being probed, and it takes no MMIO access until the first use, because the block can be power gated behind the ATC USB domains. The binding requires a second register region (the TLB invalidate doorbell) for the T8152 compatible only. The change adds: - the apple,t8152-dart compatible and its hardware description; - static topology and "first use" initialisation of every DART; - the Gen3 TLB invalidate and the fault handler; - the reset path for DARTs that the boot loader leaves locked. A DART that the boot loader leaves locked is held powered for its lifetime. That applies to Gen3 hardware only. The other generations keep their behaviour. The first-use initialisation re-reads the parameters and fails if the page size differs from the one assumed at probe. It runs under a spinlock, and every function it calls is non-sleeping (register accesses and an atomic poll). Measured on an M6 Mac mini with the earlier form of this change: the display controller DART attaches locked on every boot. This version is rebased on current integration/aurora and was compile-checked only. The USB DART paths need the T8152 PSD power domains and were not run on their own. The doorbell store and the TLBI of the Gen3 invalidate are arm64 instructions: they are built only with CONFIG_ARM64, and other architectures (COMPILE_TEST) get a stub that returns -EOPNOTSUPP. A locked Gen3 DART no longer takes the range flush through TLB_CMD, which Gen3 does not accept; it uses the full-stream Gen3 callback. Gen3 does not take commands through TLB_CMD, so the unlock after a lock-on-error exception is not sent there: the DART logs once that this is not supported. The stale-exception drain of a reset does not read 0x704 on Gen3, like the fault handler. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Add the apple,t8152-dwc3 compatible to the Apple dwc3 glue. The ATC ports of the M6 (T8152) controller never switch roles through the Type-C controller. The glue starts the controller as a fixed host, with or without a hub child, or as a fixed peripheral when the node sets dr_mode = "peripheral". The T8152 profile is USB2 only: it needs maximum-speed = "high-speed", takes no reset line, and its USB3 PHY is optional. The calibration lists come from the device tree (apple,tunable-* properties that the boot loader fills in at runtime; the binding does not require them in the board file) and are applied to the register windows in a fixed order after the core is reset. The pipe handler is set up for the selected role. The apple,t8103-dwc3 paths keep their behaviour. The controller stays a syscore device while it runs, as before: no separate suspend or resume path is added for T8152. The earlier form of this change ran on an M6 Mac mini USB2 front port. This version is rebased on current integration/aurora and was compile-checked only. SuperSpeed does not train yet and is not part of this change. A fixed peripheral does not require the host-only calibration lists at probe, since it never applies them. The binding lists exactly four iommus entries, two stream IDs on each of two DARTs. If the T8152 USB2 PHY fails to initialise or power on during core start, the failure goes through the same shutdown as a failed core init, so the reset and syscore flags set earlier are cleared again. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Describe the power management blocks and the USB controllers of the Mac mini (M6, J873) next to the peripherals fragment: - the two PMGR blocks and their power domains, in t8152-j873-pmgr.dtsi; - for each of the four USB ports (usb0, usb1, usb2 and usb3 of the SoC): two DART instances, the USB2 PHY and the dwc3 controller. The register windows, interrupts and DART tunables are the values of the Apple device tree of the machine. The boot loader adds the apple,tunable-* lists of the USB2 PHY and the controller at runtime. The bindings list the apple,t8152-pmgr and apple,t8152-pmgr-pwrstate compatibles, and the dwc3 and USB2 PHY bindings take the tunable lists as optional, because the boot loader adds them. The fragment is a plain description of the hardware. The ports that the change describes run USB2 only: SuperSpeed and USB4 are not part of it. This commit compiles to a device tree blob with dtc without warnings. It was not booted. The bring-up it comes from enumerated the front-port USB2 hub and a USB disk at 480 Mb/s. The four PSD service slots get their PMGR domains (the aon and the port domain of their port) as parents, so genpd powers them before the slot request. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The T8152 audio ADMAC is the same evolved family as the T8140 one: the
vendor driver for it matches the evolved register map at every register we
compared and never writes the global 0x28/0x2c pair, so the new variant sets
evolved_layout and clears set_unk28.
On an M6 Mac mini the base-ns ADMAC binds and probes ("Audio DMA
Controller"). No data transfer is tested; the channel registers did not
answer a read-only probe made after boot.
Not needed for the release candidate.
Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Add apple,t8152-aop. Unlike T8140 it has no setup port: the CPU is started through the wrapper and RTKit boots on the primary mailbox, with three AFK endpoints (0x20 SPUApp, 0x21 wakehint, 0x22 aop-audio) announced with EPIC sub-header version 2. The binding requires two mailboxes for T8140 and allows exactly one for T8152. MEASURED on an M6 Mac mini, with an out-of-tree probe module: RTKit v12 boots on the primary mailbox without the setup port; all three services start; 25 of 25 EPIC calls with the version 2 header were answered; the speaker, codec-out and codec-in devices attach and report power state idle. NOT measured: audio data transfer, the hpai/lpai/tap devices (they return an error on this machine). BLOCKED: this patch alone does not play audio, see the audio driver patch. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The T8152 SBR DART serves the audio DMA controllers together with firmware and coprocessor streams (AOP, MTP) in one instance, and the bootloader leaves its streams translating with page-table roots that hold firmware mappings although its lock bit is clear. Resetting it as a whole would break the firmware streams. apple,inherited-roots makes the driver treat such a DART as locked: it is never reset, TCR and TTBR are never written, and consumers publish into the vacant slots of the inherited roots, the path already used for locked DARTs. apple,owned-streams lists the streams that belong to Linux: consumer iommus entries naming another stream are refused, latched exceptions of other streams are not acknowledged, and the DART tunables are left as firmware set them. The interrupt handler applies the same filter as the probe-time drain: the pending word is masked with the owned streams before the faults are reported and before it is written back, so the exceptions of the streams firmware owns are neither logged as faults nor acknowledged. If such a stream raises an exception that stays latched, the shared interrupt line stays asserted; no foreign exception was seen on the M6 (the error registers were zero in every run). MEASURED on an M6 Mac mini with an earlier form of this change (separate compatibles instead of properties, on an older base): the shared DART probes without a reset, the AOP firmware boots, the audio DMA channels move data through it (the jack stream in real time at 48 kHz, the speaker stream in real time as mono at 48 kHz) and the error registers stay zero. NOT measured: this exact form on the current base, an exception raised by a firmware-owned stream. BLOCKED: nothing for the DART itself; the SBR DART device-tree node comes with the audio layer. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The T8152 audio DMA controller has no channel control blocks at 0x8000 and 0xc000 as the t8140 one does: a read there ends in a synchronous external abort, and the first write to such a block hangs the machine with an asynchronous SError. Instead every channel has its own 16 KiB aperture, the TX channels from 0x40000 and the RX channels from 0x80000, at a 0x4000 stride. Add a per-variant flag for that layout and use it for the T8152 variant; the descriptor FIFO ports (0x10000 for TX, 0x14000 for RX) and the global registers stay where they are. MEASURED on an M6 Mac mini with /dev/mem reads after the first power request to an AOP audio service: the global registers (+0x0, +0x94), the FIFO port pages (0x10000, 0x14000) and 13 apertures each at 0x40000 and 0x80000 (stride 0x4000, 13 being the channel count of the instance) answer; 0x8000, 0xc000 and 0x74000 abort. Writes of the bus width, SRAM carveout, FIFO control and interrupt mask registers at the start of an aperture read back correctly. The TX/RX assignment of the two halves comes from the vendor driver's descriptor and aperture code (TX channel n at 0x40000 + n * 0x4000); with the opposite assignment the channel starts but never takes a descriptor (ring register stays empty, no transfer). MEASURED with this layout: TX channel 5 (headphone jack) and TX channel 1 (speaker) accept their descriptors, the ring registers and residue move, a report with a 24 MHz timestamp arrives for every completed descriptor and the interrupt fires; the jack stream consumes data in real time at 48 kHz. NOT measured: that the samples reach the codec (nothing was listened to). BLOCKED: audio output also needs the AOP audio driver changes. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The M6 (T8152) CIO reconfigure is a request/done register pair in the PMGR block: BIT(cluster) is written to the request register, BIT(cluster) is polled in the done register (the vendor driver allows 10 s), and the done bit is cleared by writing it back. The node is a sub-node of the PMGR syscon whose reg is the offset of the request register; the reset id is the CIO cluster (0..3, the cio-cluster property of the PMGR child). The sequence follows the vendor power-management driver for this SoC. NOT measured: no M6 boot has exercised this driver yet. Compile status: see the pull request. BLOCKED: the controller node and the reset consumers (ACIO) live in the Thunderbolt/USB4 device-tree layers. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
On T8152 (J873) the AOP audio service has only the speaker, jack output and jack input devices: lpai, hpai and the speaker tap answer kIOReturnNoDevice. There is no lpai microphone to raise the gated audio fabric with, no source ring, and no AP-powered serializer leaves (the audio PMGR leaves are virtual; the firmware powers them). Match data now says whether the machine has lpai: apple,t8140-aop-audio keeps everything as it was, apple,t8152-aop-audio skips the lpai/hpai attach, the source ring, the raw sound card with its two capture PCMs, the power-domain attach and the fabric raise, and treats the tap service as absent. The speaker mute property is not requested (the firmware answers every property above 302 with 0xe00002f0, unsupported; the amplifier is muted through its own codec), the speaker front-end and back-end accept one or two channels, and the properties 200/300/301/302 of a service are logged at debug level after pw0 and pwrd, so that the stream format can be read from the log. MEASURED on an M6 Mac mini: the AOP boots, the audio service has speaker, jack output and jack input devices and no lpai/hpai/tap (kIOReturnNoDevice); the audio fabric answers after the first power request of any service; with the T8152 ADMAC apertures the jack stream (S24, 48 kHz stereo) is consumed in real time (a DMA report every 125.00 ms for 48000-byte periods); the speaker stream drains at half the frame rate in stereo and at 48 kHz in mono (24000-byte periods, one report per 124.67 ms), no hang, no DART fault; the speaker amplifier logs 'bad TDM clock' once at stream start and not again while streaming. NOT measured: sound reaching the jack codec/headset or the speaker (the speaker volume stays locked at the lowest step and no speaker-safety profile exists), capture paths, suspend/resume. BLOCKED: the amplifier unlock needs a speaker-safety profile. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
AOP-fed like the J700, with the J873's SN012776 speaker amplifier; the
speakers stay disabled until the speaker path is verified on hardware,
the jack comes first. The front-end DAI names are those of the AOP audio
component.
In the single-woofer control fixup, the J873's amplifier controls are
looked up with the amp node's sound-name-prefix ("Speaker ") instead of
the empty prefix: with the empty prefix the lookup of 'Amp Gain Volume'
fails with -EINVAL, and "* " would match the cs42l84 jack codec instead.
No other model's prefix changes.
MEASURED on an M6 Mac mini: the AOP boots, the audio service has
speaker, jack output and jack input devices and no lpai/hpai/tap
(kIOReturnNoDevice); the audio fabric answers after the first power
request of any service; with the T8152 ADMAC apertures the jack stream
(S24, 48 kHz stereo) is consumed in real time (a DMA report every 125.00
ms for 48000-byte periods); the speaker stream drains at half the frame
rate in stereo and at 48 kHz in mono (24000-byte periods, one report per
124.67 ms), no hang, no DART fault; the speaker amplifier logs 'bad TDM
clock' once at stream start and not again while streaming. NOT measured:
sound reaching the jack codec/headset or the speaker (the speaker volume
stays locked at the lowest step and no speaker-safety profile exists),
capture paths, suspend/resume. BLOCKED: the amplifier unlock needs a
speaker-safety profile.
Not needed for the release candidate.
Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
apple,t8152-acio-mailbox has a different register interface than the ASC mailboxes: the status word at +0x20 holds the receive occupancy in bits 3:0 and the number of free transmit slots in bits 11:8, the receive FIFO is at +0, the transmit FIFO at +0x10, and each 128-bit message is moved with one paired 64-bit access. Reading or writing the classic ASC offsets (control at +0x110, send at +0x800, receive at +0x830) from this window would touch unrelated registers of the wrapper block. Add a counted_fifo flag to the hardware table, test "transmit full" and "receive empty" through two helpers that honour it, and move the message read and write into helpers that use one load or store pair for the counted layout (arm64 only; the entry is refused elsewhere). Every other hardware table keeps its flags unchanged and its two separate 64-bit accesses. Measured here: arm64 compile. Run on hardware in an older tree: this layout and the paired access carried the RTKit boot of the ACIO co-processor. Not measured: this patch on this base, the send-empty interrupt path of this mailbox. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The always-on processor of the T8152 uses the same counted-FIFO post office window as the ACIO co-processor (receive at +0, transmit at +0x10, status at +0x20 with the receive occupancy and the free transmit slots), as a plain 0x80-byte window without wrapper registers. Match it with the existing hardware description under its own compatible and describe it in the binding: two interrupts, send-empty and recv-not-empty, no IOMMU and no DMA range of its own. MEASURED on an M6 Mac mini: the AOP firmware boots through this mailbox (RTKit protocol version 12 handshake, endpoints discovered, 25 of 25 EPIC calls answered, hours of audio-service use without a message error). NOT measured: sleep. BLOCKED: needs the counted-FIFO mailbox commit it builds on. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The codec is a DAI provider and sits on a machine driver's sound card where its controls are named with a prefix (sound-name-prefix), as for the speaker amplifier binding. Reference dai-common.yaml and evaluate the remaining properties through it. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Add the two audio codecs of the Mac mini on their I2C buses: the cs42l84 jack codec at 0x4b on i2c1 and the SN012776 speaker amplifier at 0x38 on i2c3, with the controllers' power slots, the 24 MHz reference clock and the SIO pinctrl the codecs' reset and interrupt lines need. This is probe wiring only: the codecs' audio path is the AOP, described by a separate change. MEASURED on an M6 Mac mini with this device tree: i2c1 0x4b binds cs42l84 and i2c3 0x38 binds the SN012776 amplifier (tas2764 driver), both through the I2C controller behind its power slot. NOT measured: the polarity encoding of the reset GPIO flags (taken from the ADT, not verified electrically) and sound. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The T8152 always-on processor is not behind a power domain: every PMGR device of the AOP block and of the audio block is firmware-managed and has no power state register of its own. Require power-domains only for the T8140 and forbid it for the T8152. MEASURED on an M6 Mac mini: the AOP firmware boots and serves audio with an AOP node that has no power domain. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
Describe the audio path of the Mac mini: the SBR DART shared with firmware (inherited roots, owned streams 0, 1, 40 and 42), the two non-secure audio DMA controllers, the AOP mailbox, the AOP with its audio service (speaker, jack output and jack input, no power domains since all audio PMGR devices are firmware-managed) and the sound card with the headphone jack and speaker links. The card driver keeps the speaker disabled until a speaker-safety profile exists. MEASURED on an M6 Mac mini with this device tree (the DART described by separate compatibles and driver changes of an earlier form of the series): the AOP boots and its audio service attaches the speaker, jack output and jack input devices, the SBR DART is used without a reset, the audio DMA channels run (the jack stream in real time at 48 kHz, the speaker stream in real time as mono at 48 kHz), the jack codec and the speaker amplifier probe on their I2C buses. NOT measured: this exact form with the DART properties, sound at the headset or speaker, capture, suspend. BLOCKED: needs the T8152 DART, ADMAC, mailbox, AOP, audio component and macaudio driver changes of the same series. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
…model The T8152 AOP offers no speaker tap, so the speaker-protection daemon that reads the amplifier's current and voltage sense cannot run on the Mac mini. The vendor protects this speaker with a thermal model driven by the signal alone; do the same in the speaker copy path, where no stream can bypass it. Every word, after the playback volume, goes through a fixed-point version of the vendor's model: the power (x * 11.9 V)^2 / 4.6 ohm heats the magnet (60 C/W, 210 s) towards ambient (50 C) and the coil (40 C/W, 3.4 s) towards the magnet, the two filters of the daemon's own model. The gain falls over the last 20 C below the 140 C limit to the level at which a full-scale square wave dissipates 98 % of the sustainable (140 - 50) / (40 + 60) = 0.9 W, which is -15.43 dB. The attack is immediate (one block of 128 words) and the release takes 20 s; the model assumes the amplifier at the vendor's 11.9 V per full scale whatever its gain setting. The speaker cools by the idle time between streams. A hard amplitude ceiling 20 dB below the sustained level (about 9 mW worst case) is built in for the first audible tests and is removed by a rebuild only. MEASURED on the host: the integer model against the closed-form step response of the two filters, a full-scale sine, square, noise and DC step from four starting temperatures stay below 140 C, ten minutes of a full-scale square wave settle at the sustained level with an equilibrium temperature of 139.9 C, the release and the idle cooling follow the model, and the kernel arithmetic (as a plain Rust test crate with overflow checks) reproduces the host model bit for bit. NOT measured: the real speaker (the vendor's resistance, thermal resistances and time constants are used as they are, the amplifier output voltage per full scale is not measured), anything audible on the machine, and the kernel build of this change. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The speaker copy path converts every sample to a float32 bit pattern, the word format the T8140 speaker DSP consumes. The T8152 has no LPAI: the AOP link hands the words to the amplifier unchanged, so the amplifier played float bit patterns as 32-bit integers. On the T8152, write the limited sample as a signed 32-bit integer instead. The T8140 path is unchanged. MEASURED: with the float words, a 440 Hz tone gave a steady 2.6 s sound whose strongest component was 880 Hz, at the same level for two volume steps 10 dB apart (room microphone, 12 to 18 inches). NOT measured: the sound with this change, and the amplifier output voltage per full scale. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The default serial link format of this card is I2S with an inverted bit clock, which makes the tas2764 driver program its receiver to sample on the falling edge. The SN012776 amplifier on the J873 does not take the AOP's speaker stream that way: it reports a bad TDM clock and stays in software shutdown. Add a platform configuration field for the DAI format of the speaker amplifier's link only and set it for the J873 to the default format with the clock polarity changed (rising RX edge, frame polarity as before). The headphone link and every other machine keep the default format. MEASURED: with the falling edge the amplifier status stays at software shutdown for a 440 Hz tone, and the room microphone (12 to 18 inches) hears nothing. Writing only the receiver edge bit of the amplifier's first TDM register to the rising value, and nothing else, puts it in the active state and the tone is heard 49 dB above the room at 440 Hz; the other four registers tried alone do not. With this change and no register writes from user space, the quietest volume step is 39 dB above the room with harmonics below -29 dB relative to the fundamental, and the step 10 dB up is 7 dB louder with harmonics below -21 dB. NOT measured: the absolute sound level, the amplifier output voltage, the loudest volume step (distorted, unexplained), the "bad TDM clock" report that still appears once when a stream starts. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The amplifier on the T8152 takes the samples in the low 24 bits of each 32-bit word of the AOP link: a word beyond 2^23 wraps. The thermal limiter works in units of a 2^30 full scale and the copy path wrote its words unscaled, so the amplifier saw every word 128 times (42 dB) larger than the limiter's model, and a word at the limiter's ceiling was already past the amplifier's full scale. Write the limited word shifted down by seven bits, so that the limiter's full scale is the amplifier's. MEASURED: with the unscaled words, a 440 Hz tone followed the word peak for peaks of 3.0e6, 5.0e6, 7.0e6 and 8.0e6 (30.9, 35.3, 38.3 and 39.7 dB above the room, third harmonic below -38 dB relative to the tone), and at 8.8e6, 9.6e6 and 1.1e7 the tone fell by 10 dB and more with the third harmonic at -4, +6 and -6 dB, the signature of a wrap at 2^23 = 8388608 (room microphone, 12 to 18 inches). NOT measured: the sound with this change, the absolute level, the amplifier output voltage. This does not enable the speaker: it stays disabled in the J873 configuration. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The speaker limiter models the power of the speaker, not its cone excursion, which for the same voltage is largest at low frequencies, where the speaker radiates least. Filter the words of the T8152 speaker path with a fixed second-order Butterworth high-pass at 100 Hz (integer, direct form I, Q28 coefficients, 64-bit state), before the limiter, and hold its output to the input's full scale (a step through a high-pass overshoots by up to twice its size), so that the ceiling stays a peak ceiling. The unit tests of the module run the filter on integer sines: the gain at 50, 100, 200 and 440 Hz is 0.2425, 0.7071, 0.9701 and 0.9987 (the ideal Butterworth values, within 0.01), and a constant input is blocked. MEASURED (room microphone, 12 to 18 inches): with the filter in the path and the speaker ceiling of the next commit, a 440 Hz tone is within 1.2 dB of its level without the filter (the repeatability of the setup is 1.9 dB) with its second to fourth harmonics at -33 dB or lower relative to the tone, a 200 Hz tone is within 0.4 dB, and the limiter's gain is unchanged. NOT measured: the attenuation of the filter on the machine (100 and 60 Hz were not played, the speaker's cone excursion is not measured), the absolute level. This does not enable the speaker: it stays disabled in the J873 configuration. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The first audible tests ran with the ceiling 20 dB below the speaker's sustained level (4 mW at the amplifier, by the limiter's model). Raise it to 0.078 of full scale: 0.93 V peak and about 94 mW for a sine at an amplifier gain of 15, by the model. A full-scale square wave at this ceiling is 0.19 W against the model's sustained 0.9 W, so the thermal gain never moves and the ceiling is a pure peak limit; a unit test checks that. The level is set from a measurement, not from the model: 6 dB below the level at which the vendor's own driver plays a 440 Hz tone at its maximum volume, settled over 20 s, measured with one microphone at one place. MEASURED (room microphone, 12 to 18 inches, a 440 Hz tone): the vendor's driver at maximum volume is 5.4 dB louder in power than this ceiling (its tone file was 1 dB lower in level than ours; two measurements of the vendor's maximum, taken hours apart, differ by 1.9 dB). 20 s of the tone at this ceiling are steady to 0.1 dB after the first 2 s. Tones of 440, 1000, 2000 and 4000 Hz at the ceiling have their second to fourth harmonics at -34 dB or lower relative to the tone; a 200 Hz tone is detected but its harmonics are below the room noise. NOT measured: the absolute level, the amplifier output voltage, the speaker's cone excursion, content other than tones and one noise burst (the noise burst is 11.9 dB quieter than the vendor's driver at maximum volume). This does not enable the speaker: it stays disabled in the J873 configuration. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The speaker of the J873 was left disabled until its path was verified on hardware. It now plays: the amplifier takes the serial data on the rising bit-clock edge, the words are scaled to its 24 bits, and the speaker path has a ceiling set against the vendor's own maximum volume, a fixed 100 Hz high-pass and a thermal model of the speaker. The speaker is protected by that limiter, not by a user-space daemon (the machine offers no sense stream for one): set safe_vol to 0, so the volume lock for such a daemon is not created and the amplifier's volume is not held at its lowest step. MEASURED (room microphone, 12 to 18 inches): tones of 200 Hz and of 440 to 4000 Hz play at the ceiling with the second to fourth harmonics of the 440 to 4000 Hz tones at -33 dB or lower relative to the tone; a 20 s tone at the ceiling is steady to 0.1 dB; the ceiling is 5.4 dB below the vendor's own driver at its maximum volume for a 440 Hz tone and 11.9 dB below it for a noise burst. NOT measured: the absolute level, the amplifier output voltage, the speaker's cone excursion at low frequencies (nothing below 200 Hz was played at the ceiling), music. The amplifier reports a bad TDM clock once at the start of each stream and plays on; that is not understood further. Not needed for the release candidate. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
The io.h dwc3_readl()/dwc3_writel() helpers reference the dwc3 tracepoints, which the dwc3 core module never exports, so dwc3-apple.ko failed MODPOST in the omarchy-pkgs package build: ERROR: modpost: "__tracepoint_dwc3_readl" [drivers/usb/dwc3/dwc3-apple.ko] undefined! Read and write the 0xc680 window with plain readl()/writel() on the core mapping, like the raw pipe-handler access in the same function. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
dwc3_apple_core_start() and dwc3_usb_role_switch_set() now reference the T8152_PIPE_* defines and the t8152_usb2, fixed_peripheral and tunable_regs members, so the dwc3-teardown host unit stopped compiling (TAP case 31, 'not ok 31 - dwc3-teardown' in CI). Mirror the defines and extend the fixture struct; the new fields stay false, leaving fixture behavior unchanged. The dwc3-teardown unit compiles and passes with cc -fsanitize=address,undefined on the host. Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com>
joshuaswarren
requested review from
chriskearney,
maralcbr and
scottjones
as code owners
November 4, 2026 23:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #201 to add the missing Signed-off-by trailers.
Summary
The audio side of the Apple M6 (T8152) Mac mini after the plumbing of #194: the DART owned-streams change, the per-channel ADMAC apertures, the CIO reset driver, the AOP audio driver variant and the macaudio card for the J873, the mailbox support the AOP and ACIO need, and the device-tree nodes. Twelve commits.
This series now enables the internal speaker on the J873 (commit 30). It stays a draft until the review of commit 30 is done. The T8152 speaker link carries 24-bit samples, and the earlier limiter and integer output commits assumed 2^30. Commit 27 fixes the scale. Commits 28 and 29 add a 100 Hz high-pass and a measured ceiling. The messages of the limiter commit (43f2664) and the plain-PCM commit (68c6401) still carry the old 2^30 wording. The scale commit says so. Before this PR is merged, ask the maintainers to squash, or rewrite those messages.
Commit 30 sets
enable_speakers = trueandsafe_vol = 0inmacaudio_j873_cfg. Before it, the speaker link was skipped unless theplease_blow_up_my_speakersmodule parameter was set.The first twelve commits of this branch are #191 (the M6 base) and #194 (audio plumbing). Only the last seventeen are new here: the diff of this PR shows the other twelve too until they merge, then I rebase. Review the last seventeen.
It is not needed for the release candidate, and there is no rush to review or merge it. Sound does not reach a codec or speaker from this branch yet (see Blocked).
Commits
Speakerprefix for the mono amplifier; speakers stay disabled in the configurationapple,t8152-acio-mailboxbinding text is only in #197, so this layer needs #197 first for that compatible; the second copy of the driver patch becomes empty when both landapple,t8152-ascwrap-v8-mailboxon the same hardware datasound-name-prefixCEILING_Q30= 83,800,000 with its measured basisenable_speakers = true,safe_vol = 0, comments updatedMeasured, on an M6 Mac mini (out-of-tree builds of the same changes, before this series was rebased)
aplay -c 1on the speaker PCM was refused before the back-end change and played after it.power-domains.Speaker series (commits 27 to 30), measured on the M6 (25 Oct)
MEASURED:
NOT measured:
Limits of the run: there was no earlier multi-frequency reference, and a dead band is excluded only at the four tones tested.
Not measured
Blocked
Compile and check receipt
arm64 clang,
W=1,CONFIG_RUST=y, 16K pages,integration/auroraat 00e601f plus the 26 commits of this branch:iommu/apple-dart.o,dma/apple-admac.o,reset/reset-apple-cio.o,soc/apple/aop.o,soc/apple/mailbox.o,apple/t8152-j873g.dtb,sound/soc/apple/t8140_aop_audio.oandsound/soc/apple/macaudio.oall rc 0 with 0 warnings; the only warning in the Rust build is an unused method inrust/kernel/dma_fence.rs, which these commits do not touch.dtcheck(dtschema 2026.9): the board file gives 0 messages; the 72 binding examples give only the existingapple,dcp-typec-routesmessage.Known edges
apple,inherited-rootsandapple,owned-streamsare meant for the T8152 DART only; the schema does not enforce it.Review
Two independent reviews, both GREEN on the first eleven commits at
4b2beadf5d49b05a6d2ef8b704d4f1c4bf12815e, and both GREEN on the twelfth (the limiter) at43f266453804e1843362c697c2dc4cec5ee09e5b, both GREEN on the thirteenth (T8152 speaker plain PCM) at68c6401203afb55e7a60706fbca7c55f57350422, and both GREEN on the fourteenth (J873 speaker link rising RX edge) at444f88a8eff09c01aa345b41654005b57f48307e, the head of this PR. The first review found one defect in the DART exception handler, which is fixed in this head. The second review recomputeddtcheck(0 messages) and the admac, PSD and DMA-channel arithmetic against the device tree.Speaker thermal limiter (commit 43f2664, t8140_aop_audio.rs only)
Correction (25 Oct): all figures in this section are in the model's units, which assume a full scale of 2^30. The amplifier's real full scale is 2^23, so they are 128 times too optimistic for the words this series sends. See the hold note at the top.
In-kernel feed-forward limiter in the T8152 speaker copy path (the speaker front-end has no mmap flags, so every sample passes through it). The T8152 AOP has no speaker sense tap, so the sense-based userspace daemon cannot run; this limiter uses these thermal model numbers (11.9 V per full scale, 4.6 ohm, coil 40 C/W with 3.4 s, magnet 60 C/W with 210 s, ambient 50 C, limit 140 C): sustained limit 0.9 W (full-scale square wave 30.78 W, so minimum gain -15.43 dB at 2 % margin), immediate attack per 128-word block, 20 s release, idle cooling between streams, fixed point (i64 only). A hard ceiling 20 dB below the sustained level is a const, removed by a rebuild only, for the first audible tests.
Receipts: host reference model plus integer model, 66 checks pass (worst-case sine, square, noise and DC step from four start temperatures stay below 140 C; closed-loop equilibrium 139.89 C); KUnit suite snd_soc_t8140_aop_audio_thermal 4/4 on an arm64 qemu (TCG) kernel at this head, 0 fail 0 skip; compile CONFIG_RUST+KUNIT 16K pages rc 0, 0 warnings; two independent GREEN reviews by hash.
NOT measured: the real amplifier output voltage per full scale, the real speaker resistance and thermal constants (the model uses these numbers as given), the loudest speaker step (distorted on the M6, unexplained) and absolute sound level (the speaker is still disabled in the configuration), the plant 25 % worse than these numbers with the amplifier above the card's gain cap reaches 229.7 C in simulation (no margin by design beyond the 3 dB of the amplifier gain cap and the 2 % power margin). enable_speakers stays false in this series. Not needed for the release candidate.
MEASURED on the M6 with the plain-PCM commit (limiter build, microphone 12 to 18 inches away): a 440 Hz tone at the quietest step is detected 38 dB above the room at 440 Hz, with harmonics below -30 dB relative to the fundamental; the next step, 10 dB up, measures 9 dB louder. Before that commit the same tone gave a steady sound whose strongest component was 880 Hz, at the same level for two steps 10 dB apart. The amplifier itself still needs its configuration and a clock-before-unmute fix in a separate driver change. With the macaudio commit (26) and no register writes from user space the amplifier leaves software shutdown: the quietest step is 39 dB above the room with harmonics below -29 dB relative to the fundamental, and the step 10 dB up is 7 dB louder. NOT measured: absolute level; the loudest step is distorted and unexplained.