1use crate::pm;
8use core::cell::Cell;
9use core::cmp;
10use core::sync::atomic;
11use enum_primitive::cast::FromPrimitive;
12use kernel::debug;
13use kernel::utilities::StaticRef;
14use kernel::utilities::cells::{OptionalCell, TakeCell};
15use kernel::utilities::registers::interfaces::{Readable, Writeable};
16use kernel::utilities::registers::{
17 ReadOnly, ReadWrite, WriteOnly, register_bitfields, register_structs,
18};
19
20register_structs! {
21 #[allow(dead_code)]
23 DMARegisters {
24 (0x000 => mar: ReadWrite<u32, MemoryAddress::Register>),
25 (0x004 => psr: ReadWrite<u8>),
26 (0x005 => _psr_padding: [u8; 3]),
27 (0x008 => tcr: ReadWrite<u32, TransferCounter::Register>),
28 (0x00C => marr: ReadWrite<u32, MemoryAddressReload::Register>),
29 (0x010 => tcrr: ReadWrite<u32, TransferCounter::Register>),
30 (0x014 => cr: WriteOnly<u32, Control::Register>),
31 (0x018 => mr: ReadWrite<u32, Mode::Register>),
32 (0x01C => sr: ReadOnly<u32, Status::Register>),
33 (0x020 => ier: WriteOnly<u32, Interrupt::Register>),
34 (0x024 => idr: WriteOnly<u32, Interrupt::Register>),
35 (0x028 => imr: ReadOnly<u32, Interrupt::Register>),
36 (0x02C => isr: ReadOnly<u32, Interrupt::Register>),
37 (0x030 => @END),
38 }
39}
40
41register_bitfields![u32,
42 MemoryAddress [
43 MADDR OFFSET(0) NUMBITS(32) []
44 ],
45
46 MemoryAddressReload [
47 MARV OFFSET(0) NUMBITS(32) []
48 ],
49
50 TransferCounter [
51 TCV OFFSET(0) NUMBITS(16) []
53 ],
54
55 Control [
56 ECLR 8,
58 TDIS 1,
60 TEN 0
62 ],
63
64 Mode [
65 RING OFFSET(3) NUMBITS(1) [
67 Disable = 0,
68 Enable = 1
69 ],
70 ETRIG OFFSET(2) NUMBITS(1) [
72 StartOnRequest = 0,
73 StartOnEvent = 1
74 ],
75 SIZE OFFSET(0) NUMBITS(2) [
77 Byte = 0,
78 Halfword = 1,
79 Word = 2
80 ]
81 ],
82
83 Status [
84 TEN 0
86 ],
87
88 Interrupt [
89 TERR 2,
91 TRC 1,
93 RCZ 0
95 ]
96];
97
98const DMA_BASE_ADDR: usize = 0x400A2000;
100
101const DMA_CHANNEL_SIZE: usize = 0x40;
103
104static NUM_ENABLED: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
107
108#[derive(Copy, Clone)]
114pub enum DMAChannelNum {
115 DMAChannel00 = 0,
117 DMAChannel01 = 1,
118 DMAChannel02 = 2,
119 DMAChannel03 = 3,
120 DMAChannel04 = 4,
121 DMAChannel05 = 5,
122 DMAChannel06 = 6,
123 DMAChannel07 = 7,
124 DMAChannel08 = 8,
125 DMAChannel09 = 9,
126 DMAChannel10 = 10,
127 DMAChannel11 = 11,
128 DMAChannel12 = 12,
129 DMAChannel13 = 13,
130 DMAChannel14 = 14,
131 DMAChannel15 = 15,
132}
133
134enum_primitive::enum_from_primitive! {
135#[allow(non_camel_case_types)]
139#[derive(Copy, Clone, PartialEq)]
140#[repr(u8)]
141pub enum DMAPeripheral {
142 USART0_RX = 0,
143 USART1_RX = 1,
144 USART2_RX = 2,
145 USART3_RX = 3,
146 SPI_RX = 4,
147 TWIM0_RX = 5,
148 TWIM1_RX = 6,
149 TWIM2_RX = 7,
150 TWIM3_RX = 8,
151 TWIS0_RX = 9,
152 TWIS1_RX = 10,
153 ADCIFE_RX = 11,
154 CATB_RX = 12,
155 IISC_CH0_RX = 14,
156 IISC_CH1_RX = 15,
157 PARC_RX = 16,
158 AESA_RX = 17,
159 USART0_TX = 18,
160 USART1_TX = 19,
161 USART2_TX = 20,
162 USART3_TX = 21,
163 SPI_TX = 22,
164 TWIM0_TX = 23,
165 TWIM1_TX = 24,
166 TWIM2_TX = 25,
167 TWIM3_TX = 26,
168 TWIS0_TX = 27,
169 TWIS1_TX = 28,
170 ADCIFE_TX = 29,
171 CATB_TX = 30,
172 ABDACB_SDR0_TX = 31,
173 ABDACB_SDR1_TX = 32,
174 IISC_CH0_TX = 33,
175 IISC_CH1_TX = 34,
176 DACC_TX = 35,
177 AESA_TX = 36,
178 LCDCA_ACMDR_TX = 37,
179 LCDCA_ABMDR_TX = 38,
180}
181}
182
183#[derive(Copy, Clone, Debug, PartialEq)]
184#[repr(u8)]
185pub enum DMAWidth {
186 Width8Bit = 0,
188 Width16Bit = 1,
190 Width32Bit = 2,
192}
193
194pub struct DMAChannel {
195 registers: StaticRef<DMARegisters>,
196 client: OptionalCell<&'static dyn DMAClient>,
197 width: Cell<DMAWidth>,
198 enabled: Cell<bool>,
199 buffer: TakeCell<'static, [u8]>,
200}
201
202pub trait DMAClient {
203 fn transfer_done(&self, pid: DMAPeripheral);
204}
205
206impl DMAChannel {
207 pub fn new(channel: DMAChannelNum) -> DMAChannel {
208 DMAChannel {
209 registers: unsafe {
210 StaticRef::new(
211 (DMA_BASE_ADDR + (channel as usize) * DMA_CHANNEL_SIZE) as *const DMARegisters,
212 )
213 },
214 client: OptionalCell::empty(),
215 width: Cell::new(DMAWidth::Width8Bit),
216 enabled: Cell::new(false),
217 buffer: TakeCell::empty(),
218 }
219 }
220
221 pub fn initialize(&self, client: &'static dyn DMAClient, width: DMAWidth) {
222 self.client.set(client);
223 self.width.set(width);
224 }
225
226 pub fn enable(&self) {
227 pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
228 pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
229
230 if !self.enabled.get() {
231 NUM_ENABLED.fetch_add(1, atomic::Ordering::Relaxed);
232
233 self.registers
235 .idr
236 .write(Interrupt::TERR::SET + Interrupt::TRC::SET + Interrupt::RCZ::SET);
237
238 self.enabled.set(true);
239 }
240 }
241
242 pub fn disable(&self) {
243 if self.enabled.get() {
244 let num_enabled = NUM_ENABLED.fetch_sub(1, atomic::Ordering::Relaxed);
245 if num_enabled == 1 {
246 pm::disable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
247 pm::disable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
248 }
249 self.registers.cr.write(Control::TDIS::SET);
250 self.enabled.set(false);
251 }
252 }
253
254 pub fn is_enabled(&self) -> bool {
255 self.enabled.get()
256 }
257
258 pub fn handle_interrupt(&self) {
259 self.registers
260 .idr
261 .write(Interrupt::TERR::SET + Interrupt::TRC::SET + Interrupt::RCZ::SET);
262 let channel = self.registers.psr.get();
263
264 match DMAPeripheral::from_u8(channel) {
265 Some(channel) => {
266 self.client.map(|client| {
267 client.transfer_done(channel);
268 });
269 }
270 None => {
271 debug!(
272 "sam4l dma: psr read back invalid DMAPeripheral value {}",
273 channel
274 );
275 }
276 }
277 }
278
279 pub fn start_transfer(&self) {
280 self.registers.cr.write(Control::TEN::SET);
281 }
282
283 pub fn prepare_transfer(&self, pid: DMAPeripheral, buf: &'static mut [u8], mut len: usize) {
284 let maxlen = buf.len()
287 / match self.width.get() {
288 DMAWidth::Width8Bit => 1,
289 DMAWidth::Width16Bit => 2,
290 DMAWidth::Width32Bit => 4,
291 };
292 len = cmp::min(len, maxlen);
293 self.registers
294 .mr
295 .write(Mode::SIZE.val(self.width.get() as u32));
296
297 self.registers.psr.set(pid as u8);
298 self.registers
299 .marr
300 .write(MemoryAddressReload::MARV.val(core::ptr::from_ref::<u8>(&buf[0]) as u32));
301 self.registers
302 .tcrr
303 .write(TransferCounter::TCV.val(len as u32));
304
305 self.registers.ier.write(Interrupt::TRC::SET);
306
307 self.buffer.replace(buf);
310 }
311
312 pub fn do_transfer(&self, pid: DMAPeripheral, buf: &'static mut [u8], len: usize) {
313 self.prepare_transfer(pid, buf, len);
314 self.start_transfer();
315 }
316
317 pub fn abort_transfer(&self) -> Option<&'static mut [u8]> {
320 self.registers
321 .idr
322 .write(Interrupt::TERR::SET + Interrupt::TRC::SET + Interrupt::RCZ::SET);
323
324 self.registers.tcr.write(TransferCounter::TCV.val(0));
326
327 self.buffer.take()
328 }
329
330 pub fn transfer_counter(&self) -> usize {
331 self.registers.tcr.read(TransferCounter::TCV) as usize
332 }
333}