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), 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"); } '''