diff --git a/arch/arm64/boot/dts/apple/t6034-j516m.dts b/arch/arm64/boot/dts/apple/t6034-j516m.dts index 22ad5251eaecef..eac430b8d0a047 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 "t6031-dcp.dtsi" #include "t603x-j514-j516.dtsi" / { @@ -38,3 +39,26 @@ compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; }; + +/* + * J516M ADT confirms the J516C display register and interrupt layout. + * External displays (dcpext, HDMI) are not described here yet. + */ +&clk_disp0 { + /* + * Preserve the captured boot-clock metadata, as the J514M path does. + * Firmware warns that this is below its video clock; + * that warning is not proof of the programmed clock or a startup veto. + * The metadata does not qualify sustained power or thermal behavior. + */ + clock-frequency = <400000000>; +}; + +&dcp { + panel { + compatible = "apple,panel-j516", "apple,panel-mini-led", "apple,panel"; + width-mm = <346>; + height-mm = <223>; + adj-height-mm = <216>; + }; +}; diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index b6a5be040ef9c8..9028388b33915b 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -139,6 +139,9 @@ EXPORT_SYMBOL_GPL(apple_drm_t6031_link_device); int apple_drm_t6034_link_device(struct device *consumer) { + if (of_machine_is_compatible("apple,j516m")) + return apple_g15_link_device(consumer, "apple,t6034", "apple,agx-t6034", + &apple_t6031_display); if (!of_machine_is_compatible("apple,j514m")) return -ENODEV; return apple_g15_link_device(consumer, "apple,t6034", "apple,agx-t6034", diff --git a/drivers/gpu/drm/apple/iomfb_v14_7.c b/drivers/gpu/drm/apple/iomfb_v14_7.c index 4c7f76b9ed6f07..93ee1ee25ee3f0 100644 --- a/drivers/gpu/drm/apple/iomfb_v14_7.c +++ b/drivers/gpu/drm/apple/iomfb_v14_7.c @@ -197,6 +197,26 @@ static const struct dcp_v14_board dcp_v14_board_j516c = { .panel_nits = true, }; +/* J516M uses the J516C image; its first boot offered only a 120 Hz panel timing. */ +static const struct dcp_v14_board dcp_v14_board_j516m = { + .name = "J516M", + .debugfs = "dcp-j516m", + .dcp_compatible = "apple,t6031-dcp", + .machine = "apple,j516m", + .soc = "apple,t6034", + .firmware_uuid = DCP_V14_J516C_FIRMWARE_UUID, + .handoff = "apple,t6031-handoff", + .panel_width = 3456, + .panel_height = 2234, + .promotion = true, + .log_bringup = true, + .base_edid = true, + /* Same pinned DCP image as J516C: zero stamps cap this panel at 60 fps. */ + .swap_timestamps = true, + /* J516C's 14.7 image uses the bounded nits block for the J516 panel. */ + .panel_nits = true, +}; + /* * J514C (MacBook Pro 14", M3 Max): the T6031 DCP running the J516C image * (the DCP image is the SoC's; its UUID is checked at probe), in the J514S @@ -236,6 +256,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 { @@ -365,7 +386,7 @@ static int dcp_v14_callback(void *cookie, u32 tag, const void *input, u32 in_siz static void dcp_v14_backlight_work(struct work_struct *work); -/* The internal panel of a board whose swap level block was validated (T6030). */ +/* The internal panel of a board admitted to the bounded swap level path. */ static bool dcp_v14_board_nits(const struct apple_dcp_v14 *v14) { return !v14->external && v14->panel_nits && v14->board && v14->board->panel_nits; @@ -1740,7 +1761,7 @@ static bool dcp_v14_panel_nits_admit(const struct dcp_v14_board *board, return board && board->panel_nits && (machine_is(ctx, "apple,j514s") || machine_is(ctx, "apple,j516s") || machine_is(ctx, "apple,j516c") || machine_is(ctx, "apple,j613") || - machine_is(ctx, "apple,j504")); + machine_is(ctx, "apple,j504") || machine_is(ctx, "apple,j516m")); } const char *iomfb_v14_7_board_name(const struct dcp_v14_board *board) diff --git a/drivers/gpu/drm/apple/v14-board-test.c b/drivers/gpu/drm/apple/v14-board-test.c index bef910f8f5becc..858b5db4e2835d 100644 --- a/drivers/gpu/drm/apple/v14-board-test.c +++ b/drivers/gpu/drm/apple/v14-board-test.c @@ -54,6 +54,8 @@ static const char *const j514c[] = { "apple,j514c", "apple,t6031", "apple,arm-pl static const char *const j514m[] = { "apple,j514m", "apple,t6034", "apple,arm-platform", NULL }; static const char *const j514m_wrong_soc[] = { "apple,j514m", "apple,t6031", NULL }; static const char *const j516m[] = { "apple,j516m", "apple,t6034", "apple,arm-platform", NULL }; +static const char *const j516m_wrong_soc[] = { "apple,j516m", "apple,t6031", NULL }; +static const char *const t6034_other[] = { "apple,j999", "apple,t6034", "apple,arm-platform", NULL }; static const char *const j516s[] = { "apple,j516s", "apple,t6030", "apple,arm-platform", NULL }; static const char *const j613[] = { "apple,j613", "apple,t8122", "apple,arm-platform", NULL }; static const char *const j504[] = { "apple,j504", "apple,t8122", "apple,arm-platform", NULL }; @@ -131,12 +133,47 @@ static void v14_board_j514m(struct kunit *test) KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", j514m, &known)); } -/* A T6031 DCP on a T6034 has no record: refused. */ +/* + * The J516M: a T6034 with the T6031 DCP layout, running the J516C image on the + * J516 panel. Admitted only on its own record, with its own SoC. + */ +static void v14_board_j516m(struct kunit *test) +{ + const struct dcp_v14_board *b; + bool known; + + b = board_for("apple,t6031-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,t6031-handoff"); + KUNIT_EXPECT_STREQ(test, b->firmware_uuid, J516C_DCP_IMAGE); + KUNIT_EXPECT_EQ(test, b->panel_width, 3456); + KUNIT_EXPECT_EQ(test, b->panel_height, 2234); + KUNIT_EXPECT_TRUE(test, b->promotion); + KUNIT_EXPECT_TRUE(test, b->base_edid); + KUNIT_EXPECT_TRUE(test, b->panel_nits); + KUNIT_EXPECT_TRUE(test, dcp_v14_board_stamps_swaps(b, false)); + KUNIT_EXPECT_TRUE(test, dcp_v14_board_admits(b, J516C_DCP_IMAGE)); + KUNIT_EXPECT_FALSE(test, dcp_v14_board_admits(b, T6030_DCP_IMAGE)); + /* Neither the J516C record nor the J514M one. */ + KUNIT_EXPECT_PTR_NE(test, b, board_for("apple,t6031-dcp", j516c, &known)); + KUNIT_EXPECT_PTR_NE(test, b, board_for("apple,t6034-dcp", j514m, &known)); + /* Its name on a T6031 root is not a J516M. */ + KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", j516m_wrong_soc, &known)); +} + +/* A T6031 DCP on any other T6034, or on a J514M, has no record: refused. */ static void v14_board_t6031_other_boards(struct kunit *test) { bool known; - KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", j516m, &known)); + KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", t6034_other, &known)); + KUNIT_EXPECT_TRUE(test, known); + KUNIT_EXPECT_NULL(test, board_for("apple,t6031-dcp", j514m, &known)); KUNIT_EXPECT_TRUE(test, known); /* Not a 14.x internal DCP at all. */ KUNIT_EXPECT_NULL(test, board_for("apple,t8112-dcp", j516c, &known)); @@ -318,6 +355,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/gpu/drm/asahi/g15/boot.rs b/drivers/gpu/drm/asahi/g15/boot.rs index b0ea7bfc44aedf..819dbb85adbba7 100644 --- a/drivers/gpu/drm/asahi/g15/boot.rs +++ b/drivers/gpu/drm/asahi/g15/boot.rs @@ -480,6 +480,10 @@ pub(crate) fn admit( && cfg.platform == hw::Platform::DeviceTree && glue::machine(kernel::c_str!("apple,j514m")) && glue::machine(kernel::c_str!("apple,t6034")); + let j516m_board = cfg.chip_id == 0x6034 + && cfg.platform == hw::Platform::DeviceTree + && glue::machine(kernel::c_str!("apple,j516m")) + && glue::machine(kernel::c_str!("apple,t6034")); if pmp { if !glue::board() { return Err(ENODEV); @@ -494,7 +498,7 @@ pub(crate) fn admit( } return Err(err); } - } else if (cfg.chip_id == 0x6034 && !j514m_board) + } else if (cfg.chip_id == 0x6034 && !j514m_board && !j516m_board) || (!glue::machine(cfg.machine) && !j514c_board) { dev_err!(dev, "G15: not a {} machine\n", cfg.name); @@ -511,7 +515,7 @@ pub(crate) fn admit( return Err(err); } } - if j514c_board || j514m_board { + if j514c_board || j514m_board || j516m_board { if let hw::Board::DeviceTree(reference) = cfg.board { dev_warn!( dev, @@ -681,6 +685,19 @@ pub(crate) fn start( ); return Err(eproto()); } + if cfg.chip_id == 0x6034 + && glue::machine(kernel::c_str!("apple,j516m")) + && !hw::j516m::identity_matches(id.version, id.counts, id.cores) + { + dev_err!( + d, + "J516M powered identity is not the 30-core G15C: version {:#x} counts {:#x} core-mask {:#x}\n", + id.version, + id.counts, + id.cores + ); + return Err(eproto()); + } // Binning: any non-empty enabled set in each cluster, nothing above the core slots. let clusters = cfg.num_clusters as usize; let slots = cfg.core_slots(); diff --git a/drivers/gpu/drm/asahi/g15/glue.c b/drivers/gpu/drm/asahi/g15/glue.c index 4a3dac630520df..90aca2c6f5cf15 100644 --- a/drivers/gpu/drm/asahi/g15/glue.c +++ b/drivers/gpu/drm/asahi/g15/glue.c @@ -165,7 +165,8 @@ int asahi_g15_display_prepare(struct device *dev) name = "T6031"; ret = apple_drm_t6031_link_device(dev); } else if (of_device_is_compatible(dev->of_node, "apple,agx-t6034")) { - compatible = "apple,t6034-display-subsystem"; + compatible = of_machine_is_compatible("apple,j516m") ? + "apple,t6031-display-subsystem" : "apple,t6034-display-subsystem"; name = "T6034"; ret = apple_drm_t6034_link_device(dev); } else { diff --git a/drivers/gpu/drm/asahi/g15/hw.rs b/drivers/gpu/drm/asahi/g15/hw.rs index 847ab6685444ad..a9987f83076674 100644 --- a/drivers/gpu/drm/asahi/g15/hw.rs +++ b/drivers/gpu/drm/asahi/g15/hw.rs @@ -11,6 +11,8 @@ use core::ops::Range; pub(crate) mod t6031; #[cfg(CONFIG_DRM_ASAHI_G15)] pub(crate) mod t6034; +#[cfg(CONFIG_DRM_ASAHI_G15)] +pub(crate) mod j516m; /// Identification register values of a qualified G15S. pub(crate) struct HwId { diff --git a/drivers/gpu/drm/asahi/g15/hw/j516m.rs b/drivers/gpu/drm/asahi/g15/hw/j516m.rs new file mode 100644 index 00000000000000..1ae58fe1a365d7 --- /dev/null +++ b/drivers/gpu/drm/asahi/g15/hw/j516m.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +//! Measured J516M/T6034 30-core profile. Share the six-channel G15C layout +//! with J514M, but retain independent machine, firmware and fused-core admission. +//! Native rendering is verified; inherited J516C power/reference values remain +//! unqualified for sustained power and thermal behavior on this board. + +use super::super::Config; +use super::FirmwareBuild; + +pub(crate) const CONFIG: Config = Config { + machine: kernel::c_str!("apple,j516m"), + firmware: &[FirmwareBuild { + name: "J516M RTKit 2419.140.12 (power qualification pending)", + 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, + ], + }], + ..super::t6034::CONFIG +}; + +/// The 14-core-CPU, 30-core-GPU J516M: its G15C revision and counts, and exactly 30 enabled +/// cores. Which cores are fused off differs between Macs of the same bin, so the mask itself is +/// not pinned (the per-cluster plausibility check in `start()` still applies). +pub(crate) const ENABLED_CORES: u32 = 30; + +pub(crate) fn identity_matches(version: u32, counts: u32, cores: u64) -> bool { + version == 0x07041100 && counts == 0x0021040a && cores.count_ones() == ENABLED_CORES +} diff --git a/drivers/gpu/drm/asahi/g15/mod.rs b/drivers/gpu/drm/asahi/g15/mod.rs index f8afd4fc7d2acd..010e5f0e5af4fc 100644 --- a/drivers/gpu/drm/asahi/g15/mod.rs +++ b/drivers/gpu/drm/asahi/g15/mod.rs @@ -203,6 +203,11 @@ impl platform::Driver for Driver<'_> { return Err(EPROBE_DEFER); } let cfg = *info.ok_or(ENODEV)?; + let cfg = if cfg.chip_id == 0x6034 && boot::glue::machine(c_str!("apple,j516m")) { + &hw::j516m::CONFIG + } else { + cfg + }; dev_info!(pdev.as_ref(), "G15: probing ({})\n", cfg.name); match crate::driver::AsahiPlatformDriver::probe_g15(pdev, cfg) { Ok(driver) => Some(driver), diff --git a/drivers/pmdomain/apple/pmp-report.c b/drivers/pmdomain/apple/pmp-report.c index fac35afc4e6cb2..adda6374407e01 100644 --- a/drivers/pmdomain/apple/pmp-report.c +++ b/drivers/pmdomain/apple/pmp-report.c @@ -699,10 +699,18 @@ static void apple_pmp_start_finish(struct apple_pmp_start *st, int result) st->result = result; complete_all(&st->started); } - if (result && READ_ONCE(st->enabled)) + if (result && READ_ONCE(st->enabled)) { + const char *fallback = st->rep->offsets->fallback; + + /* J516M shares the T6031 report layout, but has its own display gate. */ + if (of_machine_is_compatible("apple,t6034") && + of_machine_is_compatible("apple,j516m")) + fallback = "apple_t6034_display.enable=0"; + dev_err(st->rep->dev, "%s PMP start failed (%d) after the PMP was enabled: it may keep running until the next reboot. Reboot to stop it; to boot without starting it: %s, or nomodeset\n", - st->rep->offsets->name, result, st->rep->offsets->fallback); + st->rep->offsets->name, result, fallback); + } } /* Teardown has begun: a start still in progress gives up early. */ diff --git a/drivers/soc/apple/t6030-display-gate.c b/drivers/soc/apple/t6030-display-gate.c index 016abbcf6cf96f..07ba8b9f60f571 100644 --- a/drivers/soc/apple/t6030-display-gate.c +++ b/drivers/soc/apple/t6030-display-gate.c @@ -198,6 +198,21 @@ static bool __init gate_t6034_wanted(int sw) return gate_t6034_default_board() && gate_t6031_wanted(sw, true); } +/* + * J516M: the T6031 display layout on a T6034, with J514M's owner switch + * (apple_t6034_display.enable) and the same default: on unless it is 0. + */ +static bool __init gate_j516m_default_board(void) +{ + return of_machine_is_compatible("apple,t6034") && + of_machine_is_compatible("apple,j516m"); +} + +static bool __init gate_j516m_wanted(int sw) +{ + return gate_j516m_default_board() && gate_t6031_wanted(sw, true); +} + /* One SoC's internal display handoff, as the gate checks and completes it */ struct gate_soc { const char *machine; /* root compatible */ @@ -346,10 +361,38 @@ static const struct gate_soc gate_t6034 __initconst = { .fw_uuids = "asahi,t6034-fw-uuids", }; +static bool gate_j516m_requested __initdata; + +/* ADT-confirmed T6031 display layout, admitted only on the J516M. */ +static const struct gate_soc gate_j516m __initconst = { + .machine = "apple,j516m", + .prefix = "apple-t6034-display: ", + .name = "T6034", + .dcp_compat = "apple,t6031-dcp", + .display_compat = "apple,t6031-display-subsystem", + .marker = "apple,t6031-handoff", + .pwrstate_compat = "apple,t6031-pmgr-pwrstate", + .dcp_full_name = "dcp@386c00000", + .pmp_values = "/chosen/asahi,t6031-pmp", + .pmp_uuid = gate_t6031_pmp_uuid, + .report_compat = "apple,t6031-pmp-v2-report", + .disp_entry = "report@10", + .reuse_pmp = true, + .pmp_compat = "apple,t6031-pmp-v2", + .ans_entry = "report@21", + .requested = &gate_j516m_requested, + .ps_chain = { PMP_PS_DISP_FE, PMP_PS_DISP_CPU, PMP_PS_DISP_SYS }, + .pmp_ps_any_pmgr = true, + .describe = true, + .fw_uuids = "asahi,t6031-fw-uuids", + /* External displays (dcpext) are not qualified on the J516M: left off. */ +}; + static const struct gate_soc *const gate_socs[] __initconst = { &gate_t6030, &gate_t8122, &gate_t6031, + &gate_j516m, &gate_t6034, }; @@ -2053,6 +2096,16 @@ static void __init gate_run(void) board); } + if (gate_soc == &gate_j516m) { + if (!gate_j516m_default_board()) { + gate_info("unsupported board; native display stays disabled\n"); + return; + } + gate_j516m_requested = gate_j516m_wanted(gate_t6034_switch); + if (gate_t6034_switch < 0) + gate_info("native display on by default on J516M; apple_t6034_display.enable=0 keeps the boot framebuffer\n"); + } + if (gate_soc == &gate_t6034) { if (!gate_t6034_default_board()) { gate_info("unsupported board; native display stays disabled\n"); @@ -2064,7 +2117,11 @@ static void __init gate_run(void) } if (!*gate_soc->requested) { - if (gate_soc->opt_in && gate_t6031_switch < 0) + /* Each opt-in SoC's own switch: T6031's is not T6034's */ + int sw = gate_soc == &gate_t6034 || gate_soc == &gate_j516m ? + gate_t6034_switch : gate_t6031_switch; + + if (gate_soc->opt_in && sw < 0) gate_info("native display not requested (%s is not on the command line), display stays on the boot framebuffer\n", gate_soc->opt_in); else diff --git a/tools/asahi/dcp14-panel-tests.py b/tools/asahi/dcp14-panel-tests.py index 19c02cafd82010..8efbbcea6419ab 100755 --- a/tools/asahi/dcp14-panel-tests.py +++ b/tools/asahi/dcp14-panel-tests.py @@ -36,7 +36,10 @@ struct device {struct device_node *of_node;}; static const char *machine; static bool of_device_is_compatible(const struct device_node *n,const char *c){return !strcmp(n->compatible,c);} - static bool of_machine_is_compatible(const char*c){return !strcmp(machine,c);} + static bool of_machine_is_compatible(const char*c){ + if (!strcmp(machine,c)) return true; + return (!strcmp(machine,"apple,j514m") || !strcmp(machine,"apple,j516m")) && !strcmp(c,"apple,t6034"); + } static struct device_node fb={"simple-framebuffer"},dcp={"apple,t8122-dcp"}; static u32 width,height,stride,notch,marker_value=1; static const char *image_uuid; @@ -65,6 +68,9 @@ defines='\n'.join(l for l in src.splitlines() if l.startswith('#define DCP_V14_') and 'FIRMWARE_UUID' in l)+'\n' sel_start='const struct dcp_v14_board *dcp_v14_board_select(' if 'const struct dcp_v14_board *dcp_v14_board_select(' in src else 'const struct dcp_v14_board *iomfb_v14_7_board(' sel=src[src.index(sel_start):src.index('const char *iomfb_v14_7_board_name(')] + if 'bool dcp_v14_board_stamps_swaps(' in src: + stamp_start=src.index('bool dcp_v14_board_stamps_swaps(') + sel+=src[stamp_start:src.index('\n}',stamp_start)+2]+'\n' geo=src[src.index('static int dcp_v14_geometry('):src.index('/* An external processor\'s firmware:')] driver='''struct apple_dcp_v14 {struct device *dev;const struct dcp_v14_board *board;u32 fb_width,fb_height,stride,notch_rows,panel_width,panel_height;};\n''' probe=src[src.index('int iomfb_v14_7_probe('):] @@ -155,9 +161,22 @@ dcp.compatible="apple,t8122-dcp";assert(IS_ERR(iomfb_v14_7_board(&dev))); dcp.compatible="apple,t6031-dcp";machine="apple,j514s";assert(IS_ERR(iomfb_v14_7_board(&dev))); machine="apple,j613";assert(IS_ERR(iomfb_v14_7_board(&dev))); - machine="apple,j516m";assert(IS_ERR(iomfb_v14_7_board(&dev))); + machine="apple,j516m"; + const struct dcp_v14_board*m16=iomfb_v14_7_board(&dev); + assert(!IS_ERR(m16)&&m16&&!strcmp(m16->name,"J516M")); + assert(m16->promotion&&m16->swap_timestamps&&!m16->ctm_set); + assert(dcp_v14_board_stamps_swaps(m16,false)); + assert(!dcp_v14_board_stamps_swaps(m16,true)); + assert(!dcp_v14_board_stamps_swaps(NULL,false)); + image_uuid="F493F03E-CC40-3D89-9A08-5F259BA2B246"; + assert(probe_gate(&dev,m16)==0); + image_uuid="DDF38191-93B3-324A-BC8F-643006F5AC82"; + assert(probe_gate(&dev,m16)==-ENODEV); + marker_value=0;image_uuid=m16->firmware_uuid; + assert(probe_gate(&dev,m16)==-ENODEV);marker_value=1; + dcp.compatible="apple,t6030-dcp";machine="apple,j516s";assert(iomfb_v14_7_board(&dev)==&dcp_v14_board_t6030); - puts("current J615/J613/J504/T6030/J516C/J514C admission + hidden/full notch, wrong geometry controls: PASS"); + puts("current J615/J613/J504/T6030/J516C/J514C/J516M admission + hidden/full notch, wrong geometry controls: PASS"); #endif } ''' diff --git a/tools/asahi/g15-display-order-tests.py b/tools/asahi/g15-display-order-tests.py index 6ff26493965c60..8d18710802b587 100644 --- a/tools/asahi/g15-display-order-tests.py +++ b/tools/asahi/g15-display-order-tests.py @@ -221,9 +221,13 @@ 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 == &d31); + withdraw(&d31); + CHECK(prepare(&g34) == -EPROBE_DEFER && links_made == 2); + 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); @@ -328,7 +332,7 @@ def c_source(root): mod glue { use super::{call, STATE}; pub fn board() -> bool { call("board"); STATE.with(|s| s.borrow().board) } - pub fn machine(name: &str) -> bool { if !["apple,j514c", "apple,t6031", "apple,j514m", "apple,t6034"].contains(&name) { call("machine"); } STATE.with(|s| { let s=s.borrow(); match name { "apple,j514c" => s.j514c, "apple,t6031" => s.t6031, "apple,j514m" => s.j514m, "apple,t6034" => s.t6034, _ => s.machine } }) } + pub fn machine(name: &str) -> bool { if !["apple,j514c", "apple,t6031", "apple,j514m", "apple,j516m", "apple,t6034"].contains(&name) { call("machine"); } STATE.with(|s| { let s=s.borrow(); match name { "apple,j514c" => s.j514c, "apple,t6031" => s.t6031, "apple,j514m" => s.j514m, "apple,j516m" => false, "apple,t6034" => s.t6034, _ => s.machine } }) } pub unsafe fn asahi_g15_pmp_prepare(_: *mut core::ffi::c_void) -> core::ffi::c_int { call("pmp"); STATE.with(|s| s.borrow().pmp) } pub unsafe fn asahi_g15_display_prepare(_: *mut core::ffi::c_void) -> core::ffi::c_int { call("display"); STATE.with(|s| s.borrow().display) } pub fn dma_coherent(_: &super::device::Device) -> bool { call("coherent"); false } diff --git a/tools/asahi/g15-probe-init-tests.py b/tools/asahi/g15-probe-init-tests.py index 42b55f063359eb..3ee813480ae4fa 100644 --- a/tools/asahi/g15-probe-init-tests.py +++ b/tools/asahi/g15-probe-init-tests.py @@ -126,7 +126,10 @@ def item(text, marker): ) -> impl PinInit, Error> + 'bound; } } -struct Config { name: &'static str } +struct Config { name: &'static str, chip_id: u32 } +macro_rules! c_str { ($s:literal) => { $s } } +// The J516M probe swaps in its own profile; this fixture's device is never a J516M. +mod hw { pub mod j516m { pub static CONFIG: crate::Config = crate::Config { name: "j516m", chip_id: 0x6034 }; } } pub struct ThisModule; pub trait ModuleMetadata { const NAME: &'static std::ffi::CStr; } pub trait InPlaceModule: Sized { @@ -173,6 +176,7 @@ def item(text, marker): } mod boot { pub mod glue { pub fn retained() -> bool { crate::RETAINED.with(core::cell::Cell::get) } + pub fn machine(_compatible: &str) -> bool { false } pub unsafe fn asahi_g15_reprobe() { crate::activation_reprobe(); } // Reads the device tree and logs; no driver state. pub unsafe fn asahi_g15_report_loader_gpu() {} @@ -191,7 +195,7 @@ def item(text, marker): FAIL_ALLOC.set(fail_alloc); TOUCH.set(touch); PROBE_ERROR.set(error); RETAINED.set(false); ALLOCS.set(0); PROBES.set(0); } -static CFG: Config = Config { name: "test" }; +static CFG: Config = Config { name: "test", chip_id: 0x6034 }; static PDEV: platform::Device> = platform::Device { base: Device { data: Cell::new(core::ptr::null_mut()) }, ctx: PhantomData, }; diff --git a/tools/asahi/g15-t6034-profile-tests.py b/tools/asahi/g15-t6034-profile-tests.py index 4f73b5172aee76..ee8c2dccc5fb29 100644 --- a/tools/asahi/g15-t6034-profile-tests.py +++ b/tools/asahi/g15-t6034-profile-tests.py @@ -3,7 +3,7 @@ """Compile actual G15C profiles and test T6034 shape and exact firmware admission. The diagnostic profile has no firmware row. Once a measured row is present, -exercise its complete public identity and J514M binding without reading an image. +exercise the complete public identities and J514M/J516M bindings without reading an image. """ from pathlib import Path import subprocess @@ -47,6 +47,7 @@ def item(text, marker): @TYPES@ #[path="@T6031@"] pub(crate) mod t6031; #[path="@T6034@"] pub(crate) mod t6034; + #[path="@J516M@"] pub(crate) mod j516m; } } fn main() { @@ -107,7 +108,7 @@ def item(text, marker): assert_eq!(t6031::IOMAPS.iter().find(|m|m.slot==11).unwrap().map_bytes,8*0xd8000); } ''' -for token,replacement in {'@CONFIG@':config,'@REFERENCE@':reference,'@VALUE@':value,'@TYPES@':types,'@T6031@':str(G15/'hw/t6031.rs'),'@T6034@':str(G15/'hw/t6034.rs'),'@MATCHING@':str(G15/'identity/matching.rs'),'@LOOKUP@':str(G15/'identity/lookup.rs')}.items():source=source.replace(token,replacement) +for token,replacement in {'@CONFIG@':config,'@REFERENCE@':reference,'@VALUE@':value,'@TYPES@':types,'@T6031@':str(G15/'hw/t6031.rs'),'@T6034@':str(G15/'hw/t6034.rs'),'@J516M@':str(G15/'hw/j516m.rs'),'@MATCHING@':str(G15/'identity/matching.rs'),'@LOOKUP@':str(G15/'identity/lookup.rs')}.items():source=source.replace(token,replacement) identity=(G15/'identity.rs').read_text() # Run the production firmware admission against synthetic public identity bytes. firmware=item(identity,'pub(crate) fn firmware(') @@ -156,8 +157,15 @@ def item(text, marker): } ''' for token,replacement in {'FIRMWARE':firmware,'MATCHING':str(G15/'identity/matching.rs'),'LOOKUP':str(G15/'identity/lookup.rs')}.items():identity_source=identity_source.replace(token,replacement) +j516m_source = source.replace('let c=&t6034::CONFIG;', 'let c=&j516m::CONFIG;') +j516m_source = j516m_source.replace('use g15::hw::{t6031,t6034};', 'use g15::hw::{t6031,j516m};') +j516m_source = j516m_source.replace('apple,j514m', 'apple,j516m') +j516m_source = j516m_source.replace('b"apple,j516m",b"apple,j514s"', 'b"apple,j514m",b"apple,j514s"') +j516m_source = j516m_source.replace('0x7b5fc7f5fd', '0x7b5ed7f5fd') +j516m_source = j516m_source.replace('[0x1fd,0x1fd,0x1fc,0x1ed]', '[0x1fd,0x1fd,0x1ed,0x1ed]') +j516m_source = j516m_source.replace(' assert_eq!((c.hw_ids', ' assert!(j516m::identity_matches(0x07041100,0x0021040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041200,0x0021040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0001040a,0x7b5ed7f5fd));\n assert!(j516m::identity_matches(0x07041100,0x0021040a,0x7b5fc7f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0021040a,0x7b5ed7f5fc));\n assert!(!j516m::identity_matches(0x07041100,0x0021040a,0x7b5ed7f5ff));\n assert!(!j516m::identity_matches(0x07041100,0x0021040a,0));\n' + ' assert_eq!((c.hw_ids', 1) with tempfile.TemporaryDirectory(prefix='t6034-profile-') as temp: - for name,code in [('profile',source),('measurement-refusal',identity_source)]: + for name,code in [('profile-j514m',source),('profile-j516m',j516m_source),('measurement-refusal',identity_source)]: p=Path(temp)/name;p.with_suffix('.rs').write_text(code) subprocess.run(['rustc','--edition=2021','--cfg','CONFIG_DRM_ASAHI_G15','-o',str(p),str(p.with_suffix('.rs'))],check=True) subprocess.run([str(p)],check=True) diff --git a/tools/asahi/g15-zero-words-tests.py b/tools/asahi/g15-zero-words-tests.py index d443597fd1ca41..82141bcac76559 100644 --- a/tools/asahi/g15-zero-words-tests.py +++ b/tools/asahi/g15-zero-words-tests.py @@ -222,6 +222,7 @@ def main(): if name == 'hw.rs': # New SoC module wiring does not alter the golden T6030 profile. data = data.replace(b'#[cfg(CONFIG_DRM_ASAHI_G15)]\npub(crate) mod t6034;\n', b'') + data = data.replace(b'#[cfg(CONFIG_DRM_ASAHI_G15)]\npub(crate) mod j516m;\n', b'') actual = sha(data) if actual != expected: raise SystemExit("T6030 golden file changed: " + name) diff --git a/tools/asahi/t6034-display-tests.py b/tools/asahi/t6034-display-tests.py index ddd1cf54cc4c39..7647e4bcfebb0f 100644 --- a/tools/asahi/t6034-display-tests.py +++ b/tools/asahi/t6034-display-tests.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-only OR MIT -"""Run production J514M display selection and opt-out policy on the host.""" +"""Run production J514M and J516M display selection and opt-out policy on the host.""" from pathlib import Path import re import subprocess @@ -33,6 +33,7 @@ def item(s, marker): records=driver[driver.index('static const struct dcp_v14_board dcp_v14_board_t6030'):driver.index('struct dcp_v14_property {')] functions='\n'.join([item(gate,'static bool __init gate_t6031_wanted('), item(gate,'static bool __init gate_t6034_default_board('),item(gate,'static bool __init gate_t6034_wanted('), + item(gate,'static bool __init gate_j516m_default_board('),item(gate,'static bool __init gate_j516m_wanted('), item(driver,'const struct dcp_v14_board *dcp_v14_board_select('),item(driver,'bool dcp_v14_board_admits(')]) main = r''' int main(void) @@ -58,6 +59,26 @@ def item(s, marker): } board="apple,j514m";soc="apple,t6034";dcp="apple,t6031-dcp";bool known; assert(!dcp_v14_board_select(dcp_is,machine_is,NULL,&known)); + /* J516M: the T6031 display layout on a T6034; default on, apple_t6034_display.enable=0 off */ + for(unsigned i=0;iname,"J516M") && !strcmp(b->handoff,"apple,t6031-handoff")); + assert(b->promotion && b->swap_timestamps && !b->ctm_set); + assert(dcp_v14_board_admits(b,"F493F03E-CC40-3D89-9A08-5F259BA2B246")); + assert(!dcp_v14_board_admits(b,"DDF38191-93B3-324A-BC8F-643006F5AC82")); + } + } + board="apple,j516m";soc="apple,t6034";dcp="apple,t6034-dcp"; + assert(!dcp_v14_board_select(dcp_is,machine_is,NULL,&known)); return 0; } ''' @@ -67,6 +88,8 @@ def item(s, marker): 'lost-board-soc':source.replace('.soc = "apple,t6034",','.soc = NULL,'), 'lost-owner-optout':source.replace('return sw < 0 ? default_board : sw;','return sw < 0 ? default_board : true;'), 'lost-firmware-identity':source.replace('return uuid && !strcmp(uuid, board->firmware_uuid);','return uuid != NULL;'), + 'j516m-any-soc':source.replace('return of_machine_is_compatible("apple,t6034") &&\n\t of_machine_is_compatible("apple,j516m");','return of_machine_is_compatible("apple,j516m");'), + 'j516m-opt-in':source.replace('return gate_j516m_default_board() && gate_t6031_wanted(sw, true);','return gate_j516m_default_board() && sw > 0;'), } with tempfile.TemporaryDirectory(prefix='t6034-display-') as directory: for name,c in mutants.items(): @@ -76,7 +99,8 @@ def item(s, marker): assert (result.returncode==0)==(name=='control'),(name,result.stderr) print(name+': '+('pass' if name=='control' else 'caught')) assert 'gate_t6034_requested = gate_t6034_wanted(gate_t6034_switch);' in gate -print('T6034 normal display defaults, owner disable, exact root pair and firmware identity: PASS') +assert 'gate_j516m_requested = gate_j516m_wanted(gate_t6034_switch);' in gate +print('T6034 (J514M, J516M) normal display defaults, owner disable, exact root pair and firmware identity: PASS') # Compile the production report layout records and OF match table. Matching # T6034 through its generic T6020 fallback binds a report that never creates diff --git a/tools/aurora-ci/host-tests.json b/tools/aurora-ci/host-tests.json index fb9cdbdd66fc69..1a48d610093964 100644 --- a/tools/aurora-ci/host-tests.json +++ b/tools/aurora-ci/host-tests.json @@ -2226,7 +2226,7 @@ "tools/asahi/g15-t6034-profile-tests.py" ], "rust": "1.93.1", - "note": "Production G15C profiles, exact T6034 topology/six memory channels, full J514M firmware tuple and wrong-board/field refusal; strict nonempty and empty profiles never consult prefix overrides, while older policy remains unchanged. Public identity inputs only." + "note": "Production G15C profiles, exact T6034 topology/six memory channels, full J514M/J516M firmware tuples and wrong-board/field refusal; strict nonempty and empty profiles never consult prefix overrides, while older policy remains unchanged. Public identity inputs only." }, { "name": "tools/asahi/t6034-display-tests.py",