veridian_kernel/drivers/gpu_amdgpu.rs
1//! AMD GPU (amdgpu) Driver Framework
2//!
3//! Provides PCI device detection and structured types for AMD Radeon GPUs.
4//! Actual register programming requires hardware access not available in
5//! QEMU's virtio-gpu environment.
6
7#![allow(dead_code)]
8
9#[cfg(target_arch = "x86_64")]
10use alloc::format;
11use alloc::{string::String, vec::Vec};
12
13use crate::error::KernelError;
14
15// ---------------------------------------------------------------------------
16// PCI Device IDs
17// ---------------------------------------------------------------------------
18
19/// AMD GPU PCI device IDs (subset of common devices)
20pub mod device_ids {
21 // RDNA 1 (Navi 10)
22 /// Radeon RX 5700 XT
23 pub const NAVI10_RX5700XT: u16 = 0x731F;
24 /// Radeon RX 5600 XT
25 pub const NAVI10_RX5600XT: u16 = 0x7310;
26
27 // RDNA 2 (Navi 21 / Navi 22 / Navi 23)
28 /// Radeon RX 6900 XT (Navi 21)
29 pub const NAVI21_RX6900XT: u16 = 0x73BF;
30 /// Radeon RX 6700 XT (Navi 22)
31 pub const NAVI22_RX6700XT: u16 = 0x73DF;
32 /// Radeon RX 6600 XT (Navi 23)
33 pub const NAVI23_RX6600XT: u16 = 0x73FF;
34
35 // RDNA 3 (Navi 31 / Navi 33)
36 /// Radeon RX 7900 XTX (Navi 31)
37 pub const NAVI31_RX7900XTX: u16 = 0x744C;
38 /// Radeon RX 7600 (Navi 33)
39 pub const NAVI33_RX7600: u16 = 0x7480;
40}
41
42// ---------------------------------------------------------------------------
43// GPU Generation Classification
44// ---------------------------------------------------------------------------
45
46/// AMD GPU architecture generation
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum AmdGeneration {
49 /// Graphics Core Next 5th generation (Vega)
50 Gcn5,
51 /// RDNA 1st generation (Navi 10/12/14)
52 Rdna1,
53 /// RDNA 2nd generation (Navi 21/22/23/24)
54 Rdna2,
55 /// RDNA 3rd generation (Navi 31/32/33)
56 Rdna3,
57 /// Unrecognised device ID
58 Unknown,
59}
60
61impl core::fmt::Display for AmdGeneration {
62 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63 match self {
64 Self::Gcn5 => write!(f, "GCN5"),
65 Self::Rdna1 => write!(f, "RDNA1"),
66 Self::Rdna2 => write!(f, "RDNA2"),
67 Self::Rdna3 => write!(f, "RDNA3"),
68 Self::Unknown => write!(f, "Unknown"),
69 }
70 }
71}
72
73// ---------------------------------------------------------------------------
74// MMIO Register Offsets
75// ---------------------------------------------------------------------------
76
77/// MMIO register block offsets (per amdgpu driver documentation)
78pub mod regs {
79 /// Graphics Register Bus Manager status
80 pub const GRBM_STATUS: u64 = 0x8010;
81 /// System Register Bus Manager status
82 pub const SRBM_STATUS: u64 = 0x0E50;
83 /// Interrupt handler ring buffer base
84 pub const IH_RB_BASE: u64 = 0x00040;
85 /// Display Core Next engine base
86 pub const DCN_BASE: u64 = 0x12000;
87 /// Memory controller hub base
88 pub const MC_HUB_BASE: u64 = 0x0B00;
89 /// Power management base
90 pub const SMU_BASE: u64 = 0x03B00000;
91 /// GFX ring buffer base
92 pub const GFX_RING_BASE: u64 = 0x08000;
93 /// SDMA (System DMA) engine 0 base
94 pub const SDMA0_BASE: u64 = 0x04E00;
95 /// Video Core Next decode engine base
96 pub const VCN_BASE: u64 = 0x01F400;
97 /// Memory-mapped register index/data pair
98 pub const MMIO_INDEX: u64 = 0x0000;
99 /// Memory-mapped register data
100 pub const MMIO_DATA: u64 = 0x0004;
101}
102
103// ---------------------------------------------------------------------------
104// Display Types
105// ---------------------------------------------------------------------------
106
107/// Display Core Next (DCN) display output configuration
108#[derive(Debug, Clone)]
109pub struct DcnDisplay {
110 /// Display engine index
111 pub engine_id: u8,
112 /// Connector type
113 pub connector: ConnectorType,
114 /// Horizontal resolution
115 pub width: u32,
116 /// Vertical resolution
117 pub height: u32,
118 /// Refresh rate in Hz
119 pub refresh_rate: u32,
120 /// Whether the display is currently active
121 pub enabled: bool,
122}
123
124/// Display connector type
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub enum ConnectorType {
127 /// DisplayPort
128 DisplayPort,
129 /// HDMI
130 Hdmi,
131 /// DVI-D
132 DviD,
133 /// USB-C with DisplayPort alt mode
134 UsbC,
135 /// eDP (embedded DisplayPort, laptop panels)
136 Edp,
137 /// VGA (legacy, via DAC)
138 Vga,
139}
140
141// ---------------------------------------------------------------------------
142// Power Management Types
143// ---------------------------------------------------------------------------
144
145/// GPU power state
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147pub enum PowerState {
148 /// Full performance
149 D0,
150 /// Low power, display on
151 D1,
152 /// Lower power, display off
153 D2,
154 /// Suspended
155 D3Hot,
156 /// Powered off
157 D3Cold,
158}
159
160/// Clock domain frequencies (MHz)
161#[derive(Debug, Clone, Copy)]
162pub struct ClockInfo {
163 /// GPU core (shader) clock in MHz
164 pub sclk_mhz: u32,
165 /// Memory clock in MHz
166 pub mclk_mhz: u32,
167 /// Voltage in mV (0 if unknown)
168 pub voltage_mv: u32,
169}
170
171// ---------------------------------------------------------------------------
172// Device Representation
173// ---------------------------------------------------------------------------
174
175/// AMD GPU device instance
176pub struct AmdGpuDevice {
177 /// PCI vendor ID (always 0x1002 for AMD)
178 pub vendor_id: u16,
179 /// PCI device ID
180 pub device_id: u16,
181 /// Classified GPU generation
182 pub generation: AmdGeneration,
183 /// BAR0 MMIO base address
184 pub mmio_base: u64,
185 /// BAR0 MMIO region size
186 pub mmio_size: u64,
187 /// VRAM size in bytes (from BAR or discovery)
188 pub vram_size: u64,
189 /// VRAM BAR base address (BAR2 for large-BAR / resize-BAR)
190 pub vram_base: u64,
191 /// Configured display outputs
192 pub displays: Vec<DcnDisplay>,
193 /// Current power state
194 pub power_state: PowerState,
195 /// Human-readable device name
196 pub name: String,
197}
198
199impl AmdGpuDevice {
200 /// Classify GPU generation from PCI device ID.
201 ///
202 /// Device ID ranges are derived from the upstream amdgpu driver
203 /// chip identification tables.
204 pub fn classify_generation(device_id: u16) -> AmdGeneration {
205 match device_id {
206 // Vega (GCN5)
207 0x6860..=0x687F | 0x69A0..=0x69AF => AmdGeneration::Gcn5,
208 // Navi 10/12/14 (RDNA1)
209 0x7310..=0x731F | 0x7340..=0x734F | 0x7360..=0x736F => AmdGeneration::Rdna1,
210 // Navi 21/22/23/24 (RDNA2)
211 0x73A0..=0x73FF | 0x7420..=0x743F => AmdGeneration::Rdna2,
212 // Navi 31/32/33 (RDNA3)
213 0x7440..=0x749F => AmdGeneration::Rdna3,
214 _ => AmdGeneration::Unknown,
215 }
216 }
217
218 /// Return `true` if this GPU supports hardware raytracing (RDNA2+).
219 pub fn has_raytracing(&self) -> bool {
220 matches!(self.generation, AmdGeneration::Rdna2 | AmdGeneration::Rdna3)
221 }
222}
223
224// ---------------------------------------------------------------------------
225// PCI Probing
226// ---------------------------------------------------------------------------
227
228/// Probe the PCI bus for AMD GPU devices (x86_64 only).
229///
230/// Returns a list of detected AMD display-class devices with generation
231/// classification and BAR information. No register programming is performed.
232#[cfg(target_arch = "x86_64")]
233pub fn probe() -> Vec<AmdGpuDevice> {
234 let mut devices = Vec::new();
235
236 if !crate::drivers::pci::is_pci_initialized() {
237 return devices;
238 }
239
240 let bus = crate::drivers::pci::get_pci_bus().lock();
241 let pci_devices = bus.find_devices_by_class(crate::drivers::pci::class_codes::DISPLAY);
242
243 for pci_dev in &pci_devices {
244 if pci_dev.vendor_id != 0x1002 {
245 continue;
246 }
247
248 let gen = AmdGpuDevice::classify_generation(pci_dev.device_id);
249
250 let (mmio_base, mmio_size) = pci_dev
251 .bars
252 .first()
253 .map(|bar| match bar {
254 crate::drivers::pci::PciBar::Memory { address, size, .. } => (*address, *size),
255 _ => (0, 0),
256 })
257 .unwrap_or((0, 0));
258
259 // BAR2 is typically the VRAM aperture on AMD GPUs
260 let (vram_base, vram_size) = pci_dev
261 .bars
262 .get(2)
263 .map(|bar| match bar {
264 crate::drivers::pci::PciBar::Memory { address, size, .. } => (*address, *size),
265 _ => (0, 0),
266 })
267 .unwrap_or((0, 0));
268
269 devices.push(AmdGpuDevice {
270 vendor_id: pci_dev.vendor_id,
271 device_id: pci_dev.device_id,
272 generation: gen,
273 mmio_base,
274 mmio_size,
275 vram_size,
276 vram_base,
277 displays: Vec::new(),
278 power_state: PowerState::D0,
279 name: format!("AMD GPU {:04x} ({})", pci_dev.device_id, gen),
280 });
281 }
282
283 devices
284}
285
286/// Stub probe for non-x86_64 architectures.
287#[cfg(not(target_arch = "x86_64"))]
288pub fn probe() -> Vec<AmdGpuDevice> {
289 Vec::new()
290}
291
292// ---------------------------------------------------------------------------
293// Initialization
294// ---------------------------------------------------------------------------
295
296/// Initialize the AMD GPU driver (detection only).
297///
298/// Scans the PCI bus for AMD display-class devices and logs any found.
299/// No register programming or mode setting is performed.
300pub fn init() -> Result<(), KernelError> {
301 let devices = probe();
302
303 if devices.is_empty() {
304 crate::println!("[amdgpu] No AMD GPU devices found");
305 } else {
306 for dev in &devices {
307 crate::println!(
308 "[amdgpu] Found: {} (BAR0: {:#x}, VRAM: {:#x})",
309 dev.name,
310 dev.mmio_base,
311 dev.vram_size
312 );
313 }
314 }
315
316 Ok(())
317}