1#![allow(dead_code)]
3
4use core::ptr::{read_volatile, write_volatile};
5
6static mut IS_QEMU_ENV: bool = false;
7
8pub fn set_qemu_env(qemu: bool) {
9 unsafe {
10 IS_QEMU_ENV = qemu;
11 }
12}
13
14pub fn is_qemu_env() -> bool {
15 unsafe { IS_QEMU_ENV }
16}
17
18const DMA_BASE: usize = 0x3F007000;
19const DMA_ENABLE: usize = 0x3F007FF0;
20
21pub fn to_bus_address(phys_addr: u32) -> u32 {
23 phys_addr | 0xC0000000
24}
25
26#[repr(C, align(32))]
27#[derive(Debug, Clone, Copy)]
28pub struct DmaControlBlock {
29 pub ti: u32,
30 pub source_ad: u32,
31 pub dest_ad: u32,
32 pub txfr_len: u32,
33 pub stride: u32,
34 pub nextconbk: u32,
35 pub _reserved: [u32; 2],
36}
37
38pub fn dma_memcpy(_channel: usize, src_phys: u32, dst_phys: u32, len_bytes: u32) {
41 if len_bytes == 0 {
42 return;
43 }
44
45 unsafe {
46 core::ptr::copy_nonoverlapping(
47 src_phys as *const u8,
48 dst_phys as *mut u8,
49 len_bytes as usize,
50 );
51 }
52}
53
54pub fn dma_fill_rect(
57 _channel: usize,
58 color_phys: u32,
59 dst_phys: u32,
60 width: u32,
61 height: u32,
62 pitch: u32,
63) {
64 if width == 0 || height == 0 {
65 return;
66 }
67
68 unsafe {
69 let color_val = *(color_phys as *const u32);
70 let dst_ptr = dst_phys as *mut u32;
71 let stride = pitch / 4;
72 for y in 0..height {
73 let row = dst_ptr.add((y * stride) as usize);
74 let slice = core::slice::from_raw_parts_mut(row, width as usize);
75 slice.fill(color_val);
76 }
77 }
78}
79
80pub fn dma_memcpy_2d(
83 _channel: usize,
84 src_phys: u32,
85 dst_phys: u32,
86 width_bytes: u32,
87 height: u32,
88 src_pitch: u32,
89 dst_pitch: u32,
90) {
91 if width_bytes == 0 || height == 0 {
92 return;
93 }
94
95 unsafe {
96 let src_ptr = src_phys as *const u8;
97 let dst_ptr = dst_phys as *mut u8;
98 for y in 0..height {
99 let src_row = src_ptr.add((y * src_pitch) as usize);
100 let dst_row = dst_ptr.add((y * dst_pitch) as usize);
101 core::ptr::copy_nonoverlapping(src_row, dst_row, width_bytes as usize);
102 }
103 }
104}
105
106fn execute_dma(channel: usize, cb: &DmaControlBlock) {
107 let ch_base = DMA_BASE + channel * 0x100;
108 let cb_bus = to_bus_address(cb as *const _ as u32);
109
110 unsafe {
111 let mut enable = read_volatile(DMA_ENABLE as *const u32);
113 enable |= 1 << channel;
114 write_volatile(DMA_ENABLE as *mut u32, enable);
115
116 write_volatile(ch_base as *mut u32, 1 << 1); write_volatile((ch_base + 0x04) as *mut u32, cb_bus);
121
122 write_volatile(ch_base as *mut u32, 1);
124
125 let mut wait_count = 0;
127 while read_volatile(ch_base as *const u32) & (1 << 1) == 0 {
128 core::hint::spin_loop();
129 wait_count += 1;
130 if wait_count > 10_000_000 {
131 write_volatile(ch_base as *mut u32, 1 << 31);
134 crate::println!(
135 "DMA TIMEOUT on channel {}! wait_count={}",
136 channel,
137 wait_count
138 );
139 break;
140 }
141 }
142
143 write_volatile(ch_base as *mut u32, 1 << 1);
145
146 core::arch::asm!("dsb sy", options(nostack));
148 }
149}