1use core::cell::Cell;
8use core::ptr::addr_of;
9use core::ptr::addr_of_mut;
10use kernel::hil::ble_advertising;
11use kernel::hil::ble_advertising::RadioChannel;
12use kernel::utilities::cells::OptionalCell;
13use kernel::utilities::cells::TakeCell;
14use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
15use kernel::utilities::registers::{
16 register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
17};
18use kernel::utilities::StaticRef;
19use kernel::ErrorCode;
20
21const BLE_BASE: StaticRef<BleRegisters> =
22 unsafe { StaticRef::new(0x5000_C000 as *const BleRegisters) };
23
24register_structs! {
25 pub BleRegisters {
26 (0x000 => fifo: ReadWrite<u32, FIFO::Register>),
27 (0x004 => _reserved0),
28 (0x100 => fifoptr: ReadOnly<u32, FIFOPTR::Register>),
29 (0x104 => fifothr: ReadWrite<u32, FIFOTHR::Register>),
30 (0x108 => fifopop: ReadWrite<u32, FIFOPOP::Register>),
31 (0x10C => fifopush: ReadWrite<u32, FIFOPUSH::Register>),
32 (0x110 => fifoctrl: ReadWrite<u32, FIFOCTRL::Register>),
33 (0x114 => fifoloc: ReadWrite<u32, FIFOLOC::Register>),
34 (0x118 => _reserved1),
35 (0x200 => clkcfg: ReadWrite<u32, CLKCFG::Register>),
36 (0x204 => _reserved2),
37 (0x20C => cmd: ReadWrite<u32, CMD::Register>),
38 (0x210 => cmdrpt: ReadWrite<u32, CMDRPT::Register>),
39 (0x214 => offsethi: ReadWrite<u32, OFFSETHI::Register>),
40 (0x218 => cmdstat: ReadWrite<u32, CMDSTAT::Register>),
41 (0x21C => _reserved3),
42 (0x220 => inten: ReadWrite<u32, INT::Register>),
43 (0x224 => intstat: ReadWrite<u32, INT::Register>),
44 (0x228 => intclr: ReadWrite<u32, INT::Register>),
45 (0x22C => intset: ReadWrite<u32, INT::Register>),
46 (0x230 => dmatrigen: ReadWrite<u32, DMATRIGEN::Register>),
47 (0x234 => dmatrigstat: ReadWrite<u32, DMATRIGSTAT::Register>),
48 (0x238 => dmacfg: ReadWrite<u32, DMACFG::Register>),
49 (0x23C => dmatocount: ReadWrite<u32, DMATOCOUNT::Register>),
50 (0x240 => dmatargaddr: ReadWrite<u32, DMATAGADDR::Register>),
51 (0x244 => dmastat: ReadWrite<u32, DMASTAT::Register>),
52 (0x248 => cqcfg: ReadWrite<u32, CQCFG::Register>),
53 (0x24C => cqaddr: ReadWrite<u32, CQADDR::Register>),
54 (0x250 => cqstat: ReadWrite<u32, CQSTAT::Register>),
55 (0x254 => cqflags: ReadWrite<u32, CQFLAGS::Register>),
56 (0x258 => cqsetclear: WriteOnly<u32, CQSETCLEAR::Register>),
57 (0x25C => cqpauseen: ReadWrite<u32, CQPAUSEEN::Register>),
58 (0x260 => cqcuridx: ReadWrite<u32, CQCURIDX::Register>),
59 (0x264 => cqendidx: ReadWrite<u32, CQENDIDX::Register>),
60 (0x268 => status: ReadWrite<u32, STATUS::Register>),
61 (0x26C => _reserved4),
62 (0x300 => mspicfg: ReadWrite<u32, MSPICFG::Register>),
63 (0x304 => blecfg: ReadWrite<u32, BLECFG::Register>),
64 (0x308 => pwrcmd: ReadWrite<u32, PWRCMD::Register>),
65 (0x30C => bstatus: ReadWrite<u32, BSTATUS::Register>),
66 (0x310 => _reserved5),
67 (0x410 => bledbg: ReadWrite<u32, BLEDBG::Register>),
68 (0x414 => @END),
69 }
70}
71
72register_bitfields![u32,
73 FIFO [
74 FIFO OFFSET(0) NUMBITS(32) []
75 ],
76 FIFOPTR [
77 FIFO0SIZ OFFSET(0) NUMBITS(8) [],
78 FIFO0REM OFFSET(8) NUMBITS(8) [],
79 FIFO1SIZ OFFSET(16) NUMBITS(8) [],
80 FIFO1REM OFFSET(24) NUMBITS(8) []
81 ],
82 FIFOTHR [
83 FIFORTHR OFFSET(0) NUMBITS(6) [],
84 FIFOWTHR OFFSET(8) NUMBITS(6) []
85 ],
86 FIFOPOP [
87 FIFODOUT OFFSET(0) NUMBITS(32) []
88 ],
89 FIFOPUSH [
90 FIFODIN OFFSET(0) NUMBITS(32) []
91 ],
92 FIFOCTRL [
93 POPWR OFFSET(0) NUMBITS(1) [],
94 FIFORSTN OFFSET(1) NUMBITS(1) []
95 ],
96 FIFOLOC [
97 FIFOWPTR OFFSET(0) NUMBITS(4) [],
98 FIFORPTR OFFSET(8) NUMBITS(4) []
99 ],
100 CLKCFG [
101 IOCLKEN OFFSET(0) NUMBITS(1) [],
102 FSEL OFFSET(8) NUMBITS(3) [],
103 CLK32KEN OFFSET(11) NUMBITS(1) [],
104 DIV3 OFFSET(12) NUMBITS(1) []
105 ],
106 CMD [
107 CMD OFFSET(0) NUMBITS(4) [
108 WRITE = 0x01,
109 READ = 0x02
110 ],
111 OFFSETCNT OFFSET(5) NUMBITS(2) [],
112 CONT OFFSET(7) NUMBITS(1) [],
113 TSIZE OFFSET(8) NUMBITS(12) [],
114 CMDSEL OFFSET(20) NUMBITS(2) [],
115 OFFSETLO OFFSET(24) NUMBITS(8) []
116 ],
117 CMDRPT [
118 CMDRPT OFFSET(0) NUMBITS(4) []
119 ],
120 OFFSETHI [
121 OFFSETHI OFFSET(0) NUMBITS(16) []
122 ],
123 CMDSTAT [
124 CCMD OFFSET(0) NUMBITS(4) [],
125 CMDSTAT OFFSET(5) NUMBITS(3) [],
126 CTSIZE OFFSET(8) NUMBITS(12) []
127 ],
128 INT [
129 CMDCMP OFFSET(0) NUMBITS(1) [],
130 THR OFFSET(1) NUMBITS(1) [],
131 FUNDFL OFFSET(2) NUMBITS(1) [],
132 FOVFL OFFSET(3) NUMBITS(1) [],
133 B2MST OFFSET(4) NUMBITS(1) [],
134 IACC OFFSET(5) NUMBITS(1) [],
135 ICMD OFFSET(6) NUMBITS(1) [],
136 BLECIRQ OFFSET(7) NUMBITS(1) [],
137 BLECSSTAT OFFSET(8) NUMBITS(1) [],
138 DCMP OFFSET(9) NUMBITS(1) [],
139 DERR OFFSET(10) NUMBITS(1) [],
140 CQPAUSED OFFSET(11) NUMBITS(1) [],
141 CQUPD OFFSET(12) NUMBITS(1) [],
142 CQERR OFFSET(13) NUMBITS(1) [],
143 B2MSLEEP OFFSET(14) NUMBITS(1) [],
144 B2MACTIVE OFFSET(15) NUMBITS(1) [],
145 B2MSHUTDN OFFSET(16) NUMBITS(1) []
146 ],
147 DMATRIGEN [
148 DCMDCMPEN OFFSET(0) NUMBITS(1) [],
149 DTHREN OFFSET(1) NUMBITS(1) []
150 ],
151 DMATRIGSTAT [
152 DCMDCMPEN OFFSET(0) NUMBITS(1) [],
153 DTHREN OFFSET(1) NUMBITS(1) [],
154 DTOTCMP OFFSET(2) NUMBITS(1) []
155 ],
156 DMACFG [
157 DMAEN OFFSET(0) NUMBITS(1) [],
158 DMADIR OFFSET(1) NUMBITS(1) [],
159 DMAPRI OFFSET(8) NUMBITS(1) []
160 ],
161 DMATOCOUNT [
162 TOTCOUNT OFFSET(0) NUMBITS(12) []
163 ],
164 DMATAGADDR [
165 TARGADDR OFFSET(0) NUMBITS(20) [],
166 TARGADDR28 OFFSET(28) NUMBITS(1) []
167 ],
168 DMASTAT [
169 DMATIP OFFSET(0) NUMBITS(1) [],
170 DMACPL OFFSET(1) NUMBITS(1) [],
171 DMAERR OFFSET(2) NUMBITS(1) []
172 ],
173 CQCFG [
174 CQEN OFFSET(0) NUMBITS(1) [],
175 CQPRI OFFSET(1) NUMBITS(1) []
176 ],
177 CQADDR [
178 CQADDR OFFSET(2) NUMBITS(18) [],
179 CQADDR28 OFFSET(28) NUMBITS(1) []
180 ],
181 CQSTAT [
182 CQTIP OFFSET(0) NUMBITS(1) [],
183 CQPAUSED OFFSET(1) NUMBITS(1) [],
184 CQERR OFFSET(2) NUMBITS(1) []
185 ],
186 CQFLAGS [
187 CQFLAGS OFFSET(0) NUMBITS(16) [],
188 CQIRQMASK OFFSET(16) NUMBITS(16) []
189 ],
190 CQSETCLEAR [
191 CQFSET OFFSET(0) NUMBITS(8) [],
192 CQFTGL OFFSET(8) NUMBITS(8) [],
193 CQFCLR OFFSET(16) NUMBITS(8) []
194 ],
195 CQPAUSEEN [
196 CQPEN OFFSET(0) NUMBITS(16) []
197 ],
198 CQCURIDX [
199 CQCURIDX OFFSET(0) NUMBITS(8) []
200 ],
201 CQENDIDX [
202 CQENDIDX OFFSET(0) NUMBITS(8) []
203 ],
204 STATUS [
205 ERR OFFSET(0) NUMBITS(1) [],
206 CMDACT OFFSET(1) NUMBITS(1) [],
207 ISLEST OFFSET(2) NUMBITS(1) []
208 ],
209 MSPICFG [
210 SPOL OFFSET(0) NUMBITS(1) [],
211 SPHA OFFSET(1) NUMBITS(1) [],
212 FULLDUP OFFSET(2) NUMBITS(1) [],
213 WTFC OFFSET(16) NUMBITS(1) [],
214 RDFC OFFSET(17) NUMBITS(1) [],
215 WTFCPOL OFFSET(21) NUMBITS(1) [],
216 RDFCPOL OFFSET(22) NUMBITS(1) [],
217 SPILSB OFFSET(23) NUMBITS(1) [],
218 DINDLY OFFSET(24) NUMBITS(2) [],
219 DOUTDLLY OFFSET(27) NUMBITS(2) [],
220 MSPIRST OFFSET(30) NUMBITS(1) []
221 ],
222 BLECFG [
223 PWRSMEN OFFSET(0) NUMBITS(1) [],
224 BLERSTN OFFSET(1) NUMBITS(1) [],
225 WAKEUPCTL OFFSET(2) NUMBITS(2) [
226 ON = 0x3,
227 OFF = 0x2,
228 AUTO = 0x0
229 ],
230 DCDCFLGCTL OFFSET(4) NUMBITS(2) [],
231 BLEHREQCTL OFFSET(6) NUMBITS(2) [],
232 WT4ACTOFF OFFSET(8) NUMBITS(1) [],
233 MCUFRCSLP OFFSET(9) NUMBITS(1) [],
234 FRCCLK OFFSET(10) NUMBITS(1) [],
235 STAYASLEEP OFFSET(11) NUMBITS(1) [],
236 PWRISOCTL OFFSET(12) NUMBITS(2) [],
237 SPIISOCTL OFFSET(14) NUMBITS(2) []
238 ],
239 PWRCMD [
240 WAKEREQ OFFSET(0) NUMBITS(1) [],
241 RESTART OFFSET(1) NUMBITS(1) []
242 ],
243 BSTATUS [
244 B2MSTATE OFFSET(0) NUMBITS(2) [],
245 SPISTATUS OFFSET(3) NUMBITS(1) [],
246 DCDCREQ OFFSET(4) NUMBITS(1) [],
247 DCDCFLAG OFFSET(5) NUMBITS(1) [],
248 WAKEUP OFFSET(6) NUMBITS(1) [],
249 BLEIRQ OFFSET(7) NUMBITS(1) [],
250 PWRST OFFSET(8) NUMBITS(2) [],
251 BLEHACK OFFSET(11) NUMBITS(1) [],
252 BLEHREQ OFFSET(12) NUMBITS(1) []
253 ],
254 BLEDBG [
255 DBGEN OFFSET(0) NUMBITS(1) [],
256 IOCLKON OFFSET(1) NUMBITS(1) [],
257 APBCLKON OFFSET(2) NUMBITS(1) [],
258 DBGDATA OFFSET(3) NUMBITS(29) []
259 ]
260];
261
262static mut PAYLOAD: [u8; 40] = [0x00; 40];
263
264pub struct Ble<'a> {
265 registers: StaticRef<BleRegisters>,
266 rx_client: OptionalCell<&'a dyn ble_advertising::RxClient>,
267 tx_client: OptionalCell<&'a dyn ble_advertising::TxClient>,
268
269 buffer: TakeCell<'static, [u8]>,
270 write_len: Cell<usize>,
271
272 read_len: Cell<usize>,
273 read_index: Cell<usize>,
274}
275
276impl Ble<'_> {
277 pub fn new() -> Self {
278 Self {
279 registers: BLE_BASE,
280 rx_client: OptionalCell::empty(),
281 tx_client: OptionalCell::empty(),
282 buffer: TakeCell::empty(),
283 write_len: Cell::new(0),
284 read_len: Cell::new(0),
285 read_index: Cell::new(0),
286 }
287 }
288
289 pub fn setup_clocks(&self) {
290 self.registers.clkcfg.write(CLKCFG::CLK32KEN::SET);
291 self.registers.bledbg.write(BLEDBG::DBGDATA.val(1 << 14));
292 }
293
294 pub fn power_up(&self) {
295 self.registers.blecfg.write(BLECFG::PWRSMEN::SET);
296
297 while self.registers.bstatus.read(BSTATUS::PWRST) != 3 {}
298 }
299
300 pub fn ble_initialise(&self) {
301 self.registers.mspicfg.write(
303 MSPICFG::SPOL::SET
304 + MSPICFG::SPHA::SET
305 + MSPICFG::RDFC::CLEAR
306 + MSPICFG::WTFC::CLEAR
307 + MSPICFG::WTFCPOL::SET,
308 );
309 self.registers
310 .fifothr
311 .write(FIFOTHR::FIFOWTHR.val(16) + FIFOTHR::FIFORTHR.val(16));
312 self.registers.fifoctrl.modify(FIFOCTRL::POPWR::SET);
313
314 self.registers
316 .clkcfg
317 .write(CLKCFG::FSEL.val(0x04) + CLKCFG::IOCLKEN::SET + CLKCFG::CLK32KEN::SET);
318
319 self.registers.cqcfg.modify(CQCFG::CQEN::CLEAR);
321
322 }
324
325 fn reset_fifo(&self) {
326 self.registers.fifoctrl.modify(FIFOCTRL::FIFORSTN::CLEAR);
327 self.registers.fifoctrl.modify(FIFOCTRL::FIFORSTN::SET);
328 }
329
330 fn send_data(&self) {
331 self.registers
333 .fifothr
334 .write(FIFOTHR::FIFORTHR.val(16) + FIFOTHR::FIFOWTHR.val(16));
335
336 self.registers.dmatargaddr.set(addr_of!(PAYLOAD) as u32);
341 self.registers.dmatocount.set(self.write_len.get() as u32);
342 self.registers.dmatrigen.write(DMATRIGEN::DTHREN::SET);
343 self.registers
344 .dmacfg
345 .write(DMACFG::DMADIR.val(1) + DMACFG::DMAPRI.val(1));
346
347 self.registers
349 .cmd
350 .modify(CMD::TSIZE.val(self.write_len.get() as u32) + CMD::CMD::WRITE);
351
352 self.registers.dmacfg.modify(DMACFG::DMAEN::SET);
354
355 self.registers.blecfg.modify(BLECFG::WAKEUPCTL::OFF);
357 }
358
359 pub fn handle_interrupt(&self) {
360 let irqs = self.registers.intstat.extract();
361
362 self.disable_interrupts();
364
365 if irqs.is_set(INT::BLECSSTAT) || irqs.is_set(INT::B2MST) {
366 self.enable_interrupts();
368
369 if self.registers.bstatus.is_set(BSTATUS::BLEIRQ) {
370 panic!("Read requested while trying to write");
371 }
372
373 if !self.registers.bstatus.is_set(BSTATUS::SPISTATUS) {
374 panic!("SPI not ready");
375 }
376
377 if self.buffer.is_some() {
379 self.send_data();
381 }
382 }
383
384 if irqs.is_set(INT::DCMP) {
385 self.registers.dmacfg.set(0x00000000);
387
388 self.registers.blecfg.modify(BLECFG::WAKEUPCTL::OFF);
390
391 self.reset_fifo();
393
394 if self.buffer.is_some() {
395 self.tx_client.map(|client| {
396 client.transmit_event(self.buffer.take().unwrap(), Ok(()));
397 });
398 }
399
400 self.enable_interrupts();
401 }
402
403 if irqs.is_set(INT::BLECIRQ) {
404 self.rx_client.map(|client| {
405 self.registers
406 .cmd
407 .modify(CMD::TSIZE.val(0) + CMD::CMD::READ);
408
409 unsafe {
410 let mut i = 0;
411
412 while self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0 && i < 40 {
413 let temp = self.registers.fifopop.get().to_ne_bytes();
414
415 PAYLOAD[i + 0] = temp[0];
416 PAYLOAD[i + 1] = temp[1];
417 PAYLOAD[i + 2] = temp[2];
418 PAYLOAD[i + 3] = temp[3];
419
420 i += 4;
421 }
422
423 client.receive_event(&mut *addr_of_mut!(PAYLOAD), 10, Ok(()));
424 }
425 });
426 }
427 }
428
429 pub fn enable_interrupts(&self) {
430 self.registers.inten.set(0x18381);
431 }
432
433 pub fn disable_interrupts(&self) {
434 self.registers.intclr.set(0xFFFF_FFFF);
435 self.registers.inten.set(0x00);
436 }
437
438 fn replace_radio_buffer(&self, buf: &'static mut [u8]) -> &'static mut [u8] {
439 for (i, c) in buf.as_ref().iter().enumerate() {
441 unsafe {
442 PAYLOAD[i] = *c;
443 }
444 }
445 buf
446 }
447}
448
449impl<'a> ble_advertising::BleAdvertisementDriver<'a> for Ble<'a> {
450 fn transmit_advertisement(&self, buf: &'static mut [u8], len: usize, _channel: RadioChannel) {
451 let res = self.replace_radio_buffer(buf);
452
453 self.buffer.replace(res);
455 self.write_len.set(len);
456 self.read_len.set(0);
457 self.read_index.set(0);
458
459 self.enable_interrupts();
461
462 self.registers.blecfg.modify(BLECFG::WAKEUPCTL::ON);
464
465 if self.registers.bstatus.is_set(BSTATUS::SPISTATUS) {
467 self.send_data();
468 }
469 }
470
471 fn receive_advertisement(&self, _channel: RadioChannel) {
472 unimplemented!();
473 }
474
475 fn set_receive_client(&self, client: &'a dyn ble_advertising::RxClient) {
476 self.rx_client.set(client);
477 }
478
479 fn set_transmit_client(&self, client: &'a dyn ble_advertising::TxClient) {
480 self.tx_client.set(client);
481 }
482}
483
484impl ble_advertising::BleConfig for Ble<'_> {
485 fn set_tx_power(&self, _tx_power: u8) -> Result<(), ErrorCode> {
486 Ok(())
487 }
488}