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