rp2350/
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 OxidOS Automotive 2025.
4
5//! Chip trait setup.
6
7use core::fmt::Write;
8use kernel::platform::chip::Chip;
9use kernel::platform::chip::InterruptService;
10
11use crate::clocks::Clocks;
12use crate::gpio::{RPPins, SIO};
13use crate::interrupts;
14use crate::resets::Resets;
15use crate::ticks::Ticks;
16use crate::timer::RPTimer;
17use crate::uart::Uart;
18use crate::xosc::Xosc;
19use cortexm33::{interrupt_mask, CortexM33, CortexMVariant};
20
21#[repr(u8)]
22pub enum Processor {
23    Processor0 = 0,
24    Processor1 = 1,
25}
26
27pub struct Rp2350<'a, I: InterruptService + 'a> {
28    mpu: cortexm33::mpu::MPU<8>,
29    userspace_kernel_boundary: cortexm33::syscall::SysCall,
30    interrupt_service: &'a I,
31    sio: &'a SIO,
32    processor0_interrupt_mask: (u128, u128),
33    processor1_interrupt_mask: (u128, u128),
34}
35
36impl<'a, I: InterruptService> Rp2350<'a, I> {
37    pub unsafe fn new(interrupt_service: &'a I, sio: &'a SIO) -> Self {
38        Self {
39            mpu: cortexm33::mpu::new(),
40            userspace_kernel_boundary: cortexm33::syscall::SysCall::new(),
41            interrupt_service,
42            sio,
43            processor0_interrupt_mask: interrupt_mask!(interrupts::PROC1_IRQ_CTI),
44            processor1_interrupt_mask: interrupt_mask!(interrupts::PROC0_IRQ_CTI),
45        }
46    }
47}
48
49impl<I: InterruptService> Chip for Rp2350<'_, I> {
50    type MPU = cortexm33::mpu::MPU<8>;
51    type UserspaceKernelBoundary = cortexm33::syscall::SysCall;
52    type ThreadIdProvider = cortexm33::thread_id::CortexMThreadIdProvider;
53
54    fn service_pending_interrupts(&self) {
55        unsafe {
56            let mask = match self.sio.get_processor() {
57                Processor::Processor0 => self.processor0_interrupt_mask,
58                Processor::Processor1 => self.processor1_interrupt_mask,
59            };
60            while let Some(interrupt) = cortexm33::nvic::next_pending_with_mask(mask) {
61                // ignore PROC1_IRQ_CTI as it is intended for processor 1
62                // not able to unset its pending status
63                // probably only processor 1 can unset the pending by reading the fifo
64                if !self.interrupt_service.service_interrupt(interrupt) {
65                    panic!("unhandled interrupt {}", interrupt);
66                }
67                let n = cortexm33::nvic::Nvic::new(interrupt);
68                n.clear_pending();
69                n.enable();
70            }
71        }
72    }
73
74    fn has_pending_interrupts(&self) -> bool {
75        let mask = match self.sio.get_processor() {
76            Processor::Processor0 => self.processor0_interrupt_mask,
77            Processor::Processor1 => self.processor1_interrupt_mask,
78        };
79        unsafe { cortexm33::nvic::has_pending_with_mask(mask) }
80    }
81
82    fn mpu(&self) -> &Self::MPU {
83        &self.mpu
84    }
85
86    fn userspace_kernel_boundary(&self) -> &Self::UserspaceKernelBoundary {
87        &self.userspace_kernel_boundary
88    }
89
90    fn sleep(&self) {
91        unsafe {
92            cortexm33::support::wfi();
93        }
94    }
95
96    unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
97    where
98        F: FnOnce() -> R,
99    {
100        cortexm33::support::with_interrupts_disabled(f)
101    }
102
103    unsafe fn print_state(&self, writer: &mut dyn Write) {
104        CortexM33::print_cortexm_state(writer);
105    }
106}
107
108pub struct Rp2350DefaultPeripherals<'a> {
109    pub clocks: Clocks,
110    pub pins: RPPins<'a>,
111    pub resets: Resets,
112    pub sio: SIO,
113    pub ticks: Ticks,
114    pub timer0: RPTimer<'a>,
115    pub uart0: Uart<'a>,
116    pub uart1: Uart<'a>,
117    pub xosc: Xosc,
118}
119
120impl Rp2350DefaultPeripherals<'_> {
121    pub fn new() -> Self {
122        Self {
123            clocks: Clocks::new(),
124            pins: RPPins::new(),
125            resets: Resets::new(),
126            sio: SIO::new(),
127            ticks: Ticks::new(),
128            timer0: RPTimer::new_timer0(),
129            uart0: Uart::new_uart0(),
130            uart1: Uart::new_uart1(),
131            xosc: Xosc::new(),
132        }
133    }
134
135    pub fn resolve_dependencies(&'static self) {
136        self.uart0.set_clocks(&self.clocks);
137        self.ticks.set_timer0_generator();
138        self.ticks.set_timer1_generator();
139        kernel::deferred_call::DeferredCallClient::register(&self.uart0);
140        kernel::deferred_call::DeferredCallClient::register(&self.uart1);
141    }
142}
143
144impl InterruptService for Rp2350DefaultPeripherals<'_> {
145    unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
146        match interrupt {
147            interrupts::TIMER0_IRQ_0 => {
148                self.timer0.handle_interrupt();
149                true
150            }
151            interrupts::SIO_IRQ_FIFO => {
152                self.sio.handle_proc_interrupt(self.sio.get_processor());
153                true
154            }
155            interrupts::UART0_IRQ => {
156                self.uart0.handle_interrupt();
157                true
158            }
159            _ => false,
160        }
161    }
162}