use core::ptr::null_mut;
use esp_hal::dma::BurstConfig;
use esp_hal::dma::DmaDescriptor;
use esp_hal::dma::DmaTxBuffer;
use esp_hal::dma::EmptyBuf;
use esp_hal::dma::Owner;
use esp_hal::dma::Preparation;
use esp_hal::dma::TransferDirection;
const MAX_PLANES: usize = 8;
pub struct BcmTxDmaBuf {
descriptors: &'static mut [DmaDescriptor],
planes: [(*const u8, usize); MAX_PLANES],
plane_count: usize,
}
impl BcmTxDmaBuf {
pub(crate) fn new(
descriptors: &'static mut [DmaDescriptor],
fb: &impl crate::framebuffer::FrameBuffer,
) -> Self {
let pc = fb.plane_count();
assert!(pc <= MAX_PLANES, "plane_count {pc} exceeds MAX_PLANES");
let mut planes = [(null_mut() as *const u8, 0usize); MAX_PLANES];
for (i, slot) in planes.iter_mut().enumerate().take(pc) {
*slot = fb.plane_ptr_len(i);
}
let required = Self::descriptor_count_for(pc, planes[0].1);
assert!(
descriptors.len() >= required,
"need {required} descriptors, got {}",
descriptors.len()
);
Self {
descriptors,
planes,
plane_count: pc,
}
}
#[allow(dead_code)]
pub(crate) fn transfer_len(&self) -> usize {
let plane_bytes = self.planes[0].1;
let total_reps = (1usize << self.plane_count) - 1;
plane_bytes * total_reps
}
pub(crate) fn split(self) -> &'static mut [DmaDescriptor] {
self.descriptors
}
#[must_use]
pub(crate) const fn descriptor_count_for(
bcm_chunk_count: usize,
bcm_chunk_bytes: usize,
) -> usize {
crate::dma_descriptor_count(bcm_chunk_count, bcm_chunk_bytes)
}
}
unsafe impl DmaTxBuffer for BcmTxDmaBuf {
type View = Self;
type Final = Self;
fn prepare(&mut self) -> Preparation {
let mut desc_idx = 0;
for plane_idx in 0..self.plane_count {
let reps = 1usize << (self.plane_count - 1 - plane_idx);
let (plane_ptr, plane_bytes) = self.planes[plane_idx];
for _ in 0..reps {
let mut remaining = plane_bytes;
let mut offset = 0;
while remaining > 0 {
let chunk = remaining.min(4095);
let desc = &mut self.descriptors[desc_idx];
desc.buffer = unsafe { plane_ptr.add(offset) as *mut u8 };
desc.set_size(chunk);
desc.set_length(chunk);
desc.set_owner(Owner::Dma);
desc.set_suc_eof(false);
desc.next = null_mut();
remaining -= chunk;
offset += chunk;
desc_idx += 1;
}
}
}
for i in 0..desc_idx {
let is_last = i + 1 == desc_idx;
let next = if is_last {
null_mut()
} else {
unsafe { self.descriptors.as_mut_ptr().add(i + 1) }
};
let desc = &mut self.descriptors[i];
desc.set_owner(Owner::Dma);
desc.set_suc_eof(is_last);
desc.next = next;
}
let mut seed = EmptyBuf;
let mut prep: Preparation = seed.prepare();
prep.start = self.descriptors.as_mut_ptr();
prep.direction = TransferDirection::Out;
prep.burst_transfer = BurstConfig::default();
prep.check_owner = Some(false);
prep.auto_write_back = false;
prep
}
fn into_view(self) -> Self::View {
self
}
fn from_view(view: Self::View) -> Self::Final {
view
}
}