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;
#[cfg(feature = "iram")]
use esp_hal::ram;
use crate::MAX_DMA_CHUNK_SIZE;
use crate::framebuffer::BcmSegment;
use crate::framebuffer::FrameBuffer;
#[cfg(feature = "full-chain-dma")]
pub(crate) mod full_chain;
#[cfg(not(feature = "full-chain-dma"))]
pub(crate) mod linear;
pub(crate) fn validate_fb_internal_ram(fb: &impl FrameBuffer) {
fn assert_in_dram(dram: &core::ops::Range<usize>, ptr: *const (), what: &str) {
let addr = ptr as usize;
assert!(
dram.contains(&addr),
"{what} at {addr:#010X} is not in internal DRAM ({dram:#010X?}); \
PSRAM is not supported for DMA framebuffers"
);
}
let dram = esp_metadata_generated::memory_range!("DRAM");
assert_in_dram(&dram, core::ptr::from_ref(fb).cast::<()>(), "framebuffer");
for i in 0..fb.bcm_segment_count() {
let seg = fb.bcm_segment(i);
assert_in_dram(&dram, seg.ptr.cast::<()>(), "BCM segment");
}
}
#[cfg_attr(feature = "iram", ram)]
pub(super) fn make_preparation(descriptors: &mut [DmaDescriptor]) -> Preparation {
let mut empty = EmptyBuf;
let mut prep: Preparation = empty.prepare();
prep.start = descriptors.as_mut_ptr();
prep.burst_transfer = BurstConfig::default();
prep.check_owner = Some(false);
prep.auto_write_back = false;
prep
}
#[cfg_attr(feature = "iram", ram)]
pub(super) fn fill_descriptor_chain(
descriptors: &mut [DmaDescriptor],
segment_count: usize,
get_segment: impl Fn(usize) -> BcmSegment,
total_descs: usize,
last_next: *mut DmaDescriptor,
last_suc_eof: bool,
) {
let base_ptr = descriptors.as_mut_ptr();
let mut desc_idx = 0;
for seg_idx in 0..segment_count {
let seg = get_segment(seg_idx);
for _ in 0..seg.reps {
let mut remaining = seg.len;
let mut offset = 0;
while remaining > 0 {
let chunk = remaining.min(MAX_DMA_CHUNK_SIZE);
let is_last = desc_idx + 1 == total_descs;
let next = if is_last {
last_next
} else {
unsafe { base_ptr.add(desc_idx + 1) }
};
let desc = &mut descriptors[desc_idx];
desc.buffer = unsafe { seg.ptr.add(offset).cast_mut() };
desc.set_size(chunk);
desc.set_length(chunk);
desc.set_owner(Owner::Dma);
desc.set_suc_eof(is_last & last_suc_eof);
desc.next = next;
remaining -= chunk;
offset += chunk;
desc_idx += 1;
}
}
}
}