1use core::{
4 marker::PhantomData,
5 pin::Pin,
6 sync::atomic,
7 task::{Context, Poll},
8};
9
10use esp_sync::NonReentrantMutex;
11
12use crate::{
13 asynch::AtomicWaker,
14 dma::aligned::InternalMemory,
15 interrupt,
16 mipi_dsi::{
17 ConfigError,
18 MipiDsi,
19 vdma::{VdmaChannel, VdmaLinkItem},
20 },
21 peripherals::{Interrupt, MIPI_DSI_BRIDGE, MIPI_DSI_HOST, VDMA},
22 soc::clocks::{ClockTree, MipiDsiDpiClkConfig, MipiDsiInstance},
23 system::Cpu,
24};
25
26static VDMA_ISR_CHANNEL: atomic::AtomicU8 = atomic::AtomicU8::new(0);
32
33const MAX_FBS: usize = 3;
34const NUM_LLIS: usize = 2;
38const DMA_BURST_LEN: u32 = 256;
39const FIFO_EMPTY_THRESHOLD: u32 = 1024 - DMA_BURST_LEN;
40
41static LLI_STORAGE: NonReentrantMutex<InternalMemory<[VdmaLinkItem; NUM_LLIS]>> =
44 NonReentrantMutex::new(InternalMemory::new(
45 [const { VdmaLinkItem::zeroed() }; NUM_LLIS],
46 ));
47
48pub use crate::soc::clocks::MipiDsiDpiClkSclk as DpiClockSource;
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum ColorFormat {
59 Rgb888,
61 Rgb565,
63}
64
65impl ColorFormat {
66 pub(crate) fn bits_per_pixel(self) -> u32 {
67 match self {
68 Self::Rgb888 => 24,
69 Self::Rgb565 => 16,
70 }
71 }
72
73 fn raw_type(self) -> u8 {
74 match self {
75 Self::Rgb888 => 0,
76 Self::Rgb565 => 2,
77 }
78 }
79
80 fn dpi_type(self) -> u8 {
81 match self {
82 Self::Rgb888 => 0,
83 Self::Rgb565 => 2,
84 }
85 }
86
87 fn host_color_coding(self) -> u8 {
89 match self {
90 Self::Rgb888 => 5, Self::Rgb565 => 0, }
93 }
94}
95
96#[derive(Clone, Copy, Debug)]
98pub struct FrameTiming {
99 pub h_active: u32,
101 pub hsw: u32,
103 pub hbp: u32,
105 pub hfp: u32,
107 pub v_active: u32,
109 pub vsw: u32,
111 pub vbp: u32,
113 pub vfp: u32,
115}
116
117#[derive(Clone, Copy, Debug)]
119pub struct DpiConfig {
120 pub virtual_channel: u8,
122 pub pixel_clock_mhz: f32,
124 pub dpi_clk_src: DpiClockSource,
126 pub in_color_format: ColorFormat,
128 pub out_color_format: ColorFormat,
130 pub timing: FrameTiming,
132}
133
134#[crate::ram]
143#[crate::handler]
144fn vdma_block_done_isr() {
145 let channel_id = VDMA_ISR_CHANNEL.load(atomic::Ordering::Relaxed) as usize;
146 let ch = VDMA::regs().ch(channel_id);
147 ch.intclear0().write(|w| unsafe { w.bits(0xFFFFFFFF) });
148
149 LLI_STORAGE.with(|storage| {
150 let mut storage = storage.get_mut();
151 for lli in storage.iter() {
152 lli.rearm();
153 }
154
155 storage.writeback();
156 });
157}
158
159static VSYNC_WAKER: AtomicWaker = AtomicWaker::new();
162
163#[crate::handler]
164fn dsi_bridge_isr() {
165 let bridge = MIPI_DSI_BRIDGE::regs();
166 let st = bridge.int_st().read();
167 if st.vsync().bit_is_set() {
168 bridge.int_ena().modify(|_, w| w.vsync().clear_bit());
169 VSYNC_WAKER.wake();
170 }
171}
172
173pub struct DsiDpi<'d> {
180 _guard: crate::mipi_dsi::DphyGuard<'d>,
181 fb_ptrs: [*mut u8; MAX_FBS],
182 fb_size: usize,
183 num_fbs: usize,
184 current_fb: usize,
185 _phantom: PhantomData<&'d mut [u8]>,
186}
187
188impl Drop for DsiDpi<'_> {
189 fn drop(&mut self) {
190 let channel_id = self._guard.vdma_channel_id as usize;
192 let ch = VDMA::regs().ch(channel_id);
193 unsafe {
194 ch.intsignal_enable0().write_with_zero(|w| w);
195 ch.intstatus_enable0().write_with_zero(|w| w);
196 }
197 interrupt::disable(Cpu::current(), Interrupt::DMA);
198
199 let shift = channel_id as u32;
201 let val: u32 = 0x0100 << shift; unsafe { VDMA::regs().chen0().write(|w| w.bits(val)) };
203
204 MIPI_DSI_BRIDGE::regs()
205 .dpi_misc_config()
206 .modify(|_, w| w.dpi_en().clear_bit());
207 ClockTree::with(|clocks| MipiDsiInstance::MipiDsi.release_dpi_clk(clocks));
208 }
210}
211
212impl<'d> DsiDpi<'d> {
213 pub(crate) fn new(
214 bus: MipiDsi<'d>,
215 config: DpiConfig,
216 framebuffers: &[&'d mut [u8]],
217 ) -> Result<Self, ConfigError> {
218 let num_fbs = framebuffers.len();
219 debug_assert!((1..=MAX_FBS).contains(&num_fbs));
220 let fb_size = framebuffers[0].len();
221
222 let (_dpi_clk_config, real_dpi_mhz) = ClockTree::with(|clocks| {
227 let src_hz = MipiDsiInstance::dpi_clk_config_frequency(
229 clocks,
230 MipiDsiDpiClkConfig::new(config.dpi_clk_src, 0),
231 );
232 let src_mhz = src_hz as f32 / 1_000_000.0;
233 let div = ((src_mhz / config.pixel_clock_mhz) + 0.5) as u32;
234 let div = div.max(1);
235 let cfg = MipiDsiDpiClkConfig::new(config.dpi_clk_src, div - 1);
236 MipiDsiInstance::MipiDsi.configure_dpi_clk(clocks, cfg);
237 MipiDsiInstance::MipiDsi.request_dpi_clk(clocks);
238 (cfg, src_mhz / div as f32)
239 });
240
241 let host = MIPI_DSI_HOST::regs();
242 let bridge = MIPI_DSI_BRIDGE::regs();
243
244 host.dpi_vcid()
246 .modify(|_, w| unsafe { w.dpi_vcid().bits(config.virtual_channel) });
247 host.dpi_color_coding().modify(|_, w| unsafe {
248 w.dpi_color_coding()
249 .bits(config.out_color_format.host_color_coding())
250 });
251
252 host.dpi_cfg_pol().write(|w| unsafe { w.bits(0) });
254
255 host.vid_mode_cfg().modify(|_, w| unsafe {
261 w.vid_mode_type().bits(2); w.lp_vsa_en().set_bit();
263 w.lp_vbp_en().set_bit();
264 w.lp_vfp_en().set_bit();
265 w.lp_hbp_en().set_bit();
266 w.lp_hfp_en().set_bit();
267 w.lp_cmd_en().set_bit()
268 });
269
270 let t = &config.timing;
271 host.vid_pkt_size()
272 .modify(|_, w| unsafe { w.vid_pkt_size().bits(t.h_active as u16) });
273 host.vid_num_chunks()
274 .modify(|_, w| unsafe { w.vid_num_chunks().bits(0) });
275 host.vid_null_size()
276 .modify(|_, w| unsafe { w.vid_null_size().bits(0) });
277
278 let ratio = bus.lane_bit_rate_mbps / config.pixel_clock_mhz / 8.0;
280 let htotal = t.hsw + t.hbp + t.h_active + t.hfp;
281
282 let host_hsw = fround_u32(t.hsw as f32 * ratio);
283 let host_hbp = fround_u32(t.hbp as f32 * ratio);
284 let host_act = fround_u32(t.h_active as f32 * ratio);
285 let host_hfp = fround_u32(t.hfp as f32 * ratio);
286 let host_htotal = fround_u32(htotal as f32 * ratio);
287 let comp = host_htotal as i32 - (host_hsw + host_hbp + host_act + host_hfp) as i32;
288 let host_act = (host_act as i32 + comp).max(0) as u32;
289
290 host.vid_hsa_time()
291 .modify(|_, w| unsafe { w.vid_hsa_time().bits(host_hsw as u16) });
292 host.vid_hbp_time()
293 .modify(|_, w| unsafe { w.vid_hbp_time().bits(host_hbp as u16) });
294 host.vid_hline_time().modify(|_, w| unsafe {
295 w.vid_hline_time()
296 .bits((host_hsw + host_hbp + host_act + host_hfp) as u16)
297 });
298
299 host.vid_vsa_lines()
301 .modify(|_, w| unsafe { w.vsa_lines().bits(t.vsw as u16) });
302 host.vid_vbp_lines()
303 .modify(|_, w| unsafe { w.vbp_lines().bits(t.vbp as u16) });
304 host.vid_vactive_lines()
305 .modify(|_, w| unsafe { w.v_active_lines().bits(t.v_active as u16) });
306 host.vid_vfp_lines()
307 .modify(|_, w| unsafe { w.vfp_lines().bits(t.vfp as u16) });
308
309 let brg_hfp = {
311 let c = fround_u32(real_dpi_mhz / config.pixel_clock_mhz * htotal as f32) as i32
312 - htotal as i32;
313 (t.hfp as i32 + c).max(0) as u32
314 };
315 bridge.dpi_h_cfg0().modify(|_, w| unsafe {
316 w.htotal()
317 .bits((t.hsw + t.hbp + t.h_active + brg_hfp) as u16);
318 w.hdisp().bits(t.h_active as u16)
319 });
320 bridge.dpi_h_cfg1().modify(|_, w| unsafe {
321 w.hsync().bits(t.hsw as u16);
322 w.hbank().bits(t.hbp as u16)
323 });
324 bridge.dpi_v_cfg0().modify(|_, w| unsafe {
325 w.vtotal().bits((t.vsw + t.vbp + t.v_active + t.vfp) as u16);
326 w.vdisp().bits(t.v_active as u16)
327 });
328 bridge.dpi_v_cfg1().modify(|_, w| unsafe {
329 w.vsync().bits(t.vsw as u16);
330 w.vbank().bits(t.vbp as u16)
331 });
332
333 let total_bits = t.h_active * t.v_active * config.in_color_format.bits_per_pixel();
335 bridge.raw_num_cfg().modify(|_, w| unsafe {
336 w.raw_num_total().bits(total_bits.div_ceil(64));
337 w.unalign_64bit_en().bit(!total_bits.is_multiple_of(64));
338 w.raw_num_total_set().set_bit()
339 });
340 bridge
341 .dpi_misc_config()
342 .modify(|_, w| unsafe { w.fifo_underrun_discard_vcnt().bits(t.h_active as u16) });
343 bridge.pixel_type().modify(|_, w| unsafe {
344 w.raw_type().bits(config.in_color_format.raw_type());
345 w.dpi_type().bits(config.out_color_format.dpi_type());
346 w.data_in_type().clear_bit()
347 });
348 bridge.dma_flow_ctrl().modify(|_, w| unsafe {
349 w.dsi_dma_flow_controller().clear_bit();
350 w.dma_flow_multiblk_num().bits(1)
351 });
352 bridge
353 .dma_frame_interval()
354 .modify(|_, w| w.dma_multiblk_en().clear_bit());
355 bridge
356 .dma_req_cfg()
357 .modify(|_, w| unsafe { w.dma_burst_len().bits(DMA_BURST_LEN as u16) });
358 bridge.raw_buf_almost_empty_thrd().modify(|_, w| unsafe {
359 w.dsi_raw_buf_almost_empty_thrd()
360 .bits(FIFO_EMPTY_THRESHOLD as u16)
361 });
362
363 bridge.en().modify(|_, w| w.dsi_en().set_bit());
364 bridge
365 .dpi_config_update()
366 .write(|w| w.dpi_config_update().set_bit());
367
368 interrupt::bind_handler(Interrupt::DSI_BRIDGE, dsi_bridge_isr);
369
370 for fb in framebuffers.iter() {
372 unsafe {
373 crate::soc::cache_writeback_addr(fb.as_ptr() as u32, fb_size as u32);
374 }
375 }
376
377 let fb_ptrs = core::array::from_fn::<_, MAX_FBS, _>(|i| {
379 if i < num_fbs {
380 framebuffers[i].as_ptr().cast_mut()
381 } else {
382 core::ptr::null_mut::<u8>()
383 }
384 });
385
386 let vdma_channel_id = bus.guard.vdma_channel_id;
387 VDMA_ISR_CHANNEL.store(vdma_channel_id, atomic::Ordering::Relaxed);
388
389 LLI_STORAGE.with(|storage| {
390 let mut storage = storage.get_mut();
391 for i in 0..NUM_LLIS {
392 let next = &raw const storage[(i + 1) % NUM_LLIS];
393 storage[i].configure(fb_ptrs[0] as u32, fb_size, next);
394 }
395
396 storage.writeback();
398
399 VdmaChannel::new(vdma_channel_id).start(&storage[0]);
400 });
401
402 {
406 let ch = VDMA::regs().ch(vdma_channel_id as usize);
407 ch.intstatus_enable0()
408 .write(|w| w.ch1_enable_block_tfr_done_intstat().set_bit());
409 ch.intsignal_enable0()
410 .write(|w| w.ch1_enable_block_tfr_done_intsignal().set_bit());
411 }
412 interrupt::bind_handler(Interrupt::DMA, vdma_block_done_isr);
413
414 host.mode_cfg()
416 .modify(|_, w| w.cmd_video_mode().clear_bit());
417 bridge.dpi_misc_config().modify(|_, w| w.dpi_en().set_bit());
418 bridge
419 .dpi_config_update()
420 .write(|w| w.dpi_config_update().set_bit());
421
422 let MipiDsi { guard, .. } = bus;
423 Ok(Self {
424 _guard: guard,
425 fb_ptrs,
426 fb_size,
427 num_fbs,
428 current_fb: 0,
429 _phantom: PhantomData,
430 })
431 }
432
433 pub fn framebuffer_mut(&mut self) -> &mut [u8] {
438 let back = (self.current_fb + 1) % self.num_fbs;
439 unsafe { core::slice::from_raw_parts_mut(self.fb_ptrs[back], self.fb_size) }
440 }
441
442 pub fn commit(&mut self) {
452 let back = (self.current_fb + 1) % self.num_fbs;
453
454 unsafe {
456 crate::soc::cache_writeback_addr(self.fb_ptrs[back] as u32, self.fb_size as u32);
457 }
458
459 let src = self.fb_ptrs[back] as u32;
463 LLI_STORAGE.with(|storage| {
464 let storage = storage.get_mut();
465 for lli in storage.iter() {
466 lli.set_source(src);
467 }
468 });
469
470 self.current_fb = back;
473 }
474
475 pub fn wait_for_vsync(&mut self) {
481 let bridge = MIPI_DSI_BRIDGE::regs();
482 while !bridge.int_raw().read().vsync().bit_is_set() {}
483 bridge.int_clr().write(|w| w.vsync().clear_bit_by_one());
484 }
485
486 pub fn wait_for_vsync_async(&mut self) -> impl Future<Output = ()> {
488 VsyncFuture { _dpi: self }
489 }
490}
491
492#[must_use = "futures do nothing unless you `.await` or poll them"]
493struct VsyncFuture<'a, 'b> {
494 _dpi: &'a mut DsiDpi<'b>,
495}
496
497impl Future for VsyncFuture<'_, '_> {
498 type Output = ();
499
500 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
501 let bridge = MIPI_DSI_BRIDGE::regs();
502 if bridge.int_raw().read().vsync().bit_is_set() {
503 bridge.int_clr().write(|w| w.vsync().clear_bit_by_one());
504 Poll::Ready(())
505 } else {
506 VSYNC_WAKER.register(cx.waker());
507 bridge.int_ena().modify(|_, w| w.vsync().set_bit());
508 Poll::Pending
509 }
510 }
511}
512
513impl Drop for VsyncFuture<'_, '_> {
514 fn drop(&mut self) {
515 let bridge = MIPI_DSI_BRIDGE::regs();
516 bridge.int_ena().modify(|_, w| w.vsync().clear_bit());
517 }
518}
519
520#[inline]
523fn fround_u32(x: f32) -> u32 {
524 (x + 0.5) as u32
525}