use crate::{mipi_dsi::MipiDsi, peripherals::MIPI_DSI_HOST};
const DT_DCS_SHORT_WRITE_0: u8 = 0x05;
const DT_DCS_SHORT_WRITE_1: u8 = 0x15;
const DT_DCS_LONG_WRITE: u8 = 0x39;
const DT_DCS_READ_0: u8 = 0x06;
const DT_SET_MAX_RETURN_PKT: u8 = 0x37;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
PayloadTooLarge,
}
pub struct DsiDbi<'bus, 'd> {
_bus: &'bus mut MipiDsi<'d>,
virtual_channel: u8,
}
impl<'bus, 'd> DsiDbi<'bus, 'd> {
pub(crate) fn new(bus: &'bus mut MipiDsi<'d>, virtual_channel: u8) -> Self {
let h = MIPI_DSI_HOST::regs();
h.cmd_mode_cfg().modify(|_, w| {
w.tear_fx_en().clear_bit();
w.ack_rqst_en().set_bit();
w.gen_sw_0p_tx().set_bit();
w.gen_sw_1p_tx().set_bit();
w.gen_sw_2p_tx().set_bit();
w.gen_sr_0p_tx().set_bit();
w.gen_sr_1p_tx().set_bit();
w.gen_sr_2p_tx().set_bit();
w.gen_lw_tx().set_bit();
w.dcs_sw_0p_tx().set_bit();
w.dcs_sw_1p_tx().set_bit();
w.dcs_sr_0p_tx().set_bit();
w.dcs_lw_tx().set_bit();
w.max_rd_pkt_size().set_bit()
});
Self {
_bus: bus,
virtual_channel,
}
}
pub fn virtual_channel(&self) -> u8 {
self.virtual_channel
}
pub fn write_cmd(&mut self, cmd: u8, params: &[u8]) -> Result<(), Error> {
let h = MIPI_DSI_HOST::regs();
let vc = self.virtual_channel;
let payload_size = 1 + params.len();
if payload_size > u16::MAX as usize {
return Err(Error::PayloadTooLarge);
}
if payload_size > 2 {
let merged = params.len().min(3);
let mut word: u32 = cmd as u32;
for (i, &b) in params[..merged].iter().enumerate() {
word |= (b as u32) << (8 * (i + 1));
}
while h.cmd_pkt_status().read().gen_pld_w_full().bit_is_set() {}
h.gen_pld_data().write(|w| unsafe { w.bits(word) });
let rest = ¶ms[merged..];
let (chunks, tail) = rest.as_chunks::<4>();
for chunk in chunks {
let w32 = u32::from_le_bytes(*chunk);
while h.cmd_pkt_status().read().gen_pld_w_full().bit_is_set() {}
h.gen_pld_data().write(|w| unsafe { w.bits(w32) });
}
if !tail.is_empty() {
let mut w32: u32 = 0;
for (i, &b) in tail.iter().enumerate() {
w32 |= (b as u32) << (8 * i);
}
while h.cmd_pkt_status().read().gen_pld_w_full().bit_is_set() {}
h.gen_pld_data().write(|w| unsafe { w.bits(w32) });
}
let wc = payload_size as u16;
while h.cmd_pkt_status().read().gen_cmd_full().bit_is_set() {}
h.gen_hdr().write(|w| unsafe {
w.gen_vc().bits(vc);
w.gen_dt().bits(DT_DCS_LONG_WRITE);
w.gen_wc_lsbyte().bits((wc & 0xFF) as u8);
w.gen_wc_msbyte().bits((wc >> 8) as u8)
});
} else if payload_size == 2 {
while h.cmd_pkt_status().read().gen_cmd_full().bit_is_set() {}
h.gen_hdr().write(|w| unsafe {
w.gen_vc().bits(vc);
w.gen_dt().bits(DT_DCS_SHORT_WRITE_1);
w.gen_wc_lsbyte().bits(cmd);
w.gen_wc_msbyte().bits(params[0])
});
} else {
while h.cmd_pkt_status().read().gen_cmd_full().bit_is_set() {}
h.gen_hdr().write(|w| unsafe {
w.gen_vc().bits(vc);
w.gen_dt().bits(DT_DCS_SHORT_WRITE_0);
w.gen_wc_lsbyte().bits(cmd);
w.gen_wc_msbyte().bits(0)
});
}
Ok(())
}
pub fn read_cmd(&mut self, cmd: u8, out: &mut [u8]) -> Result<usize, Error> {
let h = MIPI_DSI_HOST::regs();
let vc = self.virtual_channel;
if out.len() > u16::MAX as usize {
return Err(Error::PayloadTooLarge);
}
let max_ret = out.len() as u16;
while h.cmd_pkt_status().read().gen_cmd_full().bit_is_set() {}
h.gen_hdr().write(|w| unsafe {
w.gen_vc().bits(vc);
w.gen_dt().bits(DT_SET_MAX_RETURN_PKT);
w.gen_wc_lsbyte().bits((max_ret & 0xFF) as u8);
w.gen_wc_msbyte().bits((max_ret >> 8) as u8)
});
h.mode_cfg().modify(|_, w| w.cmd_video_mode().set_bit());
h.pckhdl_cfg().modify(|_, w| w.bta_en().set_bit());
h.gen_vcid().modify(|_, w| unsafe { w.rx().bits(vc) });
while h.cmd_pkt_status().read().gen_cmd_full().bit_is_set() {}
h.gen_hdr().write(|w| unsafe {
w.gen_vc().bits(vc);
w.gen_dt().bits(DT_DCS_READ_0);
w.gen_wc_lsbyte().bits(cmd);
w.gen_wc_msbyte().bits(0)
});
while h.cmd_pkt_status().read().gen_rd_cmd_busy().bit_is_set() {}
while h.cmd_pkt_status().read().gen_pld_r_empty().bit_is_set() {}
let mut count = 0usize;
while !h.cmd_pkt_status().read().gen_pld_r_empty().bit_is_set() {
let word = h.gen_pld_data().read().bits();
for i in 0..4 {
if count < out.len() {
out[count] = ((word >> (8 * i)) & 0xFF) as u8;
count += 1;
}
}
}
Ok(count)
}
}