Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion arch/arm64/boot/dts/apple/t6041-j614c-j616c.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,13 @@
status = "okay";
};

/*
* As on the J616s, the display gate enables the display subsystem, the DCP,
* its DARTs, mailbox and panel once the boot loader has handed the internal
* display over (apple,t6041-handoff); otherwise the boot framebuffer stays.
*/
&display {
phandle = <&display>;
status = "okay";
};

&dcp {
Expand All @@ -459,6 +463,7 @@

panel: panel {
apple,max-brightness = <500>;
status = "disabled";
};
};

Expand Down
32 changes: 32 additions & 0 deletions drivers/gpu/drm/asahi/fwid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,38 @@ mod tests {
assert!(measured(build.images, 0x138000, [0x59839, 0x5991c], [0; 32]).is_none());
}

#[test]
fn t6041_builds_admit_only_their_own_images() {
let crate::g17::fw::variant::Firmware::Identified(builds) =
crate::hw::t6041::CONFIG.firmware
else {
panic!("T6041 must identify its loaded firmware");
};
assert_eq!(builds.len(), 2);
for (i, build) in builds.iter().enumerate() {
let other = &builds[1 - i];
for image in build.images {
let (entropy, digest) = (image.entropy, image.text_sha256);
let found = measured(build.images, image.data_size, entropy, digest);
assert!(core::ptr::eq(found.unwrap(), image));
assert!(measured(other.images, image.data_size, entropy, digest).is_none());
assert!(measured(build.images, 0x13c000, entropy, digest).is_none());
}
}
// Only the 25G83 build runs its own configuration: the 25G83 register map, 40 cores.
assert!(builds[0].config.is_none());
let g83 = builds[1].config.unwrap();
let map = &crate::hw::t6041::REGISTER_WINDOWS_25G83;
assert_eq!(g83.windows.len(), map.len());
for (window, expected) in g83.windows.iter().zip(map.iter()) {
assert_eq!((window.slot, window.va), (expected.slot, expected.va));
}
assert!(g83.reserved_slots.is_empty());
let cores = crate::hw::t6041::CONFIG.core_layout.cores;
assert_eq!(g83.core_layout.cores, cores);
assert_eq!(cores, Some((4, 40)));
}

#[cfg(CONFIG_DRM_ASAHI_G16)]
#[test]
fn j713_accepts_both_loaded_images() {
Expand Down
38 changes: 31 additions & 7 deletions drivers/gpu/drm/asahi/g17/fw/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1629,14 +1629,38 @@ mod ta_mode_tests {
}
}

/// The variants of the builds T6041 admits: 25F84, then 25G83.
fn t6041_variants() -> [&'static Variant; 2] {
let Firmware::Identified(builds) = crate::hw::t6041::CONFIG.firmware else {
panic!("T6041 must identify its loaded firmware");
};
assert_eq!(builds.len(), 2);
[builds[0].variant, builds[1].variant]
}

/// The TA mode of every admitted T6041 build.
fn t6041_ta_mode_1() -> bool {
let [f84, g83] = t6041_variants();
assert_eq!(f84.ta_mode_1, g83.ta_mode_1);
f84.ta_mode_1
}

#[test]
fn policy_is_local_to_the_admitted_t6041_build() {
let max = selected(&crate::hw::t6041::CONFIG.firmware);
fn policy_is_local_to_the_admitted_t6041_builds() {
let [f84, g83] = t6041_variants();
let pro = selected(&crate::hw::t6040::CONFIG.firmware);
assert_eq!(max.compute, crate::g17::fw::compute::ComputeProgram::V25F84);
assert!(max.split_firmware_area);
assert_eq!(max.programs, RegisterPrograms::V25G83);
assert!(max.ta_mode_1);
assert_eq!(f84.compute, crate::g17::fw::compute::ComputeProgram::V25F84);
assert!(f84.split_firmware_area);
// 25G83 keeps the M4 Pro's queue and compute rules on the M4 Max.
assert_eq!(g83.compute, pro.compute);
assert_eq!(g83.split_firmware_area, pro.split_firmware_area);
assert_eq!(g83.opening_record, pro.opening_record);
assert_eq!(g83.qid_floor, pro.qid_floor);
assert_eq!(g83.registration, pro.registration);
for max in [f84, g83] {
assert_eq!(max.programs, RegisterPrograms::V25G83);
assert!(max.ta_mode_1);
}
assert!(!pro.ta_mode_1);
assert!(!V25F84.ta_mode_1);
assert!(!V25G83.ta_mode_1);
Expand Down Expand Up @@ -1704,7 +1728,7 @@ mod ta_mode_tests {
for scs in [false, true] {
let mut args = args(&pass, &resources, scs);
let (before, count) = ta_registers_25g83(&args, &geometry, &words).unwrap();
args.ta_mode_1 = selected(&crate::hw::t6041::CONFIG.firmware).ta_mode_1;
args.ta_mode_1 = t6041_ta_mode_1();
let (after, new_count) = ta_registers_25g83(&args, &geometry, &words).unwrap();
assert_eq!(count, 83 + usize::from(scs));
assert_eq!(new_count, count);
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/asahi/g17/fw/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ pub(crate) struct Build {
pub(crate) images: &'static [crate::fwid::FirmwareBuild],
/// Layouts and rules of the build.
pub(crate) variant: &'static Variant,
/// The SoC configuration this build runs with, which replaces the probed one once the
/// build is identified; `None` keeps the probed configuration.
pub(crate) config: Option<&'static crate::g17::Config>,
}

/// How a SoC's firmware build is determined.
Expand Down
15 changes: 9 additions & 6 deletions drivers/gpu/drm/asahi/g17/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,9 @@ impl Gpu {
} else {
None
};
let variant = Self::firmware_variant(dev, &cfg.firmware)?;
let (variant, build_cfg) = Self::firmware_variant(dev, &cfg.firmware)?;
// A build with its own configuration of the SoC runs with that one.
let cfg = build_cfg.unwrap_or(cfg);
let id = regs.get_g17_id()?;
if let Some(calibration) = calibration {
calibration.check_cores(&id.core_masks)?;
Expand Down Expand Up @@ -1324,14 +1326,15 @@ impl Gpu {
Ok(gpu)
}

/// Returns the variant of the loaded firmware build. An identified SoC refuses a build it
/// does not know, before anything is written to the GPU.
/// Returns the variant of the loaded firmware build and the configuration it runs with, if
/// it has its own. An identified SoC refuses a build it does not know, before anything is
/// written to the GPU.
fn firmware_variant(
dev: &AsahiDrmDevice,
firmware: &fw::variant::Firmware,
) -> Result<&'static fw::Variant> {
) -> Result<(&'static fw::Variant, Option<&'static Config>)> {
let builds = match firmware {
fw::variant::Firmware::Fixed(variant) => return Ok(variant),
fw::variant::Firmware::Fixed(variant) => return Ok((variant, None)),
fw::variant::Firmware::Identified(builds) => builds,
};
let version = Self::os_firmware_version(dev);
Expand All @@ -1346,7 +1349,7 @@ impl Gpu {
for build in Iterator::chain(preferred, others) {
if Self::identify_image(dev, build).is_ok() {
dev_info!(dev.as_ref(), "GPU firmware: {}\n", build.name);
return Ok(build.variant);
return Ok((build.variant, build.config));
}
}
dev_err!(
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/asahi/hw/t6040.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub(crate) const CONFIG: Config = Config {
},
],
variant: &fw::variant::V25G83,
config: None,
}]),
// Measured on the 20-core M4 Pro; the alternative below remains experimental.
core_layout: CoreLayout {
Expand Down
158 changes: 137 additions & 21 deletions drivers/gpu/drm/asahi/hw/t6041.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use crate::hw::{GpuGen, GpuVariant};
use super::t604x::{instances, window};
use crate::mmu::UatQuirks;

pub(crate) const CONFIG: Config = Config {
/// What the configurations of both firmware builds share: the 40-core M4 Max measured with
/// 25F84. Only the register map is the build's own.
const BASE: Config = Config {
chip_id: CHIP_ID,
identity: Identity {
family: 0xa,
Expand Down Expand Up @@ -46,26 +48,7 @@ pub(crate) const CONFIG: Config = Config {
fabric_bridge: false,
recovery_slot_keys: None,
gpu_generation: GpuGen::G16,
firmware: fw::variant::Firmware::Identified(&[fw::variant::Build {
os_version: [26, 5, 2],
name: "macOS 26.5.2 (25F84, iBoot mBoot-18000.121.3)",
images: &[crate::fwid::FirmwareBuild {
name: "Apple GFX 25F84 for T6041 (normalized loaded image)",
text_size: 0x60000,
data_size: 0x138000,
entropy: [0x5983a, 0x5991d],
text_sha256: [
0x6d, 0xa4, 0xd4, 0x42, 0x35, 0x35, 0x14, 0x44, 0xf6, 0xec, 0x00, 0x33, 0xf1, 0x9c,
0xbf, 0x98, 0xd3, 0x43, 0x91, 0x28, 0x83, 0xe4, 0xe2, 0x94, 0xc1, 0x8b, 0xb8, 0xb8,
0xa3, 0xc1, 0x83, 0xe8,
],
}],
// macOS writes these tiler segment values on this machine, not the two-cluster ones.
variant: &fw::variant::Variant {
ta_mode_1: true,
..fw::variant::V25F84
},
}]),
firmware: fw::variant::Firmware::Identified(&[]),
core_layout: CoreLayout {
cores: Some((4, 40)),
alternate_core_masks: None,
Expand All @@ -75,6 +58,76 @@ pub(crate) const CONFIG: Config = Config {
},
};

/// The 40-core M4 Max. 25F84 runs this configuration; 25G83 runs [`CONFIG_25G83`].
pub(crate) const CONFIG: Config = Config {
firmware: fw::variant::Firmware::Identified(&BUILDS),
..BASE
};

const BUILDS: [fw::variant::Build; 2] = [
BUILD_25F84,
fw::variant::Build {
config: Some(&CONFIG_25G83),
..BUILD_25G83
},
];

const BUILD_25F84: fw::variant::Build = fw::variant::Build {
os_version: [26, 5, 2],
name: "macOS 26.5.2 (25F84, iBoot mBoot-18000.121.3)",
images: &[crate::fwid::FirmwareBuild {
name: "Apple GFX 25F84 for T6041 (normalized loaded image)",
text_size: 0x60000,
data_size: 0x138000,
entropy: [0x5983a, 0x5991d],
text_sha256: [
0x6d, 0xa4, 0xd4, 0x42, 0x35, 0x35, 0x14, 0x44, 0xf6, 0xec, 0x00, 0x33, 0xf1, 0x9c,
0xbf, 0x98, 0xd3, 0x43, 0x91, 0x28, 0x83, 0xe4, 0xe2, 0x94, 0xc1, 0x8b, 0xb8, 0xb8,
0xa3, 0xc1, 0x83, 0xe8,
],
}],
// macOS writes these tiler segment values on this machine, not the two-cluster ones.
variant: &fw::variant::Variant {
ta_mode_1: true,
..fw::variant::V25F84
},
config: None,
};

/// The macOS 26.6.2 boot firmware (iBoot mBoot-18000.161.10) loads the 25G83 build the M4 Pro
/// runs. iBoot fills part of the loaded TEXT for each Mac, so each admitted image is a
/// measurement. The one listed is the only T6041 image measured so far, on a 32-core J616C
/// (linux#1050); there the core count check of [`CONFIG_25G83`] refuses the GPU.
const BUILD_25G83: fw::variant::Build = fw::variant::Build {
os_version: [26, 6, 2],
name: "macOS 26.6.2 (25G83, iBoot mBoot-18000.161.10)",
images: &[crate::fwid::FirmwareBuild {
name: "Apple GFX 25G83 for T6041 (normalized loaded image, 32-core J616C)",
text_size: 0x60000,
data_size: 0x138000,
entropy: [0x59839, 0x5991c],
text_sha256: [
0xaa, 0x11, 0x3e, 0xd6, 0x20, 0x79, 0xbc, 0xfd, 0xee, 0xf0, 0xf8, 0x6c, 0x2a, 0x8d,
0x7e, 0xae, 0x9f, 0x90, 0x7b, 0x03, 0xbe, 0x28, 0xcc, 0xf2, 0x98, 0xc9, 0x43, 0x95,
0x1d, 0x0e, 0xff, 0xc5,
],
}],
// Four clusters: the tiler segment values of 25F84 on this machine.
variant: &fw::variant::Variant {
ta_mode_1: true,
..fw::variant::V25G83
},
config: None,
};

/// The 40-core M4 Max on 25G83: the 25F84 configuration with the 25G83 register map.
const CONFIG_25G83: Config = Config {
windows: &REGISTER_WINDOWS_25G83,
reserved_slots: &[],
firmware: fw::variant::Firmware::Identified(&[BUILD_25G83]),
..BASE
};

pub(crate) const CHIP_ID: u32 = 0x6041;

pub(crate) const REGISTER_WINDOWS: [RegisterWindow; 25] = [
Expand Down Expand Up @@ -113,6 +166,69 @@ pub(crate) const REGISTER_WINDOWS: [RegisterWindow; 25] = [
window(43, 0x2_88e6_0000, 0x2f_8000, 0x58, 0xe6_0000, 2),
];

/// The register map of the 25G83 build: the windows of [`REGISTER_WINDOWS`] (slot 3 holds the
/// eight memory controllers) laid out as 25G83 lays them out on the M4 Pro
/// ([`super::t6040::REGISTER_WINDOWS`]), from `+0x20_0000`, each window followed by a 16K
/// guard page, with no reserved slots. The windows after slot 3 lie 0x60000 further than the M4
/// Pro's, for its four more controllers.
pub(crate) const REGISTER_WINDOWS_25G83: [RegisterWindow; 25] = [
window(0, 0x5_0241_4000, 0x20_0000, 0x4000, 0, 2),
instances(
window(3, 0x2_201c_4000, 0x20_8000, 0x1_8000, 0, 2),
8,
0x200_0000,
),
window(4, 0x5_0244_c000, 0x2c_c000, 0x4000, 0, 0),
window(9, 0x5_003d_0000, 0x2d_4000, 0x4000, 0, 2),
window(10, 0x5_003c_0000, 0x2d_c000, 0x4000, 0, 0),
window(11, 0x5_003d_8000, 0x2e_4000, 0x4000, 0, 2),
window(12, 0x4_8565_c000, 0x2e_c000, 0x4000, 0, 2),
window(14, 0x5_0040_0000, 0x2f_4000, 0x1_0000, 0, 0),
window(15, 0x5_0cdc_0000, 0x30_8000, 0x4000, 0, 0),
window(17, 0x2_8800_0000, 0x31_0000, 0x2_1400, 0, 2),
instances(
window(20, 0x2_8b00_0000, 0x33_8000, 0x4_0000, 0, 2),
4,
0x20_0000,
),
window(22, 0x2_8900_0000, 0x43_c000, 0x8000, 0, 2),
window(26, 0x2_88d0_4000, 0x44_8000, 0x8000, 0xd0_4000, 2),
window(28, 0x2_88d5_8000, 0x45_4000, 0x8000, 0xd5_8000, 2),
window(29, 0x2_88d1_0000, 0x46_0000, 0x4000, 0xd1_0000, 2),
window(31, 0x2_88d4_0000, 0x46_8000, 0x4000, 0xd4_0000, 2),
window(32, 0x2_88d6_0000, 0x47_0000, 0x2_0000, 0xd6_0000, 2),
window(33, 0x2_88d4_4000, 0x49_4000, 0x4000, 0xd4_4000, 2),
window(34, 0x2_88d4_c000, 0x49_c000, 0x200, 0xd4_c000, 2),
window(35, 0x2_88e0_0000, 0x4a_4000, 0x4000, 0xe0_0000, 2),
window(37, 0x2_88e4_0000, 0x4a_c000, 0x4000, 0xe4_0000, 2),
window(39, 0x2_88e0_8000, 0x4b_4000, 0x8000, 0, 2),
window(40, 0x2_88e1_c000, 0x4c_0000, 0x4000, 0xe1_c000, 2),
window(41, 0x2_88e1_f800, 0x4c_b800, 0x4000, 0, 2),
window(43, 0x2_88e6_0000, 0x4d_4000, 0x58, 0xe6_0000, 2),
];

// The 25G83 map holds the 25F84 windows, laid out as 25G83 lays out the M4 Pro's.
const _: () = {
assert!(super::t604x::laid_out_25g83(
&super::t6040::REGISTER_WINDOWS
));
assert!(super::t604x::laid_out_25g83(&REGISTER_WINDOWS_25G83));
let mut index = 0;
while index < REGISTER_WINDOWS.len() {
let (f84, g83) = (&REGISTER_WINDOWS[index], &REGISTER_WINDOWS_25G83[index]);
assert!(
f84.slot == g83.slot
&& f84.phys == g83.phys
&& f84.size == g83.size
&& f84.unk_18 == g83.unk_18
&& f84.unk_20 == g83.unk_20
&& f84.instances == g83.instances
&& f84.phys_stride == g83.phys_stride
);
index += 1;
}
};

const RESERVED_SLOTS: [usize; 14] = [2, 5, 6, 7, 8, 27, 30, 38, 42, 46, 47, 48, 49, 52];

pub(crate) const PERF: PerfConfig = PerfConfig {
Expand Down
18 changes: 18 additions & 0 deletions drivers/gpu/drm/asahi/hw/t604x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,21 @@ pub(super) const fn instances(window: RegisterWindow, instances: u32, phys_strid
..window
}
}

/// Whether `windows` are laid out as the 25G83 build lays out its register map: in order from
/// `+0x20_0000`, the pages of each window's instances followed by a 16K guard page.
pub(super) const fn laid_out_25g83(windows: &[RegisterWindow]) -> bool {
let mut next = MMIO_APERTURE + 0x20_0000;
let mut index = 0;
while index < windows.len() {
let window = &windows[index];
let page_offset = window.phys & 0x3fff;
if window.va != next + page_offset {
return false;
}
let pages = (page_offset + window.size as u64 + 0x3fff) & !0x3fff;
next += pages * window.instances as u64 + 0x4000;
index += 1;
}
true
}
5 changes: 3 additions & 2 deletions drivers/soc/apple/display-gate-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
* leaves the internal panel alone.
* - T6041 on the J616c (t6041-gate-test.dtso): no PMP; each external chain
* is enabled once its processor has firmware memory, one without it or
* already enabled stays as it is, and the display subsystem is never
* written.
* already enabled stays as it is, and the chains never write the display
* subsystem's status. The tree has no dcp alias, so the internal display
* handoff finds nothing to adopt.
* Included at the end of display-gate.c.
*
* The test trees are applied once and stay: the gate gives some properties
Expand Down
Loading
Loading