1use crate::int::InterruptSource;
4use crate::pac::{DMAC, DMAC0, DMAC1, DMAC2, DMAC3};
5use enumflags2::{bitflags, BitFlags};
6use mips_mcu::PhysicalAddress;
7
8#[bitflags]
10#[derive(Copy, Clone, Debug, PartialEq)]
11#[repr(u8)]
12pub enum DmaIrq {
13 CHSD = 0x80,
15 CHSH = 0x40,
17 CHDD = 0x20,
19 CHDH = 0x10,
21 CHBC = 0x08,
23 CHCC = 0x04,
25 CHTA = 0x02,
27 CHER = 0x01,
29}
30
31#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum XferMode {
35 OneShot,
36 Auto,
37}
38
39pub trait Ops {
43 fn set_source(&mut self, addr: PhysicalAddress, size: usize);
45
46 fn set_dest(&mut self, addr: PhysicalAddress, size: usize);
48
49 fn set_cell_size(&mut self, size: usize);
51
52 fn set_start_event(&mut self, event: Option<InterruptSource>);
54
55 fn set_abort_event(&mut self, event: Option<InterruptSource>);
57
58 fn set_abort_pattern(&mut self, pattern: Option<u8>);
60
61 fn source_pointer(&self) -> PhysicalAddress;
63
64 fn destination_pointer(&self) -> PhysicalAddress;
66
67 fn irq_enable(&mut self, irq: BitFlags<DmaIrq>);
71
72 fn irq_flags(&self) -> BitFlags<DmaIrq>;
74
75 fn set_irq_flags(&mut self, flags: BitFlags<DmaIrq>);
77
78 fn clear_all_irq_flags(&mut self) {
80 self.set_irq_flags(BitFlags::<DmaIrq>::default());
81 }
82
83 unsafe fn enable(&mut self, mode: XferMode);
90
91 fn is_enabled(&self) -> bool;
95
96 fn disable(&mut self);
98
99 fn force(&mut self);
101}
102
103pub struct DmaChannel<D> {
104 ch: D,
105}
106
107macro_rules! dma {
108 ($Id:ident, $Dmac:ident) => {
109 impl Ops for DmaChannel<$Dmac> {
110 fn set_source(&mut self, addr: PhysicalAddress, size: usize) {
111 unsafe {
112 self.ch.ssa.write(|w| w.bits(addr.address() as u32));
113 self.ch.ssiz.write(|w| w.bits(size as u32));
114 }
115 }
116
117 fn set_dest(&mut self, addr: PhysicalAddress, size: usize) {
118 unsafe {
119 self.ch.dsa.write(|w| w.bits(addr.address() as u32));
120 self.ch.dsiz.write(|w| w.bits(size as u32));
121 }
122 }
123
124 fn set_cell_size(&mut self, size: usize) {
125 unsafe {
126 self.ch.csiz.write(|w| w.bits(size as u32));
127 }
128 }
129
130 fn set_start_event(&mut self, event: Option<InterruptSource>) {
131 match event {
132 Some(e) => {
133 self.ch
134 .econ
135 .modify(|_, w| unsafe { w.chsirq().bits(e as u8).sirqen().bit(true) });
136 }
137 None => {
138 self.ch.econclr.write(|w| w.sirqen().bit(true));
139 }
140 }
141 }
142
143 fn set_abort_event(&mut self, event: Option<InterruptSource>) {
144 match event {
145 Some(e) => {
146 self.ch
147 .econ
148 .modify(|_, w| unsafe { w.chairq().bits(e as u8).airqen().bit(true) });
149 }
150 None => {
151 self.ch.econclr.write(|w| w.airqen().bit(true));
152 }
153 }
154 }
155
156 fn set_abort_pattern(&mut self, pattern: Option<u8>) {
157 match pattern {
158 Some(p) => {
159 self.ch.dat.write(|w| unsafe { w.dchpdat().bits(p) });
160 self.ch.econset.write(|w| w.paten().bit(true));
161 }
162 None => {
163 self.ch.econclr.write(|w| w.paten().bit(true));
164 }
165 }
166 }
167
168 fn source_pointer(&self) -> PhysicalAddress {
169 PhysicalAddress::from_usize(self.ch.sptr.read().bits() as usize)
170 }
171
172 fn destination_pointer(&self) -> PhysicalAddress {
173 PhysicalAddress::from_usize(self.ch.dptr.read().bits() as usize)
174 }
175
176 fn irq_enable(&mut self, irq: BitFlags<DmaIrq>) {
177 self.ch
178 .int
179 .write(|w| unsafe { w.bits((irq.bits() as u32) << 16) });
180 }
181
182 fn irq_flags(&self) -> BitFlags<DmaIrq> {
183 let int = self.ch.int.read().bits();
184 unsafe { BitFlags::from_bits_unchecked(int as u8) }
185 }
186
187 fn set_irq_flags(&mut self, flags: BitFlags<DmaIrq>) {
188 self.ch.int.modify(|r, w| unsafe {
189 w.bits((r.bits() & 0xffff_ff00) | flags.bits() as u32)
190 });
191 }
192
193 unsafe fn enable(&mut self, mode: XferMode) {
194 match mode {
195 XferMode::OneShot => self.ch.contclr.write(|w| w.chaen().bit(true)),
196 XferMode::Auto => self.ch.contset.write(|w| w.chaen().bit(true)),
197 }
198 self.ch.contset.write(|w| w.chen().bit(true));
199 }
200
201 fn is_enabled(&self) -> bool {
202 self.ch.cont.read().chen().bit()
203 }
204
205 fn disable(&mut self) {
206 self.ch.contclr.write(|w| w.chen().bit(true));
207 while self.ch.cont.read().chbusy().bit() {}
208 }
209
210 fn force(&mut self) {
211 self.ch.econset.write(|w| w.cforce().bit(true));
212 }
213 }
214
215 impl DmaChannel<$Dmac> {
216 pub fn $Id(ch: $Dmac) -> Self {
217 unsafe {
219 (*DMAC::ptr()).dmaconset.write(|w| w.on().bit(true));
220 }
221 DmaChannel { ch }
222 }
223 }
224 };
225}
226
227dma!(channel0, DMAC0);
228dma!(channel1, DMAC1);
229dma!(channel2, DMAC2);
230dma!(channel3, DMAC3);