Skip to content

ASoC: apple: t8152-aop-audio: Capture the J714s (M5 Pro) microphone array - #1557

Merged
DjDeveloperr merged 30 commits into
integration/aurorafrom
m5-parity/t6050-mic
Nov 11, 2026
Merged

DjDeveloperr merged 30 commits into
integration/aurorafrom
m5-parity/t6050-mic

Conversation

@DjDeveloperr

@DjDeveloperr DjDeveloperr commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Microphones on the MacBook Pro 14-inch M5 Pro (J714s, T6050): the three-microphone array, as a capture card of its own (AppleJ714HPAI), the same way J813's works.

Stacked on #1521 → #1423 and no longer on #1554. The speakers aren't audible yet, so #1554 stays a draft, and this PR carries only what the microphones need. The last 4 commits are this PR's. Rebased (11-11) onto #1423's head 18fa06f and #1521's 3c16dac with the same patches as ad6f44c (identical patch-id), so once #1423 and #1521 merge, only those 4 commits remain. The earlier version, stacked on #1554, is kept on m5-parity/t6050-mic-on-speakers (1026d29).

Change

  1. ASoC: apple: t8152-aop-audio: Add T6050 (MacBook Pro J714s), from J714s: sound through the AOP (speakers and headphone jack) #1554 unchanged: the apple,t6050-aop-audio entry and its hardware configuration. On T6050 the firmware powers the MCA serializer leaves (no AP power state in the ADT), so the driver binds without them there. On its own this registers the AOP audio component and no sound card: the J714 macaudio entry and the amp and jack nodes stay in J714s: sound through the AOP (speakers and headphone jack) #1554.
  2. ASoC: apple: t8152-aop-audio: Capture the T6050 microphone array. On T6050 the array's LEAP leaves, like its MCA leaves, have no AP power state: the firmware raises them with the hpai service's pw0 . The driver registered the microphone card only when the DT gave it all three LEAP power domains, so the J714s had none. A new ap_leap field in the hardware configuration is true for T8152 and T8142 (unchanged) and false for T6050. Without AP-held leaves, the DT's hpai DMA channel alone says whether there is a microphone array.
  3. arm64: dts: apple: t6050: Put the leap-s proxy ADMAC at its real address.
    • The ADT's admac-hp-mic-ec-proxy / admac-sllb-ec-proxy reg is not behind the arm-io translation. Like the AOP setup port in soc: apple: aop: Boot the T6050 (M5 Pro/Max) AOP through its setup port #1521, it is the real address, 0x2d3200000; the tree had the translation, 0x4d3200000.
    • Described as an ADMAC, as the T8140 and T8142 trees do for theirs: 9 channels, the leap-s interrupt 638, dart-aop stream 11 with the ADT's vm-base-11/vm-size-11.
    • The J716s ADT coverage manifest's two lines follow.
  4. arm64: dts: apple: t6050-j714s: Add the microphone array. ADT audio-hp-mic (three microphones, 48 kHz) on leap-s RX0 through the proxy ADMAC (Linux channel 1, as on J813). The audio node gets the card identity and its DMA list (the base-ns channels its binding requires, plus hpai), and both ADMACs are enabled. The speaker amp buses (i2c1/i2c3) and the jack codec bus (i2c2) stay off.

Validation (J714s)

Setup: the board's default kernel (7.3.0-m5-argb2) with #1521's aop.rs and this PR's t8152_aop_audio.rs as modules, booted on a DT whose proxy ADMAC and audio nodes match this PR's J714s DTB.

  • Both ADMACs bind, the proxy at 0x2d3200000 with no SError.
  • The card registers by itself: AppleJ714HPAI, "MacBook Pro J714 HPAI", device hpai "Microphone Array".
  • arecord -D hw:CARD=AppleJ714HPAI -f FLOAT_LE -c 3 -r 48000 -d 3 records three live channels in a quiet room, with matching levels, and the channels correlate with each other (a shared sound field rather than independent noise).
  • Only the first ~0.15 s is silent while the stream starts. No new errors or warnings in the log.
  • ADT coverage checker (J716s, J873s): MISSING unchanged, 0 broken paths.

Split (11-11), validated on the M5 (run mic4): the mic-only tree at ad6f44c was booted on the J714s with this exact DTB. Its audio node matches the earlier validated one, and the split leaves out only the amp, jack and sound-card nodes, which the microphone card doesn't use. The rebase onto 18fa06f/3c16dac7 changes none of this PR's patches. CI runs the dt-schema pass and the Rust build.

🤖 Generated with Claude Code

sithglan and others added 19 commits November 10, 2026 13:41
Add the MacBook Air (M5, J813) and Mac mini (M6, J873) sound cards.
t8142-j813-audio.dtsi already names apple,j813-macaudio.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J873 (Mac mini M6) AOP runs the same firmware generation as T8140
(EPIC v4, iBoot-loaded, started by the AP), but the T8140 "setup port"
is not reachable from the AP: mailbox 1 of the AOP's mailbox bank and the
ADT aop-exclave-mailbox both bus-error. The firmware boots without it:
RTKit protocol 12, then its "audio" EPIC service. Add apple,t8152-aop
with the T8140 configuration minus the setup port, starting every
advertised endpoint.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The Mac mini (M6, J873) speaker runs a 250-BCLK TDM frame, which the
SN012776's ratio auto-detection rejects. Describe the property that fixes
the ratio instead.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J873 (Mac mini M6) AOP runs the speaker frame at 250 BCLKs of 12 MHz.
The SN012776 cannot auto-detect that ratio and mutes with "fault: bad
TDM clock". With TAS2764_CLK_CFG (register 0x60) set to 0x30 and
TDM_CFG0 bit 6 set it accepts the frame and plays. Do that when the new
ti,bclk-ratio property names the ratio; only this one ratio is supported.

Source of the value: the register write was first seen in the macOS
SN012776 driver; it is a single register value, and its effect (no fault,
correct playback) was verified on J873 hardware. No table or code was
taken from macOS.

The field is initialised in probe, so non-OF matches keep auto-detection.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The SDOUT1 mux offers the ASP receive channels as a source, but no DAPM
route connected them, so selecting "ASP RX CH1" or "ASP RX CH2" left the
capture path without an input. The J873 and J813 AOP audio services use
it to loop the playback stream back.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
On T8152 (J873, Mac mini M6) the AOP firmware owns the audio fabric, as
on T8140. Its "audio" EPIC service offers cout/cin (the CS42L84 jack,
base-ns ADMAC TX5/RX5, MCA4) and spkr (the SN012776 speaker, TX1, MCA0).

Each service is an ASoC back-end DAI: startup attaches it, requests pw0
(which raises the audio fabric) and powers the MCA leaves, all of which
are required. pwrd starts the serializer clocks at prepare, before ASoC
unmutes the codecs: the jack codec locks its PLL to the bit clock, and
the speaker amplifier reports "bad TDM clock" whenever it runs without
one. The jack restarts its clocks on every prepare so that a stream
restarted after an underrun begins on a frame boundary; the mono speaker
(one slot per frame) keeps them running. The front-ends are dmaengine
PCMs on the base-ns channels: the jack in stereo, the speaker in mono
(its serializer runs one 32-bit slot; stereo frames play at half pitch).

The firmware's serializer configuration (property 701) is byte-identical
to the one macOS publishes, so the driver leaves it alone.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J873 (Mac mini M6) uses the T8152 AOP audio driver as its CPU
component: the CS42L84 jack on "cout" (DSP_A | IB_NF, one-BCLK sync
pulse) and one SN012776 on "spkr" (I2S, NB_IF: data sampled on the rising
edge, as macOS programs the amp).

Each AOP front-end owns the DMA channel of one serializer, so the speaker
can only be fed from the secondary front-end; the new spk_secondary_only
sets the speaker mux accordingly, and spk_dai_fmt gives the speaker link
its own format.

There is no qualified speaker protection for J873 yet (no verified sense
path, thermal model or power budget) and no safe level, so
macaudio_speakers_allowed() keeps the speaker off. The jack is not
affected.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The T8142 AOP (MacBook Air J813) waits for the host on a setup port, as
the T8140 one does: the ADT's aop-exclave-mailbox at 0x3d067c000 (AOP
ASC + 0x4007c000, not behind the arm-io translation). Its EPMAP announces
other service endpoints than T8140's fixed set (0x4, 0x20, 0x23 and 0x32
on J813), so take the endpoints that must get buffers from the EPMAP when
the match data says so.

The firmware places its own crash log buffer in its firmware-mapped DART
slot; accept it as the firmware's, as for G17P.

After the setup boot all AFK endpoints start, and with the audio fabric
left to the firmware (see the J813 device tree) the firmware announces
its "audio" EPIC service.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Behind an AOP the serializer feeding a capture channel is the firmware's,
and it stops in the middle of a frame whenever it likes. A capture that
stays open across such stops (the speaker V/I sense, which a protection
daemon reads for as long as it runs) then carries the partial frame
forward: every later frame is off by its words, and the samples of one
amplifier are read as another's. On the MacBook Air J813 one restart in
three slipped by one 16-bit word.

Let a client pass the frame size in bytes as a u32 in
dma_slave_config.peripheral_config. A paused cyclic capture on such a
channel resumes at the next frame boundary of its current period: the
reports completed before the pause are accounted for, the rings are
reset and the rest of the period is submitted from the aligned address,
then whole periods as before. Without a frame size nothing changes.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J813 speaker stream (ADT iop-audio-controller/audio-speaker) differs
from J873's: four SN012776 in 32-bit playback slots 0-3, and their voltage
and current sense back on the same stream's RX side (base-ns RX0) as eight
16-bit slots. Make the speaker and sense shapes per-SoC match data:
J873 keeps one playback channel; T8142 gets four, and an 8-channel S16_LE
"Speaker Sense" front-end.

The sense capture is the speaker serializer's RX, which the firmware
stops anywhere in a frame. Before every `pwrd` of the speaker, restart a
running sense capture at a frame boundary (apple-admac realignment, the
partial frame reads as zeros), so that a protection daemon that keeps it
open attributes each amplifier's voltage and current to the right one.

The sense back-end also attaches the speaker service and requests `pw0 `
at startup: its front-end requests the ADMAC channel next, and the ADMAC
only answers while the firmware holds the audio fabric up. Opening the
sense before any other stream since the AOP started (speakersafetyd at
boot) otherwise faults the bus.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
MacBook Air 13" M5 (T8142): as on J873 the AOP firmware owns the audio
fabric and the CPU component is the T8152-style AOP audio driver. The
jack is a CS42L84 on "cout", the speakers four SN012776 (one woofer and
one tweeter per side) on "spkr", with their V/I sense on the same stream.

As on the other SN012776 laptops the table has a safe level, so the
speakers are behind the speaker protection interfaces from the bind:
under "Speaker Volume Unlock" their volumes stay at the lock's ceiling
until a protection daemon (speakersafetyd) holds them, and under "Speaker
Protection" they stay at the floor and no speaker start is admitted until
an owner is granted. Each amp's level is its apple,speaker-config from
the boot loader.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The MacBook Air J813's three microphones are the AOP's "hpai" service
(ADT iop-audio-controller/audio-hp-mic): the firmware runs the PDM part
and delivers 48 kHz float32 frames of three channels (the ADT's
audio-hp-mic-proxy description: 12 bytes per frame) on leap-s ADMAC RX0.
There is no codec, so it gets a card of its own with one capture PCM,
named like the other AOP microphone cards (AppleJ813HPAI, "MacBook Air
J813 High-Power Audio Interface", driver aop_audio) so that the existing
UCM and DSP configurations for those apply.

As on T8140: open attaches the service and requests pw0 (which raises
the LEAP fabric), powers the LEAP leaves (leap-s ADMAC, RX0, LEAP MCA),
and only then requests the channel, whose registers fault without them.
The trigger starts the DMA and queues pwrd behind it; started earlier,
the LEAP produces into a channel nobody services. Close releases the
channel, then pw0 and the leaves.

The card exists only where the DT gives the LEAP power domains (all
three); J873 is unchanged. The dmaengine substream setup moves into a
helper shared with the ASoC front-ends.

Tested on J813: a tone from the speakers reads -44 to -49 dBFS on all
three channels, 70 dB over the quiet floor, exactly while it plays;
PipeWire picks up the card with asahi-audio's J613 beamformer graph.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The MacBook Air (M5, J813) gets its jack, speakers and microphones from
the T8152 AOP audio driver. Build it beside the T8140 one.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
ti,bclk-ratio is only on the AOP-fed amplifiers (J813, J873). Test that
an amp without it, as on every MCA machine, keeps the ratio
auto-detection and that its probe writes neither TAS2764_CLK_CFG nor
TDM_CFG0's fixed-ratio bit, through a register map that records every
write; that 250 BCLKs programs code 0x30 and sets only that bit; and
that a ratio without a known code fails the probe.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The paused-capture restart at a frame boundary is the T8152 AOP audio
driver's alone: it passes a u32 frame size in the peripheral config for
its speaker sense capture. Test that a slave config as mca_hw_params()
builds it (zeroed, no peripheral config) and one with a peripheral config
of another size give no frame size, and that a resume realigns only a
capture channel with a frame size and a transfer, never a playback one,
so the MCA machines' channels resume as before.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Cover the AOP-fed machines in the speaker KUnit suites:

- apple-speaker-admission: J813 is admitted (it has a safe level), J873
  is not (it has none).
- apple-speaker-amp-level: neither carries an SN012776 gain; each amp's
  level is its apple,speaker-config from the boot loader.
- apple-speaker-interface: on the J813 table the four SN012776 volumes
  start at the volume lock's ceiling, go up only once a daemon holds the
  lock and pings, and under "Speaker Protection" sit at the floor with no
  speaker start admitted until an owner is granted.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The driver also runs the J813 (T8142, MacBook Air M5) speakers and
its microphone array card. Say so in the Kconfig help and the module
description, which still named only the Mac mini jack and speaker.

Signed-off-by: Diljit Singh <hey@djdev.me>
TAS2764_CLK_CFG went in between TAS2764_INT_CLK_CFG and its
TAS2764_INT_CLK_CFG_IRQZ_CLR field. Put the field back under its
register. No functional change.

Signed-off-by: Diljit Singh <hey@djdev.me>
Flush queued HPAI startup before releasing its dmaengine runtime, and
provide sync_stop so ALSA waits for asynchronous DMA termination before
reusing or freeing the capture buffer. This carries the microphone
lifetime handling already present in the J815 extension into the common
J813/T8152 foundation.

No speaker admission, gain, protection or device-tree behavior changes.

Signed-off-by: Diljit Singh <hey@djdev.me>

@DjDeveloperr DjDeveloperr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex (GPT-6.1 Sol), reviewing on @DjDeveloperr’s behalf.

Keep draft until the explicit audio chain is reviewed and ready:1554 is still draft and1521/1423 are unmerged prerequisites. The focused AP-LEAP/three-channel capture delta has no independent blocker identified, but the PR carries the foundation and cannot bypass its protection/lifecycle gates by being called mic-only. The reported module/DT capture is not an exact full-head kernel boot or known-source mic qualification. Rust job130580931614 failed before compilation in Ubuntu apt DNS setup, not at a compiler diagnostic; do not infer a source failure or a green build. Any mic recording stays local; no new test or speaker playback was performed/requested by this review.

Pair the dmaengine front-end asynchronous STOP with sync_stop before
ALSA reuses or releases its buffer. Skip ASoC back-ends, which have no
dmaengine runtime, just as the T8140 AOP component does.

Signed-off-by: Diljit Singh <hey@djdev.me>
@DjDeveloperr
DjDeveloperr marked this pull request as ready for review November 11, 2026 15:35

@DjDeveloperr DjDeveloperr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex (GPT-6.1 Sol), reviewing on @DjDeveloperr’s behalf.

Reviewed the mic-only split at ad6f44c. The earlier #1554/draft-speaker prerequisite no longer applies: this version is directly on #1521 → #1423 and excludes the speaker/jack/macaudio nodes. The four focused commits keep T8152/T8142 AP power-domain requirements unchanged, select firmware-owned MCA/LEAP leaves only for T6050, and enable the proxy ADMAC/mic card only on J714s. No additional blocker found in that delta.

Merge still waits for #1423 and #1521 and integration of #1423’s current DMA/work shutdown synchronization (2b671f4); this split still has the older foundation. Preserve that fix when rebasing, then validate the actual updated sound object as well as the fresh required checks. The hosted SEP rust-build compiles SEP, not t8152_aop_audio.rs, so it cannot establish this audio build by itself.

The author’s prior module/DT capture is useful composition evidence; the newly split DTB is explicitly not yet booted, and known-source capture/stream restart-close qualification remains a hardware follow-up. This review does not request recordings or speaker playback, and does not qualify the separate speaker feature.

@DjDeveloperr

Copy link
Copy Markdown
Contributor Author

Validated this exact head (ad6f44c) on a J714s (MacBook Pro 14-inch, M5 Pro).

  • Built this head's own t6050-j714s.dtb and booted it by chainload with the board's 7.3.0-m5-argb2 kernel. t8152_aop_audio.rs at this head is byte-identical to the module used: the module was built from it, with soc: apple: aop: Boot the T6050 (M5 Pro/Max) AOP through its setup port #1521's aop.rs.
  • The card registers by itself at boot: AppleJ714HPAI, "MacBook Pro J714 HPAI", capture device hpai "Microphone Array".
  • Both ADMACs bind, including the leap-s proxy at 0x2d3200000, with no SError.
  • arecord -D hw:CARD=AppleJ714HPAI -f FLOAT_LE -c 3 -r 48000 -d 3 (nothing played): all three channels are live and correlated (0.90-1.00), as one sound field would be. Only the first 0.15 s is silent while the stream starts.
  • No new errors or warnings in the log. The default boot was restored and checked afterwards.

The same checks also passed on the earlier stack (run with #1554 underneath).

DjDeveloperr and others added 5 commits November 11, 2026 12:16
…tion

Retain the reviewed DMA/work and FE/BE sync-stop lifetime fix, and combine
T8142 dynamic setup endpoints with current main AOP source/bound rings,
LPAI and other interfaces. Carry the reviewed policy-window test-only
correction, including unsafe-call negative controls.

The audio driver source is unchanged; actual object compilation follows.

Assisted-by: LLM
integration/aurora now has the agreed fix for the policy-window test,
#1561 (ea10c4d). The earlier merge into this branch had carried a
different version of the same test change, and combining the two leaves
#1561's deferred-call count at zero, which fails the source check. Take
integration/aurora's test file as it is: this pull request is J813
audio and changes nothing under tools/aurora-sep.

Signed-off-by: Diljit Singh <hey@djdev.me>
The T6050 (M5 Pro and Max) AOP boots through a setup port, as the T8142
one does. Its endpoint map names system endpoint 4 besides the service
endpoints 0x20, 0x23 and 0x32, but endpoint 4 never asks for a buffer.
With the T8142 configuration the boot therefore times out with 3 of 4
endpoints, and the AFK endpoints never start.

Add a T6050 configuration that doesn't wait for system endpoints. A
buffer request from one is still answered.

On a J714s the AOP then opens its AFK endpoints and announces its
services, among them accel, gyro, las, als, als-temp, devmotion6,
aop-audio and aop-voicetrigger.

Signed-off-by: Diljit Singh <hey@djdev.me>
Both use the T8140 setup-port register layout. T8142 already names its
own compatible in the J813 device tree.

Signed-off-by: Diljit Singh <hey@djdev.me>
The ADT reg of aop-exclave-mailbox is not behind the arm-io translation.
As on T8140 and T8142 it is the AOP ASC + 0x4007c000, 0x2d067c000. The
0x4d067c000 this tree used takes an SError, which is why the AOP was
described as booting without its setup port. At 0x2d067c000 the port's
control words read back and the AOP firmware runs its setup handshake
on it.

Describe it as the setup-port mailbox, with T8142's interrupt names and
dart-aop stream 1 (ADT vm-base-1 0x20000000000, vm-size-1 0x2000000000),
and give the AOP both mailboxes. The J716s and J873s ADT coverage
manifests carried the old address; they now name the real one.

Signed-off-by: Diljit Singh <hey@djdev.me>
Boot the AOP through its setup port: its RTKit mailbox, the setup port,
dart-aop and the AOP itself.

Signed-off-by: Diljit Singh <hey@djdev.me>
The T6050 AOP runs the same audio service as T8142: the CS42L84 jack on
cout/cin and the SN012776 speakers on spkr, their voltage and current
sense on the stream's RX. The J714s has six amps, so its speaker stream
carries six playback slots and twelve 16-bit sense slots.

Its MCA serializer leaves have no AP power state in the ADT (no-ps, with
no register), unlike T8142's: the firmware powers them. Only bind
without them where the AP does not own them.

Signed-off-by: Diljit Singh <hey@djdev.me>
On T6050 the microphone array's LEAP leaves, like its MCA leaves, have
no AP power state: the firmware raises them with the hpai service's
"pw0 ". The driver registered the microphone card only when the DT gave
it all three LEAP power domains, so the J714s had no microphones.

Add ap_leap to the hardware configuration. Where the AP doesn't power
the leaves, the DT's "hpai" DMA channel alone says whether there is a
microphone array.

Signed-off-by: Diljit Singh <hey@djdev.me>
The ADT's admac-hp-mic-ec-proxy and admac-sllb-ec-proxy name the leap-s
ADMAC's proxy aperture. Their ADT reg is not behind the arm-io
translation: like the AOP setup port it is the real address, 0x2d3200000.
The 0x4d3200000 this tree used is the translation.

Describe it as an ADMAC, as the T8140 and T8142 trees do for theirs:
nine channels, the leap-s interrupt 638, dart-aop stream 11 with the
ADT's vm-base-11 and vm-size-11. Fix the J716s ADT coverage manifest's
two lines to match.

Signed-off-by: Diljit Singh <hey@djdev.me>
ADT audio-hp-mic: three microphones on leap-s RX0, through the proxy
ADMAC (Linux channel 1, as on J813). The AOP audio service captures
them on a card of its own, so they need neither the speaker amps nor
the jack codec, whose buses stay off. The audio node names the base-ns
channels of its other services, as its binding requires, and that ADMAC
is enabled as on the other AOP-fed machines.

Signed-off-by: Diljit Singh <hey@djdev.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants