Use MMIODerefWrapper everywhere

pull/71/head
Andre Richter 4 years ago
parent 87d82ea559
commit 3a0b676402
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -132,15 +132,17 @@ diff -uNr 05_safe_globals/src/_arch/aarch64/cpu.rs 06_drivers_gpio_uart/src/_arc
diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
--- 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
+++ 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
@@ -0,0 +1,160 @@
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! GPIO Driver.
+
+use crate::{cpu, driver, synchronization, synchronization::NullLock};
+use core::ops;
+use crate::{
+ bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
+ synchronization::NullLock,
+};
+use register::{mmio::*, register_bitfields, register_structs};
+
+//--------------------------------------------------------------------------------------------------
@ -205,9 +207,8 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_drivers_g
+ }
+}
+
+struct GPIOInner {
+ base_addr: usize,
+}
+/// Abstraction for the associated MMIO registers.
+type Registers = MMIODerefWrapper<RegisterBlock>;
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
@ -215,30 +216,7 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_drivers_g
+
+/// Representation of the GPIO HW.
+pub struct GPIO {
+ inner: NullLock<GPIOInner>,
+}
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+impl ops::Deref for GPIOInner {
+ type Target = RegisterBlock;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.ptr() }
+ }
+}
+
+impl GPIOInner {
+ const fn new(base_addr: usize) -> Self {
+ Self { base_addr }
+ }
+
+ /// Return a pointer to the associated MMIO register block.
+ fn ptr(&self) -> *const RegisterBlock {
+ self.base_addr as *const _
+ }
+ registers: NullLock<Registers>,
+}
+
+//--------------------------------------------------------------------------------------------------
@ -253,7 +231,7 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_drivers_g
+ /// - The user must ensure to provide the correct `base_addr`.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self {
+ inner: NullLock::new(GPIOInner::new(base_addr)),
+ registers: NullLock::new(Registers::new(base_addr)),
+ }
+ }
+
@ -262,23 +240,23 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_drivers_g
+ /// TX to pin 14
+ /// RX to pin 15
+ pub fn map_pl011_uart(&self) {
+ let mut r = &self.inner;
+ r.lock(|inner| {
+ let mut r = &self.registers;
+ r.lock(|registers| {
+ // Map to pins.
+ inner
+ registers
+ .GPFSEL1
+ .modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
+
+ // Enable pins 14 and 15.
+ inner.GPPUD.set(0);
+ registers.GPPUD.set(0);
+ cpu::spin_for_cycles(150);
+
+ inner
+ registers
+ .GPPUDCLK0
+ .write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
+ cpu::spin_for_cycles(150);
+
+ inner.GPPUDCLK0.set(0);
+ registers.GPPUDCLK0.set(0);
+ })
+ }
+}
@ -297,15 +275,18 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_drivers_g
diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+++ 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
@@ -0,0 +1,322 @@
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! PL011 UART driver.
+
+use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
+use core::{fmt, ops};
+use crate::{
+ bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
+ synchronization::NullLock,
+};
+use core::fmt;
+use register::{mmio::*, register_bitfields, register_structs};
+
+//--------------------------------------------------------------------------------------------------
@ -413,10 +394,6 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_dri
+ ]
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+register_structs! {
+ #[allow(non_snake_case)]
+ pub RegisterBlock {
@ -434,8 +411,15 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_dri
+ }
+}
+
+/// Abstraction for the associated MMIO registers.
+type Registers = MMIODerefWrapper<RegisterBlock>;
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+pub struct PL011UartInner {
+ base_addr: usize,
+ registers: Registers,
+ chars_written: usize,
+ chars_read: usize,
+}
@ -452,24 +436,6 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_dri
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Deref to RegisterBlock.
+///
+/// Allows writing
+/// ```
+/// self.DR.read()
+/// ```
+/// instead of something along the lines of
+/// ```
+/// unsafe { (*PL011UartInner::ptr()).DR.read() }
+/// ```
+impl ops::Deref for PL011UartInner {
+ type Target = RegisterBlock;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.ptr() }
+ }
+}
+
+impl PL011UartInner {
+ /// Create an instance.
+ ///
@ -478,7 +444,7 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_dri
+ /// - The user must ensure to provide the correct `base_addr`.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self {
+ base_addr,
+ registers: Registers::new(base_addr),
+ chars_written: 0,
+ chars_read: 0,
+ }
@ -490,31 +456,28 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_dri
+ /// firmware).
+ pub fn init(&mut self) {
+ // Turn it off temporarily.
+ self.CR.set(0);
+ self.registers.CR.set(0);
+
+ self.ICR.write(ICR::ALL::CLEAR);
+ self.IBRD.write(IBRD::IBRD.val(13));
+ self.FBRD.write(FBRD::FBRD.val(2));
+ self.LCRH
+ self.registers.ICR.write(ICR::ALL::CLEAR);
+ self.registers.IBRD.write(IBRD::IBRD.val(13));
+ self.registers.FBRD.write(FBRD::FBRD.val(2));
+ self.registers
+ .LCRH
+ .write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
+ self.CR
+ self.registers
+ .CR
+ .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
+ }
+
+ /// Return a pointer to the register block.
+ fn ptr(&self) -> *const RegisterBlock {
+ self.base_addr as *const _
+ }
+
+ /// Send a character.
+ fn write_char(&mut self, c: char) {
+ // Spin while TX FIFO full is set, waiting for an empty slot.
+ while self.FR.matches_all(FR::TXFF::SET) {
+ while self.registers.FR.matches_all(FR::TXFF::SET) {
+ cpu::nop();
+ }
+
+ // Write the character to the buffer.
+ self.DR.set(c as u32);
+ self.registers.DR.set(c as u32);
+
+ self.chars_written += 1;
+ }
@ -589,12 +552,12 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_dri
+ let mut r = &self.inner;
+ r.lock(|inner| {
+ // Spin while RX FIFO empty is set.
+ while inner.FR.matches_all(FR::RXFE::SET) {
+ while inner.registers.FR.matches_all(FR::RXFE::SET) {
+ cpu::nop();
+ }
+
+ // Read one character.
+ let mut ret = inner.DR.get() as u8 as char;
+ let mut ret = inner.registers.DR.get() as u8 as char;
+
+ // Convert carrige return to newline.
+ if ret == '\r' {
@ -637,10 +600,50 @@ diff -uNr 05_safe_globals/src/bsp/device_driver/bcm.rs 06_drivers_gpio_uart/src/
+pub use bcm2xxx_gpio::*;
+pub use bcm2xxx_pl011_uart::*;
diff -uNr 05_safe_globals/src/bsp/device_driver/common.rs 06_drivers_gpio_uart/src/bsp/device_driver/common.rs
--- 05_safe_globals/src/bsp/device_driver/common.rs
+++ 06_drivers_gpio_uart/src/bsp/device_driver/common.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! Common device driver code.
+
+use core::{marker::PhantomData, ops};
+
+pub struct MMIODerefWrapper<T> {
+ base_addr: usize,
+ phantom: PhantomData<T>,
+}
+
+impl<T> MMIODerefWrapper<T> {
+ /// Create an instance.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self {
+ base_addr,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Return a pointer to the associated MMIO register block.
+ fn ptr(&self) -> *const T {
+ self.base_addr as *const _
+ }
+}
+
+impl<T> ops::Deref for MMIODerefWrapper<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.ptr() }
+ }
+}
diff -uNr 05_safe_globals/src/bsp/device_driver.rs 06_drivers_gpio_uart/src/bsp/device_driver.rs
--- 05_safe_globals/src/bsp/device_driver.rs
+++ 06_drivers_gpio_uart/src/bsp/device_driver.rs
@@ -0,0 +1,11 @@
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
@ -649,6 +652,7 @@ diff -uNr 05_safe_globals/src/bsp/device_driver.rs 06_drivers_gpio_uart/src/bsp/
+
+#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
+mod bcm;
+mod common;
+
+#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
+pub use bcm::*;

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -289,12 +274,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -197,7 +197,7 @@ diff -uNr 06_drivers_gpio_uart/src/_arch/aarch64/cpu.rs 07_uart_chainloader/src/
diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+++ 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
@@ -282,6 +282,16 @@
@@ -267,6 +267,16 @@
let mut r = &self.inner;
r.lock(|inner| fmt::Write::write_fmt(inner, args))
}
@ -206,7 +206,7 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0
+ // Spin until TX FIFO empty is set.
+ let mut r = &self.inner;
+ r.lock(|inner| {
+ while !inner.FR.matches_all(FR::TXFE::SET) {
+ while !inner.registers.FR.matches_all(FR::TXFE::SET) {
+ cpu::nop();
+ }
+ });
@ -214,12 +214,12 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0
}
impl console::interface::Read for PL011Uart {
@@ -293,18 +303,21 @@
@@ -278,18 +288,21 @@
cpu::nop();
}
- // Read one character.
- let mut ret = inner.DR.get() as u8 as char;
- let mut ret = inner.registers.DR.get() as u8 as char;
-
- // Convert carrige return to newline.
- if ret == '\r' {
@ -231,7 +231,7 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0
- ret
+ // Read one character.
+ inner.DR.get() as u8 as char
+ inner.registers.DR.get() as u8 as char
+ })
+ }
+
@ -239,8 +239,8 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0
+ let mut r = &self.inner;
+ r.lock(|inner| {
+ // Read from the RX FIFO until it is indicating empty.
+ while !inner.FR.matches_all(FR::RXFE::SET) {
+ inner.DR.get();
+ while !inner.registers.FR.matches_all(FR::RXFE::SET) {
+ inner.registers.DR.get();
+ }
})
}

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,7 +284,7 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
@ -307,7 +292,7 @@ impl console::interface::Read for PL011Uart {
inner.chars_read += 1;
// Read one character.
inner.DR.get() as u8 as char
inner.registers.DR.get() as u8 as char
})
}
@ -315,8 +300,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -227,12 +227,12 @@ diff -uNr 07_uart_chainloader/src/_arch/aarch64/time.rs 08_timestamps/src/_arch/
diff -uNr 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+++ 08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
@@ -303,11 +303,18 @@
@@ -288,11 +288,18 @@
cpu::nop();
}
+ // Read one character.
+ let mut ret = inner.DR.get() as u8 as char;
+ let mut ret = inner.registers.DR.get() as u8 as char;
+
+ // Convert carrige return to newline.
+ if ret == '\r' {
@ -243,7 +243,7 @@ diff -uNr 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 08
inner.chars_read += 1;
- // Read one character.
- inner.DR.get() as u8 as char
- inner.registers.DR.get() as u8 as char
+ ret
})
}

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -322,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -322,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -322,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -619,26 +619,6 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+ }
+}
diff -uNr 10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+++ 11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
@@ -118,6 +118,7 @@
//--------------------------------------------------------------------------------------------------
register_structs! {
+ #[allow(missing_docs)]
#[allow(non_snake_case)]
pub RegisterBlock {
(0x00 => DR: ReadWrite<u32>),
@@ -134,6 +135,7 @@
}
}
+#[allow(missing_docs)]
pub struct PL011UartInner {
base_addr: usize,
chars_written: usize,
diff -uNr 10_privilege_level/src/bsp/raspberrypi/link.ld 11_virtual_memory/src/bsp/raspberrypi/link.ld
--- 10_privilege_level/src/bsp/raspberrypi/link.ld
+++ 11_virtual_memory/src/bsp/raspberrypi/link.ld

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,12 +116,7 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(missing_docs)]
#[allow(non_snake_case)]
pub RegisterBlock {
(0x00 => DR: ReadWrite<u32>),
@ -135,9 +133,15 @@ register_structs! {
}
}
#[allow(missing_docs)]
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -154,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -180,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -192,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -289,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -301,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -324,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -883,26 +883,6 @@ diff -uNr 11_virtual_memory/src/_arch/aarch64/exception.S 12_exceptions_part1_gr
+
+ eret
diff -uNr 11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+++ 12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
@@ -118,7 +118,6 @@
//--------------------------------------------------------------------------------------------------
register_structs! {
- #[allow(missing_docs)]
#[allow(non_snake_case)]
pub RegisterBlock {
(0x00 => DR: ReadWrite<u32>),
@@ -135,7 +134,6 @@
}
}
-#[allow(missing_docs)]
pub struct PL011UartInner {
base_addr: usize,
chars_written: usize,
diff -uNr 11_virtual_memory/src/bsp/raspberrypi/memory/mmu.rs 12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs
--- 11_virtual_memory/src/bsp/raspberrypi/memory/mmu.rs
+++ 12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -322,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -322,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}

@ -242,10 +242,10 @@ impl exception::asynchronous::interface::IRQHandler for PL011Uart {
fn handle(&self) -> Result<(), &'static str> {
let mut r = &self.inner;
r.lock(|inner| {
let pending = inner.MIS.extract();
let pending = inner.registers.MIS.extract();
// Clear all pending IRQs.
inner.ICR.write(ICR::ALL::CLEAR);
inner.registers.ICR.write(ICR::ALL::CLEAR);
// Check for any kind of RX interrupt.
if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) {
@ -874,15 +874,14 @@ diff -uNr 13_integrated_testing/src/_arch/aarch64/exception.rs 14_exceptions_par
diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs
--- 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs
+++ 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs
@@ -0,0 +1,146 @@
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! GICC Driver - GIC CPU interface.
+
+use crate::exception;
+use core::ops;
+use crate::{bsp::device_driver::common::MMIODerefWrapper, exception};
+use register::{mmio::*, register_bitfields, register_structs};
+
+//--------------------------------------------------------------------------------------------------
@ -913,10 +912,6 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ ]
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+register_structs! {
+ #[allow(non_snake_case)]
+ pub RegisterBlock {
@ -929,23 +924,22 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ }
+}
+
+/// Abstraction for the associated MMIO registers.
+type Registers = MMIODerefWrapper<RegisterBlock>;
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+/// Representation of the GIC CPU interface.
+pub struct GICC {
+ base_addr: usize,
+ registers: Registers,
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+impl ops::Deref for GICC {
+ type Target = RegisterBlock;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.ptr() }
+ }
+}
+
+impl GICC {
+ /// Create an instance.
+ ///
@ -953,12 +947,9 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ ///
+ /// - The user must ensure to provide the correct `base_addr`.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self { base_addr }
+ }
+
+ /// Return a pointer to the associated MMIO register block.
+ fn ptr(&self) -> *const RegisterBlock {
+ self.base_addr as *const _
+ Self {
+ registers: Registers::new(base_addr),
+ }
+ }
+
+ /// Accept interrupts of any priority.
@ -973,7 +964,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead
+ /// of `&mut self`.
+ pub fn priority_accept_all(&self) {
+ self.PMR.write(PMR::Priority.val(255)); // Comment in arch spec.
+ self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec.
+ }
+
+ /// Enable the interface - start accepting IRQs.
@ -983,7 +974,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead
+ /// of `&mut self`.
+ pub fn enable(&self) {
+ self.CTLR.write(CTLR::Enable::SET);
+ self.registers.CTLR.write(CTLR::Enable::SET);
+ }
+
+ /// Extract the number of the highest-priority pending IRQ.
@ -999,7 +990,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ &self,
+ _ic: &exception::asynchronous::IRQContext<'irq_context>,
+ ) -> usize {
+ self.IAR.read(IAR::InterruptID) as usize
+ self.registers.IAR.read(IAR::InterruptID) as usize
+ }
+
+ /// Complete handling of the currently active IRQ.
@ -1018,7 +1009,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ irq_number: u32,
+ _ic: &exception::asynchronous::IRQContext<'irq_context>,
+ ) {
+ self.EOIR.write(EOIR::EOIINTID.val(irq_number));
+ self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number));
+ }
+}
@ -1092,10 +1083,10 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+}
+
+/// Abstraction for the non-banked parts of the associated MMIO registers.
+type SharedRegs = MMIODerefWrapper<SharedRegisterBlock>;
+type SharedRegisters = MMIODerefWrapper<SharedRegisterBlock>;
+
+/// Abstraction for the banked parts of the associated MMIO registers.
+type BankedRegs = MMIODerefWrapper<BankedRegisterBlock>;
+type BankedRegisters = MMIODerefWrapper<BankedRegisterBlock>;
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
@ -1104,17 +1095,17 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+/// Representation of the GIC Distributor.
+pub struct GICD {
+ /// Access to shared registers is guarded with a lock.
+ shared_regs: IRQSafeNullLock<SharedRegs>,
+ shared_registers: IRQSafeNullLock<SharedRegisters>,
+
+ /// Access to banked registers is unguarded.
+ banked_regs: BankedRegs,
+ banked_registers: BankedRegisters,
+}
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+impl SharedRegs {
+impl SharedRegisters {
+ /// Return the number of IRQs that this HW implements.
+ #[inline(always)]
+ fn num_irqs(&mut self) -> usize {
@ -1131,7 +1122,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+
+ // Calculate the max index of the shared ITARGETSR array.
+ //
+ // The first 32 IRQs are private, so not included in `shared_regs`. Each ITARGETS
+ // The first 32 IRQs are private, so not included in `shared_registers`. Each ITARGETS
+ // register has four entries, so shift right by two. Subtract one because we start
+ // counting at zero.
+ let spi_itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1;
@ -1154,8 +1145,8 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+ /// - The user must ensure to provide the correct `base_addr`.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self {
+ shared_regs: IRQSafeNullLock::new(SharedRegs::new(base_addr)),
+ banked_regs: BankedRegs::new(base_addr),
+ shared_registers: IRQSafeNullLock::new(SharedRegisters::new(base_addr)),
+ banked_registers: BankedRegisters::new(base_addr),
+ }
+ }
+
@ -1166,7 +1157,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+ /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that
+ /// corresponds only to the processor reading the register."
+ fn local_gic_target_mask(&self) -> u32 {
+ self.banked_regs.ITARGETSR[0].read(ITARGETSR::Offset0)
+ self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0)
+ }
+
+ /// Route all SPIs to the boot core and enable the distributor.
@ -1179,7 +1170,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+ // Target all SPIs to the boot core only.
+ let mask = self.local_gic_target_mask();
+
+ let mut r = &self.shared_regs;
+ let mut r = &self.shared_registers;
+ r.lock(|regs| {
+ for i in regs.implemented_itargets_slice().iter() {
+ i.write(
@ -1207,14 +1198,14 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 14_excep
+ match irq_num {
+ // Private.
+ 0..=31 => {
+ let enable_reg = &self.banked_regs.ISENABLER;
+ let enable_reg = &self.banked_registers.ISENABLER;
+ enable_reg.set(enable_reg.get() | enable_bit);
+ }
+ // Shared.
+ _ => {
+ let enable_reg_index_shared = enable_reg_index - 1;
+
+ let mut r = &self.shared_regs;
+ let mut r = &self.shared_registers;
+ r.lock(|regs| {
+ let enable_reg = &regs.ISENABLER[enable_reg_index_shared];
+ enable_reg.set(enable_reg.get() | enable_bit);
@ -1468,69 +1459,30 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm.rs 14_exceptions_part2
diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
--- 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
+++ 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
@@ -4,8 +4,10 @@
//! GPIO Driver.
@@ -6,7 +6,7 @@
-use crate::{cpu, driver, synchronization, synchronization::NullLock};
-use core::ops;
+use crate::{
+ bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
- synchronization::NullLock,
+ synchronization::IRQSafeNullLock,
+};
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@@ -70,9 +72,8 @@
}
}
-struct GPIOInner {
- base_addr: usize,
-}
+/// Abstraction for the associated MMIO registers.
+type Regs = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@@ -80,30 +81,7 @@
@@ -81,7 +81,7 @@
/// Representation of the GPIO HW.
pub struct GPIO {
- inner: NullLock<GPIOInner>,
-}
-
-//--------------------------------------------------------------------------------------------------
-// Private Code
-//--------------------------------------------------------------------------------------------------
-
-impl ops::Deref for GPIOInner {
- type Target = RegisterBlock;
-
- fn deref(&self) -> &Self::Target {
- unsafe { &*self.ptr() }
- }
-}
-
-impl GPIOInner {
- const fn new(base_addr: usize) -> Self {
- Self { base_addr }
- }
-
- /// Return a pointer to the associated MMIO register block.
- fn ptr(&self) -> *const RegisterBlock {
- self.base_addr as *const _
- }
+ inner: IRQSafeNullLock<Regs>,
- registers: NullLock<Registers>,
+ registers: IRQSafeNullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@@ -118,7 +96,7 @@
@@ -96,7 +96,7 @@
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
- inner: NullLock::new(GPIOInner::new(base_addr)),
+ inner: IRQSafeNullLock::new(Regs::new(base_addr)),
- registers: NullLock::new(Registers::new(base_addr)),
+ registers: IRQSafeNullLock::new(Registers::new(base_addr)),
}
}
@ -1578,10 +1530,10 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
+}
+
+/// Abstraction for the WriteOnly parts of the associated MMIO registers.
+type WriteOnlyRegs = MMIODerefWrapper<WORegisterBlock>;
+type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
+
+/// Abstraction for the ReadOnly parts of the associated MMIO registers.
+type ReadOnlyRegs = MMIODerefWrapper<RORegisterBlock>;
+type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
+
+type HandlerTable =
+ [Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
@ -1593,10 +1545,10 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
+/// Representation of the peripheral interrupt regsler.
+pub struct PeripheralIC {
+ /// Access to write registers is guarded with a lock.
+ wo_regs: IRQSafeNullLock<WriteOnlyRegs>,
+ wo_registers: IRQSafeNullLock<WriteOnlyRegisters>,
+
+ /// Register read access is unguarded.
+ ro_regs: ReadOnlyRegs,
+ ro_registers: ReadOnlyRegisters,
+
+ /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards.
+ handler_table: InitStateLock<HandlerTable>,
@ -1614,16 +1566,16 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
+ /// - The user must ensure to provide the correct `base_addr`.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self {
+ wo_regs: IRQSafeNullLock::new(WriteOnlyRegs::new(base_addr)),
+ ro_regs: ReadOnlyRegs::new(base_addr),
+ wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(base_addr)),
+ ro_registers: ReadOnlyRegisters::new(base_addr),
+ handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]),
+ }
+ }
+
+ /// Query the list of pending IRQs.
+ fn get_pending(&self) -> PendingIRQs {
+ let pending_mask: u64 = (u64::from(self.ro_regs.PENDING_2.get()) << 32)
+ | u64::from(self.ro_regs.PENDING_1.get());
+ let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32)
+ | u64::from(self.ro_registers.PENDING_1.get());
+
+ PendingIRQs::new(pending_mask)
+ }
@ -1657,7 +1609,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
+ }
+
+ fn enable(&self, irq: Self::IRQNumberType) {
+ let mut r = &self.wo_regs;
+ let mut r = &self.wo_registers;
+ r.lock(|regs| {
+ let enable_reg = if irq.get() <= 31 {
+ &regs.ENABLE_1
@ -1846,18 +1798,18 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+++ 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
@@ -4,7 +4,9 @@
@@ -5,8 +5,8 @@
//! PL011 UART driver.
-use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
+use crate::{
+ bsp, console, cpu, driver, exception, synchronization, synchronization::IRQSafeNullLock,
+};
use core::{fmt, ops};
use crate::{
- bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
- synchronization::NullLock,
+ bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception,
+ synchronization, synchronization::IRQSafeNullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
@@ -106,6 +108,48 @@
@@ -109,6 +109,48 @@
]
],
@ -1906,20 +1858,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
/// Interrupt Clear Register
ICR [
/// Meta field for all pending interrupts
@@ -113,6 +157,12 @@
]
}
+#[derive(PartialEq)]
+enum BlockingMode {
+ Blocking,
+ NonBlocking,
+}
+
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
@@ -128,7 +178,10 @@
@@ -127,7 +169,10 @@
(0x28 => FBRD: WriteOnly<u32, FBRD::Register>),
(0x2c => LCRH: WriteOnly<u32, LCRH::Register>),
(0x30 => CR: WriteOnly<u32, CR::Register>),
@ -1931,7 +1870,20 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
(0x44 => ICR: WriteOnly<u32, ICR::Register>),
(0x48 => @END),
}
@@ -145,7 +198,8 @@
@@ -136,6 +181,12 @@
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
+#[derive(PartialEq)]
+enum BlockingMode {
+ Blocking,
+ NonBlocking,
+}
+
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
@@ -151,7 +202,8 @@
/// Representation of the UART.
pub struct PL011Uart {
@ -1941,16 +1893,18 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
}
//--------------------------------------------------------------------------------------------------
@@ -197,6 +251,8 @@
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
@@ -186,6 +238,10 @@
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
+ self.IFLS.write(IFLS::RXIFLSEL::OneEigth); // RX FIFO fill level at 1/8
+ self.IMSC.write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); // RX IRQ + RX timeout IRQ
self.CR
+ self.registers.IFLS.write(IFLS::RXIFLSEL::OneEigth); // RX FIFO fill level at 1/8
+ self.registers
+ .IMSC
+ .write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); // RX IRQ + RX timeout IRQ
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
@@ -218,6 +274,35 @@
@@ -203,6 +259,35 @@
self.chars_written += 1;
}
@ -1958,20 +1912,20 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+ /// Retrieve a character.
+ fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option<char> {
+ // If RX FIFO is empty,
+ if self.FR.matches_all(FR::RXFE::SET) {
+ if self.registers.FR.matches_all(FR::RXFE::SET) {
+ // immediately return in non-blocking mode.
+ if blocking_mode == BlockingMode::NonBlocking {
+ return None;
+ }
+
+ // Otherwise, wait until a char was received.
+ while self.FR.matches_all(FR::RXFE::SET) {
+ while self.registers.FR.matches_all(FR::RXFE::SET) {
+ cpu::nop();
+ }
+ }
+
+ // Read one character.
+ let mut ret = self.DR.get() as u8 as char;
+ let mut ret = self.registers.DR.get() as u8 as char;
+
+ // Convert carrige return to newline.
+ if ret == '\r' {
@ -1986,7 +1940,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
}
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
@@ -243,9 +328,10 @@
@@ -228,9 +313,10 @@
/// # Safety
///
/// - The user must ensure to provide the correct `base_addr`.
@ -1999,7 +1953,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
}
}
}
@@ -266,6 +352,21 @@
@@ -251,6 +337,21 @@
Ok(())
}
@ -2021,18 +1975,18 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
}
impl console::interface::Write for PL011Uart {
@@ -297,25 +398,7 @@
@@ -282,25 +383,7 @@
impl console::interface::Read for PL011Uart {
fn read_char(&self) -> char {
let mut r = &self.inner;
- r.lock(|inner| {
- // Spin while RX FIFO empty is set.
- while inner.FR.matches_all(FR::RXFE::SET) {
- while inner.registers.FR.matches_all(FR::RXFE::SET) {
- cpu::nop();
- }
-
- // Read one character.
- let mut ret = inner.DR.get() as u8 as char;
- let mut ret = inner.registers.DR.get() as u8 as char;
-
- // Convert carrige return to newline.
- if ret == '\r' {
@ -2048,7 +2002,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
}
fn clear(&self) {
@@ -340,3 +423,25 @@
@@ -325,3 +408,25 @@
r.lock(|inner| inner.chars_read)
}
}
@ -2057,10 +2011,10 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
+ fn handle(&self) -> Result<(), &'static str> {
+ let mut r = &self.inner;
+ r.lock(|inner| {
+ let pending = inner.MIS.extract();
+ let pending = inner.registers.MIS.extract();
+
+ // Clear all pending IRQs.
+ inner.ICR.write(ICR::ALL::CLEAR);
+ inner.registers.ICR.write(ICR::ALL::CLEAR);
+
+ // Check for any kind of RX interrupt.
+ if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) {
@ -2091,50 +2045,10 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm.rs 14_exceptions_part2
+pub use bcm2xxx_interrupt_controller::*;
pub use bcm2xxx_pl011_uart::*;
diff -uNr 13_integrated_testing/src/bsp/device_driver/common.rs 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/common.rs
--- 13_integrated_testing/src/bsp/device_driver/common.rs
+++ 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/common.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! Common device driver code.
+
+use core::{marker::PhantomData, ops};
+
+pub struct MMIODerefWrapper<T> {
+ base_addr: usize,
+ phantom: PhantomData<T>,
+}
+
+impl<T> MMIODerefWrapper<T> {
+ /// Create an instance.
+ pub const unsafe fn new(base_addr: usize) -> Self {
+ Self {
+ base_addr,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Return a pointer to the associated MMIO register block.
+ fn ptr(&self) -> *const T {
+ self.base_addr as *const _
+ }
+}
+
+impl<T> ops::Deref for MMIODerefWrapper<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.ptr() }
+ }
+}
diff -uNr 13_integrated_testing/src/bsp/device_driver.rs 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver.rs
--- 13_integrated_testing/src/bsp/device_driver.rs
+++ 14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver.rs
@@ -4,8 +4,13 @@
@@ -4,9 +4,13 @@
//! Device driver.
@ -2142,7 +2056,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver.rs 14_exceptions_part2_per
+mod arm;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
+mod common;
mod common;
+#[cfg(feature = "bsp_rpi4")]
+pub use arm::*;

@ -4,8 +4,7 @@
//! GICC Driver - GIC CPU interface.
use crate::exception;
use core::ops;
use crate::{bsp::device_driver::common::MMIODerefWrapper, exception};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -36,10 +35,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -52,23 +47,22 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
/// Representation of the GIC CPU interface.
pub struct GICC {
base_addr: usize,
registers: Registers,
}
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GICC {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GICC {
/// Create an instance.
///
@ -76,12 +70,9 @@ impl GICC {
///
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
Self {
registers: Registers::new(base_addr),
}
}
/// Accept interrupts of any priority.
@ -96,7 +87,7 @@ impl GICC {
/// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead
/// of `&mut self`.
pub fn priority_accept_all(&self) {
self.PMR.write(PMR::Priority.val(255)); // Comment in arch spec.
self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec.
}
/// Enable the interface - start accepting IRQs.
@ -106,7 +97,7 @@ impl GICC {
/// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead
/// of `&mut self`.
pub fn enable(&self) {
self.CTLR.write(CTLR::Enable::SET);
self.registers.CTLR.write(CTLR::Enable::SET);
}
/// Extract the number of the highest-priority pending IRQ.
@ -122,7 +113,7 @@ impl GICC {
&self,
_ic: &exception::asynchronous::IRQContext<'irq_context>,
) -> usize {
self.IAR.read(IAR::InterruptID) as usize
self.registers.IAR.read(IAR::InterruptID) as usize
}
/// Complete handling of the currently active IRQ.
@ -141,6 +132,6 @@ impl GICC {
irq_number: u32,
_ic: &exception::asynchronous::IRQContext<'irq_context>,
) {
self.EOIR.write(EOIR::EOIINTID.val(irq_number));
self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number));
}
}

@ -64,10 +64,10 @@ register_structs! {
}
/// Abstraction for the non-banked parts of the associated MMIO registers.
type SharedRegs = MMIODerefWrapper<SharedRegisterBlock>;
type SharedRegisters = MMIODerefWrapper<SharedRegisterBlock>;
/// Abstraction for the banked parts of the associated MMIO registers.
type BankedRegs = MMIODerefWrapper<BankedRegisterBlock>;
type BankedRegisters = MMIODerefWrapper<BankedRegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -76,17 +76,17 @@ type BankedRegs = MMIODerefWrapper<BankedRegisterBlock>;
/// Representation of the GIC Distributor.
pub struct GICD {
/// Access to shared registers is guarded with a lock.
shared_regs: IRQSafeNullLock<SharedRegs>,
shared_registers: IRQSafeNullLock<SharedRegisters>,
/// Access to banked registers is unguarded.
banked_regs: BankedRegs,
banked_registers: BankedRegisters,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl SharedRegs {
impl SharedRegisters {
/// Return the number of IRQs that this HW implements.
#[inline(always)]
fn num_irqs(&mut self) -> usize {
@ -103,7 +103,7 @@ impl SharedRegs {
// Calculate the max index of the shared ITARGETSR array.
//
// The first 32 IRQs are private, so not included in `shared_regs`. Each ITARGETS
// The first 32 IRQs are private, so not included in `shared_registers`. Each ITARGETS
// register has four entries, so shift right by two. Subtract one because we start
// counting at zero.
let spi_itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1;
@ -126,8 +126,8 @@ impl GICD {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
shared_regs: IRQSafeNullLock::new(SharedRegs::new(base_addr)),
banked_regs: BankedRegs::new(base_addr),
shared_registers: IRQSafeNullLock::new(SharedRegisters::new(base_addr)),
banked_registers: BankedRegisters::new(base_addr),
}
}
@ -138,7 +138,7 @@ impl GICD {
/// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that
/// corresponds only to the processor reading the register."
fn local_gic_target_mask(&self) -> u32 {
self.banked_regs.ITARGETSR[0].read(ITARGETSR::Offset0)
self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0)
}
/// Route all SPIs to the boot core and enable the distributor.
@ -151,7 +151,7 @@ impl GICD {
// Target all SPIs to the boot core only.
let mask = self.local_gic_target_mask();
let mut r = &self.shared_regs;
let mut r = &self.shared_registers;
r.lock(|regs| {
for i in regs.implemented_itargets_slice().iter() {
i.write(
@ -179,14 +179,14 @@ impl GICD {
match irq_num {
// Private.
0..=31 => {
let enable_reg = &self.banked_regs.ISENABLER;
let enable_reg = &self.banked_registers.ISENABLER;
enable_reg.set(enable_reg.get() | enable_bit);
}
// Shared.
_ => {
let enable_reg_index_shared = enable_reg_index - 1;
let mut r = &self.shared_regs;
let mut r = &self.shared_registers;
r.lock(|regs| {
let enable_reg = &regs.ISENABLER[enable_reg_index_shared];
enable_reg.set(enable_reg.get() | enable_bit);

@ -73,7 +73,7 @@ register_structs! {
}
/// Abstraction for the associated MMIO registers.
type Regs = MMIODerefWrapper<RegisterBlock>;
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -81,7 +81,7 @@ type Regs = MMIODerefWrapper<RegisterBlock>;
/// Representation of the GPIO HW.
pub struct GPIO {
inner: IRQSafeNullLock<Regs>,
registers: IRQSafeNullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -96,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: IRQSafeNullLock::new(Regs::new(base_addr)),
registers: IRQSafeNullLock::new(Registers::new(base_addr)),
}
}
@ -105,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -37,10 +37,10 @@ register_structs! {
}
/// Abstraction for the WriteOnly parts of the associated MMIO registers.
type WriteOnlyRegs = MMIODerefWrapper<WORegisterBlock>;
type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegs = MMIODerefWrapper<RORegisterBlock>;
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
@ -52,10 +52,10 @@ type HandlerTable =
/// Representation of the peripheral interrupt regsler.
pub struct PeripheralIC {
/// Access to write registers is guarded with a lock.
wo_regs: IRQSafeNullLock<WriteOnlyRegs>,
wo_registers: IRQSafeNullLock<WriteOnlyRegisters>,
/// Register read access is unguarded.
ro_regs: ReadOnlyRegs,
ro_registers: ReadOnlyRegisters,
/// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards.
handler_table: InitStateLock<HandlerTable>,
@ -73,16 +73,16 @@ impl PeripheralIC {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
wo_regs: IRQSafeNullLock::new(WriteOnlyRegs::new(base_addr)),
ro_regs: ReadOnlyRegs::new(base_addr),
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(base_addr)),
ro_registers: ReadOnlyRegisters::new(base_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]),
}
}
/// Query the list of pending IRQs.
fn get_pending(&self) -> PendingIRQs {
let pending_mask: u64 = (u64::from(self.ro_regs.PENDING_2.get()) << 32)
| u64::from(self.ro_regs.PENDING_1.get());
let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32)
| u64::from(self.ro_registers.PENDING_1.get());
PendingIRQs::new(pending_mask)
}
@ -116,7 +116,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC {
}
fn enable(&self, irq: Self::IRQNumberType) {
let mut r = &self.wo_regs;
let mut r = &self.wo_registers;
r.lock(|regs| {
let enable_reg = if irq.get() <= 31 {
&regs.ENABLE_1

@ -5,9 +5,10 @@
//! PL011 UART driver.
use crate::{
bsp, console, cpu, driver, exception, synchronization, synchronization::IRQSafeNullLock,
bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception,
synchronization, synchronization::IRQSafeNullLock,
};
use core::{fmt, ops};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -157,16 +158,6 @@ register_bitfields! {
]
}
#[derive(PartialEq)]
enum BlockingMode {
Blocking,
NonBlocking,
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -187,8 +178,21 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
#[derive(PartialEq)]
enum BlockingMode {
Blocking,
NonBlocking,
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -206,24 +210,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -232,7 +218,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -244,33 +230,32 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.IFLS.write(IFLS::RXIFLSEL::OneEigth); // RX FIFO fill level at 1/8
self.IMSC.write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); // RX IRQ + RX timeout IRQ
self.CR
self.registers.IFLS.write(IFLS::RXIFLSEL::OneEigth); // RX FIFO fill level at 1/8
self.registers
.IMSC
.write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); // RX IRQ + RX timeout IRQ
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -278,20 +263,20 @@ impl PL011UartInner {
/// Retrieve a character.
fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option<char> {
// If RX FIFO is empty,
if self.FR.matches_all(FR::RXFE::SET) {
if self.registers.FR.matches_all(FR::RXFE::SET) {
// immediately return in non-blocking mode.
if blocking_mode == BlockingMode::NonBlocking {
return None;
}
// Otherwise, wait until a char was received.
while self.FR.matches_all(FR::RXFE::SET) {
while self.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
}
// Read one character.
let mut ret = self.DR.get() as u8 as char;
let mut ret = self.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -388,7 +373,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -405,8 +390,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}
@ -428,10 +413,10 @@ impl exception::asynchronous::interface::IRQHandler for PL011Uart {
fn handle(&self) -> Result<(), &'static str> {
let mut r = &self.inner;
r.lock(|inner| {
let pending = inner.MIS.extract();
let pending = inner.registers.MIS.extract();
// Clear all pending IRQs.
inner.ICR.write(ICR::ALL::CLEAR);
inner.registers.ICR.write(ICR::ALL::CLEAR);
// Check for any kind of RX interrupt.
if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) {

Binary file not shown.

Binary file not shown.

@ -6,6 +6,7 @@
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
mod bcm;
mod common;
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
pub use bcm::*;

@ -4,8 +4,10 @@
//! GPIO Driver.
use crate::{cpu, driver, synchronization, synchronization::NullLock};
use core::ops;
use crate::{
bsp::device_driver::common::MMIODerefWrapper, cpu, driver, synchronization,
synchronization::NullLock,
};
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -70,9 +72,8 @@ register_structs! {
}
}
struct GPIOInner {
base_addr: usize,
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -80,30 +81,7 @@ struct GPIOInner {
/// Representation of the GPIO HW.
pub struct GPIO {
inner: NullLock<GPIOInner>,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
impl ops::Deref for GPIOInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl GPIOInner {
const fn new(base_addr: usize) -> Self {
Self { base_addr }
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
registers: NullLock<Registers>,
}
//--------------------------------------------------------------------------------------------------
@ -118,7 +96,7 @@ impl GPIO {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
inner: NullLock::new(GPIOInner::new(base_addr)),
registers: NullLock::new(Registers::new(base_addr)),
}
}
@ -127,23 +105,23 @@ impl GPIO {
/// TX to pin 14
/// RX to pin 15
pub fn map_pl011_uart(&self) {
let mut r = &self.inner;
r.lock(|inner| {
let mut r = &self.registers;
r.lock(|registers| {
// Map to pins.
inner
registers
.GPFSEL1
.modify(GPFSEL1::FSEL14::AltFunc0 + GPFSEL1::FSEL15::AltFunc0);
// Enable pins 14 and 15.
inner.GPPUD.set(0);
registers.GPPUD.set(0);
cpu::spin_for_cycles(150);
inner
registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
cpu::spin_for_cycles(150);
inner.GPPUDCLK0.set(0);
registers.GPPUDCLK0.set(0);
})
}
}

@ -4,8 +4,11 @@
//! PL011 UART driver.
use crate::{console, cpu, driver, synchronization, synchronization::NullLock};
use core::{fmt, ops};
use crate::{
bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization,
synchronization::NullLock,
};
use core::fmt;
use register::{mmio::*, register_bitfields, register_structs};
//--------------------------------------------------------------------------------------------------
@ -113,10 +116,6 @@ register_bitfields! {
]
}
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
@ -134,8 +133,15 @@ register_structs! {
}
}
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub struct PL011UartInner {
base_addr: usize,
registers: Registers,
chars_written: usize,
chars_read: usize,
}
@ -152,24 +158,6 @@ pub struct PL011Uart {
// Public Code
//--------------------------------------------------------------------------------------------------
/// Deref to RegisterBlock.
///
/// Allows writing
/// ```
/// self.DR.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*PL011UartInner::ptr()).DR.read() }
/// ```
impl ops::Deref for PL011UartInner {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl PL011UartInner {
/// Create an instance.
///
@ -178,7 +166,7 @@ impl PL011UartInner {
/// - The user must ensure to provide the correct `base_addr`.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
registers: Registers::new(base_addr),
chars_written: 0,
chars_read: 0,
}
@ -190,31 +178,28 @@ impl PL011UartInner {
/// firmware).
pub fn init(&mut self) {
// Turn it off temporarily.
self.CR.set(0);
self.registers.CR.set(0);
self.ICR.write(ICR::ALL::CLEAR);
self.IBRD.write(IBRD::IBRD.val(13));
self.FBRD.write(FBRD::FBRD.val(2));
self.LCRH
self.registers.ICR.write(ICR::ALL::CLEAR);
self.registers.IBRD.write(IBRD::IBRD.val(13));
self.registers.FBRD.write(FBRD::FBRD.val(2));
self.registers
.LCRH
.write(LCRH::WLEN::EightBit + LCRH::FEN::FifosEnabled); // 8N1 + Fifo on
self.CR
self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
/// Return a pointer to the register block.
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
/// Send a character.
fn write_char(&mut self, c: char) {
// Spin while TX FIFO full is set, waiting for an empty slot.
while self.FR.matches_all(FR::TXFF::SET) {
while self.registers.FR.matches_all(FR::TXFF::SET) {
cpu::nop();
}
// Write the character to the buffer.
self.DR.set(c as u32);
self.registers.DR.set(c as u32);
self.chars_written += 1;
}
@ -287,7 +272,7 @@ impl console::interface::Write for PL011Uart {
// Spin until TX FIFO empty is set.
let mut r = &self.inner;
r.lock(|inner| {
while !inner.FR.matches_all(FR::TXFE::SET) {
while !inner.registers.FR.matches_all(FR::TXFE::SET) {
cpu::nop();
}
});
@ -299,12 +284,12 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Spin while RX FIFO empty is set.
while inner.FR.matches_all(FR::RXFE::SET) {
while inner.registers.FR.matches_all(FR::RXFE::SET) {
cpu::nop();
}
// Read one character.
let mut ret = inner.DR.get() as u8 as char;
let mut ret = inner.registers.DR.get() as u8 as char;
// Convert carrige return to newline.
if ret == '\r' {
@ -322,8 +307,8 @@ impl console::interface::Read for PL011Uart {
let mut r = &self.inner;
r.lock(|inner| {
// Read from the RX FIFO until it is indicating empty.
while !inner.FR.matches_all(FR::RXFE::SET) {
inner.DR.get();
while !inner.registers.FR.matches_all(FR::RXFE::SET) {
inner.registers.DR.get();
}
})
}

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
//! Common device driver code.
use core::{marker::PhantomData, ops};
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<T>,
}
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
pub const unsafe fn new(base_addr: usize) -> Self {
Self {
base_addr,
phantom: PhantomData,
}
}
/// Return a pointer to the associated MMIO register block.
fn ptr(&self) -> *const T {
self.base_addr as *const _
}
}
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
Loading…
Cancel
Save