apollo3/
ble.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! BLE driver.
6
7use 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        // Configure the SPI
302        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        // Clock config
315        self.registers
316            .clkcfg
317            .write(CLKCFG::FSEL.val(0x04) + CLKCFG::IOCLKEN::SET + CLKCFG::CLK32KEN::SET);
318
319        // Disable command queue
320        self.registers.cqcfg.modify(CQCFG::CQEN::CLEAR);
321
322        // TODO: Apply the BLE patch
323    }
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        // Set the FIFO levels
332        self.registers
333            .fifothr
334            .write(FIFOTHR::FIFORTHR.val(16) + FIFOTHR::FIFOWTHR.val(16));
335
336        // Disable the FIFO
337        //self.registers.fifothr.write(FIFOTHR::FIFORTHR::CLEAR + FIFOTHR::FIFOWTHR::CLEAR);
338
339        // Setup the DMA
340        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        // Setup the operation
348        self.registers
349            .cmd
350            .modify(CMD::TSIZE.val(self.write_len.get() as u32) + CMD::CMD::WRITE);
351
352        // Enable DMA
353        self.registers.dmacfg.modify(DMACFG::DMAEN::SET);
354
355        // Set the wake low
356        self.registers.blecfg.modify(BLECFG::WAKEUPCTL::OFF);
357    }
358
359    pub fn handle_interrupt(&self) {
360        let irqs = self.registers.intstat.extract();
361
362        // Disable and clear interrupts
363        self.disable_interrupts();
364
365        if irqs.is_set(INT::BLECSSTAT) || irqs.is_set(INT::B2MST) {
366            // Enable interrupts
367            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 we have data, send it
378            if self.buffer.is_some() {
379                // Send the data
380                self.send_data();
381            }
382        }
383
384        if irqs.is_set(INT::DCMP) {
385            // Disable and clear DMA
386            self.registers.dmacfg.set(0x00000000);
387
388            // Disable the wake controller
389            self.registers.blecfg.modify(BLECFG::WAKEUPCTL::OFF);
390
391            // Reset FIFOs
392            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        // set payload
440        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        // Setup all of the buffers
454        self.buffer.replace(res);
455        self.write_len.set(len);
456        self.read_len.set(0);
457        self.read_index.set(0);
458
459        // Enable interrupts
460        self.enable_interrupts();
461
462        // Wakeup BLE
463        self.registers.blecfg.modify(BLECFG::WAKEUPCTL::ON);
464
465        // See if we can send the data
466        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}