1206bb143SJohn Hubbard // SPDX-License-Identifier: GPL-2.0 2206bb143SJohn Hubbard // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3206bb143SJohn Hubbard 4fcdd74aaSJohn Hubbard //! Blackwell GB10x framebuffer HAL. 5206bb143SJohn Hubbard 6206bb143SJohn Hubbard use kernel::{ 7a5bf742bSJohn Hubbard io::{ 8a5bf742bSJohn Hubbard register::{ 9a5bf742bSJohn Hubbard RegisterBase, 10a5bf742bSJohn Hubbard WithBase, // 11a5bf742bSJohn Hubbard }, 12a5bf742bSJohn Hubbard Io, // 13a5bf742bSJohn Hubbard }, 14a5bf742bSJohn Hubbard num::Bounded, 15206bb143SJohn Hubbard prelude::*, 16206bb143SJohn Hubbard ptr::{ 17206bb143SJohn Hubbard const_align_up, 18206bb143SJohn Hubbard Alignment, // 19206bb143SJohn Hubbard }, 20206bb143SJohn Hubbard sizes::*, // 21206bb143SJohn Hubbard }; 22206bb143SJohn Hubbard 23206bb143SJohn Hubbard use crate::{ 24206bb143SJohn Hubbard driver::Bar0, 25206bb143SJohn Hubbard fb::hal::FbHal, 26a5bf742bSJohn Hubbard num::usize_into_u32, 27a5bf742bSJohn Hubbard regs, // 28206bb143SJohn Hubbard }; 29206bb143SJohn Hubbard 30206bb143SJohn Hubbard struct Gb100; 31206bb143SJohn Hubbard 32a5bf742bSJohn Hubbard impl RegisterBase<regs::Hshub0Base> for Gb100 { 33a5bf742bSJohn Hubbard const BASE: usize = 0x0087_0000; 34a5bf742bSJohn Hubbard } 35a5bf742bSJohn Hubbard 36*99676aedSGary Guo fn read_sysmem_flush_page_gb100(bar: Bar0<'_>) -> u64 { 37a5bf742bSJohn Hubbard let lo = u64::from( 38a5bf742bSJohn Hubbard bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>()) 39a5bf742bSJohn Hubbard .adr(), 40a5bf742bSJohn Hubbard ); 41a5bf742bSJohn Hubbard let hi = u64::from( 42a5bf742bSJohn Hubbard bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>()) 43a5bf742bSJohn Hubbard .adr(), 44a5bf742bSJohn Hubbard ); 45a5bf742bSJohn Hubbard 46a5bf742bSJohn Hubbard lo | (hi << 32) 47a5bf742bSJohn Hubbard } 48a5bf742bSJohn Hubbard 49a5bf742bSJohn Hubbard /// Write the sysmem flush page address through the GB10x HSHUB0 registers. 50a5bf742bSJohn Hubbard /// 51a5bf742bSJohn Hubbard /// Both the primary and EG (egress) register pairs must be programmed to the same address, 52a5bf742bSJohn Hubbard /// as required by hardware. 53*99676aedSGary Guo fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) { 54a5bf742bSJohn Hubbard // CAST: lower 32 bits. Hardware ignores bits 7:0. 55a5bf742bSJohn Hubbard let addr_lo = *addr as u32; 56a5bf742bSJohn Hubbard let addr_hi = addr.shr::<32, 20>().cast::<u32>(); 57a5bf742bSJohn Hubbard 58a5bf742bSJohn Hubbard // Write HI first. The hardware will trigger the flush on the LO write. 59a5bf742bSJohn Hubbard 60a5bf742bSJohn Hubbard // Primary HSHUB pair. 61a5bf742bSJohn Hubbard bar.write( 62a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(), 63a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi), 64a5bf742bSJohn Hubbard ); 65a5bf742bSJohn Hubbard bar.write( 66a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(), 67a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo), 68a5bf742bSJohn Hubbard ); 69a5bf742bSJohn Hubbard 70a5bf742bSJohn Hubbard // EG (egress) pair -- must match the primary pair. 71a5bf742bSJohn Hubbard bar.write( 72a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(), 73a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi), 74a5bf742bSJohn Hubbard ); 75a5bf742bSJohn Hubbard bar.write( 76a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(), 77a5bf742bSJohn Hubbard regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo), 78a5bf742bSJohn Hubbard ); 79a5bf742bSJohn Hubbard } 80a5bf742bSJohn Hubbard 81fcdd74aaSJohn Hubbard pub(super) const fn pmu_reserved_size_gb100() -> u32 { 82206bb143SJohn Hubbard usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>( 83206bb143SJohn Hubbard ) 84206bb143SJohn Hubbard } 85206bb143SJohn Hubbard 86206bb143SJohn Hubbard impl FbHal for Gb100 { 87*99676aedSGary Guo fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 { 88a5bf742bSJohn Hubbard read_sysmem_flush_page_gb100(bar) 89206bb143SJohn Hubbard } 90206bb143SJohn Hubbard 91*99676aedSGary Guo fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result { 92a5bf742bSJohn Hubbard let addr = Bounded::<u64, 52>::try_new(addr).ok_or(EINVAL)?; 93a5bf742bSJohn Hubbard 94a5bf742bSJohn Hubbard write_sysmem_flush_page_gb100(bar, addr); 95206bb143SJohn Hubbard 96206bb143SJohn Hubbard Ok(()) 97206bb143SJohn Hubbard } 98206bb143SJohn Hubbard 99*99676aedSGary Guo fn supports_display(&self, bar: Bar0<'_>) -> bool { 100206bb143SJohn Hubbard super::ga100::display_enabled_ga100(bar) 101206bb143SJohn Hubbard } 102206bb143SJohn Hubbard 103*99676aedSGary Guo fn vidmem_size(&self, bar: Bar0<'_>) -> u64 { 104206bb143SJohn Hubbard super::ga102::vidmem_size_ga102(bar) 105206bb143SJohn Hubbard } 106206bb143SJohn Hubbard 107206bb143SJohn Hubbard fn pmu_reserved_size(&self) -> u32 { 108206bb143SJohn Hubbard pmu_reserved_size_gb100() 109206bb143SJohn Hubbard } 110206bb143SJohn Hubbard 111fcdd74aaSJohn Hubbard fn non_wpr_heap_size(&self) -> u32 { 112fcdd74aaSJohn Hubbard // Non-WPR heap for GB10x (see Open RM: kgspGetNonWprHeapSize, GB100/GB102). 113fcdd74aaSJohn Hubbard u32::SZ_2M 114fcdd74aaSJohn Hubbard } 115fcdd74aaSJohn Hubbard 116206bb143SJohn Hubbard fn frts_size(&self) -> u64 { 117206bb143SJohn Hubbard super::tu102::frts_size_tu102() 118206bb143SJohn Hubbard } 119206bb143SJohn Hubbard } 120206bb143SJohn Hubbard 121206bb143SJohn Hubbard const GB100: Gb100 = Gb100; 122206bb143SJohn Hubbard pub(super) const GB100_HAL: &dyn FbHal = &GB100; 123