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