1 // SPDX-License-Identifier: GPL-2.0 2 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 4 //! Blackwell GB10x framebuffer HAL. 5 6 use kernel::{ 7 io::{ 8 register::{ 9 RegisterBase, 10 WithBase, // 11 }, 12 Io, // 13 }, 14 num::Bounded, 15 prelude::*, 16 ptr::{ 17 const_align_up, 18 Alignment, // 19 }, 20 sizes::*, // 21 }; 22 23 use crate::{ 24 driver::Bar0, 25 fb::hal::FbHal, 26 num::usize_into_u32, 27 regs, // 28 }; 29 30 struct Gb100; 31 32 impl RegisterBase<regs::Hshub0Base> for Gb100 { 33 const BASE: usize = 0x0087_0000; 34 } 35 36 fn read_sysmem_flush_page_gb100(bar: Bar0<'_>) -> u64 { 37 let lo = u64::from( 38 bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>()) 39 .adr(), 40 ); 41 let hi = u64::from( 42 bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>()) 43 .adr(), 44 ); 45 46 lo | (hi << 32) 47 } 48 49 /// Write the sysmem flush page address through the GB10x HSHUB0 registers. 50 /// 51 /// Both the primary and EG (egress) register pairs must be programmed to the same address, 52 /// as required by hardware. 53 fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) { 54 // CAST: lower 32 bits. Hardware ignores bits 7:0. 55 let addr_lo = *addr as u32; 56 let addr_hi = addr.shr::<32, 20>().cast::<u32>(); 57 58 // Write HI first. The hardware will trigger the flush on the LO write. 59 60 // Primary HSHUB pair. 61 bar.write( 62 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(), 63 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi), 64 ); 65 bar.write( 66 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(), 67 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo), 68 ); 69 70 // EG (egress) pair -- must match the primary pair. 71 bar.write( 72 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(), 73 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi), 74 ); 75 bar.write( 76 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(), 77 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo), 78 ); 79 } 80 81 pub(super) const fn pmu_reserved_size_gb100() -> u32 { 82 usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>( 83 ) 84 } 85 86 impl FbHal for Gb100 { 87 fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 { 88 read_sysmem_flush_page_gb100(bar) 89 } 90 91 fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result { 92 let addr = Bounded::<u64, 52>::try_new(addr).ok_or(EINVAL)?; 93 94 write_sysmem_flush_page_gb100(bar, addr); 95 96 Ok(()) 97 } 98 99 fn supports_display(&self, bar: Bar0<'_>) -> bool { 100 super::ga100::display_enabled_ga100(bar) 101 } 102 103 fn vidmem_size(&self, bar: Bar0<'_>) -> u64 { 104 super::ga102::vidmem_size_ga102(bar) 105 } 106 107 fn pmu_reserved_size(&self) -> u32 { 108 pmu_reserved_size_gb100() 109 } 110 111 fn non_wpr_heap_size(&self) -> u32 { 112 // Non-WPR heap for GB10x (see Open RM: kgspGetNonWprHeapSize, GB100/GB102). 113 u32::SZ_2M 114 } 115 116 fn frts_size(&self) -> u64 { 117 super::tu102::frts_size_tu102() 118 } 119 } 120 121 const GB100: Gb100 = Gb100; 122 pub(super) const GB100_HAL: &dyn FbHal = &GB100; 123