Skip to content
24 changes: 24 additions & 0 deletions arch/arm64/boot/dts/apple/t6034-j516m.dts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
/dts-v1/;

#include "t6034.dtsi"
#include "t6031-dcp.dtsi"
#include "t603x-j514-j516.dtsi"

/ {
Expand Down Expand Up @@ -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 {

Check warning on line 57 in arch/arm64/boot/dts/apple/t6034-j516m.dts

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check unmatched (1 DTB)

/soc/dcp@386c00000: compatible ['apple,t6031-dcp'] matches no binding In: apple/t6034-j516m.dtb failed to match any schema with compatible: ['apple,t6031-dcp']

Check warning on line 57 in arch/arm64/boot/dts/apple/t6034-j516m.dts

View workflow job for this annotation

GitHub Actions / requested build / device trees

dt-check unmatched (1 DTB)

/soc/dcp@386c00000: compatible ['apple,t6031-dcp'] matches no binding In: apple/t6034-j516m.dtb failed to match any schema with compatible: ['apple,t6031-dcp']
panel {
compatible = "apple,panel-j516", "apple,panel-mini-led", "apple,panel";
width-mm = <346>;
height-mm = <223>;
adj-height-mm = <216>;
};
};
3 changes: 3 additions & 0 deletions drivers/gpu/drm/apple/apple_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
25 changes: 23 additions & 2 deletions drivers/gpu/drm/apple/iomfb_v14_7.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
42 changes: 40 additions & 2 deletions drivers/gpu/drm/apple/v14-board-test.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/*
* The 14.x IOMFB board records: which record a DCP gets on which machine,
Expand Down Expand Up @@ -54,6 +54,8 @@
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 };
Expand Down Expand Up @@ -131,12 +133,47 @@
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));
Expand Down Expand Up @@ -318,6 +355,7 @@
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),
Expand Down
21 changes: 19 additions & 2 deletions drivers/gpu/drm/asahi/g15/boot.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! Admission and firmware start to READY.
Expand Down Expand Up @@ -480,6 +480,10 @@
&& 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);
Expand All @@ -494,7 +498,7 @@
}
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);
Expand All @@ -511,7 +515,7 @@
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,
Expand Down Expand Up @@ -681,6 +685,19 @@
);
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();
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/asahi/g15/glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/asahi/g15/hw.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! G15 hardware and firmware-ABI constants (layout values are shared by several modules; change
Expand All @@ -11,6 +11,8 @@
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 {
Expand Down
35 changes: 35 additions & 0 deletions drivers/gpu/drm/asahi/g15/hw/j516m.rs
Original file line number Diff line number Diff line change
@@ -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
}
5 changes: 5 additions & 0 deletions drivers/gpu/drm/asahi/g15/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! G15 GPU support (T6030, M3 Pro: J514S, J516S; firmware RTKit 2419, the macOS 14.7-14.8 stub).
Expand Down Expand Up @@ -203,6 +203,11 @@
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),
Expand Down
12 changes: 10 additions & 2 deletions drivers/pmdomain/apple/pmp-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
59 changes: 58 additions & 1 deletion drivers/soc/apple/t6030-display-gate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -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");
Expand All @@ -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
Expand Down
Loading
Loading