use core::ptr;
use core::sync::atomic::{
compiler_fence,
Ordering,
};
use nb;
use crate::{
init_state,
raw::{
self,
dma::{
ACTIVE0,
CFG,
ENABLESET0,
SETTRIG0,
XFERCFG,
},
},
reg_proxy::{
Reg,
RegProxy,
},
syscon,
};
pub struct DMA {
dma: raw::DMA,
}
impl DMA {
pub(crate) fn new(dma: raw::DMA) -> Self {
DMA { dma }
}
pub fn split(self, descriptors: &'static mut DescriptorTable) -> Parts {
let srambase = descriptors as *mut _ as u32;
Parts {
handle : Handle::new(self.dma, srambase),
channels: Channels::new(descriptors),
}
}
pub fn free(self) -> raw::DMA {
self.dma
}
}
pub struct Parts {
pub handle: Handle<init_state::Disabled>,
pub channels: Channels,
}
pub struct Handle<State = init_state::Enabled> {
_state : State,
dma : raw::DMA,
srambase: u32,
}
impl Handle<init_state::Disabled> {
pub(crate) fn new(dma: raw::DMA, srambase: u32) -> Self {
Handle {
_state : init_state::Disabled,
dma : dma,
srambase: srambase,
}
}
}
impl<'dma> Handle<init_state::Disabled> {
pub fn enable(self, syscon: &mut syscon::Handle)
-> Handle<init_state::Enabled>
{
syscon.enable_clock(&self.dma);
self.dma.srambase.write(|w|
unsafe { w.bits(self.srambase) }
);
self.dma.ctrl.write(|w| w.enable().enabled());
Handle {
_state : init_state::Enabled(()),
dma : self.dma,
srambase: self.srambase,
}
}
}
impl Handle<init_state::Enabled> {
pub fn disable(self, syscon: &mut syscon::Handle)
-> Handle<init_state::Disabled>
{
syscon.disable_clock(&self.dma);
Handle {
_state : init_state::Disabled,
dma : self.dma,
srambase: self.srambase,
}
}
}
#[repr(C, align(512))]
pub struct DescriptorTable([ChannelDescriptor; 18]);
impl DescriptorTable {
pub const fn new() -> Self {
DescriptorTable([
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
ChannelDescriptor::new(),
])
}
}
#[repr(C, align(16))]
struct ChannelDescriptor {
config : u32,
source_end: *const u8,
dest_end : *mut u8,
next_desc : *const ChannelDescriptor,
}
impl ChannelDescriptor {
const fn new() -> Self {
ChannelDescriptor {
config : 0,
source_end: ptr::null(),
dest_end : ptr::null_mut(),
next_desc : ptr::null(),
}
}
}
unsafe impl Send for ChannelDescriptor {}
pub struct Channel<T, S> where T: ChannelTrait {
ty : T,
_state : S,
descriptor: &'static mut ChannelDescriptor,
cfg : RegProxy<T::Cfg>,
xfercfg: RegProxy<T::Xfercfg>,
active0 : RegProxy<ACTIVE0>,
enableset0: RegProxy<ENABLESET0>,
settrig0 : RegProxy<SETTRIG0>,
}
impl<T> Channel<T, init_state::Disabled> where T: ChannelTrait {
pub fn enable<'dma>(self, dma: &'dma Handle)
-> Channel<T, init_state::Enabled<&'dma Handle>>
{
Channel {
ty : self.ty,
_state : init_state::Enabled(dma),
descriptor: self.descriptor,
cfg : self.cfg,
xfercfg: self.xfercfg,
active0 : self.active0,
enableset0: self.enableset0,
settrig0 : self.settrig0,
}
}
}
impl<'dma, T> Channel<T, init_state::Enabled<&'dma Handle>>
where T: ChannelTrait
{
pub fn start_transfer<D>(self,
source: &'static mut [u8],
mut dest : D,
)
-> Transfer<'dma, T, D>
where D: Dest
{
compiler_fence(Ordering::SeqCst);
if source.len() == 0 {
return Transfer {
channel: self,
source : source,
dest : dest,
}
}
self.cfg.write(|w| {
let w = w
.periphreqen().enabled()
.hwtrigen().disabled()
.trigburst().single_transfer();
unsafe { w.chpriority().bits(0) }
});
self.xfercfg.write(|w| {
let w = w
.cfgvalid().valid()
.reload().disabled()
.swtrig().notset()
.clrtrig().cleared()
.setinta().no_effect()
.setintb().no_effect()
.width()._8_bit_transfers_are()
.srcinc()._1_x_width()
.dstinc().no_increment();
unsafe { w.xfercount().bits(source.len() as u16 - 1) }
});
let source_end = unsafe { source.as_ptr().add(source.len() - 1) };
self.descriptor.source_end = source_end;
self.descriptor.dest_end = dest.end_addr();
self.enableset0.write(|w| unsafe { w.ena().bits(T::FLAG) });
self.settrig0.write(|w| unsafe { w.trig().bits(T::FLAG) });
Transfer {
channel: self,
source : source,
dest : dest,
}
}
}
pub trait ChannelTrait {
const INDEX: usize;
const FLAG : u32;
type Cfg: Reg<Target=CFG>;
type Xfercfg: Reg<Target=XFERCFG>;
}
macro_rules! channels {
($($field:ident, $name:ident, $index:expr, $cfg:ty, $xfercfg:ty;)*) => {
#[allow(missing_docs)]
pub struct Channels {
$(pub $field: Channel<$name, init_state::Disabled>,)*
}
impl Channels {
fn new(descriptors: &'static mut DescriptorTable) -> Self {
let mut descriptors = (&mut descriptors.0).into_iter();
Channels {
$(
$field: Channel {
ty : $name(()),
_state : init_state::Disabled,
descriptor: descriptors.next().unwrap(),
cfg : RegProxy::new(),
xfercfg: RegProxy::new(),
active0 : RegProxy::new(),
enableset0: RegProxy::new(),
settrig0 : RegProxy::new(),
},
)*
}
}
}
$(
pub struct $name(());
impl ChannelTrait for $name {
const INDEX: usize = $index;
const FLAG : u32 = 0x1 << Self::INDEX;
type Cfg = $cfg;
type Xfercfg = $xfercfg;
}
)*
}
}
channels!(
channel_0 , Channel0 , 0, CFG0 , XFERCFG0 ;
channel_1 , Channel1 , 1, CFG1 , XFERCFG1 ;
channel_2 , Channel2 , 2, CFG2 , XFERCFG2 ;
channel_3 , Channel3 , 3, CFG3 , XFERCFG3 ;
channel_4 , Channel4 , 4, CFG4 , XFERCFG4 ;
channel_5 , Channel5 , 5, CFG5 , XFERCFG5 ;
channel_6 , Channel6 , 6, CFG6 , XFERCFG6 ;
channel_7 , Channel7 , 7, CFG7 , XFERCFG7 ;
channel_8 , Channel8 , 8, CFG8 , XFERCFG8 ;
channel_9 , Channel9 , 9, CFG9 , XFERCFG9 ;
channel_10, Channel10, 10, CFG10, XFERCFG10;
channel_11, Channel11, 11, CFG11, XFERCFG11;
channel_12, Channel12, 12, CFG12, XFERCFG12;
channel_13, Channel13, 13, CFG13, XFERCFG13;
channel_14, Channel14, 14, CFG14, XFERCFG14;
channel_15, Channel15, 15, CFG15, XFERCFG15;
channel_16, Channel16, 16, CFG16, XFERCFG16;
channel_17, Channel17, 17, CFG17, XFERCFG17;
);
pub trait Dest {
type Error;
fn wait(&mut self) -> nb::Result<(), Self::Error>;
fn end_addr(&mut self) -> *mut u8;
}
pub struct Transfer<'dma, T, D> where T: ChannelTrait {
channel: Channel<T, init_state::Enabled<&'dma Handle>>,
source : &'static mut [u8],
dest : D,
}
impl<'dma, T, D> Transfer<'dma, T, D>
where
T: ChannelTrait,
D: Dest,
{
pub fn wait(mut self)
-> Result<
(
Channel<T, init_state::Enabled<&'dma Handle>>,
&'static mut [u8],
D
),
D::Error
>
{
while self.channel.active0.read().act().bits() & T::FLAG != 0 {}
loop {
match self.dest.wait() {
Err(nb::Error::WouldBlock) => continue,
Ok(()) => break,
Err(nb::Error::Other(error)) => {
compiler_fence(Ordering::SeqCst);
return Err(error);
}
}
}
compiler_fence(Ordering::SeqCst);
Ok((self.channel, self.source, self.dest))
}
}
pub struct CFG0;
pub struct CFG1;
pub struct CFG2;
pub struct CFG3;
pub struct CFG4;
pub struct CFG5;
pub struct CFG6;
pub struct CFG7;
pub struct CFG8;
pub struct CFG9;
pub struct CFG10;
pub struct CFG11;
pub struct CFG12;
pub struct CFG13;
pub struct CFG14;
pub struct CFG15;
pub struct CFG16;
pub struct CFG17;
pub struct XFERCFG0;
pub struct XFERCFG1;
pub struct XFERCFG2;
pub struct XFERCFG3;
pub struct XFERCFG4;
pub struct XFERCFG5;
pub struct XFERCFG6;
pub struct XFERCFG7;
pub struct XFERCFG8;
pub struct XFERCFG9;
pub struct XFERCFG10;
pub struct XFERCFG11;
pub struct XFERCFG12;
pub struct XFERCFG13;
pub struct XFERCFG14;
pub struct XFERCFG15;
pub struct XFERCFG16;
pub struct XFERCFG17;
reg!(CFG0 , CFG, raw::DMA, cfg0 );
reg!(CFG1 , CFG, raw::DMA, cfg1 );
reg!(CFG2 , CFG, raw::DMA, cfg2 );
reg!(CFG3 , CFG, raw::DMA, cfg3 );
reg!(CFG4 , CFG, raw::DMA, cfg4 );
reg!(CFG5 , CFG, raw::DMA, cfg5 );
reg!(CFG6 , CFG, raw::DMA, cfg6 );
reg!(CFG7 , CFG, raw::DMA, cfg7 );
reg!(CFG8 , CFG, raw::DMA, cfg8 );
reg!(CFG9 , CFG, raw::DMA, cfg9 );
reg!(CFG10, CFG, raw::DMA, cfg10);
reg!(CFG11, CFG, raw::DMA, cfg11);
reg!(CFG12, CFG, raw::DMA, cfg12);
reg!(CFG13, CFG, raw::DMA, cfg13);
reg!(CFG14, CFG, raw::DMA, cfg14);
reg!(CFG15, CFG, raw::DMA, cfg15);
reg!(CFG16, CFG, raw::DMA, cfg16);
reg!(CFG17, CFG, raw::DMA, cfg17);
reg!(XFERCFG0 , XFERCFG, raw::DMA, xfercfg0 );
reg!(XFERCFG1 , XFERCFG, raw::DMA, xfercfg1 );
reg!(XFERCFG2 , XFERCFG, raw::DMA, xfercfg2 );
reg!(XFERCFG3 , XFERCFG, raw::DMA, xfercfg3 );
reg!(XFERCFG4 , XFERCFG, raw::DMA, xfercfg4 );
reg!(XFERCFG5 , XFERCFG, raw::DMA, xfercfg5 );
reg!(XFERCFG6 , XFERCFG, raw::DMA, xfercfg6 );
reg!(XFERCFG7 , XFERCFG, raw::DMA, xfercfg7 );
reg!(XFERCFG8 , XFERCFG, raw::DMA, xfercfg8 );
reg!(XFERCFG9 , XFERCFG, raw::DMA, xfercfg9 );
reg!(XFERCFG10, XFERCFG, raw::DMA, xfercfg10);
reg!(XFERCFG11, XFERCFG, raw::DMA, xfercfg11);
reg!(XFERCFG12, XFERCFG, raw::DMA, xfercfg12);
reg!(XFERCFG13, XFERCFG, raw::DMA, xfercfg13);
reg!(XFERCFG14, XFERCFG, raw::DMA, xfercfg14);
reg!(XFERCFG15, XFERCFG, raw::DMA, xfercfg15);
reg!(XFERCFG16, XFERCFG, raw::DMA, xfercfg16);
reg!(XFERCFG17, XFERCFG, raw::DMA, xfercfg17);
reg!(ACTIVE0 , ACTIVE0 , raw::DMA, active0 );
reg!(ENABLESET0, ENABLESET0, raw::DMA, enableset0);
reg!(SETTRIG0 , SETTRIG0 , raw::DMA, settrig0 );