1#![allow(dead_code)]
3
4use crate::kernel::mailbox;
5use core::ptr::{read_volatile, write_volatile};
6
7const V3D_BASE: usize = 0x3FC00000;
8const V3D_IDENT0: *const u32 = V3D_BASE as *const u32;
9const V3D_IDENT1: *const u32 = (V3D_BASE + 0x004) as *const u32;
10const V3D_IDENT2: *const u32 = (V3D_BASE + 0x008) as *const u32;
11const V3D_CT1CS: *mut u32 = (V3D_BASE + 0x110) as *mut u32; const V3D_CT1EA: *mut u32 = (V3D_BASE + 0x114) as *mut u32; const V3D_CT1CA: *mut u32 = (V3D_BASE + 0x118) as *mut u32; pub fn init() -> Result<(), &'static str> {
17 if mailbox::enable_v3d().is_err() {
19 crate::kernel::dma::set_qemu_env(true);
20 return Err("Failed to enable V3D via Mailbox.");
21 }
22
23 let ident0 = unsafe { read_volatile(V3D_IDENT0) };
25
26 if ident0 == 0xDEADBEEF || ident0 == 0 {
27 crate::kernel::dma::set_qemu_env(true);
28 return Err("V3D registers are not accessible (power/clock may be off).");
29 }
30
31 if ident0 != 0x02443356 {
33 println!(
35 "Warning: V3D IDENT0 is 0x{:08X}, expected 0x02443356",
36 ident0
37 );
38 } else {
39 println!(
40 "V3D Engine (VideoCore IV) successfully initialized! (IDENT0: 0x{:08X})",
41 ident0
42 );
43 }
44
45 let ident1 = unsafe { read_volatile(V3D_IDENT1) };
46 let ident2 = unsafe { read_volatile(V3D_IDENT2) };
47 println!("V3D IDENT1: 0x{:08X}, IDENT2: 0x{:08X}", ident1, ident2);
48
49 Ok(())
50}
51
52pub fn v3d_clear(vram_phys: u32, width: u32, height: u32, color: u32) -> Result<(), &'static str> {
54 let ident0 = unsafe { read_volatile(V3D_IDENT0) };
56 if ident0 == 0xDEADBEEF || ident0 == 0 {
57 return Err("V3D is not initialized or power domain is off.");
58 }
59
60 #[repr(C, align(32))]
62 struct AlignBuffer {
63 data: [u8; 4096], }
65 static mut RENDER_CL: AlignBuffer = AlignBuffer { data: [0; 4096] };
66
67 unsafe {
68 let cl = &mut RENDER_CL.data;
69 let mut idx = 0;
70
71 cl[idx] = 114;
73 idx += 1;
74 cl[idx..idx + 4].copy_from_slice(&color.to_le_bytes());
75 idx += 4; cl[idx..idx + 4].copy_from_slice(&color.to_le_bytes());
77 idx += 4; cl[idx] = 0xFF;
79 cl[idx + 1] = 0xFF;
80 cl[idx + 2] = 0xFF;
81 cl[idx + 3] = 0;
82 idx += 4; cl[idx] = 113;
86 idx += 1;
87 let vram_bus = crate::kernel::dma::to_bus_address(vram_phys);
88 cl[idx..idx + 4].copy_from_slice(&vram_bus.to_le_bytes());
89 idx += 4;
90 cl[idx..idx + 2].copy_from_slice(&(width as u16).to_le_bytes());
91 idx += 2;
92 cl[idx..idx + 2].copy_from_slice(&(height as u16).to_le_bytes());
93 idx += 2;
94 let flags: u16 = 1 << 2; cl[idx..idx + 2].copy_from_slice(&flags.to_le_bytes());
96 idx += 2;
97
98 let tiles_x = width.div_ceil(64);
101 let tiles_y = height.div_ceil(64);
102
103 for ty in 0..tiles_y {
104 for tx in 0..tiles_x {
105 cl[idx] = 115;
107 idx += 1;
108 cl[idx] = tx as u8;
109 idx += 1;
110 cl[idx] = ty as u8;
111 idx += 1;
112
113 cl[idx] = 28;
115 idx += 1;
116 let store_flags: u16 = 1 << 6; cl[idx..idx + 2].copy_from_slice(&store_flags.to_le_bytes());
118 idx += 2;
119
120 let tile_offset = (ty * 64 * width + tx * 64) * 4;
122 let tile_vram_bus = crate::kernel::dma::to_bus_address(vram_phys + tile_offset);
123 cl[idx..idx + 4].copy_from_slice(&tile_vram_bus.to_le_bytes());
124 idx += 4;
125 }
126 }
127
128 cl[idx] = 19;
130 idx += 1;
131
132 let cl_ptr = cl.as_ptr() as usize;
134 crate::kernel::mmu::clean_dcache_range(cl_ptr, idx);
135
136 while (read_volatile(V3D_CT1CS) & (1 << 5)) != 0 {
138 core::hint::spin_loop();
139 }
140
141 let cl_bus = crate::kernel::dma::to_bus_address(cl_ptr as u32);
142 let cl_end_bus = cl_bus + idx as u32;
143
144 write_volatile(V3D_CT1CA, cl_bus);
145 write_volatile(V3D_CT1EA, cl_end_bus);
146
147 let mut timeout = 0;
149 while (read_volatile(V3D_CT1CS) & (1 << 5)) != 0 {
150 core::hint::spin_loop();
151 timeout += 1;
152 if timeout > 10_000_000 {
153 return Err("V3D rendering timeout.");
154 }
155 }
156 }
157
158 Ok(())
159}