Skip to content

Commit 34512a6

Browse files
committed
feat(12): Add initial BSP structure for Raspberry Pi 5
This commit ports the foundational Raspberry Pi 5 support from Tutorial 11 to the new workspace structure of Tutorial 12. It includes: - The 'bsp_rpi5' feature in kernel/Cargo.toml and a version bump to 0.12.0. - The Pi 5 BSP directory structure ('kernel/src/bsp/raspberrypi5'). - The RP1 GPIO driver and updated conditional compilation logic in the shared driver modules to correctly export drivers for each target. - The Pi 5-specific baud rate fix for the shared PL011 UART driver.
1 parent 13208cb commit 34512a6

File tree

11 files changed

+510
-26
lines changed

11 files changed

+510
-26
lines changed

12_integrated_testing/kernel/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
[package]
22
name = "mingo"
33
version = "0.12.0"
4-
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
4+
authors = ["Andre Richter <andre.o.richter@gmail.com>", "Devansh Lodha <devanshlodha12@gmail.com>"]
55
edition = "2021"
66

77
[features]
88
default = []
99
bsp_rpi3 = ["tock-registers"]
1010
bsp_rpi4 = ["tock-registers"]
11+
bsp_rpi5 = ["tock-registers"]
1112
test_build = ["qemu-exit"]
1213

1314
##--------------------------------------------------------------------------------------------------

12_integrated_testing/kernel/src/bsp.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22
//
33
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
4+
// Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
45

56
//! Conditional reexporting of Board Support Packages.
67
@@ -11,3 +12,9 @@ mod raspberrypi;
1112

1213
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
1314
pub use raspberrypi::*;
15+
16+
#[cfg(feature = "bsp_rpi5")]
17+
mod raspberrypi5;
18+
19+
#[cfg(feature = "bsp_rpi5")]
20+
pub use raspberrypi5::*;
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22
//
3-
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
3+
// Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
4+
// Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
45

56
//! Device driver.
67
7-
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
8+
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4", feature = "bsp_rpi5"))]
89
mod bcm;
10+
#[cfg(feature = "bsp_rpi5")]
11+
mod rp1_gpio;
12+
913
mod common;
1014

15+
// For RPi3 and RPi4, re-export everything from the `bcm` module, which includes
16+
// both the GPIO and UART drivers.
1117
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
1218
pub use bcm::*;
19+
20+
// For RPi5, re-export only the drivers it uses: the common PL011Uart from the bcm
21+
// module and its specific GPIO driver from the rp1_gpio module.
22+
#[cfg(feature = "bsp_rpi5")]
23+
pub use bcm::PL011Uart;
24+
#[cfg(feature = "bsp_rpi5")]
25+
pub use rp1_gpio::GPIO;
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22
//
3-
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
3+
// Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
4+
// Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
45

56
//! BCM driver top level.
67
8+
// The bcm2xxx_gpio driver is only for RPi3 and RPi4.
9+
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
710
mod bcm2xxx_gpio;
11+
12+
// The PL011 UART is used by all supported RPi versions.
813
mod bcm2xxx_pl011_uart;
914

15+
// Re-export the GPIO driver only for RPi3 and RPi4.
16+
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
1017
pub use bcm2xxx_gpio::*;
18+
19+
// Re-export the UART driver for all.
1120
pub use bcm2xxx_pl011_uart::*;

12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22
//
3-
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
3+
// Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
4+
// Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
45

56
//! PL011 UART driver.
67
//!
@@ -201,22 +202,6 @@ impl PL011UartInner {
201202
}
202203

203204
/// Set up baud rate and characteristics.
204-
///
205-
/// This results in 8N1 and 921_600 baud.
206-
///
207-
/// The calculation for the BRD is (we set the clock to 48 MHz in config.txt):
208-
/// `(48_000_000 / 16) / 921_600 = 3.2552083`.
209-
///
210-
/// This means the integer part is `3` and goes into the `IBRD`.
211-
/// The fractional part is `0.2552083`.
212-
///
213-
/// `FBRD` calculation according to the PL011 Technical Reference Manual:
214-
/// `INTEGER((0.2552083 * 64) + 0.5) = 16`.
215-
///
216-
/// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a
217-
/// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`.
218-
///
219-
/// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`.
220205
pub fn init(&mut self) {
221206
// Execution can arrive here while there are still characters queued in the TX FIFO and
222207
// actively being sent out by the UART hardware. If the UART is turned off in this case,
@@ -240,9 +225,26 @@ impl PL011UartInner {
240225
// updated on a single write strobe generated by a LCR_H write. So, to internally update the
241226
// contents of IBRD or FBRD, a LCR_H write must always be performed at the end.
242227
//
243-
// Set the baud rate, 8N1 and FIFO enabled.
244-
self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3));
245-
self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16));
228+
// Set the baud rate.
229+
#[cfg(feature = "bsp_rpi5")]
230+
{
231+
// For Pi 5, use the known-good 115200 baud configuration.
232+
// This is proven to work with the default 48MHz UART clock.
233+
// BAUDDIV = 48,000,000 / (16 * 115200) = 26.0416...
234+
// IBRD = 26, FBRD = 3
235+
self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(26));
236+
self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(3));
237+
}
238+
#[cfg(not(feature = "bsp_rpi5"))]
239+
{
240+
// Original configuration for RPi3/4 at 921600 baud.
241+
// BAUDDIV = 48_000,000 / (16 * 921_600) = 3.2552...
242+
// IBRD = 3, FBRD = 16
243+
self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3));
244+
self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16));
245+
}
246+
247+
// Set 8N1 and FIFO enabled.
246248
self.registers
247249
.LCR_H
248250
.write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled);
@@ -255,7 +257,18 @@ impl PL011UartInner {
255257

256258
/// Send a character.
257259
fn write_char(&mut self, c: char) {
258-
// Spin while TX FIFO full is set, waiting for an empty slot.
260+
// If the character is a newline, prepend a carriage return.
261+
if c == '\n' {
262+
// Spin while TX FIFO full is set.
263+
while self.registers.FR.matches_all(FR::TXFF::SET) {
264+
cpu::nop();
265+
}
266+
// Write the carriage return character.
267+
self.registers.DR.set('\r' as u32);
268+
}
269+
270+
// Now, send the original character.
271+
// Spin while TX FIFO full is set.
259272
while self.registers.FR.matches_all(FR::TXFF::SET) {
260273
cpu::nop();
261274
}
@@ -292,7 +305,8 @@ impl PL011UartInner {
292305
// Read one character.
293306
let mut ret = self.registers.DR.get() as u8 as char;
294307

295-
// Convert carrige return to newline.
308+
// Convert carriage return to newline. This is a standard behavior
309+
// for console input.
296310
if ret == '\r' {
297311
ret = '\n'
298312
}
@@ -316,6 +330,7 @@ impl PL011UartInner {
316330
impl fmt::Write for PL011UartInner {
317331
fn write_str(&mut self, s: &str) -> fmt::Result {
318332
for c in s.chars() {
333+
// The `write_char` function now correctly handles `\n` -> `\r\n` conversion.
319334
self.write_char(c);
320335
}
321336

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
//
3+
// Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
4+
// Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
5+
6+
//! RP1 GPIO Driver for Raspberry Pi 5.
7+
8+
use crate::{
9+
bsp::device_driver::common::MMIODerefWrapper, driver, synchronization,
10+
synchronization::NullLock,
11+
};
12+
use tock_registers::{
13+
interfaces::{Readable, Writeable},
14+
register_structs,
15+
registers::ReadWrite,
16+
};
17+
18+
//--------------------------------------------------------------------------------------------------
19+
// Private Definitions
20+
//--------------------------------------------------------------------------------------------------
21+
22+
// Describes the layout of the IO_BANK0 registers.
23+
// Found in the "RP1 Peripherals" datasheet, section 3.1.4, Table 6.
24+
register_structs! {
25+
#[allow(non_snake_case)]
26+
IoBank0RegisterBlock {
27+
(0x000 => _reserved1),
28+
(0x074 => GPIO14_CTRL: ReadWrite<u32>), // GPIO 14 Control Register
29+
(0x078 => _reserved2),
30+
(0x07c => GPIO15_CTRL: ReadWrite<u32>), // GPIO 15 Control Register
31+
(0x080 => @END),
32+
}
33+
}
34+
35+
// Describes the layout of the PADS_BANK0 registers.
36+
// Found in the "RP1 Peripherals" datasheet, section 3.1.4, Table 19.
37+
register_structs! {
38+
#[allow(non_snake_case)]
39+
PadsBank0RegisterBlock {
40+
(0x000 => _reserved1),
41+
(0x03c => GPIO14: ReadWrite<u32>), // Pad control for GPIO 14
42+
(0x040 => GPIO15: ReadWrite<u32>), // Pad control for GPIO 15
43+
(0x044 => @END),
44+
}
45+
}
46+
47+
/// Abstraction for the IO_BANK0 registers.
48+
type IoBank0Registers = MMIODerefWrapper<IoBank0RegisterBlock>;
49+
50+
/// Abstraction for the PADS_BANK0 registers.
51+
type PadsBank0Registers = MMIODerefWrapper<PadsBank0RegisterBlock>;
52+
53+
// The inner state of the GPIO driver.
54+
struct GPIOInner {
55+
io_bank0: IoBank0Registers,
56+
pads_bank0: PadsBank0Registers,
57+
}
58+
59+
//--------------------------------------------------------------------------------------------------
60+
// Public Definitions
61+
//--------------------------------------------------------------------------------------------------
62+
63+
/// Representation of the GPIO peripheral.
64+
pub struct GPIO {
65+
inner: NullLock<GPIOInner>,
66+
}
67+
68+
//--------------------------------------------------------------------------------------------------
69+
// Implementation
70+
//--------------------------------------------------------------------------------------------------
71+
72+
impl GPIOInner {
73+
/// Create an instance.
74+
///
75+
/// # Safety
76+
///
77+
/// - The user must ensure to provide correct MMIO start addresses.
78+
pub const unsafe fn new(
79+
io_bank0_mmio_start_addr: usize,
80+
pads_bank0_mmio_start_addr: usize,
81+
) -> Self {
82+
Self {
83+
io_bank0: IoBank0Registers::new(io_bank0_mmio_start_addr),
84+
pads_bank0: PadsBank0Registers::new(pads_bank0_mmio_start_addr),
85+
}
86+
}
87+
88+
/// Map PL011 UART to GPIO pins 14 and 15.
89+
pub fn map_pl011_uart(&mut self) {
90+
// From RP1 Peripherals datasheet, Table 21: PADS_BANK0 GPIO0 Register
91+
const BIT_PADS_OD: u32 = 1 << 7; // Output Disable
92+
const BIT_PADS_IE: u32 = 1 << 6; // Input Enable
93+
const BIT_PADS_PUE: u32 = 1 << 3; // Pull-Up Enable
94+
95+
// From RP1 Peripherals datasheet, Table 4: GPIO function selection
96+
const FUNCSEL_FIELD_LSB: u32 = 0;
97+
const FUNCSEL_FIELD_MASK: u32 = 0x1F << FUNCSEL_FIELD_LSB;
98+
const FUNC_UART0: u32 = 4; // UART0 is alternate function 4
99+
100+
// --- Configure GPIO 14 as UART0 TX ---
101+
102+
// 1. Set pad electrical properties in PADS_BANK0.
103+
// - Clear Output Disable (OD) bit to enable output.
104+
let mut pads14_val = self.pads_bank0.GPIO14.get();
105+
pads14_val &= !BIT_PADS_OD;
106+
self.pads_bank0.GPIO14.set(pads14_val);
107+
108+
// 2. Set pin function in IO_BANK0.
109+
let mut io14_val = self.io_bank0.GPIO14_CTRL.get();
110+
io14_val &= !FUNCSEL_FIELD_MASK; // Clear the function field.
111+
io14_val |= FUNC_UART0 << FUNCSEL_FIELD_LSB; // Set to UART0.
112+
self.io_bank0.GPIO14_CTRL.set(io14_val);
113+
114+
// --- Configure GPIO 15 as UART0 RX ---
115+
116+
// 1. Set pad electrical properties.
117+
// - Set Input Enable (IE) bit.
118+
// - Set Pull-Up Enable (PUE) as per datasheet recommendation.
119+
let mut pads15_val = self.pads_bank0.GPIO15.get();
120+
pads15_val |= BIT_PADS_IE | BIT_PADS_PUE;
121+
self.pads_bank0.GPIO15.set(pads15_val);
122+
123+
// 2. Set pin function.
124+
let mut io15_val = self.io_bank0.GPIO15_CTRL.get();
125+
io15_val &= !FUNCSEL_FIELD_MASK; // Clear the function field.
126+
io15_val |= FUNC_UART0 << FUNCSEL_FIELD_LSB; // Set to UART0.
127+
self.io_bank0.GPIO15_CTRL.set(io15_val);
128+
}
129+
}
130+
131+
impl GPIO {
132+
pub const COMPATIBLE: &'static str = "RP1 GPIO";
133+
134+
/// Create an instance.
135+
///
136+
/// # Safety
137+
///
138+
/// - The user must ensure to provide correct MMIO start addresses for both register blocks.
139+
pub const unsafe fn new(
140+
io_bank0_mmio_start_addr: usize,
141+
pads_bank0_mmio_start_addr: usize,
142+
) -> Self {
143+
Self {
144+
inner: NullLock::new(GPIOInner::new(
145+
io_bank0_mmio_start_addr,
146+
pads_bank0_mmio_start_addr,
147+
)),
148+
}
149+
}
150+
151+
/// Concurrency-safe version of `GPIOInner.map_pl011_uart()`.
152+
pub fn map_pl011_uart(&self) {
153+
self.inner.lock(|inner| inner.map_pl011_uart())
154+
}
155+
}
156+
157+
//------------------------------------------------------------------------------
158+
// OS Interface Code
159+
//------------------------------------------------------------------------------
160+
use synchronization::interface::Mutex;
161+
162+
impl driver::interface::DeviceDriver for GPIO {
163+
fn compatible(&self) -> &'static str {
164+
Self::COMPATIBLE
165+
}
166+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
//
3+
// Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
4+
// Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
5+
6+
//! Top-level BSP file for the Raspberry Pi 5.
7+
8+
pub mod cpu;
9+
pub mod driver;
10+
pub mod memory;
11+
12+
//--------------------------------------------------------------------------------------------------
13+
// Public Code
14+
//--------------------------------------------------------------------------------------------------
15+
16+
/// Board identification.
17+
pub fn board_name() -> &'static str {
18+
"Raspberry Pi 5"
19+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
//
3+
// Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
4+
5+
//! BSP Processor code for the Raspberry Pi 5.
6+
7+
//--------------------------------------------------------------------------------------------------
8+
// Public Definitions
9+
//--------------------------------------------------------------------------------------------------
10+
11+
/// Used by `arch` code to find the early boot core.
12+
#[no_mangle]
13+
#[link_section = ".text._start_arguments"]
14+
pub static BOOT_CORE_ID: u64 = 0;

0 commit comments

Comments
 (0)