diff --git a/arch/arm64/boot/dts/apple/t6041-j614c-j616c.dtsi b/arch/arm64/boot/dts/apple/t6041-j614c-j616c.dtsi index de5eed04aed63..98337a09a596f 100644 --- a/arch/arm64/boot/dts/apple/t6041-j614c-j616c.dtsi +++ b/arch/arm64/boot/dts/apple/t6041-j614c-j616c.dtsi @@ -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 { @@ -459,6 +463,7 @@ panel: panel { apple,max-brightness = <500>; + status = "disabled"; }; }; diff --git a/drivers/gpu/drm/asahi/fwid.rs b/drivers/gpu/drm/asahi/fwid.rs index 34c65a0d8a097..514f09539dc73 100644 --- a/drivers/gpu/drm/asahi/fwid.rs +++ b/drivers/gpu/drm/asahi/fwid.rs @@ -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() { diff --git a/drivers/gpu/drm/asahi/g17/fw/render.rs b/drivers/gpu/drm/asahi/g17/fw/render.rs index 8fcc25500ab2d..f63821c904fd2 100644 --- a/drivers/gpu/drm/asahi/g17/fw/render.rs +++ b/drivers/gpu/drm/asahi/g17/fw/render.rs @@ -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); @@ -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); diff --git a/drivers/gpu/drm/asahi/g17/fw/variant.rs b/drivers/gpu/drm/asahi/g17/fw/variant.rs index c5287e66a641d..222473a8b8c36 100644 --- a/drivers/gpu/drm/asahi/g17/fw/variant.rs +++ b/drivers/gpu/drm/asahi/g17/fw/variant.rs @@ -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. diff --git a/drivers/gpu/drm/asahi/g17/mod.rs b/drivers/gpu/drm/asahi/g17/mod.rs index ffb0c20d0267f..df5a31f621a3c 100644 --- a/drivers/gpu/drm/asahi/g17/mod.rs +++ b/drivers/gpu/drm/asahi/g17/mod.rs @@ -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)?; @@ -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); @@ -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!( diff --git a/drivers/gpu/drm/asahi/hw/t6040.rs b/drivers/gpu/drm/asahi/hw/t6040.rs index d531e20c7e9f9..5f6b9944a811e 100644 --- a/drivers/gpu/drm/asahi/hw/t6040.rs +++ b/drivers/gpu/drm/asahi/hw/t6040.rs @@ -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 { diff --git a/drivers/gpu/drm/asahi/hw/t6041.rs b/drivers/gpu/drm/asahi/hw/t6041.rs index 8be466f7842ab..956aa0cc7728b 100644 --- a/drivers/gpu/drm/asahi/hw/t6041.rs +++ b/drivers/gpu/drm/asahi/hw/t6041.rs @@ -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, @@ -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, @@ -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: ®ISTER_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] = [ @@ -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(®ISTER_WINDOWS_25G83)); + let mut index = 0; + while index < REGISTER_WINDOWS.len() { + let (f84, g83) = (®ISTER_WINDOWS[index], ®ISTER_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 { diff --git a/drivers/gpu/drm/asahi/hw/t604x.rs b/drivers/gpu/drm/asahi/hw/t604x.rs index 961cef76cf4aa..6021419eeb1dd 100644 --- a/drivers/gpu/drm/asahi/hw/t604x.rs +++ b/drivers/gpu/drm/asahi/hw/t604x.rs @@ -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 +} diff --git a/drivers/soc/apple/display-gate-test.c b/drivers/soc/apple/display-gate-test.c index c767a064e9280..a732f844683b8 100644 --- a/drivers/soc/apple/display-gate-test.c +++ b/drivers/soc/apple/display-gate-test.c @@ -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 diff --git a/drivers/soc/apple/display-gate.c b/drivers/soc/apple/display-gate.c index bdb4b6dac2031..73c56cc29ca21 100644 --- a/drivers/soc/apple/display-gate.c +++ b/drivers/soc/apple/display-gate.c @@ -78,11 +78,12 @@ * driver of its own, t6041-display-gate.c, by Ryan Murray and František * Balázsy. * - * On the M4 Max (J616c, apple,t6041) the PMP never runs: iBoot leaves the - * external chains powered and the boot loader fills each external display - * processor's firmware memory. The gate enables a chain once its processor has - * that memory, before any device exists (see gate_t6041_max_run()), and never - * touches the internal display. + * On the M4 Max (J614c and J616c, apple,t6041) the internal display is + * handed over and enabled as on the M4 Pro. The PMP never runs there: iBoot + * leaves the external chains powered and the boot loader fills each external + * display processor's firmware memory. The gate enables a chain once its + * processor has that memory and the display subsystem is enabled, before any + * device exists (see gate_t6041_max_run()). */ #define pr_fmt(fmt) fmt @@ -336,11 +337,17 @@ static const struct gate_soc gate_t6041 __initconst = { static void __init gate_t6041_max_run(void); -/* T6041 (M4 Max): no PMP; the external chains follow the boot loader's firmware memory. */ +/* + * T6041 (M4 Max): the M4 Pro's internal display handoff; no PMP, so the + * external chains follow the boot loader's firmware memory. + */ static const struct gate_soc gate_t6041_max __initconst = { .machine = "apple,t6041", .prefix = "apple-t6041-display: ", .name = "T6041", + .dcp_compat = "apple,t6041-dcp", + .display_compat = "apple,display-subsystem", + .marker = "apple,t6041-handoff", .run = gate_t6041_max_run, }; @@ -3030,12 +3037,13 @@ static int __init t6041_max_apply(unsigned int i, struct device_node *display) } /* - * Each chain is enabled in one changeset, once its processor has firmware - * memory. A chain that has none, or is not all there and disabled (a boot - * loader that enabled it itself), stays as it is, and the other chain does not - * depend on it. The display subsystem only gains the DART of an enabled chain: - * its status is never written, so the internal display stays as the boot - * loader left it whatever happens here. + * The internal display first, as on the M4 Pro: an accepted handoff enables + * the display subsystem with the DCP. Then each external chain is enabled in + * one changeset, once its processor has firmware memory. A chain that has + * none, or is not all there and disabled (a boot loader that enabled it + * itself), stays as it is, and the other chain does not depend on it. The + * chains need the display subsystem enabled, by the handoff or by the boot + * loader, and only add their DARTs to it: its status is not written here. */ static void __init gate_t6041_max_run(void) { @@ -3046,10 +3054,15 @@ static void __init gate_t6041_max_run(void) if (IS_ENABLED(CONFIG_VIDEO) && video_firmware_drivers_only()) return; + gate_t6041_internal(); staged_prefix = gate_soc->prefix; display = of_find_node_by_path("/display-subsystem"); - if (!display || !of_device_is_available(display)) { + if (!display) { staged_err("no display subsystem, nothing enabled\n"); + return; + } + if (!of_device_is_available(display)) { + staged_info("display subsystem not enabled, external displays left off\n"); of_node_put(display); return; } diff --git a/drivers/soc/apple/t6041-gate-test.dtso b/drivers/soc/apple/t6041-gate-test.dtso index 96c0eaa541ced..d12929a73c0c9 100644 --- a/drivers/soc/apple/t6041-gate-test.dtso +++ b/drivers/soc/apple/t6041-gate-test.dtso @@ -7,8 +7,9 @@ * heap regions of both processors are the boot loader's disabled * placeholders, the text region the one it adds. * - * The display subsystem is the only node that is enabled. It sits at the - * root, as on the J616c, so a tree that has one does not get this applied. + * The display subsystem is the only node that is enabled, as the internal + * display handoff leaves it. It sits at the root, as on the J616c, so a tree + * that has one does not get this applied. */ /dts-v1/; diff --git a/tools/asahi/g17-firmware-selection-tests.py b/tools/asahi/g17-firmware-selection-tests.py index 771c9c19c6e1e..2a3cae91fdb08 100644 --- a/tools/asahi/g17-firmware-selection-tests.py +++ b/tools/asahi/g17-firmware-selection-tests.py @@ -34,6 +34,7 @@ def method(source, signature): image: u32, checked: std::cell::RefCell>, } +struct Config(u32); mod fw { pub struct Variant(pub u32); pub mod variant { @@ -43,6 +44,7 @@ def method(source, signature): pub name: &'static str, pub image: u32, pub variant: &'static Variant, + pub config: Option<&'static crate::Config>, } pub enum Firmware { Fixed(&'static Variant), Identified(&'static [Build]) } } @@ -60,9 +62,11 @@ def method(source, signature): } static FIRST: fw::Variant = fw::Variant(1); static SECOND: fw::Variant = fw::Variant(2); +static OWN: Config = Config(7); static BUILDS: [fw::variant::Build; 2] = [ - fw::variant::Build { os_version: [26,6,2], name: "first", image: 1, variant: &FIRST }, - fw::variant::Build { os_version: [27,0,0], name: "second", image: 2, variant: &SECOND }, + fw::variant::Build { os_version: [26,6,2], name: "first", image: 1, variant: &FIRST, config: None }, + fw::variant::Build { os_version: [27,0,0], name: "second", image: 2, variant: &SECOND, + config: Some(&OWN) }, ]; fn device(version: Option<[u32; 3]>, image: u32) -> AsahiDrmDevice { AsahiDrmDevice { version, image, checked: std::cell::RefCell::new(Vec::new()) } @@ -71,18 +75,26 @@ def method(source, signature): use fw::variant::Firmware; for version in [None, Some([26,6,2]), Some([26,7,0]), Some([99,0,0])] { let dev = device(version, 1); - assert_eq!(Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).unwrap().0, 1); + let (variant, config) = Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).unwrap(); + assert_eq!(variant.0, 1); + assert!(config.is_none(), "a build without its own configuration keeps the probed one"); } let dev = device(Some([27,0,0]), 1); - assert_eq!(Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).unwrap().0, 1); + assert_eq!(Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).unwrap().0.0, 1); assert_eq!(*dev.checked.borrow(), [2,1], "the OS version only orders the candidates"); + let dev = device(None, 2); + let (variant, config) = Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).unwrap(); + assert_eq!((variant.0, config.map(|c| c.0)), (2, Some(7)), "the identified build's configuration"); let dev = device(Some([26,6,2]), 9); assert!(Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).is_err()); assert_eq!(*dev.checked.borrow(), [1,2]); let dev = device(None, 9); - assert_eq!(Gpu::firmware_variant(&dev, &Firmware::Fixed(&SECOND)).unwrap().0, 2); + let (variant, config) = Gpu::firmware_variant(&dev, &Firmware::Fixed(&SECOND)).unwrap(); + assert_eq!(variant.0, 2); + assert!(config.is_none()); assert!(dev.checked.borrow().is_empty(), "fixed Neo admission is unchanged"); - println!("PASS G17 selection: exact image required, OS hint optional, fixed Neo unchanged"); + println!("PASS G17 selection: exact image required, OS hint optional, build configuration \ + follows the image, fixed Neo unchanged"); } ''' diff --git a/tools/asahi/g17-t6041-initdata-tests.py b/tools/asahi/g17-t6041-initdata-tests.py index 05ddc6b145d9d..a48174df48547 100644 --- a/tools/asahi/g17-t6041-initdata-tests.py +++ b/tools/asahi/g17-t6041-initdata-tests.py @@ -102,6 +102,7 @@ def item(source, start): ] T6041_ITEMS = SOC_ITEMS + [ + "pub(crate) const REGISTER_WINDOWS_25G83", "const RESERVED_SLOTS", "const MAX_POWER_MW", "const CHIP: ", @@ -190,9 +191,20 @@ def aux(name, rows): &t6041::RESERVED_SLOTS, &t6041::PERF, &T6041_OPPS, &T6041_AUX, &t6041::CHIP, &t6041::REGION_C, 40); println!("T6041 initialization objects built"); - std::fs::write(format!("{}/t6041-hwdata.bin", out), hw).unwrap(); - std::fs::write(format!("{}/t6041-power-config.bin", out), power).unwrap(); - std::fs::write(format!("{}/t6041-region-c.bin", out), region).unwrap(); + std::fs::write(format!("{}/t6041-hwdata.bin", out), &hw).unwrap(); + std::fs::write(format!("{}/t6041-power-config.bin", out), &power).unwrap(); + std::fs::write(format!("{}/t6041-region-c.bin", out), ®ion).unwrap(); + // 25G83: the same configuration with its own register map. + let (hw_g83, power_g83, region_g83) = build(t6041::CHIP_ID, &t6041::REGISTER_WINDOWS_25G83, + &[], &t6041::PERF, &T6041_OPPS, &T6041_AUX, &t6041::CHIP, &t6041::REGION_C, 40); + println!("T6041 25G83 initialization objects built"); + assert_eq!(power_g83, power, "the register map changes only the hardware data"); + assert_eq!(region_g83, region, "the register map changes only the hardware data"); + let map = 0x640..0x640 + REGISTER_MAP_SLOTS * core::mem::size_of::(); + let outside = |a: &[u8], b: &[u8]| a.iter().zip(b).enumerate() + .filter(|(i, (x, y))| x != y && !map.contains(i)).count(); + assert_eq!(outside(&hw_g83, &hw), 0, "the 25G83 hardware data differs only in its register map"); + std::fs::write(format!("{}/t6041-25g83-hwdata.bin", out), &hw_g83).unwrap(); } """