⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

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}