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::{ 26 hal::FbHal, 27 regs, // 28 }, 29 num::usize_into_u32, 30 }; 31 32 struct Gb100; 33 34 impl RegisterBase<regs::Hshub0Base> for Gb100 { 35 const BASE: usize = 0x0087_0000; 36 } 37 38 fn read_sysmem_flush_page_gb100(bar: Bar0<'_>) -> u64 { 39 let lo = u64::from( 40 bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>()) 41 .adr(), 42 ); 43 let hi = u64::from( 44 bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>()) 45 .adr(), 46 ); 47 48 lo | (hi << 32) 49 } 50 51 /// Write the sysmem flush page address through the GB10x HSHUB0 registers. 52 /// 53 /// Both the primary and EG (egress) register pairs must be programmed to the same address, 54 /// as required by hardware. 55 fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) { 56 // CAST: lower 32 bits. Hardware ignores bits 7:0. 57 let addr_lo = *addr as u32; 58 let addr_hi = addr.shr::<32, 20>().cast::<u32>(); 59 60 // Write HI first. The hardware will trigger the flush on the LO write. 61 62 // Primary HSHUB pair. 63 bar.write( 64 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(), 65 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi), 66 ); 67 bar.write( 68 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(), 69 regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo), 70 ); 71 72 // EG (egress) pair -- must match the primary pair. 73 bar.write( 74 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(), 75 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi), 76 ); 77 bar.write( 78 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(), 79 regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo), 80 ); 81 } 82 83 // This PMU reservation size is r570-specific. 84 pub(super) const fn pmu_reserved_size_gb100() -> u32 { 85 usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>( 86 ) 87 } 88 89 impl FbHal for Gb100 { 90 fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 { 91 read_sysmem_flush_page_gb100(bar) 92 } 93 94 fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result { 95 let addr = Bounded::<u64, 52>::try_new(addr).ok_or(EINVAL)?; 96 97 write_sysmem_flush_page_gb100(bar, addr); 98 99 Ok(()) 100 } 101 102 fn supports_display(&self, bar: Bar0<'_>) -> bool { 103 super::ga100::display_enabled_ga100(bar) 104 } 105 106 fn vidmem_size(&self, bar: Bar0<'_>) -> u64 { 107 super::ga102::vidmem_size_ga102(bar) 108 } 109 110 fn pmu_reserved_size(&self) -> u32 { 111 pmu_reserved_size_gb100() 112 } 113 114 fn non_wpr_heap_size(&self) -> u64 { 115 // Non-WPR heap for GB10x (see Open RM: kgspGetNonWprHeapSize, GB100/GB102). 116 u64::SZ_2M 117 } 118 119 fn frts_size(&self) -> u64 { 120 super::tu102::frts_size_tu102() 121 } 122 } 123 124 const GB100: Gb100 = Gb100; 125 pub(super) const GB100_HAL: &dyn FbHal = &GB100; 126