rp2040/
chip.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//! Chip trait setup.
6
7use core::fmt::Write;
8use kernel::platform::chip::Chip;
9use kernel::platform::chip::InterruptService;
10
11use crate::adc;
12use crate::clocks::Clocks;
13use crate::gpio::{RPGpio, RPPins, SIO};
14use crate::i2c;
15use crate::interrupts;
16use crate::pio::Pio;
17use crate::pwm;
18use crate::resets::Resets;
19use crate::rtc;
20use crate::spi;
21use crate::sysinfo;
22use crate::timer::RPTimer;
23use crate::uart::Uart;
24use crate::usb;
25use crate::watchdog::Watchdog;
26use crate::xosc::Xosc;
27use cortexm0p::{interrupt_mask, CortexM0P, CortexMVariant};
28
29#[repr(u8)]
30pub enum Processor {
31    Processor0 = 0,
32    Processor1 = 1,
33}
34
35pub struct Rp2040<'a, I: InterruptService + 'a> {
36    mpu: cortexm0p::mpu::MPU,
37    userspace_kernel_boundary: cortexm0p::syscall::SysCall,
38    interrupt_service: &'a I,
39    sio: &'a SIO,
40    processor0_interrupt_mask: (u128, u128),
41    processor1_interrupt_mask: (u128, u128),
42}
43
44impl<'a, I: InterruptService> Rp2040<'a, I> {
45    pub unsafe fn new(interrupt_service: &'a I, sio: &'a SIO) -> Self {
46        Self {
47            mpu: cortexm0p::mpu::new(),
48            userspace_kernel_boundary: cortexm0p::syscall::SysCall::new(),
49            interrupt_service,
50            sio,
51            processor0_interrupt_mask: interrupt_mask!(interrupts::SIO_IRQ_PROC1),
52            processor1_interrupt_mask: interrupt_mask!(interrupts::SIO_IRQ_PROC0),
53        }
54    }
55}
56
57impl<I: InterruptService> Chip for Rp2040<'_, I> {
58    type MPU = cortexm0p::mpu::MPU;
59    type UserspaceKernelBoundary = cortexm0p::syscall::SysCall;
60    type ThreadIdProvider = cortexm0p::thread_id::CortexMThreadIdProvider;
61
62    fn service_pending_interrupts(&self) {
63        unsafe {
64            let mask = match self.sio.get_processor() {
65                Processor::Processor0 => self.processor0_interrupt_mask,
66                Processor::Processor1 => self.processor1_interrupt_mask,
67            };
68            while let Some(interrupt) = cortexm0p::nvic::next_pending_with_mask(mask) {
69                // ignore SIO_IRQ_PROC1 as it is intended for processor 1
70                // not able to unset its pending status
71                // probably only processor 1 can unset the pending by reading the fifo
72                if !self.interrupt_service.service_interrupt(interrupt) {
73                    panic!("unhandled interrupt {}", interrupt);
74                }
75                let n = cortexm0p::nvic::Nvic::new(interrupt);
76                n.clear_pending();
77                n.enable();
78            }
79        }
80    }
81
82    fn has_pending_interrupts(&self) -> bool {
83        // ignore SIO_IRQ_PROC1 as it is intended for processor 1
84        // not able to unset its pending status
85        // probably only processor 1 can unset the pending by reading the fifo
86        let mask = match self.sio.get_processor() {
87            Processor::Processor0 => self.processor0_interrupt_mask,
88            Processor::Processor1 => self.processor1_interrupt_mask,
89        };
90        unsafe { cortexm0p::nvic::has_pending_with_mask(mask) }
91    }
92
93    fn mpu(&self) -> &Self::MPU {
94        &self.mpu
95    }
96
97    fn userspace_kernel_boundary(&self) -> &Self::UserspaceKernelBoundary {
98        &self.userspace_kernel_boundary
99    }
100
101    fn sleep(&self) {
102        unsafe {
103            cortexm0p::support::wfi();
104        }
105    }
106
107    unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
108    where
109        F: FnOnce() -> R,
110    {
111        cortexm0p::support::with_interrupts_disabled(f)
112    }
113
114    unsafe fn print_state(&self, writer: &mut dyn Write) {
115        CortexM0P::print_cortexm_state(writer);
116    }
117}
118
119pub struct Rp2040DefaultPeripherals<'a> {
120    pub adc: adc::Adc<'a>,
121    pub clocks: Clocks,
122    pub i2c0: i2c::I2c<'a, 'a>,
123    pub pins: RPPins<'a>,
124    pub pio0: Pio,
125    pub pio1: Pio,
126    pub pwm: pwm::Pwm<'a>,
127    pub resets: Resets,
128    pub sio: SIO,
129    pub spi0: spi::Spi<'a>,
130    pub sysinfo: sysinfo::SysInfo,
131    pub timer: RPTimer<'a>,
132    pub uart0: Uart<'a>,
133    pub uart1: Uart<'a>,
134    pub usb: usb::UsbCtrl<'a>,
135    pub watchdog: Watchdog<'a>,
136    pub xosc: Xosc,
137    pub rtc: rtc::Rtc<'a>,
138}
139
140impl Rp2040DefaultPeripherals<'_> {
141    pub fn new() -> Self {
142        Self {
143            adc: adc::Adc::new(),
144            clocks: Clocks::new(),
145            i2c0: i2c::I2c::new_i2c0(),
146            pins: RPPins::new(),
147            pio0: Pio::new_pio0(),
148            pio1: Pio::new_pio1(),
149            pwm: pwm::Pwm::new(),
150            resets: Resets::new(),
151            sio: SIO::new(),
152            spi0: spi::Spi::new_spi0(),
153            sysinfo: sysinfo::SysInfo::new(),
154            timer: RPTimer::new(),
155            uart0: Uart::new_uart0(),
156            uart1: Uart::new_uart1(),
157            usb: usb::UsbCtrl::new(),
158            watchdog: Watchdog::new(),
159            xosc: Xosc::new(),
160            rtc: rtc::Rtc::new(),
161        }
162    }
163
164    pub fn resolve_dependencies(&'static self) {
165        self.pwm.set_clocks(&self.clocks);
166        self.watchdog.resolve_dependencies(&self.resets);
167        self.spi0.set_clocks(&self.clocks);
168        self.uart0.set_clocks(&self.clocks);
169        kernel::deferred_call::DeferredCallClient::register(&self.uart0);
170        kernel::deferred_call::DeferredCallClient::register(&self.uart1);
171        kernel::deferred_call::DeferredCallClient::register(&self.rtc);
172        self.i2c0.resolve_dependencies(&self.clocks, &self.resets);
173        self.usb.set_gpio(self.pins.get_pin(RPGpio::GPIO15));
174        self.rtc.set_clocks(&self.clocks);
175    }
176}
177
178impl InterruptService for Rp2040DefaultPeripherals<'_> {
179    unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
180        match interrupt {
181            interrupts::PIO0_IRQ_0 => {
182                self.pio0.handle_interrupt();
183                true
184            }
185            interrupts::TIMER_IRQ_0 => {
186                self.timer.handle_interrupt();
187                true
188            }
189            interrupts::SIO_IRQ_PROC0 => {
190                self.sio.handle_proc_interrupt(Processor::Processor0);
191                true
192            }
193            interrupts::SIO_IRQ_PROC1 => {
194                self.sio.handle_proc_interrupt(Processor::Processor1);
195                true
196            }
197            interrupts::SPI0_IRQ => {
198                self.spi0.handle_interrupt();
199                true
200            }
201            interrupts::UART0_IRQ => {
202                self.uart0.handle_interrupt();
203                true
204            }
205            interrupts::ADC_IRQ_FIFO => {
206                self.adc.handle_interrupt();
207                true
208            }
209            interrupts::USBCTRL_IRQ => {
210                self.usb.handle_interrupt();
211                true
212            }
213            interrupts::IO_IRQ_BANK0 => {
214                self.pins.handle_interrupt();
215                true
216            }
217
218            interrupts::I2C0_IRQ => {
219                self.i2c0.handle_interrupt();
220                true
221            }
222            interrupts::PWM_IRQ_WRAP => {
223                // As the PWM HIL doesn't provide any support for interrupts, they are
224                // simply ignored.
225                //
226                // Note that PWM interrupts are raised only during unit tests.
227                true
228            }
229            _ => false,
230        }
231    }
232}