xref: /linux/drivers/gpu/nova-core/fb/hal/gb100.rs (revision 4b99990cdf9560e8a071640baf19f312e6ae02f4)
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