From 3162d9144759835e97c473916fe6fae671198335 Mon Sep 17 00:00:00 2001 From: Philip Wallage Date: Sat, 7 Nov 2026 19:41:41 +0100 Subject: [PATCH 1/3] drm/apple: drive the J516M internal display by default The 16" binned M3 Max MacBook Pro (J516M) carries the J514M's T6034 die: its ADT names the same DCP image (F493F03E-...), and m1n1 gives it the same T6034 handoff. Its chassis and panel are the J516C's. Give it a v14 board record with the J514M's DCP, image and handoff, and the J516 panel: 3456x2234 with 74 notch rows above the 3456x2160 boot framebuffer, ProMotion allowed and bring-up logging on. As on the J514M, the panel controls stay off. The display gate starts native display by default on the J514M and J516M, and apple_t6034_display.enable=0 still keeps the boot framebuffer. The T6034 GPU link follows the display on both boards. Tests: a KUnit case for the J516M record, the T6034 display host test admits the J516M and catches dropping it from the gate or the record, and the display-order test links the J516M GPU while an unknown T6034 board (apple,j999) stays refused. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Philip Wallage --- drivers/gpu/drm/apple/apple_drv.c | 3 ++- drivers/gpu/drm/apple/iomfb_v14_7.c | 21 +++++++++++++++++++++ drivers/gpu/drm/apple/v14-board-test.c | 26 +++++++++++++++++++++++++- drivers/soc/apple/t6030-display-gate.c | 5 +++-- tools/asahi/g15-display-order-tests.py | 8 +++++--- tools/asahi/t6034-display-tests.py | 4 +++- 6 files changed, 59 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index b6a5be040ef9c8..9c9740a53a5048 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -139,7 +139,8 @@ EXPORT_SYMBOL_GPL(apple_drm_t6031_link_device); int apple_drm_t6034_link_device(struct device *consumer) { - if (!of_machine_is_compatible("apple,j514m")) + if (!of_machine_is_compatible("apple,j514m") && + !of_machine_is_compatible("apple,j516m")) return -ENODEV; return apple_g15_link_device(consumer, "apple,t6034", "apple,agx-t6034", &apple_t6034_display); diff --git a/drivers/gpu/drm/apple/iomfb_v14_7.c b/drivers/gpu/drm/apple/iomfb_v14_7.c index 4f381ab769f315..8497de19e4ae25 100644 --- a/drivers/gpu/drm/apple/iomfb_v14_7.c +++ b/drivers/gpu/drm/apple/iomfb_v14_7.c @@ -203,6 +203,26 @@ static const struct dcp_v14_board dcp_v14_board_j514m = { .log_bringup = true, }; +/* + * J516M (MacBook Pro 16", binned M3 Max): the T6034 DCP, image and handoff + * of the J514M in the J516C chassis, so the J516 panel: 3456x2234 with 74 + * notch rows above the 3456x2160 boot framebuffer. Panel controls stay off + * as on the J514M. + */ +static const struct dcp_v14_board dcp_v14_board_j516m = { + .name = "J516M", + .debugfs = "dcp-j516m", + .dcp_compatible = "apple,t6034-dcp", + .machine = "apple,j516m", + .soc = "apple,t6034", + .firmware_uuid = DCP_V14_J516C_FIRMWARE_UUID, + .handoff = "apple,t6034-handoff", + .panel_width = 3456, + .panel_height = 2234, + .promotion = true, + .log_bringup = true, +}; + static const struct dcp_v14_board *const dcp_v14_boards[] = { &dcp_v14_board_t6030, &dcp_v14_board_j613, @@ -210,6 +230,7 @@ static const struct dcp_v14_board *const dcp_v14_boards[] = { &dcp_v14_board_j516c, &dcp_v14_board_j514c, &dcp_v14_board_j514m, + &dcp_v14_board_j516m, }; struct dcp_v14_property { diff --git a/drivers/gpu/drm/apple/v14-board-test.c b/drivers/gpu/drm/apple/v14-board-test.c index 23453f1368ee14..1b2cbd0cd8d879 100644 --- a/drivers/gpu/drm/apple/v14-board-test.c +++ b/drivers/gpu/drm/apple/v14-board-test.c @@ -125,10 +125,33 @@ static void v14_board_j514m(struct kunit *test) KUNIT_EXPECT_FALSE(test, dcp_v14_board_admits(b, T6030_DCP_IMAGE)); KUNIT_EXPECT_FALSE(test, b->panel_nits); KUNIT_EXPECT_NULL(test, board_for("apple,t6034-dcp", j514m_wrong_soc, &known)); - KUNIT_EXPECT_NULL(test, board_for("apple,t6034-dcp", j516m, &known)); + /* The J516M has a record of its own. */ + KUNIT_EXPECT_PTR_NE(test, b, board_for("apple,t6034-dcp", j516m, &known)); KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", j514m, &known)); } +/* The J516M: the J514M's T6034 DCP and image, with the J516 panel. */ +static void v14_board_j516m(struct kunit *test) +{ + const struct dcp_v14_board *b; + bool known; + + b = board_for("apple,t6034-dcp", j516m, &known); + KUNIT_ASSERT_NOT_NULL(test, b); + KUNIT_EXPECT_TRUE(test, known); + KUNIT_EXPECT_STREQ(test, b->name, "J516M"); + KUNIT_EXPECT_STREQ(test, b->debugfs, "dcp-j516m"); + KUNIT_EXPECT_STREQ(test, b->machine, "apple,j516m"); + KUNIT_EXPECT_STREQ(test, b->soc, "apple,t6034"); + KUNIT_EXPECT_STREQ(test, b->handoff, "apple,t6034-handoff"); + KUNIT_EXPECT_EQ(test, b->panel_width, 3456); + KUNIT_EXPECT_EQ(test, b->panel_height, 2234); + KUNIT_EXPECT_TRUE(test, dcp_v14_board_admits(b, J516C_DCP_IMAGE)); + KUNIT_EXPECT_FALSE(test, dcp_v14_board_admits(b, T6030_DCP_IMAGE)); + KUNIT_EXPECT_FALSE(test, b->panel_nits); + KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", j516m, &known)); +} + /* A T6031 DCP on a T6034 has no record: refused. */ static void v14_board_t6031_other_boards(struct kunit *test) { @@ -277,6 +300,7 @@ static struct kunit_case v14_board_cases[] = { KUNIT_CASE(v14_board_j516c), KUNIT_CASE(v14_board_j514c), KUNIT_CASE(v14_board_j514m), + KUNIT_CASE(v14_board_j516m), KUNIT_CASE(v14_board_t6031_other_boards), KUNIT_CASE(v14_board_j516c_image), KUNIT_CASE(v14_board_unchanged), diff --git a/drivers/soc/apple/t6030-display-gate.c b/drivers/soc/apple/t6030-display-gate.c index 016abbcf6cf96f..0de143fd52db27 100644 --- a/drivers/soc/apple/t6030-display-gate.c +++ b/drivers/soc/apple/t6030-display-gate.c @@ -190,7 +190,8 @@ static bool gate_t6034_requested __initdata; static bool __init gate_t6034_default_board(void) { return of_machine_is_compatible("apple,t6034") && - of_machine_is_compatible("apple,j514m"); + (of_machine_is_compatible("apple,j514m") || + of_machine_is_compatible("apple,j516m")); } static bool __init gate_t6034_wanted(int sw) @@ -2060,7 +2061,7 @@ static void __init gate_run(void) } gate_t6034_requested = gate_t6034_wanted(gate_t6034_switch); if (gate_t6034_switch < 0) - gate_info("native display on by default on J514M; apple_t6034_display.enable=0 keeps the boot framebuffer\n"); + gate_info("native display on by default on J514M/J516M; apple_t6034_display.enable=0 keeps the boot framebuffer\n"); } if (!*gate_soc->requested) { diff --git a/tools/asahi/g15-display-order-tests.py b/tools/asahi/g15-display-order-tests.py index 6ff26493965c60..a1f7f8ea371381 100644 --- a/tools/asahi/g15-display-order-tests.py +++ b/tools/asahi/g15-display-order-tests.py @@ -221,9 +221,11 @@ def c_source(root): CHECK(publish(&d34) == 0 && d34.refs == 1); CHECK(prepare(&g34) == 0 && links_made == 1 && last_link.supplier == &d34); machine("apple,t6034", "apple,j516m"); - CHECK(prepare(&g34) == -ENODEV && links_made == 1); + CHECK(prepare(&g34) == 0 && links_made == 2 && last_link.supplier == &d34); + machine("apple,t6034", "apple,j999"); + CHECK(prepare(&g34) == -ENODEV && links_made == 2); machine("apple,t6031", "apple,j514m"); - CHECK(prepare(&g34) == -ENODEV && links_made == 1); + CHECK(prepare(&g34) == -ENODEV && links_made == 2); machine("apple,t6034", "apple,j514m"); withdraw(&d34); CHECK(!d34.refs && prepare(&g34) == -EPROBE_DEFER); @@ -243,7 +245,7 @@ def c_source(root): "t6031-reads-t6030-slot": ("&apple_t6031_display);", "&apple_t6030_display);"), "t6034-reads-t6031-slot": ("&apple_t6034_display);", "&apple_t6031_display);"), "t6034-published-as-t6031": ("return &apple_t6034_display;", "return &apple_t6031_display;"), - "t6034-no-board-check": ('if (!of_machine_is_compatible("apple,j514m"))', 'if (false)'), + "t6034-no-board-check": ('if (!of_machine_is_compatible("apple,j514m") &&\n\t !of_machine_is_compatible("apple,j516m"))', 'if (false)'), "t6031-published-as-t6030": ("return &apple_t6031_display;", "return &apple_t6030_display;"), "no-machine-check": ("!of_machine_is_compatible(machine) ||", ""), "withdraw-keeps-display": ("*slot = NULL;", ";"), diff --git a/tools/asahi/t6034-display-tests.py b/tools/asahi/t6034-display-tests.py index ddd1cf54cc4c39..f2b1f14205edac 100644 --- a/tools/asahi/t6034-display-tests.py +++ b/tools/asahi/t6034-display-tests.py @@ -41,7 +41,7 @@ def item(s, marker): const char *socs[]={"apple,t6034","apple,t6031","apple,t6030",NULL}; dcp="apple,t6034-dcp"; for(unsigned i=0;ifirmware_uuid);','return uuid != NULL;'), } From 468da4dfc3527732b1336b93a1ac306ee749e37f Mon Sep 17 00:00:00 2001 From: Philip Wallage Date: Sat, 7 Nov 2026 19:41:41 +0100 Subject: [PATCH 2/3] arm64: dts: apple: t6034-j516m: describe the internal display Include the T6034 DCP and give the J516M's DCP its panel node. The panel is the J516C's (same 16" chassis): 346 x 223 mm, 216 mm below the notch, 500 nits. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Philip Wallage --- arch/arm64/boot/dts/apple/t6034-j516m.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6034-j516m.dts b/arch/arm64/boot/dts/apple/t6034-j516m.dts index 22ad5251eaecef..a8d651917c313e 100644 --- a/arch/arm64/boot/dts/apple/t6034-j516m.dts +++ b/arch/arm64/boot/dts/apple/t6034-j516m.dts @@ -10,6 +10,7 @@ /dts-v1/; #include "t6034.dtsi" +#include "t6034-dcp.dtsi" #include "t603x-j514-j516.dtsi" / { @@ -29,6 +30,17 @@ brcm,board-type = "apple,jura"; }; +/* J516 panel dimensions, as on the J516C (same 16-inch chassis and panel). */ +&dcp { + panel { + compatible = "apple,panel-j516", "apple,panel-mini-led", "apple,panel"; + width-mm = <346>; + height-mm = <223>; + adj-height-mm = <216>; + apple,max-brightness = <500>; + }; +}; + &aop_audio { apple,chassis-name = "J516"; apple,machine-kind = "MacBook Pro"; From 09ffb61538a9a6b65ec2a37c2e4c6b7c92c29776 Mon Sep 17 00:00:00 2001 From: Philip Wallage Date: Sat, 7 Nov 2026 19:41:41 +0100 Subject: [PATCH 3/3] drm/asahi: admit the J516M on the measured T6034 GPU firmware The J516M loads the J514M's 14.7 G15C image: on a J516M the loaded firmware measured TEXT 0x64000, DATA 0x140000, GKTS 0x5cf28 and the J514M's TEXT sha256 (4ca24b65...04b7), and the GPU reports the same B1 identity (version 0x7041100, counts 0x21040a) with 30 enabled cores in four ten-slot clusters ([8, 8, 7, 7]). Admit apple,j516m with apple,t6034 alongside the J514M, and pin the image to the J516M on a row of its own, so neither board's row admits the other. The PMP, display, record and hardware identity checks are unchanged. The profile test checks both rows, that each board pins only its own, and that a changed digest is refused on the J516M too. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Philip Wallage --- drivers/gpu/drm/asahi/g15/boot.rs | 12 +++++++----- drivers/gpu/drm/asahi/g15/hw/t6034.rs | 13 +++++++++++++ tools/asahi/g15-t6034-profile-tests.py | 15 +++++++++++---- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/asahi/g15/boot.rs b/drivers/gpu/drm/asahi/g15/boot.rs index b0ea7bfc44aedf..2b4c22f9af0d0b 100644 --- a/drivers/gpu/drm/asahi/g15/boot.rs +++ b/drivers/gpu/drm/asahi/g15/boot.rs @@ -476,9 +476,11 @@ pub(crate) fn admit( && cfg.platform == hw::Platform::DeviceTree && glue::machine(kernel::c_str!("apple,j514c")) && glue::machine(kernel::c_str!("apple,t6031")); - let j514m_board = cfg.chip_id == 0x6034 + // T6034 boards: the J514M and the 16-inch J516M, which carries the same die. + let t6034_board = cfg.chip_id == 0x6034 && cfg.platform == hw::Platform::DeviceTree - && glue::machine(kernel::c_str!("apple,j514m")) + && (glue::machine(kernel::c_str!("apple,j514m")) + || glue::machine(kernel::c_str!("apple,j516m"))) && glue::machine(kernel::c_str!("apple,t6034")); if pmp { if !glue::board() { @@ -494,8 +496,8 @@ pub(crate) fn admit( } return Err(err); } - } else if (cfg.chip_id == 0x6034 && !j514m_board) - || (!glue::machine(cfg.machine) && !j514c_board) + } else if (cfg.chip_id == 0x6034 && !t6034_board) + || (!glue::machine(cfg.machine) && !j514c_board && !t6034_board) { dev_err!(dev, "G15: not a {} machine\n", cfg.name); return Err(ENODEV); @@ -511,7 +513,7 @@ pub(crate) fn admit( return Err(err); } } - if j514c_board || j514m_board { + if j514c_board || t6034_board { if let hw::Board::DeviceTree(reference) = cfg.board { dev_warn!( dev, diff --git a/drivers/gpu/drm/asahi/g15/hw/t6034.rs b/drivers/gpu/drm/asahi/g15/hw/t6034.rs index 1c0ec130cc177e..a26bf06ea88e02 100644 --- a/drivers/gpu/drm/asahi/g15/hw/t6034.rs +++ b/drivers/gpu/drm/asahi/g15/hw/t6034.rs @@ -85,6 +85,19 @@ pub(crate) const CONFIG: Config = Config { 0xe4, 0x1e, 0x5d, 0xaf, 0x86, 0x32, 0x51, 0x50, 0x77, 0xb5, 0x37, 0xca, 0x19, 0xe6, 0xd0, 0xdc, 0x77, 0x04, 0xb7, ], + }, FirmwareBuild { + // Measured on a J516M: the J514M's 14.7 image (RTKit 2419.140.12), + // byte for byte. Pinned to the J516M on its own row. + name: "J516M RTKit 2419.140.12", + machine: Some(kernel::c_str!("apple,j516m")), + text_size: 0x64000, + data_size: 0x140000, + marker: 0x5cf28, + text_sha256: [ + 0x4c, 0xa2, 0x4b, 0x65, 0x8f, 0x8e, 0xbe, 0x7c, 0x27, 0x37, 0x5f, 0xdf, 0x38, + 0xe4, 0x1e, 0x5d, 0xaf, 0x86, 0x32, 0x51, 0x50, 0x77, 0xb5, 0x37, 0xca, 0x19, + 0xe6, 0xd0, 0xdc, 0x77, 0x04, 0xb7, + ], }], machine: kernel::c_str!("apple,j514m"), platform: super::Platform::DeviceTree, diff --git a/tools/asahi/g15-t6034-profile-tests.py b/tools/asahi/g15-t6034-profile-tests.py index 4f73b5172aee76..16fde7183569a4 100644 --- a/tools/asahi/g15-t6034-profile-tests.py +++ b/tools/asahi/g15-t6034-profile-tests.py @@ -58,13 +58,17 @@ def item(text, marker): assert_eq!(c.gpu_revision,0x11); assert_eq!((c.hw_ids[0].version,c.hw_ids[0].counts),(0x07041100,0x0021040a)); // An empty table is the first diagnostic build. A completed profile may - // contain only the measured row for this exact board. - assert_eq!(c.firmware.len(),1); + // contain only the measured rows, each pinned to its exact board: the J514M, + // and the J516M, measured with the same image. + assert_eq!(c.firmware.len(),2); if !c.firmware.is_empty() { use lookup::{Measured,Verdict}; - assert_eq!(c.firmware.len(),1); let b=&c.firmware[0]; assert_eq!(b.machine.map(|m|m.to_bytes()),Some(b"apple,j514m".as_slice())); + let j516m=&c.firmware[1]; + assert_eq!(j516m.machine.map(|m|m.to_bytes()),Some(b"apple,j516m".as_slice())); + assert_eq!((j516m.text_size,j516m.data_size,j516m.marker,j516m.text_sha256), + (b.text_size,b.data_size,b.marker,b.text_sha256)); let exact=Measured {text_size:b.text_size,data_size:b.data_size,marker:b.marker,sha256:b.text_sha256}; let verdict=|measured:&Measured,board:&[u8]| { let qualified=c.firmware.iter().map(|b| { @@ -74,10 +78,13 @@ def item(text, marker): lookup::verdict(measured,qualified,0) }; assert_eq!(verdict(&exact,b"apple,j514m"),Verdict::Pinned(0)); - for board in [b"apple,j514c".as_slice(),b"apple,j516c",b"apple,j516m",b"apple,j514s",b"apple,j999"] { + assert_eq!(verdict(&exact,b"apple,j516m"),Verdict::Pinned(1)); + for board in [b"apple,j514c".as_slice(),b"apple,j516c",b"apple,j514s",b"apple,j999"] { assert_eq!(verdict(&exact,board),Verdict::Refused); } let mut changed=exact;changed.sha256[31]^=1; + assert_eq!(verdict(&changed,b"apple,j516m"),Verdict::Refused); + let mut changed=exact;changed.sha256[31]^=1; assert_eq!(verdict(&changed,b"apple,j514m"),Verdict::Refused); let mut changed=exact;changed.text_size+=0x4000; assert_eq!(verdict(&changed,b"apple,j514m"),Verdict::Refused);