1#![allow(dead_code)]
3
4extern crate alloc;
5use crate::os_lib::mml::Note;
6use alloc::vec::Vec;
7use spin::Mutex;
8
9const GPIO_BASE: usize = 0x3F20_0000;
10const GPFSEL4: *mut u32 = (GPIO_BASE + 0x10) as *mut u32;
11
12const CM_BASE: usize = 0x3F10_1000;
13const CM_PWMCTL: *mut u32 = (CM_BASE + 0x10A0) as *mut u32;
14const CM_PWMDIV: *mut u32 = (CM_BASE + 0x10A4) as *mut u32;
15
16const PWM_BASE: usize = 0x3F20_C000;
17const PWM_CTL: *mut u32 = PWM_BASE as *mut u32;
18const PWM_STA: *mut u32 = (PWM_BASE + 0x04) as *mut u32;
19const PWM_DMAC: *mut u32 = (PWM_BASE + 0x08) as *mut u32;
20const PWM_RNG1: *mut u32 = (PWM_BASE + 0x10) as *mut u32;
21const PWM_DAT1: *mut u32 = (PWM_BASE + 0x14) as *mut u32;
22const PWM_FIF1: *mut u32 = (PWM_BASE + 0x18) as *mut u32;
23const PWM_RNG2: *mut u32 = (PWM_BASE + 0x20) as *mut u32;
24const PWM_DAT2: *mut u32 = (PWM_BASE + 0x24) as *mut u32;
25
26const I2S_BASE: usize = 0x3F20_3000;
28const I2S_CS: *mut u32 = I2S_BASE as *mut u32;
29const I2S_FIFO: *mut u32 = (I2S_BASE + 0x04) as *mut u32;
30const I2S_MODE: *mut u32 = (I2S_BASE + 0x08) as *mut u32;
31const I2S_RXC: *mut u32 = (I2S_BASE + 0x0C) as *mut u32;
32const I2S_TXC: *mut u32 = (I2S_BASE + 0x10) as *mut u32;
33const I2S_DREQ: *mut u32 = (I2S_BASE + 0x14) as *mut u32;
34
35const DMA3_BASE: usize = 0x3F00_7300;
37const DMA3_CS: *mut u32 = DMA3_BASE as *mut u32;
38const DMA3_CONBLK_AD: *mut u32 = (DMA3_BASE + 0x04) as *mut u32;
39
40const DMA4_BASE: usize = 0x3F00_7400;
41const DMA4_CS: *mut u32 = DMA4_BASE as *mut u32;
42const DMA4_CONBLK_AD: *mut u32 = (DMA4_BASE + 0x04) as *mut u32;
43
44const PWM_CLOCK_FREQ: u32 = 1_200_000;
46
47static PLAY_QUEUE: Mutex<Vec<Note>> = Mutex::new(Vec::new());
49static PLAY_INDEX: Mutex<usize> = Mutex::new(0);
50static IS_PLAYING: Mutex<bool> = Mutex::new(false);
51static THREAD_STARTED: Mutex<bool> = Mutex::new(false);
52
53static mut PCM_BUFFER_PWM: [u8; 65536] = [0; 65536];
55static mut PCM_BUFFER_I2S: [i16; 65536] = [0; 65536];
56static mut DMA_CB_PWM: crate::kernel::dma::DmaControlBlock = crate::kernel::dma::DmaControlBlock {
57 ti: 0,
58 source_ad: 0,
59 dest_ad: 0,
60 txfr_len: 0,
61 stride: 0,
62 nextconbk: 0,
63 _reserved: [0; 2],
64};
65static mut DMA_CB_I2S: crate::kernel::dma::DmaControlBlock = crate::kernel::dma::DmaControlBlock {
66 ti: 0,
67 source_ad: 0,
68 dest_ad: 0,
69 txfr_len: 0,
70 stride: 0,
71 nextconbk: 0,
72 _reserved: [0; 2],
73};
74
75pub struct Audio;
76
77impl Audio {
78 pub fn init() {
80 unsafe {
81 let mut val = core::ptr::read_volatile(GPFSEL4);
83 val &= !0b111; val |= 0b100; val &= !(0b111 << 15); val |= 0b100 << 15; core::ptr::write_volatile(GPFSEL4, val);
88
89 core::ptr::write_volatile(CM_PWMCTL, 0x5A00_0000);
92 for _ in 0..1000 {
93 core::arch::asm!("nop");
94 }
95
96 core::ptr::write_volatile(CM_PWMDIV, 0x5A00_0000 | (16 << 12));
98 for _ in 0..1000 {
99 core::arch::asm!("nop");
100 }
101
102 core::ptr::write_volatile(CM_PWMCTL, 0x5A00_0010 | 0x01);
104 for _ in 0..1000 {
105 core::arch::asm!("nop");
106 }
107
108 core::ptr::write_volatile(PWM_CTL, 0);
111 for _ in 0..1000 {
112 core::arch::asm!("nop");
113 }
114
115 core::ptr::write_volatile(PWM_RNG1, 1024);
117 core::ptr::write_volatile(PWM_RNG2, 1024);
118
119 core::ptr::write_volatile(PWM_DAT1, 0);
121 core::ptr::write_volatile(PWM_DAT2, 0);
122
123 core::ptr::write_volatile(PWM_CTL, (1 << 0) | (1 << 1) | (1 << 8) | (1 << 9));
125
126 core::ptr::write_volatile(I2S_CS, 0); core::ptr::write_volatile(I2S_MODE, 0);
130 core::ptr::write_volatile(I2S_TXC, (1 << 30) | (1 << 29) | (8 << 16) | (1 << 15)); core::ptr::write_volatile(I2S_DREQ, (8 << 24) | (8 << 8)); core::ptr::write_volatile(I2S_CS, 1 << 2); let dma_en_ptr = 0x3F007FF0 as *mut u32;
138 let current_en = core::ptr::read_volatile(dma_en_ptr);
139 core::ptr::write_volatile(dma_en_ptr, current_en | (1 << 3) | (1 << 4));
140 }
142
143 crate::info!(
144 "[AUD] Hardware PWM (Analog) and I2S (HDMI) audio engines initialized successfully."
145 );
146 }
147
148 fn ensure_playback_thread() {
153 let mut started = THREAD_STARTED.lock();
154 if !*started {
155 *started = true;
156 let pid = crate::kernel::scheduler::spawn(
161 Self::playback_thread_entry,
162 crate::kernel::scheduler::Priority::High,
163 "mml_player",
164 );
165 if pid == 0 {
166 crate::warn!("[AUDIO] 再生スレッドを起動できません(ヒープ不足)");
167 *started = false;
168 }
169 }
170 }
171
172 pub fn set_tone(freq: u32) {
174 if freq == 0 {
175 Self::mute();
176 return;
177 }
178
179 let rng = PWM_CLOCK_FREQ / freq;
180 let dat = rng / 2; unsafe {
183 core::ptr::write_volatile(PWM_RNG1, rng);
184 core::ptr::write_volatile(PWM_RNG2, rng);
185 core::ptr::write_volatile(PWM_DAT1, dat);
186 core::ptr::write_volatile(PWM_DAT2, dat);
187 }
188 }
189
190 pub fn mute() {
192 unsafe {
193 core::ptr::write_volatile(PWM_DAT1, 0);
194 core::ptr::write_volatile(PWM_DAT2, 0);
195 }
196 }
197
198 pub fn play_mml(mml_str: &str) {
200 let notes = crate::os_lib::mml::parse_mml(mml_str);
201 if notes.is_empty() {
202 return;
203 }
204
205 Self::ensure_playback_thread();
206 {
207 let mut queue = PLAY_QUEUE.lock();
208 let mut idx = PLAY_INDEX.lock();
209 let mut playing = IS_PLAYING.lock();
210
211 *queue = notes;
213 *idx = 0;
214 *playing = true;
215 }
216 }
217
218 pub fn is_playing() -> bool {
220 *IS_PLAYING.lock()
221 }
222
223 pub fn stop_mml() {
225 let mut queue = PLAY_QUEUE.lock();
226 let mut idx = PLAY_INDEX.lock();
227 queue.clear();
228 *idx = 0;
229 Self::mute();
230 }
231
232 pub fn play_tone_async(freq: u32, duration_ms: u32) {
234 let notes = alloc::vec![Note { freq, duration_ms }];
235
236 Self::ensure_playback_thread();
237 {
238 let mut queue = PLAY_QUEUE.lock();
239 let mut idx = PLAY_INDEX.lock();
240 let mut playing = IS_PLAYING.lock();
241
242 *queue = notes;
244 *idx = 0;
245 *playing = true;
246 }
247 }
248
249 fn playback_thread_entry() {
251 loop {
252 let note_opt = {
253 let mut queue = PLAY_QUEUE.lock();
254 let mut idx = PLAY_INDEX.lock();
255 if *idx < queue.len() {
256 let note = queue[*idx];
257 *idx += 1;
258 Some(note)
259 } else {
260 queue.clear();
262 *idx = 0;
263 let mut playing = IS_PLAYING.lock();
264 *playing = false;
265 None
266 }
267 };
268
269 if let Some(note) = note_opt {
270 if note.freq == 0 {
271 Self::mute();
272 } else {
273 Self::set_tone(note.freq);
274 }
275
276 let ticks = (note.duration_ms / 10) as usize;
278 if ticks > 0 {
279 crate::kernel::scheduler::sleep(ticks);
280 } else {
281 crate::kernel::scheduler::sleep(1);
282 }
283
284 Self::mute();
286 crate::kernel::scheduler::sleep(1);
287 } else {
288 crate::kernel::scheduler::sleep(2);
290 }
291 }
292 }
293
294 pub fn play_pcm_stream(pcm_data: &[i16]) {
296 if pcm_data.is_empty() {
297 return;
298 }
299
300 unsafe {
301 let len = pcm_data.len().min(65536);
303
304 core::ptr::copy_nonoverlapping(pcm_data.as_ptr(), PCM_BUFFER_I2S.as_mut_ptr(), len);
306
307 for i in 0..len {
309 let sample_8 = (((pcm_data[i] as i32 + 32768) >> 8) & 0xFF) as u8;
311 PCM_BUFFER_PWM[i] = ((sample_8 as u32 * 4).min(1023)) as u8;
313 }
314
315 let pwm_buf_ptr = PCM_BUFFER_PWM.as_ptr() as usize;
317 let i2s_buf_ptr = PCM_BUFFER_I2S.as_ptr() as usize;
318
319 crate::kernel::mmu::clean_dcache_range(pwm_buf_ptr, len);
320 crate::kernel::mmu::clean_dcache_range(i2s_buf_ptr, len * 2);
321
322 DMA_CB_PWM = crate::kernel::dma::DmaControlBlock {
324 ti: (5 << 16) | (1 << 8) | (1 << 4) | (1 << 3), source_ad: crate::kernel::dma::to_bus_address(pwm_buf_ptr as u32),
326 dest_ad: crate::kernel::dma::to_bus_address(PWM_FIF1 as u32),
327 txfr_len: len as u32,
328 stride: 0,
329 nextconbk: 0,
330 _reserved: [0; 2],
331 };
332 crate::kernel::mmu::clean_dcache_range(
333 &DMA_CB_PWM as *const _ as usize,
334 core::mem::size_of::<crate::kernel::dma::DmaControlBlock>(),
335 );
336
337 DMA_CB_I2S = crate::kernel::dma::DmaControlBlock {
339 ti: (6 << 16) | (1 << 8) | (1 << 4) | (1 << 3), source_ad: crate::kernel::dma::to_bus_address(i2s_buf_ptr as u32),
341 dest_ad: crate::kernel::dma::to_bus_address(I2S_FIFO as u32),
342 txfr_len: (len * 2) as u32,
343 stride: 0,
344 nextconbk: 0,
345 _reserved: [0; 2],
346 };
347 crate::kernel::mmu::clean_dcache_range(
348 &DMA_CB_I2S as *const _ as usize,
349 core::mem::size_of::<crate::kernel::dma::DmaControlBlock>(),
350 );
351
352 if !crate::kernel::dma::is_qemu_env() {
353 core::ptr::write_volatile(
356 DMA3_CONBLK_AD,
357 crate::kernel::dma::to_bus_address(&DMA_CB_PWM as *const _ as *const _ as u32),
358 );
359 core::ptr::write_volatile(DMA3_CS, (1 << 0) | (8 << 16)); core::ptr::write_volatile(
363 DMA4_CONBLK_AD,
364 crate::kernel::dma::to_bus_address(&DMA_CB_I2S as *const _ as *const _ as u32),
365 );
366 core::ptr::write_volatile(DMA4_CS, (1 << 0) | (8 << 16)); }
368 }
369 }
370}
371
372#[derive(Clone, Copy, Debug)]
373pub enum SeType {
374 Apply, Save, Delete, Close, }
379
380pub fn play_system_se(se: SeType) {
382 if !crate::kernel::config::get_config().enable_sound {
384 return;
385 }
386
387 let mml = match se {
388 SeType::Apply => "T180 L16 O5 C E G",
389 SeType::Save => "T240 L16 O5 G O6 C",
390 SeType::Delete => "T150 L12 O4 C O3 G",
391 SeType::Close => "T240 L16 O5 F D",
392 };
393
394 Audio::play_mml(mml);
395}