154e6baf1SDanilo Krummrich // SPDX-License-Identifier: GPL-2.0 254e6baf1SDanilo Krummrich 354e6baf1SDanilo Krummrich use kernel::{ 454e6baf1SDanilo Krummrich device, devres::Devres, error::code::*, firmware, fmt, pci, prelude::*, str::CString, 554e6baf1SDanilo Krummrich }; 654e6baf1SDanilo Krummrich 754e6baf1SDanilo Krummrich use crate::driver::Bar0; 854e6baf1SDanilo Krummrich use crate::regs; 954e6baf1SDanilo Krummrich use crate::util; 1054e6baf1SDanilo Krummrich use core::fmt; 1154e6baf1SDanilo Krummrich 1254e6baf1SDanilo Krummrich macro_rules! define_chipset { 1354e6baf1SDanilo Krummrich ({ $($variant:ident = $value:expr),* $(,)* }) => 1454e6baf1SDanilo Krummrich { 1554e6baf1SDanilo Krummrich /// Enum representation of the GPU chipset. 1654e6baf1SDanilo Krummrich #[derive(fmt::Debug)] 1754e6baf1SDanilo Krummrich pub(crate) enum Chipset { 1854e6baf1SDanilo Krummrich $($variant = $value),*, 1954e6baf1SDanilo Krummrich } 2054e6baf1SDanilo Krummrich 2154e6baf1SDanilo Krummrich impl Chipset { 2254e6baf1SDanilo Krummrich pub(crate) const ALL: &'static [Chipset] = &[ 2354e6baf1SDanilo Krummrich $( Chipset::$variant, )* 2454e6baf1SDanilo Krummrich ]; 2554e6baf1SDanilo Krummrich 2654e6baf1SDanilo Krummrich pub(crate) const NAMES: [&'static str; Self::ALL.len()] = [ 2754e6baf1SDanilo Krummrich $( util::const_bytes_to_str( 2854e6baf1SDanilo Krummrich util::to_lowercase_bytes::<{ stringify!($variant).len() }>( 2954e6baf1SDanilo Krummrich stringify!($variant) 3054e6baf1SDanilo Krummrich ).as_slice() 3154e6baf1SDanilo Krummrich ), )* 3254e6baf1SDanilo Krummrich ]; 3354e6baf1SDanilo Krummrich } 3454e6baf1SDanilo Krummrich 3554e6baf1SDanilo Krummrich // TODO replace with something like derive(FromPrimitive) 3654e6baf1SDanilo Krummrich impl TryFrom<u32> for Chipset { 3754e6baf1SDanilo Krummrich type Error = kernel::error::Error; 3854e6baf1SDanilo Krummrich 3954e6baf1SDanilo Krummrich fn try_from(value: u32) -> Result<Self, Self::Error> { 4054e6baf1SDanilo Krummrich match value { 4154e6baf1SDanilo Krummrich $( $value => Ok(Chipset::$variant), )* 4254e6baf1SDanilo Krummrich _ => Err(ENODEV), 4354e6baf1SDanilo Krummrich } 4454e6baf1SDanilo Krummrich } 4554e6baf1SDanilo Krummrich } 4654e6baf1SDanilo Krummrich } 4754e6baf1SDanilo Krummrich } 4854e6baf1SDanilo Krummrich 4954e6baf1SDanilo Krummrich define_chipset!({ 5054e6baf1SDanilo Krummrich // Turing 5154e6baf1SDanilo Krummrich TU102 = 0x162, 5254e6baf1SDanilo Krummrich TU104 = 0x164, 5354e6baf1SDanilo Krummrich TU106 = 0x166, 5454e6baf1SDanilo Krummrich TU117 = 0x167, 5554e6baf1SDanilo Krummrich TU116 = 0x168, 5654e6baf1SDanilo Krummrich // Ampere 5754e6baf1SDanilo Krummrich GA102 = 0x172, 5854e6baf1SDanilo Krummrich GA103 = 0x173, 5954e6baf1SDanilo Krummrich GA104 = 0x174, 6054e6baf1SDanilo Krummrich GA106 = 0x176, 6154e6baf1SDanilo Krummrich GA107 = 0x177, 6254e6baf1SDanilo Krummrich // Ada 6354e6baf1SDanilo Krummrich AD102 = 0x192, 6454e6baf1SDanilo Krummrich AD103 = 0x193, 6554e6baf1SDanilo Krummrich AD104 = 0x194, 6654e6baf1SDanilo Krummrich AD106 = 0x196, 6754e6baf1SDanilo Krummrich AD107 = 0x197, 6854e6baf1SDanilo Krummrich }); 6954e6baf1SDanilo Krummrich 7054e6baf1SDanilo Krummrich impl Chipset { arch(&self) -> Architecture7154e6baf1SDanilo Krummrich pub(crate) fn arch(&self) -> Architecture { 7254e6baf1SDanilo Krummrich match self { 7354e6baf1SDanilo Krummrich Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 7454e6baf1SDanilo Krummrich Architecture::Turing 7554e6baf1SDanilo Krummrich } 7654e6baf1SDanilo Krummrich Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 7754e6baf1SDanilo Krummrich Architecture::Ampere 7854e6baf1SDanilo Krummrich } 7954e6baf1SDanilo Krummrich Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { 8054e6baf1SDanilo Krummrich Architecture::Ada 8154e6baf1SDanilo Krummrich } 8254e6baf1SDanilo Krummrich } 8354e6baf1SDanilo Krummrich } 8454e6baf1SDanilo Krummrich } 8554e6baf1SDanilo Krummrich 8654e6baf1SDanilo Krummrich // TODO 8754e6baf1SDanilo Krummrich // 8854e6baf1SDanilo Krummrich // The resulting strings are used to generate firmware paths, hence the 8954e6baf1SDanilo Krummrich // generated strings have to be stable. 9054e6baf1SDanilo Krummrich // 9154e6baf1SDanilo Krummrich // Hence, replace with something like strum_macros derive(Display). 9254e6baf1SDanilo Krummrich // 9354e6baf1SDanilo Krummrich // For now, redirect to fmt::Debug for convenience. 9454e6baf1SDanilo Krummrich impl fmt::Display for Chipset { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result9554e6baf1SDanilo Krummrich fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 96*211dcf77SMiguel Ojeda write!(f, "{self:?}") 9754e6baf1SDanilo Krummrich } 9854e6baf1SDanilo Krummrich } 9954e6baf1SDanilo Krummrich 10054e6baf1SDanilo Krummrich /// Enum representation of the GPU generation. 10154e6baf1SDanilo Krummrich #[derive(fmt::Debug)] 10254e6baf1SDanilo Krummrich pub(crate) enum Architecture { 10354e6baf1SDanilo Krummrich Turing, 10454e6baf1SDanilo Krummrich Ampere, 10554e6baf1SDanilo Krummrich Ada, 10654e6baf1SDanilo Krummrich } 10754e6baf1SDanilo Krummrich 10854e6baf1SDanilo Krummrich pub(crate) struct Revision { 10954e6baf1SDanilo Krummrich major: u8, 11054e6baf1SDanilo Krummrich minor: u8, 11154e6baf1SDanilo Krummrich } 11254e6baf1SDanilo Krummrich 11354e6baf1SDanilo Krummrich impl Revision { from_boot0(boot0: regs::Boot0) -> Self11454e6baf1SDanilo Krummrich fn from_boot0(boot0: regs::Boot0) -> Self { 11554e6baf1SDanilo Krummrich Self { 11654e6baf1SDanilo Krummrich major: boot0.major_rev(), 11754e6baf1SDanilo Krummrich minor: boot0.minor_rev(), 11854e6baf1SDanilo Krummrich } 11954e6baf1SDanilo Krummrich } 12054e6baf1SDanilo Krummrich } 12154e6baf1SDanilo Krummrich 12254e6baf1SDanilo Krummrich impl fmt::Display for Revision { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result12354e6baf1SDanilo Krummrich fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 12454e6baf1SDanilo Krummrich write!(f, "{:x}.{:x}", self.major, self.minor) 12554e6baf1SDanilo Krummrich } 12654e6baf1SDanilo Krummrich } 12754e6baf1SDanilo Krummrich 12854e6baf1SDanilo Krummrich /// Structure holding the metadata of the GPU. 12954e6baf1SDanilo Krummrich pub(crate) struct Spec { 13054e6baf1SDanilo Krummrich chipset: Chipset, 13154e6baf1SDanilo Krummrich /// The revision of the chipset. 13254e6baf1SDanilo Krummrich revision: Revision, 13354e6baf1SDanilo Krummrich } 13454e6baf1SDanilo Krummrich 13554e6baf1SDanilo Krummrich impl Spec { new(bar: &Devres<Bar0>) -> Result<Spec>13654e6baf1SDanilo Krummrich fn new(bar: &Devres<Bar0>) -> Result<Spec> { 13754e6baf1SDanilo Krummrich let bar = bar.try_access().ok_or(ENXIO)?; 13854e6baf1SDanilo Krummrich let boot0 = regs::Boot0::read(&bar); 13954e6baf1SDanilo Krummrich 14054e6baf1SDanilo Krummrich Ok(Self { 14154e6baf1SDanilo Krummrich chipset: boot0.chipset().try_into()?, 14254e6baf1SDanilo Krummrich revision: Revision::from_boot0(boot0), 14354e6baf1SDanilo Krummrich }) 14454e6baf1SDanilo Krummrich } 14554e6baf1SDanilo Krummrich } 14654e6baf1SDanilo Krummrich 14754e6baf1SDanilo Krummrich /// Structure encapsulating the firmware blobs required for the GPU to operate. 14854e6baf1SDanilo Krummrich #[expect(dead_code)] 14954e6baf1SDanilo Krummrich pub(crate) struct Firmware { 15054e6baf1SDanilo Krummrich booter_load: firmware::Firmware, 15154e6baf1SDanilo Krummrich booter_unload: firmware::Firmware, 15254e6baf1SDanilo Krummrich bootloader: firmware::Firmware, 15354e6baf1SDanilo Krummrich gsp: firmware::Firmware, 15454e6baf1SDanilo Krummrich } 15554e6baf1SDanilo Krummrich 15654e6baf1SDanilo Krummrich impl Firmware { new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware>15754e6baf1SDanilo Krummrich fn new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware> { 15854e6baf1SDanilo Krummrich let mut chip_name = CString::try_from_fmt(fmt!("{}", spec.chipset))?; 15954e6baf1SDanilo Krummrich chip_name.make_ascii_lowercase(); 16054e6baf1SDanilo Krummrich 16154e6baf1SDanilo Krummrich let request = |name_| { 16254e6baf1SDanilo Krummrich CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver)) 16354e6baf1SDanilo Krummrich .and_then(|path| firmware::Firmware::request(&path, dev)) 16454e6baf1SDanilo Krummrich }; 16554e6baf1SDanilo Krummrich 16654e6baf1SDanilo Krummrich Ok(Firmware { 16754e6baf1SDanilo Krummrich booter_load: request("booter_load")?, 16854e6baf1SDanilo Krummrich booter_unload: request("booter_unload")?, 16954e6baf1SDanilo Krummrich bootloader: request("bootloader")?, 17054e6baf1SDanilo Krummrich gsp: request("gsp")?, 17154e6baf1SDanilo Krummrich }) 17254e6baf1SDanilo Krummrich } 17354e6baf1SDanilo Krummrich } 17454e6baf1SDanilo Krummrich 17554e6baf1SDanilo Krummrich /// Structure holding the resources required to operate the GPU. 17654e6baf1SDanilo Krummrich #[pin_data] 17754e6baf1SDanilo Krummrich pub(crate) struct Gpu { 17854e6baf1SDanilo Krummrich spec: Spec, 17954e6baf1SDanilo Krummrich /// MMIO mapping of PCI BAR 0 18054e6baf1SDanilo Krummrich bar: Devres<Bar0>, 18154e6baf1SDanilo Krummrich fw: Firmware, 18254e6baf1SDanilo Krummrich } 18354e6baf1SDanilo Krummrich 18454e6baf1SDanilo Krummrich impl Gpu { new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>>18554e6baf1SDanilo Krummrich pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>> { 18654e6baf1SDanilo Krummrich let spec = Spec::new(&bar)?; 18754e6baf1SDanilo Krummrich let fw = Firmware::new(pdev.as_ref(), &spec, "535.113.01")?; 18854e6baf1SDanilo Krummrich 18954e6baf1SDanilo Krummrich dev_info!( 19054e6baf1SDanilo Krummrich pdev.as_ref(), 19154e6baf1SDanilo Krummrich "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", 19254e6baf1SDanilo Krummrich spec.chipset, 19354e6baf1SDanilo Krummrich spec.chipset.arch(), 19454e6baf1SDanilo Krummrich spec.revision 19554e6baf1SDanilo Krummrich ); 19654e6baf1SDanilo Krummrich 19754e6baf1SDanilo Krummrich Ok(pin_init!(Self { spec, bar, fw })) 19854e6baf1SDanilo Krummrich } 19954e6baf1SDanilo Krummrich } 200