strat9_kernel/hardware/amdgpu/
mod.rs1pub mod regs;
8
9use alloc::vec::Vec;
10use core::sync::atomic::{AtomicBool, Ordering};
11use spin::Mutex;
12
13use crate::{
14 arch::x86_64::pci,
15 memory::{allocate_zeroed_frame, PhysFrame},
16};
17
18pub const AMD_VENDOR: u16 = 0x1002;
20
21const CLASS_DISPLAY: u8 = 0x03;
23
24struct Mmio {
26 base: usize,
27}
28
29impl Mmio {
30 unsafe fn new(base: usize) -> Self {
33 Self { base }
34 }
35
36 fn read32(&self, off: u32) -> u32 {
37 unsafe { core::ptr::read_volatile((self.base + off as usize) as *const u32) }
38 }
39
40 fn write32(&self, off: u32, val: u32) {
41 unsafe { core::ptr::write_volatile((self.base + off as usize) as *mut u32, val) }
42 }
43}
44
45pub struct AmdGpu {
47 mmio: Mmio,
48 fb_phys: u64,
49 fb_virt: usize,
50 fb_pitch: u32,
51 fb_width: u32,
52 fb_height: u32,
53 fb_bpp: u32,
54 fb_size: usize,
55 _frames: Vec<PhysFrame>,
56}
57
58static GPU: Mutex<Option<AmdGpu>> = Mutex::new(None);
59static AVAILABLE: AtomicBool = AtomicBool::new(false);
60
61pub fn is_available() -> bool {
62 AVAILABLE.load(Ordering::Relaxed)
63}
64
65pub fn get_gpu() -> Option<spin::MutexGuard<'static, Option<AmdGpu>>> {
66 if AVAILABLE.load(Ordering::Relaxed) {
67 Some(GPU.lock())
68 } else {
69 None
70 }
71}
72
73pub fn init() {
75 crate::serial_println!("[amdgpu] Probing PCI for AMD display...");
76
77 let devs = pci::probe_all(pci::ProbeCriteria {
78 vendor_id: Some(AMD_VENDOR),
79 class_code: Some(CLASS_DISPLAY),
80 ..pci::ProbeCriteria::any()
81 });
82
83 if devs.is_empty() {
84 crate::serial_println!("[amdgpu] No AMD display device found");
85 return;
86 }
87
88 let dev = &devs[0];
89 crate::serial_println!(
90 "[amdgpu] Found: {:04X}:{:04X} (class {:02X}:{:02X})",
91 dev.vendor_id,
92 dev.device_id,
93 dev.class_code,
94 dev.subclass
95 );
96
97 let bar0 = match dev.read_bar_raw(0) {
98 Some(addr) => addr,
99 None => {
100 crate::serial_println!("[amdgpu] BAR0 not available");
101 return;
102 }
103 };
104
105 let hhdm = crate::memory::hhdm_offset();
106 let mmio = unsafe { Mmio::new((bar0 + hhdm) as usize) };
107
108 let chip_id = mmio.read32(regs::CHIP_ID);
109 crate::serial_println!("[amdgpu] CHIP_ID={:#x}", chip_id);
110
111 let vram_mb = match (chip_id >> 24) & 0xFF {
112 0x26..=0x2D => 1024,
113 0x32..=0x3D => 2048,
114 0x4A..=0x4D => 4096,
115 0x50..=0x56 => 8192,
116 0x66..=0x6C => 8192,
117 0x73..=0x7A => 16384,
118 0x88..=0x8D => 16384,
119 _ => 4096,
120 };
121 crate::serial_println!("[amdgpu] VRAM: {} MB", vram_mb);
122
123 let (w, h, bpp) = (1024u32, 768u32, 32u32);
125 let pitch = w * (bpp / 8);
126 let fb_size = (pitch * h) as usize;
127 let fb_pages = (fb_size + 4095) / 4096;
128
129 let mut frames = Vec::new();
130 for _ in 0..fb_pages {
131 match allocate_zeroed_frame() {
132 Some(f) => frames.push(f),
133 None => {
134 crate::serial_println!("[amdgpu] FB alloc failed");
135 return;
136 }
137 }
138 }
139
140 let fb_phys = frames[0].start_address.as_u64();
141 let hhdm = crate::memory::hhdm_offset();
142 let fb_virt = (fb_phys + hhdm) as usize;
143
144 let gpu = AmdGpu {
145 mmio,
146 fb_phys: fb_phys as u64,
147 fb_virt,
148 fb_pitch: pitch,
149 fb_width: w,
150 fb_height: h,
151 fb_bpp: bpp,
152 fb_size,
153 _frames: frames,
154 };
155
156 gpu.configure_crtc();
157
158 *GPU.lock() = Some(gpu);
159 AVAILABLE.store(true, Ordering::Relaxed);
160 crate::serial_println!("[amdgpu] Display: {}x{} @ {}bpp", w, h, bpp);
161}
162
163impl AmdGpu {
164 fn configure_crtc(&self) {
165 self.mmio.write32(regs::CRTC_CONTROL, 0);
166 for _ in 0..10000 {
168 core::hint::spin_loop();
169 }
170
171 self.mmio
172 .write32(regs::CRTC_FB_BASE_LO, self.fb_phys as u32);
173 self.mmio
174 .write32(regs::CRTC_FB_BASE_HI, (self.fb_phys >> 32) as u32);
175 self.mmio.write32(regs::CRTC_FB_PITCH, self.fb_pitch / 4);
176 self.mmio
177 .write32(regs::CRTC_FB_SIZE, self.fb_width | (self.fb_height << 16));
178 self.mmio.write32(
179 regs::CRTC_DIMENSIONS,
180 self.fb_width | (self.fb_height << 16),
181 );
182 self.mmio.write32(
183 regs::CRTC_H_TOTAL,
184 (self.fb_width + 160 - 1) | ((self.fb_width + 160 - 1) << 16),
185 );
186 self.mmio.write32(
187 regs::CRTC_V_TOTAL,
188 (self.fb_height + 30 - 1) | ((self.fb_height + 30 - 1) << 16),
189 );
190 self.mmio.write32(regs::CRTC_FORMAT, 0);
191 self.mmio.write32(regs::CRTC_CONTROL, 1 << 0);
192 for _ in 0..50000 {
194 core::hint::spin_loop();
195 }
196
197 crate::serial_println!("[amdgpu] CRTC configured");
198 }
199
200 pub fn present_region(&self, _x: u32, _y: u32, _w: u32, _h: u32) {}
201
202 pub fn framebuffer_info(&self) -> (u32, u32, u32, u32) {
203 (
204 self.fb_phys as u32,
205 self.fb_width,
206 self.fb_height,
207 self.fb_pitch,
208 )
209 }
210}