From 64a542f098f32b1219931d486f836d13ed6722f4 Mon Sep 17 00:00:00 2001 From: AxxzyWasTaken Date: Tue, 3 Nov 2026 11:36:07 +0000 Subject: [PATCH 1/2] drm/asahi: add the T6041 25G83 profile captured on the J616C The 32-core M4 Max in the J616C boots through a macOS 26.6.2 stub (iBoot mBoot-18000.161.10), which loads a T6041 image of the 25G83 GPU firmware the M4 Pro runs. Its loaded TEXT (0x60000 bytes, GKTS and ECAP records at 0x59839 and 0x5991c, DATA 0x138000) normalizes to sha256 aa113ed62079bcfdeef0f86c2a8d7eae9f907b03be28ccf298c943951d0effc5. T6041 admits only its 25F84 image, on 40 cores, so this unit's GPU is refused. Admit that image as a second T6041 build. A firmware build can now name the SoC configuration it was measured with; once the build is identified, that configuration replaces the probed one. The 25F84 build names none and keeps its static profile; T6040 and T8140 only gain the empty fields. Built on the host from the driver sources, the T6041 25F84 hardware data, power configuration and region C, and the T6040 builder output, are byte-identical before and after this change. The 25G83 configuration (hw/t6041_25g83.rs) is the one the J616C has run with on this firmware: - 4 clusters with 32 enabled cores (core mask 0xf6_fdbf6fdb), which the probe requires. - Operand-state banks for all 40 core slots (0x80000 bytes), as for 25F84; the enabled slots run to 39. With banks for the 32 enabled cores only (0x68000 bytes, followed by the queue context), a compute load beside rendering hit reason-0 recoveries in 5 of 5 runs, and in 0 of 4 with 40 banks. - Four-cluster deflake and TA mode 1, as for 25F84. Clustered tiling hangs this GPU until the cluster buffers are sized for four clusters. - A compute pool of 96 blocks, which the J616C has run with since 23 Oct 2026; 21 blocks hang its firmware on grids of more than ten workgroups. - The captured register map: six memory controller instances in slot 3 (apple,sgx-active-mcc-bit-vector 0x3f, 32 MiB apart), which moves every window after it 0x30000 further than on the M4 Pro, and no reserved slots. Its hardware data, power configuration, region C and AON table are applied, not built: the contents built on this unit and captured from it on 25 Oct 2026 (hw/t6041_captured.rs), with only the runtime words written over them (completion-ring descriptors and QoS pointer; configuration-status pointer, AON pointer and random word). They equal what the 25G83 builders write for the M4 Pro except for the chip ID, the core count, the register map, four GPU cluster temperature sources, a second sensor-mask word, and the values below. Some captured values exist only because the device tree the J616C boots with has no GPU operating-point, CS or AFR tables and none of the calibration properties the T6040 builder reads (apple,perf-map-a/b, apple,perf-relative-a/b, apple,max-power-mw, the leakage coefficients): this unit's binned operating points in the performance, CS and AFR tables, its 110586 mW power limit and the coefficient derived from it, and the four clusters' leakage coefficients. With those tables in its device tree, the builders could produce them instead. The GPU is not started if the captured contents do not fit: it must have the captured 32 cores, the captured chip ID and register map must equal the configuration's (with no reserved slots), and the FNV-1a 64 hashes of the hardware data and power configuration without their runtime words, and of region C, must equal the capture's. On the host, the written contents hash to those values, and the checks refuse another chip ID, the 25F84 and T6040 register windows, a missing or duplicated window and reserved slots. Not run on hardware: the J616C has run these contents on this firmware only with the 7.2 port of the G17 driver. Signed-off-by: AxxzyWasTaken --- .../gpu/drm/asahi/g17/fw/initdata/v25g83.rs | 180 ++++- drivers/gpu/drm/asahi/g17/fw/render.rs | 32 +- drivers/gpu/drm/asahi/g17/fw/variant.rs | 3 + drivers/gpu/drm/asahi/g17/initdata/v25g83.rs | 187 +++-- drivers/gpu/drm/asahi/g17/mod.rs | 18 +- drivers/gpu/drm/asahi/hw/mod.rs | 2 + drivers/gpu/drm/asahi/hw/t6040.rs | 2 + drivers/gpu/drm/asahi/hw/t6041.rs | 48 +- drivers/gpu/drm/asahi/hw/t6041_25g83.rs | 193 +++++ drivers/gpu/drm/asahi/hw/t6041_captured.rs | 710 ++++++++++++++++++ drivers/gpu/drm/asahi/hw/t8140.rs | 1 + 11 files changed, 1276 insertions(+), 100 deletions(-) create mode 100644 drivers/gpu/drm/asahi/hw/t6041_25g83.rs create mode 100644 drivers/gpu/drm/asahi/hw/t6041_captured.rs diff --git a/drivers/gpu/drm/asahi/g17/fw/initdata/v25g83.rs b/drivers/gpu/drm/asahi/g17/fw/initdata/v25g83.rs index 863a90fc52a34..cf9e76ddd03ba 100644 --- a/drivers/gpu/drm/asahi/g17/fw/initdata/v25g83.rs +++ b/drivers/gpu/drm/asahi/g17/fw/initdata/v25g83.rs @@ -17,7 +17,7 @@ //! firmware on the M4 Pro, by evaluating them for this SoC; see the commit that added them. use super::{ - fill_words, perf_states, CompletionRingDescriptor, HwDataArgs, Opp, PerfGroup, + fill_words, perf_states, CompletionRingDescriptor, HwDataArgs, Opp, PerfGroup, RegionC, RegisterMapEntry, Words, COMPLETION_RING_ENTRIES, COMPLETION_RING_ENTRY_SIZE, COMPLETION_RING_INDEX, PERF_STATES, REGISTER_MAP_SLOTS, }; @@ -371,6 +371,24 @@ impl HwData25G83 { self.unk_25fc = 1; self.unk_2614 = 1; self.unk_261c = 0x100; + self.set_runtime_words(args); + self.unk_26c0 = 1; + self.unk_26c4 = 1; + self.unk_26f4 = 1; + // SAFETY: `HwData25G83` consists of integers only and has no padding, so any bytes are a + // valid value. + let bytes = unsafe { + core::slice::from_raw_parts_mut((self as *mut Self).cast::(), size_of::()) + }; + if let Some(chip) = ext.chip { + overlay_words(bytes, chip.hw_data_words)?; + } + Ok(()) + } + + /// Writes the words the host sets at every boot: the completion-ring descriptors and the + /// QoS pointer. + fn set_runtime_words(&mut self, args: &HwDataArgs<'_>) { for (ring, index) in args.completion_rings.iter().zip(COMPLETION_RING_INDEX) { self.completion_rings[index as usize] = CompletionRingDescriptor { low_va: ring.low_va, @@ -382,19 +400,80 @@ impl HwData25G83 { }; } self.qos_va = args.qos_va; - self.unk_26c0 = 1; - self.unk_26c4 = 1; - self.unk_26f4 = 1; - // SAFETY: `HwData25G83` consists of integers only and has no padding, so any bytes are a - // valid value. - let bytes = unsafe { - core::slice::from_raw_parts_mut((self as *mut Self).cast::(), size_of::()) - }; - if let Some(chip) = ext.chip { - overlay_words(bytes, chip.hw_data_words)?; + } + + /// Initializes the hardware data from captured contents, then writes the runtime words. + /// + /// The captured chip identifier and register map must be the ones `args` names: the + /// firmware finds its register windows through the map, and the driver maps exactly + /// `args.windows`. + pub(crate) fn init_captured(&mut self, captured: &Captured, args: &HwDataArgs<'_>) -> Result { + fill_words(self.bytes_mut(), captured.hw_data); + if !args.reserved_slots.is_empty() || { self.chip_id } != args.chip_id { + return Err(EINVAL); + } + let mut expected = [[0u8; size_of::()]; REGISTER_MAP_SLOTS]; + let mut used = [false; REGISTER_MAP_SLOTS]; + for window in args.windows { + match used.get_mut(window.slot) { + Some(used) if !*used => *used = true, + _ => return Err(EINVAL), + } + expected[window.slot] = RegisterMapEntry::window(window).to_bytes(); + } + let map = core::mem::offset_of!(Self, register_map); + let bytes = self.bytes_mut(); + for (slot, entry) in expected.iter().enumerate() { + let at = map + slot * entry.len(); + if bytes[at..at + entry.len()] != entry[..] { + return Err(EINVAL); + } } + self.set_runtime_words(args); Ok(()) } + + /// The runtime words, which [`Self::hash_captured`] leaves out. + const RUNTIME: [(usize, usize); 2] = [(COMPLETION_DESCRIPTORS, 0x80), (QOS_POINTER, 8)]; + + /// Hash of captured contents: everything but the runtime words. + pub(crate) fn hash_captured(&self) -> u64 { + hash_without(self.bytes(), &Self::RUNTIME) + } + + fn bytes(&self) -> &[u8] { + // SAFETY: `HwData25G83` consists of integers only and has no padding. + unsafe { + core::slice::from_raw_parts((self as *const Self).cast::(), size_of::()) + } + } + + fn bytes_mut(&mut self) -> &mut [u8] { + // SAFETY: `HwData25G83` consists of integers only and has no padding, so every byte is + // initialized and any byte pattern is a valid value. + unsafe { + core::slice::from_raw_parts_mut((self as *mut Self).cast::(), size_of::()) + } + } +} + +impl RegisterMapEntry { + /// The entry as the firmware reads it. + fn to_bytes(&self) -> [u8; size_of::()] { + let mut bytes = [0; size_of::()]; + for (at, field) in [ + (0x0, &self.phys.to_le_bytes()[..]), + (0x8, &self.va.to_le_bytes()[..]), + (0x10, &self.total_size.to_le_bytes()[..]), + (0x14, &self.element_size.to_le_bytes()[..]), + (0x18, &self.unk_18.to_le_bytes()[..]), + (0x20, &self.unk_20.to_le_bytes()[..]), + (0x24, &self.unk_24.to_le_bytes()[..]), + ] { + bytes[at..at + field.len()].copy_from_slice(field); + } + bytes + } } fn overlay_words(bytes: &mut [u8], words: Words) -> Result { @@ -633,15 +712,90 @@ impl PowerConfig25G83 { for offset in [0x9e0, 0x2a04] { self.0[offset..offset + 4].copy_from_slice(&power.to_le_bytes()); } + self.set_runtime_words(config_va, aon_va, entropy); + } + + pub(crate) fn apply_chip(&mut self, chip: &Chip) -> Result { + overlay_words(&mut self.0, chip.power_config_words) + } + + /// Initializes the power configuration from captured contents, then writes the runtime + /// words. + pub(crate) fn init_captured( + &mut self, + words: Words, + config_va: u64, + aon_va: u64, + entropy: u32, + ) { + fill_words(&mut self.0, words); + self.set_runtime_words(config_va, aon_va, entropy); + } + + /// Writes the pointers and the random word ([`Self::RUNTIME`]). + fn set_runtime_words(&mut self, config_va: u64, aon_va: u64, entropy: u32) { self.0[CONFIG_STATUS_POINTER..CONFIG_STATUS_POINTER + 8] .copy_from_slice(&(config_va + 0x80).to_le_bytes()); self.0[AON_POINTER..AON_POINTER + 8].copy_from_slice(&aon_va.to_le_bytes()); self.0[ENTROPY..ENTROPY + 4].copy_from_slice(&entropy.to_le_bytes()); } - pub(crate) fn apply_chip(&mut self, chip: &Chip) -> Result { - overlay_words(&mut self.0, chip.power_config_words) + /// The pointers and the random word, which [`Self::hash`] leaves out. + const RUNTIME: [(usize, usize); 3] = + [(CONFIG_STATUS_POINTER, 8), (AON_POINTER, 8), (ENTROPY, 4)]; + + /// Hash of the contents without the pointers and the random word. + pub(crate) fn hash(&self) -> u64 { + hash_without(&self.0, &Self::RUNTIME) + } +} + +/// 25G83 initialization contents captured on one unit, which a configuration whose device +/// tree has no inputs for the builders above applies instead of what they produce. Only the +/// runtime words are written over them. +pub(crate) struct Captured { + /// The [`HwData25G83`], without its runtime words. + pub(crate) hw_data: Words, + /// The [`PowerConfig25G83`] and its auxiliary data, without the runtime words. + pub(crate) power_config: Words, + /// Region C. + pub(crate) region_c: Words, + /// The AON temperature-source rows. + pub(crate) aon_table: &'static [u32], + /// Enabled GPU cores the contents were captured with. The captured performance tables + /// are that unit's binned operating points; another core count is another part. + pub(crate) active_cores: u32, + /// Hashes ([`hash_without`]) of the captured hardware data without its runtime words + /// ([`HwData25G83::hash_captured`]), power configuration ([`PowerConfig25G83::hash`]) and + /// region C, which what the driver wrote must equal. + pub(crate) expected: [u64; 3], +} + +impl RegionC { + /// Initializes region C from captured contents. + pub(crate) fn init_captured(&mut self, words: Words) { + // SAFETY: `RegionC` consists of integers only and is packed, so every byte is + // initialized and any byte pattern is a valid value. + let bytes = unsafe { + core::slice::from_raw_parts_mut((self as *mut Self).cast::(), size_of::()) + }; + fill_words(bytes, words); + } +} + +/// FNV-1a 64 of `bytes` with the `(offset, length)` ranges in `skip` left out. +pub(crate) fn hash_without(bytes: &[u8], skip: &[(usize, usize)]) -> u64 { + let mut hash = 0xcbf2_9ce4_8422_2325u64; + for (offset, byte) in bytes.iter().enumerate() { + if skip + .iter() + .any(|&(at, len)| (at..at + len).contains(&offset)) + { + continue; + } + hash = (hash ^ u64::from(*byte)).wrapping_mul(0x100_0000_01b3); } + hash } /// The AON temperature-source rows the power configuration names: the GPU cluster 0, GPU diff --git a/drivers/gpu/drm/asahi/g17/fw/render.rs b/drivers/gpu/drm/asahi/g17/fw/render.rs index 8fcc25500ab2d..f9eeb23cfe02e 100644 --- a/drivers/gpu/drm/asahi/g17/fw/render.rs +++ b/drivers/gpu/drm/asahi/g17/fw/render.rs @@ -1629,14 +1629,32 @@ 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); + 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 +1722,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..b87717b20881c 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 measured with this build, which replaces the probed one when + /// 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/initdata/v25g83.rs b/drivers/gpu/drm/asahi/g17/initdata/v25g83.rs index f7b1952685761..abe4d2bfdc3c0 100644 --- a/drivers/gpu/drm/asahi/g17/initdata/v25g83.rs +++ b/drivers/gpu/drm/asahi/g17/initdata/v25g83.rs @@ -98,7 +98,10 @@ impl InitData { let status_a_va = cluster_va + v::private::STATUS_A as u64; let status_b_va = cluster_va + v::private::STATUS_B as u64; let chip = cfg.chip; - let aon_table = chip.map_or(v::AON_TABLE.as_slice(), |chip| chip.aon_table); + let aon_table = match cfg.captured { + Some(captured) => captured.aon_table, + None => chip.map_or(v::AON_TABLE.as_slice(), |chip| chip.aon_table), + }; let aon_va = match aon_table.is_empty() { true => 0, false => self.object(objects.aon)?.gpu_va(), @@ -114,61 +117,65 @@ impl InitData { *va = self.object(index)?.gpu_va(); } - let opps = Self::opps(env.dev, cfg.opps, env.clusters)?; - let cs_opps = Self::opp_table(env.dev, c_str!("apple,cs-opp"))?; - let afr_opps = Self::opp_table(env.dev, c_str!("apple,afr-opp"))?; - let calibration = if chip.is_none() { - let calibration = Calibration::read(env.dev)?; - calibration.check_opps(&opps)?; - Some(calibration) + if let Some(captured) = cfg.captured { + self.write_captured_25g83(env, cfg, captured, active_cores, bundle, config_va, aon_va)?; } else { - None - }; - let (perf, max_power_mw, leakage) = match (calibration.as_ref(), chip) { - (Some(calibration), None) => ( - &calibration.perf, - calibration.max_power_mw, - &calibration.leakage, - ), - (None, Some(chip)) => (cfg.perf, chip.max_power_mw, &chip.leakage), - _ => return Err(EINVAL), - }; - let hw_args = abi::HwDataArgs { - chip_id: cfg.chip_id, - windows: cfg.windows, - reserved_slots: cfg.reserved_slots, - opps: &opps, - perf, - completion_rings: bundle.completion_rings, - qos_va: self.object(bundle.qos)?.gpu_va(), - }; - let hw_args_25g83 = v::HwDataArgs25G83 { - active_cores, - cs_opps: &cs_opps, - afr_opps: &afr_opps, - chip, - }; - // SAFETY: Plain C entropy source. - let entropy = unsafe { kernel::bindings::get_random_u32() }; - self.object_mut(self.bundle)? - .initialize::(0, |hw| { - hw.init(&hw_args, &hw_args_25g83)?; - Ok(()) - })?; - self.object_mut(self.bundle)? - .initialize::(v::POWER_CONFIG, |power| { - power.init(config_va, aon_va, entropy, max_power_mw, leakage); - if let Some(chip) = chip { - power.apply_chip(chip)?; - } - Ok(()) - })?; - self.object_mut(self.region_c)? - .initialize::(0, |region| { - region.init(cfg.region_c); - region.max_power_mw = max_power_mw; - Ok(()) - })?; + let opps = Self::opps(env.dev, cfg.opps, env.clusters)?; + let cs_opps = Self::opp_table(env.dev, c_str!("apple,cs-opp"))?; + let afr_opps = Self::opp_table(env.dev, c_str!("apple,afr-opp"))?; + let calibration = if chip.is_none() { + let calibration = Calibration::read(env.dev)?; + calibration.check_opps(&opps)?; + Some(calibration) + } else { + None + }; + let (perf, max_power_mw, leakage) = match (calibration.as_ref(), chip) { + (Some(calibration), None) => ( + &calibration.perf, + calibration.max_power_mw, + &calibration.leakage, + ), + (None, Some(chip)) => (cfg.perf, chip.max_power_mw, &chip.leakage), + _ => return Err(EINVAL), + }; + let hw_args = abi::HwDataArgs { + chip_id: cfg.chip_id, + windows: cfg.windows, + reserved_slots: cfg.reserved_slots, + opps: &opps, + perf, + completion_rings: bundle.completion_rings, + qos_va: self.object(bundle.qos)?.gpu_va(), + }; + let hw_args_25g83 = v::HwDataArgs25G83 { + active_cores, + cs_opps: &cs_opps, + afr_opps: &afr_opps, + chip, + }; + // SAFETY: Plain C entropy source. + let entropy = unsafe { kernel::bindings::get_random_u32() }; + self.object_mut(self.bundle)? + .initialize::(0, |hw| { + hw.init(&hw_args, &hw_args_25g83)?; + Ok(()) + })?; + self.object_mut(self.bundle)? + .initialize::(v::POWER_CONFIG, |power| { + power.init(config_va, aon_va, entropy, max_power_mw, leakage); + if let Some(chip) = chip { + power.apply_chip(chip)?; + } + Ok(()) + })?; + self.object_mut(self.region_c)? + .initialize::(0, |region| { + region.init(cfg.region_c); + region.max_power_mw = max_power_mw; + Ok(()) + })?; + } for (index, word) in aon_table.iter().enumerate() { self.object_mut(objects.aon)?.write(index * 4, *word)?; } @@ -256,4 +263,74 @@ impl InitData { fence(Ordering::SeqCst); Ok(()) } + + /// Writes the hardware data, power configuration and region C captured on one unit, with + /// this boot's runtime words over them, and checks the result against the capture's hashes. + /// No operating points are read from the device tree: the captured tables hold the unit's. + fn write_captured_25g83( + &mut self, + env: &BuildEnv<'_>, + cfg: &Config, + captured: &v::Captured, + active_cores: u32, + bundle: &BundleObjects, + config_va: u64, + aon_va: u64, + ) -> Result { + if active_cores != captured.active_cores { + dev_err!( + env.dev.as_ref(), + "25G83 initialization data was captured with {} cores, the GPU has {}\n", + captured.active_cores, + active_cores + ); + return Err(EINVAL); + } + let hw_args = abi::HwDataArgs { + chip_id: cfg.chip_id, + windows: cfg.windows, + reserved_slots: cfg.reserved_slots, + opps: &[], + perf: cfg.perf, + completion_rings: bundle.completion_rings, + qos_va: self.object(bundle.qos)?.gpu_va(), + }; + // SAFETY: Plain C entropy source. + let entropy = unsafe { kernel::bindings::get_random_u32() }; + let mut hashes = [0; 3]; + self.object_mut(self.bundle)? + .initialize::(0, |hw| { + hw.init_captured(captured, &hw_args).inspect_err(|_| { + dev_err!( + env.dev.as_ref(), + "Captured 25G83 hardware data does not match chip {:#x} and its register windows\n", + cfg.chip_id + ); + })?; + hashes[0] = hw.hash_captured(); + Ok(()) + })?; + self.object_mut(self.bundle)? + .initialize::(v::POWER_CONFIG, |power| { + power.init_captured(captured.power_config, config_va, aon_va, entropy); + hashes[1] = power.hash(); + Ok(()) + })?; + self.object_mut(self.region_c)? + .initialize::(0, |region| { + region.init_captured(captured.region_c); + Ok(()) + })?; + hashes[2] = v::hash_without(self.object_mut(self.region_c)?.bytes_mut(), &[]); + if hashes != captured.expected { + dev_err!( + env.dev.as_ref(), + "25G83 initialization data differs from its capture: {:#x?}, expected {:#x?}\n", + hashes, + captured.expected + ); + return Err(EINVAL); + } + Ok(()) + } } diff --git a/drivers/gpu/drm/asahi/g17/mod.rs b/drivers/gpu/drm/asahi/g17/mod.rs index ffb0c20d0267f..d3de36a70b63d 100644 --- a/drivers/gpu/drm/asahi/g17/mod.rs +++ b/drivers/gpu/drm/asahi/g17/mod.rs @@ -194,6 +194,9 @@ pub(crate) struct Config { /// The SoC's values of region C. pub(crate) region_c: &'static fw::initdata::RegionCConfig, pub(crate) chip: Option<&'static fw::initdata::v25g83::Chip>, + /// 25G83 initialization contents captured on one unit, written instead of what the + /// builders produce; `None` builds them. + pub(crate) captured: Option<&'static fw::initdata::v25g83::Captured>, /// Physical address of the firmware's per-slot recovery keys, read while the firmware is /// halted to attribute a fault; `None` where it is unknown (recovery then relies on the /// firmware's own blame). @@ -1173,7 +1176,9 @@ impl Gpu { } else { None }; - let variant = Self::firmware_variant(dev, &cfg.firmware)?; + let (variant, measured) = Self::firmware_variant(dev, &cfg.firmware)?; + // A build measured with its own configuration of the SoC runs with that one. + let cfg = measured.unwrap_or(cfg); let id = regs.get_g17_id()?; if let Some(calibration) = calibration { calibration.check_cores(&id.core_masks)?; @@ -1324,14 +1329,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 measured with it, + /// 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 +1352,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/mod.rs b/drivers/gpu/drm/asahi/hw/mod.rs index 438d071de971c..7c683a354e6c4 100644 --- a/drivers/gpu/drm/asahi/hw/mod.rs +++ b/drivers/gpu/drm/asahi/hw/mod.rs @@ -15,6 +15,8 @@ pub(crate) mod t600x; pub(crate) mod t602x; pub(crate) mod t6040; pub(crate) mod t6041; +mod t6041_25g83; +mod t6041_captured; mod t604x; pub(crate) mod t8103; pub(crate) mod t8112; diff --git a/drivers/gpu/drm/asahi/hw/t6040.rs b/drivers/gpu/drm/asahi/hw/t6040.rs index d531e20c7e9f9..ef65a67cb06c7 100644 --- a/drivers/gpu/drm/asahi/hw/t6040.rs +++ b/drivers/gpu/drm/asahi/hw/t6040.rs @@ -53,6 +53,7 @@ pub(crate) const CONFIG: Config = Config { }, region_c: ®ION_C, chip: None, + captured: None, adopt_root_entries: false, fabric_bridge: false, // The firmware's per-slot recovery keys are not known for this build; recovery relies on @@ -100,6 +101,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..4cd6b13b79d44 100644 --- a/drivers/gpu/drm/asahi/hw/t6041.rs +++ b/drivers/gpu/drm/asahi/hw/t6041.rs @@ -42,30 +42,40 @@ pub(crate) const CONFIG: Config = Config { }, region_c: ®ION_C, chip: Some(&CHIP), + captured: None, adopt_root_entries: false, 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 + // 25F84 runs the static profile of this configuration; 25G83 runs the profile captured on + // the 32-core J616C ([`super::t6041_25g83::CONFIG`]). + 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 + }, + config: None, }, - }]), + fw::variant::Build { + config: Some(&super::t6041_25g83::CONFIG), + ..super::t6041_25g83::BUILD + }, + ]), core_layout: CoreLayout { cores: Some((4, 40)), alternate_core_masks: None, diff --git a/drivers/gpu/drm/asahi/hw/t6041_25g83.rs b/drivers/gpu/drm/asahi/hw/t6041_25g83.rs new file mode 100644 index 0000000000000..2d5fdac2db501 --- /dev/null +++ b/drivers/gpu/drm/asahi/hw/t6041_25g83.rs @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +//! T6041 (M4 Max) on the 25G83 firmware build: the profile captured on the 32-core J616C. +//! +//! The J616C boots through a macOS 26.6.2 stub (iBoot mBoot-18000.161.10), which loads a T6041 +//! image of the 25G83 build the M4 Pro runs ([`fw::variant::V25G83`]). [`super::t6041::CONFIG`] +//! selects this configuration when it identifies that image. +//! +//! The hardware data, power configuration, region C and AON table are the ones built on this +//! unit and captured from it ([`super::t6041_captured`]), with only the runtime words written +//! over them ([`Captured`]): the device tree the J616C boots with has no GPU operating-point, +//! CS or AFR tables and no calibration for the builders. The register windows are the captured +//! register map; the GPU is not started if the two differ. + +use super::t604x::{instances, window}; +use super::{t6041, t6041_captured as captured}; +use crate::g17::fw::{ + self, + initdata::{v25g83::Captured, PerfConfig, RegionCConfig, RegisterWindow, PERF_STATES}, +}; +use crate::g17::{Config, CoreLayout, CrashBuffers, FixedBuffer, Identity}; +use crate::hw::{GpuGen, GpuVariant}; +use crate::mmu::UatQuirks; + +pub(super) const CONFIG: Config = Config { + chip_id: t6041::CHIP_ID, + identity: Identity { + family: 0xa, + // ID register 0x0a04_1100 (J616C): family 0xa, variant 4, revision 0x11 (B1). + variant: 4, + num_dies: 1, + gpu_variant: GpuVariant::C, + usc_generation: 3, + hal_generation: 200, + }, + uat_ias: 42, + uat_oas: 42, + secondary_root_offset: None, + crash_buffers: CrashBuffers::FirmwareData, + pm_metrics: FixedBuffer { + va: 0x10_0008_0000, + size: 0x8000, + }, + windows: ®ISTER_WINDOWS, + reserved_slots: &[], + perf: &PERF, + opps: OPPS, + // The M4 Pro's policy, which the J616C has run with on this build. + uat_quirks: UatQuirks { + reserved_tables: true, + clean_tables: true, + page_tlbi: true, + handoff_lock: false, + handoff_slot: 0xffff_ffff, + native_gpu_permissions: true, + }, + region_c: ®ION_C, + chip: None, + captured: Some(&CAPTURED), + adopt_root_entries: false, + fabric_bridge: false, + recovery_slot_keys: None, + gpu_generation: GpuGen::G16, + firmware: fw::variant::Firmware::Identified(&[BUILD]), + // The cores the contents were captured with; other core counts are refused at probe. + core_layout: CoreLayout { + cores: Some((4, 32)), + alternate_core_masks: None, + // Banks for all forty core slots: the firmware indexes them by physical slot, and the + // J616C's enabled slots run to 39 (core mask 0xf6_fdbf6fdb). + operand_state: fw::compute::OperandState::FOUR_BY_TEN, + deflake: fw::render::Deflake::FOUR_CLUSTERS, + // The compute pool the J616C has run with since 23 Oct 2026; the M4 Pro's 21 blocks + // hang this GPU's firmware on grids of more than ten workgroups. + compute_blocks: 96, + }, +}; + +/// The 25G83 build as the J616C loads it. +pub(super) const BUILD: 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)", + 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, + ], + }], + // Non-clustered tiling (TA mode 1), as for 25F84. Clustered tiling hangs the J616C unless + // the cluster buffers are sized for four clusters, which this driver does not do yet. + variant: &fw::variant::Variant { + ta_mode_1: true, + ..fw::variant::V25G83 + }, + config: None, +}; + +/// The captured register map: slot 3 holds the six memory controllers (ADT +/// `apple,sgx-active-mcc-bit-vector` 0x3f, 32 MiB apart), slot 20 the four AFR blocks. The +/// windows after slot 3 lie 0x30000 further than the M4 Pro's. +const REGISTER_WINDOWS: [RegisterWindow; 25] = [ + window(0, 0x5_0241_4000, 0x20_0000, 0x4000, 0, 2), + instances( + window(3, 0x2_201c_4000, 0x20_8000, 0x1_8000, 0, 2), + 6, + 0x200_0000, + ), + window(4, 0x5_0244_c000, 0x29_c000, 0x4000, 0, 0), + window(9, 0x5_003d_0000, 0x2a_4000, 0x4000, 0, 2), + window(10, 0x5_003c_0000, 0x2a_c000, 0x4000, 0, 0), + window(11, 0x5_003d_8000, 0x2b_4000, 0x4000, 0, 2), + window(12, 0x4_8565_c000, 0x2b_c000, 0x4000, 0, 2), + window(14, 0x5_0040_0000, 0x2c_4000, 0x1_0000, 0, 0), + window(15, 0x5_0cdc_0000, 0x2d_8000, 0x4000, 0, 0), + window(17, 0x2_8800_0000, 0x2e_0000, 0x2_1400, 0, 2), + instances( + window(20, 0x2_8b00_0000, 0x30_8000, 0x4_0000, 0, 2), + 4, + 0x20_0000, + ), + window(22, 0x2_8900_0000, 0x40_c000, 0x8000, 0, 2), + window(26, 0x2_88d0_4000, 0x41_8000, 0x8000, 0xd0_4000, 2), + window(28, 0x2_88d5_8000, 0x42_4000, 0x8000, 0xd5_8000, 2), + window(29, 0x2_88d1_0000, 0x43_0000, 0x4000, 0xd1_0000, 2), + window(31, 0x2_88d4_0000, 0x43_8000, 0x4000, 0xd4_0000, 2), + window(32, 0x2_88d6_0000, 0x44_0000, 0x2_0000, 0xd6_0000, 2), + window(33, 0x2_88d4_4000, 0x46_4000, 0x4000, 0xd4_4000, 2), + window(34, 0x2_88d4_c000, 0x46_c000, 0x200, 0xd4_c000, 2), + window(35, 0x2_88e0_0000, 0x47_4000, 0x4000, 0xe0_0000, 2), + window(37, 0x2_88e4_0000, 0x47_c000, 0x4000, 0xe4_0000, 2), + window(39, 0x2_88e0_8000, 0x48_4000, 0x8000, 0, 2), + window(40, 0x2_88e1_c000, 0x49_0000, 0x4000, 0xe1_c000, 2), + window(41, 0x2_88e1_f800, 0x49_b800, 0x4000, 0, 2), + window(43, 0x2_88e6_0000, 0x4a_4000, 0x58, 0xe6_0000, 2), +]; + +/// The ADT ladders of this unit (`apple,m4-index-a`, `apple,m4-index-b`, `apple,m4-relative-a`, +/// `apple,m4-relative-b`), which the captured performance tables hold. The builders, which +/// would use them, do not run for this configuration. +const PERF: PerfConfig = PerfConfig { + states_a: [0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 15], + states_b: [0, 1, 2, 3, 4, 5, 7, 9, 11, 13, 15], + relative_a: [0, 9, 16, 23, 29, 38, 49, 60, 69, 79, 100], + relative_b: [0, 0, 22, 36, 47, 57, 68, 78, 84, 91, 100], + sram_min_mv: 810, +}; + +const OPPS: usize = 16; + +const _: () = { + let mut index = 0; + while index < PERF_STATES { + assert!((PERF.states_a[index] as usize) < OPPS); + assert!((PERF.states_b[index] as usize) < OPPS); + index += 1; + } +}; + +/// Region C as captured: the M4 Pro's with this unit's power limit (110586 mW, +/// `apple,m4-max-power-mw`). Only the builders would use it. +const REGION_C: RegionCConfig = RegionCConfig { + unk_54: 0x0fa0, + unk_78: [1, 0, 0], + max_power_mw: 110_586, + unk_9c: 0, + unk_a0: 0, + unk_7c4: 1500, + unk_9e0: [ + 1, + 0x0102_0200, + 0x010a_2801, + 0x2802_0101, + 0x0101_010a, + 0x010a_2802, + 0x2801_0101, + 0x0001_010a, + ], +}; + +/// The contents captured on the J616C on 25 Oct 2026. +const CAPTURED: Captured = Captured { + hw_data: captured::HW_DATA, + power_config: captured::POWER_CONFIG, + region_c: captured::REGION_C, + aon_table: &captured::AON_TABLE, + active_cores: 32, + expected: captured::EXPECTED, +}; diff --git a/drivers/gpu/drm/asahi/hw/t6041_captured.rs b/drivers/gpu/drm/asahi/hw/t6041_captured.rs new file mode 100644 index 0000000000000..bbc8ef18e864d --- /dev/null +++ b/drivers/gpu/drm/asahi/hw/t6041_captured.rs @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +//! The 25G83 initialization contents of the M4 Max (T6041), captured on the J616C. +//! +//! Generated from `j616c-fwdata-dump-25oct.txt` (sha256 `fbf179298c02a67e…`), the nonzero +//! 32-byte rows of the hardware data, power configuration, region C and AON table that the +//! previous T6041 driver (j616c/b25, Gravity Linux encoders evaluated from the device tree) +//! built on this unit on 25 Oct 2026, the contents the GPU has run with since 22 Oct. +//! +//! The words the host writes at every boot are left out (zero here): the completion-ring +//! descriptors and QoS pointer of the hardware data, the configuration-status pointer, AON +//! pointer and random word of the power configuration. [`EXPECTED`] holds the hashes +//! ([`hash_without`](crate::g17::fw::initdata::v25g83::hash_without), without those words) of +//! the dumped objects; the GPU is not started if what the driver wrote differs. +//! +//! What differs from the M4 Pro constants: chip 0x6041, 32 enabled cores, this unit's binned +//! operating points (four voltage lanes, the 15-step ladders of the ADT), six memory controller +//! instances in register slot 3 (and the register windows after it 0x30000 further), the 110586 +//! mW power limit (`apple,m4-max-power-mw`, the M4 Pro's scaled to 32 cores), four GPU cluster +//! temperature sources, four clusters' leakage coefficients and the second temperature-sensor +//! mask word at `+0x3b5c`. + +/// The hardware data ([`HwData25G83`], `0x3db4` bytes at bundle `+0`), without the +/// completion-ring descriptors and the QoS pointer. +pub(super) const HW_DATA: &[(usize, u32, usize)] = &[ + (0x0004, 0x0000006f, 1), + (0x0008, 0xffc00000, 1), + (0x0014, 0x00000010, 1), + (0x001c, 0x00000010, 1), + (0x0020, 0xffff8000, 1), + (0x0024, 0x000002ff, 1), + (0x0028, 0x81400000, 1), + (0x002c, 0xfffffc21, 1), + (0x0640, 0x02414000, 1), + (0x0644, 0x00000005, 1), + (0x0648, 0x80200000, 1), + (0x064c, 0xfffffc21, 1), + (0x0650, 0x00004000, 2), + (0x0660, 0x00000002, 1), + (0x06b8, 0x201c4000, 1), + (0x06bc, 0x00000002, 1), + (0x06c0, 0x80208000, 1), + (0x06c4, 0xfffffc21, 1), + (0x06c8, 0x00090000, 1), + (0x06cc, 0x00018000, 1), + (0x06d8, 0x00000002, 1), + (0x06e0, 0x0244c000, 1), + (0x06e4, 0x00000005, 1), + (0x06e8, 0x8029c000, 1), + (0x06ec, 0xfffffc21, 1), + (0x06f0, 0x00004000, 2), + (0x07a8, 0x003d0000, 1), + (0x07ac, 0x00000005, 1), + (0x07b0, 0x802a4000, 1), + (0x07b4, 0xfffffc21, 1), + (0x07b8, 0x00004000, 2), + (0x07c8, 0x00000002, 1), + (0x07d0, 0x003c0000, 1), + (0x07d4, 0x00000005, 1), + (0x07d8, 0x802ac000, 1), + (0x07dc, 0xfffffc21, 1), + (0x07e0, 0x00004000, 2), + (0x07f8, 0x003d8000, 1), + (0x07fc, 0x00000005, 1), + (0x0800, 0x802b4000, 1), + (0x0804, 0xfffffc21, 1), + (0x0808, 0x00004000, 2), + (0x0818, 0x00000002, 1), + (0x0820, 0x8565c000, 1), + (0x0824, 0x00000004, 1), + (0x0828, 0x802bc000, 1), + (0x082c, 0xfffffc21, 1), + (0x0830, 0x00004000, 2), + (0x0840, 0x00000002, 1), + (0x0870, 0x00400000, 1), + (0x0874, 0x00000005, 1), + (0x0878, 0x802c4000, 1), + (0x087c, 0xfffffc21, 1), + (0x0880, 0x00010000, 2), + (0x0898, 0x0cdc0000, 1), + (0x089c, 0x00000005, 1), + (0x08a0, 0x802d8000, 1), + (0x08a4, 0xfffffc21, 1), + (0x08a8, 0x00004000, 2), + (0x08e8, 0x88000000, 1), + (0x08ec, 0x00000002, 1), + (0x08f0, 0x802e0000, 1), + (0x08f4, 0xfffffc21, 1), + (0x08f8, 0x00021400, 2), + (0x0908, 0x00000002, 1), + (0x0960, 0x8b000000, 1), + (0x0964, 0x00000002, 1), + (0x0968, 0x80308000, 1), + (0x096c, 0xfffffc21, 1), + (0x0970, 0x00100000, 1), + (0x0974, 0x00040000, 1), + (0x0980, 0x00000002, 1), + (0x09b0, 0x89000000, 1), + (0x09b4, 0x00000002, 1), + (0x09b8, 0x8040c000, 1), + (0x09bc, 0xfffffc21, 1), + (0x09c0, 0x00008000, 2), + (0x09d0, 0x00000002, 1), + (0x0a50, 0x88d04000, 1), + (0x0a54, 0x00000002, 1), + (0x0a58, 0x80418000, 1), + (0x0a5c, 0xfffffc21, 1), + (0x0a60, 0x00008000, 2), + (0x0a68, 0x00d04000, 1), + (0x0a70, 0x00000002, 1), + (0x0aa0, 0x88d58000, 1), + (0x0aa4, 0x00000002, 1), + (0x0aa8, 0x80424000, 1), + (0x0aac, 0xfffffc21, 1), + (0x0ab0, 0x00008000, 2), + (0x0ab8, 0x00d58000, 1), + (0x0ac0, 0x00000002, 1), + (0x0ac8, 0x88d10000, 1), + (0x0acc, 0x00000002, 1), + (0x0ad0, 0x80430000, 1), + (0x0ad4, 0xfffffc21, 1), + (0x0ad8, 0x00004000, 2), + (0x0ae0, 0x00d10000, 1), + (0x0ae8, 0x00000002, 1), + (0x0b18, 0x88d40000, 1), + (0x0b1c, 0x00000002, 1), + (0x0b20, 0x80438000, 1), + (0x0b24, 0xfffffc21, 1), + (0x0b28, 0x00004000, 2), + (0x0b30, 0x00d40000, 1), + (0x0b38, 0x00000002, 1), + (0x0b40, 0x88d60000, 1), + (0x0b44, 0x00000002, 1), + (0x0b48, 0x80440000, 1), + (0x0b4c, 0xfffffc21, 1), + (0x0b50, 0x00020000, 2), + (0x0b58, 0x00d60000, 1), + (0x0b60, 0x00000002, 1), + (0x0b68, 0x88d44000, 1), + (0x0b6c, 0x00000002, 1), + (0x0b70, 0x80464000, 1), + (0x0b74, 0xfffffc21, 1), + (0x0b78, 0x00004000, 2), + (0x0b80, 0x00d44000, 1), + (0x0b88, 0x00000002, 1), + (0x0b90, 0x88d4c000, 1), + (0x0b94, 0x00000002, 1), + (0x0b98, 0x8046c000, 1), + (0x0b9c, 0xfffffc21, 1), + (0x0ba0, 0x00000200, 2), + (0x0ba8, 0x00d4c000, 1), + (0x0bb0, 0x00000002, 1), + (0x0bb8, 0x88e00000, 1), + (0x0bbc, 0x00000002, 1), + (0x0bc0, 0x80474000, 1), + (0x0bc4, 0xfffffc21, 1), + (0x0bc8, 0x00004000, 2), + (0x0bd0, 0x00e00000, 1), + (0x0bd8, 0x00000002, 1), + (0x0c08, 0x88e40000, 1), + (0x0c0c, 0x00000002, 1), + (0x0c10, 0x8047c000, 1), + (0x0c14, 0xfffffc21, 1), + (0x0c18, 0x00004000, 2), + (0x0c20, 0x00e40000, 1), + (0x0c28, 0x00000002, 1), + (0x0c58, 0x88e08000, 1), + (0x0c5c, 0x00000002, 1), + (0x0c60, 0x80484000, 1), + (0x0c64, 0xfffffc21, 1), + (0x0c68, 0x00008000, 2), + (0x0c78, 0x00000002, 1), + (0x0c80, 0x88e1c000, 1), + (0x0c84, 0x00000002, 1), + (0x0c88, 0x80490000, 1), + (0x0c8c, 0xfffffc21, 1), + (0x0c90, 0x00004000, 2), + (0x0c98, 0x00e1c000, 1), + (0x0ca0, 0x00000002, 1), + (0x0ca8, 0x88e1f800, 1), + (0x0cac, 0x00000002, 1), + (0x0cb0, 0x8049b800, 1), + (0x0cb4, 0xfffffc21, 1), + (0x0cb8, 0x00004000, 2), + (0x0cc8, 0x00000002, 1), + (0x0cf8, 0x88e60000, 1), + (0x0cfc, 0x00000002, 1), + (0x0d00, 0x804a4000, 1), + (0x0d04, 0xfffffc21, 1), + (0x0d08, 0x00000058, 2), + (0x0d10, 0x00e60000, 1), + (0x0d18, 0x00000002, 1), + (0x0e90, 0x00006041, 1), + (0x0e94, 0x00000001, 2), + (0x0ea0, 0x00000001, 2), + (0x0eb8, 0x00000001, 1), + (0x0ec0, 0x00000001, 1), + (0x0ec8, 0x00000001, 1), + (0x0ed0, 0x00005dc0, 1), + (0x0ed4, 0x00000001, 1), + (0x0ed8, 0x00000008, 1), + (0x0ee0, 0x00000001, 3), + (0x0f04, 0x0000001f, 1), + (0x0f24, 0x07002004, 1), + (0x0f28, 0x00000006, 1), + (0x0f34, 0x00000001, 2), + (0x0f4c, 0x00000031, 1), + (0x0f88, 0x00000020, 1), + (0x0f8c, 0x0000000f, 1), + (0x0fb8, 0x0000001c, 1), + (0x0fbc, 0x00000004, 1), + (0x0fc0, 0x00000020, 1), + (0x0fc4, 0x0000000a, 1), + (0x0fcc, 0x00000152, 1), + (0x0fd0, 0x0000026a, 1), + (0x0fd4, 0x0000031c, 1), + (0x0fd8, 0x0000039c, 1), + (0x0fdc, 0x00000420, 1), + (0x0fe0, 0x0000049e, 1), + (0x0fe4, 0x00000520, 1), + (0x0fe8, 0x00000564, 1), + (0x0fec, 0x000005be, 1), + (0x0ff0, 0x0000062a, 1), + (0x1008, 0x0000007d, 4), + (0x1048, 0x00000258, 1), + (0x104c, 0x00000253, 1), + (0x1050, 0x00000267, 1), + (0x1054, 0x00000258, 1), + (0x1088, 0x0000028a, 1), + (0x108c, 0x00000285, 1), + (0x1090, 0x00000294, 2), + (0x10c8, 0x000002b7, 1), + (0x10cc, 0x000002b2, 1), + (0x10d0, 0x000002c1, 1), + (0x10d4, 0x000002bc, 1), + (0x1108, 0x000002d0, 2), + (0x1110, 0x000002d5, 1), + (0x1114, 0x000002cb, 1), + (0x1148, 0x00000302, 1), + (0x114c, 0x000002f8, 1), + (0x1150, 0x00000307, 1), + (0x1154, 0x00000302, 1), + (0x1188, 0x0000032f, 1), + (0x118c, 0x00000325, 3), + (0x11c8, 0x00000366, 1), + (0x11cc, 0x00000352, 1), + (0x11d0, 0x00000357, 1), + (0x11d4, 0x0000035c, 1), + (0x1208, 0x0000038e, 1), + (0x120c, 0x0000037a, 1), + (0x1210, 0x0000037f, 1), + (0x1214, 0x00000384, 1), + (0x1248, 0x000003b6, 1), + (0x124c, 0x000003a2, 1), + (0x1250, 0x000003a7, 1), + (0x1254, 0x000003ac, 1), + (0x1288, 0x00000406, 1), + (0x128c, 0x00000401, 1), + (0x1290, 0x00000406, 1), + (0x1294, 0x000003fc, 1), + (0x1408, 0x0000032a, 4), + (0x1448, 0x0000032a, 4), + (0x1488, 0x0000032a, 4), + (0x14c8, 0x0000032a, 4), + (0x1508, 0x0000032a, 4), + (0x1548, 0x0000032a, 4), + (0x1588, 0x0000032f, 1), + (0x158c, 0x0000032a, 3), + (0x15c8, 0x00000366, 1), + (0x15cc, 0x00000352, 1), + (0x15d0, 0x00000357, 1), + (0x15d4, 0x0000035c, 1), + (0x1608, 0x0000038e, 1), + (0x160c, 0x0000037a, 1), + (0x1610, 0x0000037f, 1), + (0x1614, 0x00000384, 1), + (0x1648, 0x000003b6, 1), + (0x164c, 0x000003a2, 1), + (0x1650, 0x000003a7, 1), + (0x1654, 0x000003ac, 1), + (0x1688, 0x00000406, 1), + (0x168c, 0x00000401, 1), + (0x1690, 0x00000406, 1), + (0x1694, 0x000003fc, 1), + (0x180c, 0x00000152, 1), + (0x1810, 0x0000026a, 1), + (0x1814, 0x0000031c, 1), + (0x1818, 0x0000039c, 1), + (0x181c, 0x000003b8, 1), + (0x1820, 0x00000426, 1), + (0x1824, 0x0000049e, 1), + (0x1828, 0x000004da, 1), + (0x182c, 0x0000052e, 1), + (0x1830, 0x0000062a, 1), + (0x1848, 0x3f828f5c, 11), + (0x18cc, 0x00000009, 1), + (0x18d0, 0x00000010, 1), + (0x18d4, 0x00000017, 1), + (0x18d8, 0x0000001d, 1), + (0x18dc, 0x00000026, 1), + (0x18e0, 0x00000031, 1), + (0x18e4, 0x0000003c, 1), + (0x18e8, 0x00000045, 1), + (0x18ec, 0x0000004f, 1), + (0x18f0, 0x00000064, 1), + (0x1910, 0x00000016, 1), + (0x1914, 0x00000024, 1), + (0x1918, 0x0000002f, 1), + (0x191c, 0x00000039, 1), + (0x1920, 0x00000044, 1), + (0x1924, 0x0000004e, 1), + (0x1928, 0x00000054, 1), + (0x192c, 0x0000005b, 1), + (0x1930, 0x00000064, 1), + (0x19cc, 0x00000001, 1), + (0x19d0, 0x00000002, 1), + (0x19d4, 0x00000003, 1), + (0x19d8, 0x00000004, 1), + (0x19dc, 0x00000006, 1), + (0x19e0, 0x00000008, 1), + (0x19e4, 0x0000000a, 1), + (0x19e8, 0x0000000c, 1), + (0x19ec, 0x0000000e, 1), + (0x19f0, 0x0000000f, 1), + (0x1a0c, 0x00000001, 1), + (0x1a10, 0x00000002, 1), + (0x1a14, 0x00000003, 1), + (0x1a18, 0x00000004, 1), + (0x1a1c, 0x00000005, 1), + (0x1a20, 0x00000007, 1), + (0x1a24, 0x00000009, 1), + (0x1a28, 0x0000000b, 1), + (0x1a2c, 0x0000000d, 1), + (0x1a30, 0x0000000f, 1), + (0x1a48, 0x00000007, 2), + (0x1a50, 0x00000018, 1), + (0x1a54, 0x00000152, 1), + (0x1a58, 0x0000026a, 1), + (0x1a5c, 0x0000031c, 1), + (0x1a60, 0x000003e0, 1), + (0x1a64, 0x000004a4, 1), + (0x1a68, 0x00000564, 1), + (0x1a6c, 0x000005be, 1), + (0x1a90, 0x00000249, 1), + (0x1a98, 0x00000249, 1), + (0x1aa0, 0x00000276, 1), + (0x1aa8, 0x000002a8, 1), + (0x1ab0, 0x000002d0, 1), + (0x1ab8, 0x00000302, 1), + (0x1ac0, 0x00000361, 1), + (0x1ac8, 0x00000384, 1), + (0x1b10, 0x0000032a, 1), + (0x1b18, 0x0000032a, 1), + (0x1b20, 0x0000032a, 1), + (0x1b28, 0x0000032a, 1), + (0x1b30, 0x0000032a, 1), + (0x1b38, 0x0000032a, 1), + (0x1b40, 0x00000361, 1), + (0x1b48, 0x00000384, 1), + (0x1b90, 0x00000007, 2), + (0x1b98, 0x00000018, 1), + (0x1b9c, 0x00000152, 1), + (0x1ba0, 0x0000026a, 1), + (0x1ba4, 0x0000031c, 1), + (0x1ba8, 0x000003e0, 1), + (0x1bac, 0x000004a4, 1), + (0x1bb0, 0x00000564, 1), + (0x1bb4, 0x000005be, 1), + (0x1bd8, 0x00000249, 1), + (0x1be0, 0x00000249, 1), + (0x1be8, 0x00000276, 1), + (0x1bf0, 0x000002a8, 1), + (0x1bf8, 0x000002d0, 1), + (0x1c00, 0x00000302, 1), + (0x1c08, 0x00000361, 1), + (0x1c10, 0x00000384, 1), + (0x1c58, 0x0000032a, 1), + (0x1c60, 0x0000032a, 1), + (0x1c68, 0x0000032a, 1), + (0x1c70, 0x0000032a, 1), + (0x1c78, 0x0000032a, 1), + (0x1c80, 0x0000032a, 1), + (0x1c88, 0x00000361, 1), + (0x1c90, 0x00000384, 1), + (0x1cd8, 0x0000000a, 1), + (0x1ce0, 0x00000152, 1), + (0x1ce4, 0x0000026a, 1), + (0x1ce8, 0x0000031c, 1), + (0x1cec, 0x0000039c, 1), + (0x1cf0, 0x000003b8, 1), + (0x1cf4, 0x00000426, 1), + (0x1cf8, 0x0000049e, 1), + (0x1cfc, 0x000004da, 1), + (0x1d00, 0x0000052e, 1), + (0x1d04, 0x0000062a, 1), + (0x1d1c, 0x0000007d, 4), + (0x1d5c, 0x00000258, 1), + (0x1d60, 0x00000253, 1), + (0x1d64, 0x00000267, 1), + (0x1d68, 0x00000258, 1), + (0x1d9c, 0x0000028a, 1), + (0x1da0, 0x00000285, 1), + (0x1da4, 0x00000294, 2), + (0x1ddc, 0x000002b7, 1), + (0x1de0, 0x000002b2, 1), + (0x1de4, 0x000002c1, 1), + (0x1de8, 0x000002bc, 1), + (0x1e1c, 0x000002d0, 2), + (0x1e24, 0x000002d5, 1), + (0x1e28, 0x000002cb, 1), + (0x1e5c, 0x00000302, 1), + (0x1e60, 0x000002f8, 1), + (0x1e64, 0x00000307, 1), + (0x1e68, 0x00000302, 1), + (0x1e9c, 0x0000032f, 1), + (0x1ea0, 0x00000325, 3), + (0x1edc, 0x00000366, 1), + (0x1ee0, 0x00000352, 1), + (0x1ee4, 0x00000357, 1), + (0x1ee8, 0x0000035c, 1), + (0x1f1c, 0x0000038e, 1), + (0x1f20, 0x0000037a, 1), + (0x1f24, 0x0000037f, 1), + (0x1f28, 0x00000384, 1), + (0x1f5c, 0x000003b6, 1), + (0x1f60, 0x000003a2, 1), + (0x1f64, 0x000003a7, 1), + (0x1f68, 0x000003ac, 1), + (0x1f9c, 0x00000406, 1), + (0x1fa0, 0x00000401, 1), + (0x1fa4, 0x00000406, 1), + (0x1fa8, 0x000003fc, 1), + (0x211c, 0x0000032a, 4), + (0x215c, 0x0000032a, 4), + (0x219c, 0x0000032a, 4), + (0x21dc, 0x0000032a, 4), + (0x221c, 0x0000032a, 4), + (0x225c, 0x0000032a, 4), + (0x229c, 0x0000032f, 1), + (0x22a0, 0x0000032a, 3), + (0x22dc, 0x00000366, 1), + (0x22e0, 0x00000352, 1), + (0x22e4, 0x00000357, 1), + (0x22e8, 0x0000035c, 1), + (0x231c, 0x0000038e, 1), + (0x2320, 0x0000037a, 1), + (0x2324, 0x0000037f, 1), + (0x2328, 0x00000384, 1), + (0x235c, 0x000003b6, 1), + (0x2360, 0x000003a2, 1), + (0x2364, 0x000003a7, 1), + (0x2368, 0x000003ac, 1), + (0x239c, 0x00000406, 1), + (0x23a0, 0x00000401, 1), + (0x23a4, 0x00000406, 1), + (0x23a8, 0x000003fc, 1), + (0x2544, 0x00000005, 1), + (0x2548, 0x00000006, 1), + (0x254c, 0x00000003, 1), + (0x2550, 0x00000007, 2), + (0x2570, 0x00000020, 1), + (0x2578, 0x00000001, 1), + (0x259c, 0x00000001, 3), + (0x25ac, 0x00000001, 3), + (0x25bc, 0xffffffff, 12), + (0x25f4, 0x00000002, 1), + (0x25fc, 0x00000001, 1), + (0x2614, 0x00000001, 1), + (0x261c, 0x00000100, 1), + (0x26c0, 0x00000001, 2), + (0x26f4, 0x00000001, 1), +]; + +/// The power configuration and its auxiliary data ([`PowerConfig25G83`], `0x6510` bytes at +/// bundle `+0x5380`), without the configuration-status and AON pointers and the random word. +pub(super) const POWER_CONFIG: &[(usize, u32, usize)] = &[ + (0x0004, 0x00030d40, 2), + (0x0010, 0x00000004, 1), + (0x0014, 0x3f800000, 1), + (0x002c, 0x00000001, 2), + (0x0040, 0x00000064, 1), + (0x0044, 0x00000001, 1), + (0x0048, 0x000003e8, 1), + (0x0050, 0x00000064, 1), + (0x0060, 0x00000004, 1), + (0x0064, 0x3f800000, 1), + (0x006c, 0x00000001, 2), + (0x0080, 0x00000064, 1), + (0x0084, 0x00000001, 1), + (0x0088, 0x000003e8, 1), + (0x0090, 0x00000064, 1), + (0x00c0, 0x3f828f5c, 11), + (0x09b8, 0x00000271, 1), + (0x09c4, 0x3f7f2e9f, 1), + (0x09cc, 0x3b516154, 1), + (0x09d4, 0x3ca59586, 1), + (0x09e0, 0x47d7fd00, 1), + (0x09e4, 0x40a90fdb, 1), + (0x09ec, 0xbc1427fc, 1), + (0x09f0, 0x00000064, 1), + (0x09f4, 0x000003e8, 2), + (0x0a04, 0x0001affa, 1), + (0x0a38, 0x000003e8, 1), + (0x0a70, 0x00000008, 1), + (0x0a7c, 0x3f000000, 1), + (0x0a84, 0x3f000000, 1), + (0x0a8c, 0x3e3bd7b3, 1), + (0x0a98, 0x47800000, 1), + (0x0a9c, 0x3ecf2e49, 1), + (0x0aa8, 0x00000064, 1), + (0x0aac, 0x000003e8, 1), + (0x0abc, 0x0001affa, 1), + (0x0ac8, 0x00000010, 1), + (0x0ad0, 0x0005dc00, 1), + (0x0b28, 0x00000050, 1), + (0x0b30, 0x00000055, 1), + (0x0b34, 0x00000032, 1), + (0x0b38, 0x00000006, 1), + (0x0b40, 0x00000006, 1), + (0x0b44, 0x00000001, 1), + (0x0b4c, 0x3f4ccccd, 1), + (0x0b50, 0x3f7eb852, 1), + (0x0b54, 0x3e4ccccd, 1), + (0x0b58, 0x3ba3d70a, 1), + (0x0b5c, 0x3f64c986, 2), + (0x0b68, 0x42be0000, 1), + (0x0b6c, 0x403ea7f0, 2), + (0x0b74, 0x41179436, 1), + (0x0b78, 0x00000064, 1), + (0x0b7c, 0x000003e8, 1), + (0x0b80, 0x00000064, 1), + (0x0b8c, 0x00000050, 1), + (0x0bc0, 0x00000064, 1), + (0x1bec, 0xff000000, 1), + (0x1bf0, 0xff7fff7f, 255), + (0x1fec, 0x007fff7f, 1), + (0x21f0, 0x47800000, 1), + (0x21f4, 0x42c80000, 1), + (0x21f8, 0x447a0000, 1), + (0x21fc, 0x0000062a, 1), + (0x2210, 0x00000064, 1), + (0x2218, 0x42c80000, 1), + (0x221c, 0x000003e8, 1), + (0x2224, 0x3f4ccccd, 1), + (0x2228, 0x3e4ccccd, 1), + (0x2268, 0x2a222aa2, 1), + (0x2270, 0x00001f40, 1), + (0x2278, 0x00000004, 1), + (0x228c, 0x3f800000, 1), + (0x2294, 0x414eeeee, 1), + (0x22a0, 0x47800000, 1), + (0x22a4, 0x42140000, 1), + (0x22b0, 0x00000064, 1), + (0x22b4, 0x000003e8, 2), + (0x22c4, 0x00002af8, 1), + (0x22f8, 0x000003e8, 1), + (0x2728, 0xb8520000, 1), + (0x272c, 0x00003f7e, 1), + (0x2730, 0xd70a0000, 1), + (0x2734, 0x00003ba3, 1), + (0x273c, 0x000043c8, 1), + (0x2748, 0x00004780, 1), + (0x274c, 0x000042c8, 1), + (0x2754, 0x0384bac8, 1), + (0x2758, 0x03e80000, 2), + (0x2764, 0x80000000, 1), + (0x2768, 0x26ac453b, 1), + (0x279c, 0x03e80000, 1), + (0x27b8, 0x00c80000, 1), + (0x2870, 0x000003e8, 1), + (0x28c0, 0x00000001, 1), + (0x28c8, 0x0001affa, 3), + (0x28e0, 0x3f800000, 1), + (0x28e4, 0x00000004, 1), + (0x28e8, 0x00000008, 1), + (0x28ec, 0x0002ee00, 1), + (0x29bc, 0x0000007c, 1), + (0x29c8, 0x3f77bdef, 1), + (0x29d0, 0x3d042108, 1), + (0x29d8, 0x3d25bea1, 1), + (0x29e4, 0x47800000, 1), + (0x29e8, 0x3f4f2e49, 1), + (0x29f4, 0x00000028, 1), + (0x29f8, 0x000003e8, 2), + (0x2a04, 0x47d7fd00, 1), + (0x2a08, 0x0001affa, 1), + (0x2a14, 0x000000f8, 1), + (0x2a1c, 0x005ad200, 1), + (0x2a3c, 0x000003e8, 1), + (0x2b4c, 0x00000032, 1), + (0x2b50, 0x00000001, 1), + (0x2b58, 0x3f638e39, 1), + (0x2b5c, 0x3f2aaaab, 1), + (0x2b60, 0x3de38e39, 1), + (0x2b64, 0x3eaaaaab, 1), + (0x2b68, 0xbecccccd, 2), + (0x2b74, 0x47800000, 1), + (0x2b78, 0xc0a00000, 2), + (0x2b84, 0x00000064, 1), + (0x2b88, 0x000003e8, 1), + (0x2b8c, 0x00000064, 1), + (0x2b94, 0x45fa0000, 1), + (0x2b98, 0x00000578, 1), + (0x2ba4, 0x00000048, 1), + (0x2ba8, 0x00000018, 1), + (0x2bac, 0x001a5e00, 1), + (0x2bb4, 0x0008ca00, 1), + (0x2bc0, 0x47800000, 1), + (0x2be8, 0x00001f40, 1), + (0x2bec, 0x00000004, 1), + (0x2bf0, 0x000009c4, 1), + (0x2bf4, 0x00000258, 1), + (0x2bf8, 0x00000002, 1), + (0x2bfc, 0x00000004, 1), + (0x2c00, 0x00000032, 1), + (0x2c30, 0x47800000, 1), + (0x2c40, 0x00000064, 1), + (0x2c44, 0x000003e8, 1), + (0x2e2c, 0x00000004, 1), + (0x2e38, 0x3f780000, 1), + (0x2e40, 0x3d000000, 1), + (0x2e48, 0x40a00000, 1), + (0x2e54, 0x47800000, 1), + (0x2e58, 0x41700000, 1), + (0x2e64, 0x00000384, 1), + (0x2e68, 0x000003e8, 2), + (0x2e78, 0x000003e8, 1), + (0x2eac, 0x000003e8, 1), + (0x2eec, 0x00000064, 1), + (0x2f08, 0x2a222aa2, 1), + (0x2f10, 0x0000007d, 1), + (0x2f14, 0x00000001, 1), + (0x3b58, 0x2a222aa2, 2), + (0x3b60, 0x00000001, 1), + (0x5b64, 0x40a00000, 1), + (0x6320, 0x67305452, 1), + (0x6324, 0x67315452, 1), + (0x6328, 0x67325452, 1), + (0x632c, 0x67335452, 1), + (0x6360, 0x00000005, 1), + (0x6368, 0x72305452, 1), + (0x6370, 0x00000001, 1), + (0x6420, 0x00000001, 1), + (0x642c, 0x44f03000, 1), + (0x6430, 0x44f30000, 1), + (0x6434, 0x44f03000, 1), + (0x6438, 0x44f30000, 1), + (0x64ac, 0x43730000, 4), + (0x64fc, 0x437b0000, 1), + (0x6504, 0x43bdc000, 1), +]; + +/// Region C (`0x1000` bytes). +pub(super) const REGION_C: &[(usize, u32, usize)] = &[ + (0x0024, 0x00000bb8, 1), + (0x0030, 0x00000001, 2), + (0x003c, 0x00000078, 1), + (0x0054, 0x00280fa0, 1), + (0x0058, 0x0000ffff, 1), + (0x005c, 0x00010000, 2), + (0x0064, 0x00030000, 1), + (0x0068, 0x00010000, 1), + (0x0078, 0x00000001, 1), + (0x0084, 0x0001affa, 1), + (0x0088, 0x000003e8, 2), + (0x0098, 0x000003e8, 1), + (0x07c4, 0x000005dc, 1), + (0x07c8, 0x3f800000, 1), + (0x07cc, 0x3f4ccccd, 1), + (0x07d0, 0x3e4ccccd, 1), + (0x07d4, 0x3f666666, 1), + (0x07d8, 0x3dcccccd, 1), + (0x07dc, 0x3e800000, 1), + (0x07e0, 0x3f19999a, 1), + (0x07e4, 0x3f666666, 1), + (0x07e8, 0x00000006, 1), + (0x07ec, 0x00000001, 2), + (0x07f4, 0x00000064, 2), + (0x0998, 0x00000028, 1), + (0x099c, 0x0000000a, 1), + (0x09a0, 0x000000fa, 1), + (0x09a4, 0x00000001, 1), + (0x09b8, 0x00000002, 1), + (0x09bc, 0x00000028, 1), + (0x09c0, 0x00000005, 1), + (0x09c8, 0x00000028, 1), + (0x09cc, 0x00000032, 1), + (0x09d0, 0x00000001, 1), + (0x09e0, 0x00000001, 1), + (0x09e4, 0x01020200, 1), + (0x09e8, 0x010a2801, 1), + (0x09ec, 0x28020101, 1), + (0x09f0, 0x0101010a, 1), + (0x09f4, 0x010a2802, 1), + (0x09f8, 0x28010101, 1), + (0x09fc, 0x0001010a, 1), + (0x0e1c, 0x00000100, 1), + (0x0e38, 0x00000300, 1), + (0x0e3c, 0x00000100, 1), +]; + +/// The AON temperature-source rows (12 bytes each) the power configuration names: GPU +/// clusters 0 to 3 and the SoC. +pub(super) const AON_TABLE: [u32; 15] = [ + 0x67305452, 0x00c20001, 0x00001401, 0x67315452, 0x00970001, 0x00001401, 0x67325452, 0x00920001, + 0x00001401, 0x67335452, 0x00c70001, 0x00001401, 0x72305452, 0x012c0001, 0x00001401, +]; + +/// Hashes of the hardware data, power configuration and region C, without the runtime words. +pub(super) const EXPECTED: [u64; 3] = [0xd781973f99831e35, 0xc36d7dbaa597aac4, 0x91a4c67017e30a24]; diff --git a/drivers/gpu/drm/asahi/hw/t8140.rs b/drivers/gpu/drm/asahi/hw/t8140.rs index 93d1c86e3425d..59fe770e23517 100644 --- a/drivers/gpu/drm/asahi/hw/t8140.rs +++ b/drivers/gpu/drm/asahi/hw/t8140.rs @@ -52,6 +52,7 @@ pub(crate) const CONFIG: Config = Config { uat_quirks: crate::mmu::UatQuirks::DEFAULT, region_c: &crate::g17::fw::initdata::REGION_C_26A428, chip: None, + captured: None, adopt_root_entries: true, fabric_bridge: true, firmware: crate::g17::fw::variant::Firmware::Fixed(&crate::g17::fw::variant::V26A428), From 4a10da5455148ab8063129409891ee08e6f0319c Mon Sep 17 00:00:00 2001 From: AxxzyWasTaken Date: Tue, 3 Nov 2026 23:00:28 +0000 Subject: [PATCH 2/2] tools/asahi: model the configuration of a firmware build firmware_variant() now also returns the SoC configuration a build was measured with, so the selection test no longer compiled. Give its model of Build the field, and check that the configuration follows the identified image, and that a build without one and a fixed variant keep the probed configuration. Signed-off-by: AxxzyWasTaken --- tools/asahi/g17-firmware-selection-tests.py | 26 ++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/asahi/g17-firmware-selection-tests.py b/tools/asahi/g17-firmware-selection-tests.py index 771c9c19c6e1e..7bd936c5ce125 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>, } +pub struct Config(pub 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 SECOND_CONFIG: Config = Config(2); 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(&SECOND_CONFIG) }, ]; fn device(version: Option<[u32; 3]>, image: u32) -> AsahiDrmDevice { AsahiDrmDevice { version, image, checked: std::cell::RefCell::new(Vec::new()) } @@ -71,18 +75,28 @@ 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 a configuration keeps the probed one"); } + let dev = device(None, 2); + let (variant, config) = Gpu::firmware_variant(&dev, &Firmware::Identified(&BUILDS)).unwrap(); + assert_eq!(variant.0, 2); + assert_eq!(config.unwrap().0, 2, "the configuration follows the identified image"); let dev = device(Some([27,0,0]), 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(), "the OS hint does not pick a configuration"); assert_eq!(*dev.checked.borrow(), [2,1], "the OS version only orders the candidates"); 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, fixed Neo unchanged, configuration follows the image"); } '''