From 3a0b67640201e93414bcebaa1a62456f34d22a56 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Sun, 12 Jul 2020 12:44:03 +0200 Subject: [PATCH] Use MMIODerefWrapper everywhere --- 06_drivers_gpio_uart/README.md | 164 +++++----- 06_drivers_gpio_uart/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 67 ++--- .../src/bsp/device_driver/common.rs | 35 +++ 07_uart_chainloader/README.md | 14 +- 07_uart_chainloader/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- .../src/bsp/device_driver/common.rs | 35 +++ 08_timestamps/README.md | 6 +- 08_timestamps/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- 08_timestamps/src/bsp/device_driver/common.rs | 35 +++ 09_hw_debug_JTAG/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- .../src/bsp/device_driver/common.rs | 35 +++ 10_privilege_level/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- .../src/bsp/device_driver/common.rs | 35 +++ 11_virtual_memory/README.md | 20 -- 11_virtual_memory/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 75 ++--- .../src/bsp/device_driver/common.rs | 35 +++ 12_exceptions_part1_groundwork/README.md | 20 -- .../src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- .../src/bsp/device_driver/common.rs | 35 +++ .../src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- .../src/bsp/device_driver/common.rs | 35 +++ 14_exceptions_part2_peripheral_IRQs/README.md | 282 ++++++------------ .../src/bsp/device_driver/arm/gicv2/gicc.rs | 41 +-- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 24 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 18 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 95 +++--- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 7096 -> 7096 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7080 -> 7080 bytes X1_JTAG_boot/src/bsp/device_driver.rs | 1 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 50 +--- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 73 ++--- X1_JTAG_boot/src/bsp/device_driver/common.rs | 35 +++ 49 files changed, 986 insertions(+), 1143 deletions(-) create mode 100644 06_drivers_gpio_uart/src/bsp/device_driver/common.rs create mode 100644 07_uart_chainloader/src/bsp/device_driver/common.rs create mode 100644 08_timestamps/src/bsp/device_driver/common.rs create mode 100644 09_hw_debug_JTAG/src/bsp/device_driver/common.rs create mode 100644 10_privilege_level/src/bsp/device_driver/common.rs create mode 100644 11_virtual_memory/src/bsp/device_driver/common.rs create mode 100644 12_exceptions_part1_groundwork/src/bsp/device_driver/common.rs create mode 100644 13_integrated_testing/src/bsp/device_driver/common.rs create mode 100644 X1_JTAG_boot/src/bsp/device_driver/common.rs diff --git a/06_drivers_gpio_uart/README.md b/06_drivers_gpio_uart/README.md index e7ce37da..56726716 100644 --- a/06_drivers_gpio_uart/README.md +++ b/06_drivers_gpio_uart/README.md @@ -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 + +//! 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; + +//-------------------------------------------------------------------------------------------------- +// 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, -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// 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, +} + +//-------------------------------------------------------------------------------------------------- @@ -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 + +//! 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; ++ ++//-------------------------------------------------------------------------------------------------- ++// 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 ++ ++//! Common device driver code. ++ ++use core::{marker::PhantomData, ops}; ++ ++pub struct MMIODerefWrapper { ++ base_addr: usize, ++ phantom: PhantomData, ++} ++ ++impl MMIODerefWrapper { ++ /// 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 ops::Deref for MMIODerefWrapper { ++ 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 @@ -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::*; diff --git a/06_drivers_gpio_uart/src/bsp/device_driver.rs b/06_drivers_gpio_uart/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/06_drivers_gpio_uart/src/bsp/device_driver.rs +++ b/06_drivers_gpio_uart/src/bsp/device_driver.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::*; diff --git a/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 60dfb62f..efd4125c 100644 --- a/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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' { diff --git a/06_drivers_gpio_uart/src/bsp/device_driver/common.rs b/06_drivers_gpio_uart/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/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 + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/07_uart_chainloader/README.md b/07_uart_chainloader/README.md index cbe2a7af..f5af6405 100644 --- a/07_uart_chainloader/README.md +++ b/07_uart_chainloader/README.md @@ -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(); + } }) } diff --git a/07_uart_chainloader/src/bsp/device_driver.rs b/07_uart_chainloader/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/07_uart_chainloader/src/bsp/device_driver.rs +++ b/07_uart_chainloader/src/bsp/device_driver.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::*; diff --git a/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 223abc5c..cae5cf09 100644 --- a/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/07_uart_chainloader/src/bsp/device_driver/common.rs b/07_uart_chainloader/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/07_uart_chainloader/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/08_timestamps/README.md b/08_timestamps/README.md index c3474fea..8421db63 100644 --- a/08_timestamps/README.md +++ b/08_timestamps/README.md @@ -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 }) } diff --git a/08_timestamps/src/bsp/device_driver.rs b/08_timestamps/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/08_timestamps/src/bsp/device_driver.rs +++ b/08_timestamps/src/bsp/device_driver.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::*; diff --git a/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b15ba818..20efe3a3 100644 --- a/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/08_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/08_timestamps/src/bsp/device_driver/common.rs b/08_timestamps/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/08_timestamps/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/09_hw_debug_JTAG/src/bsp/device_driver.rs b/09_hw_debug_JTAG/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/09_hw_debug_JTAG/src/bsp/device_driver.rs +++ b/09_hw_debug_JTAG/src/bsp/device_driver.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::*; diff --git a/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b15ba818..20efe3a3 100644 --- a/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/09_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/09_hw_debug_JTAG/src/bsp/device_driver/common.rs b/09_hw_debug_JTAG/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/09_hw_debug_JTAG/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/10_privilege_level/src/bsp/device_driver.rs b/10_privilege_level/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/10_privilege_level/src/bsp/device_driver.rs +++ b/10_privilege_level/src/bsp/device_driver.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::*; diff --git a/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b15ba818..20efe3a3 100644 --- a/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/10_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/10_privilege_level/src/bsp/device_driver/common.rs b/10_privilege_level/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/10_privilege_level/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/11_virtual_memory/README.md b/11_virtual_memory/README.md index 81b6e069..873d959b 100644 --- a/11_virtual_memory/README.md +++ b/11_virtual_memory/README.md @@ -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), -@@ -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 diff --git a/11_virtual_memory/src/bsp/device_driver.rs b/11_virtual_memory/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/11_virtual_memory/src/bsp/device_driver.rs +++ b/11_virtual_memory/src/bsp/device_driver.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::*; diff --git a/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 714e293e..20efe3a3 100644 --- a/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/11_virtual_memory/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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), @@ -135,9 +133,15 @@ register_structs! { } } -#[allow(missing_docs)] +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/11_virtual_memory/src/bsp/device_driver/common.rs b/11_virtual_memory/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/11_virtual_memory/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/12_exceptions_part1_groundwork/README.md b/12_exceptions_part1_groundwork/README.md index 7f4ebdcb..abe6d1c4 100644 --- a/12_exceptions_part1_groundwork/README.md +++ b/12_exceptions_part1_groundwork/README.md @@ -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), -@@ -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 diff --git a/12_exceptions_part1_groundwork/src/bsp/device_driver.rs b/12_exceptions_part1_groundwork/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/12_exceptions_part1_groundwork/src/bsp/device_driver.rs +++ b/12_exceptions_part1_groundwork/src/bsp/device_driver.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::*; diff --git a/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b15ba818..20efe3a3 100644 --- a/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/12_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/12_exceptions_part1_groundwork/src/bsp/device_driver/common.rs b/12_exceptions_part1_groundwork/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/12_exceptions_part1_groundwork/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/13_integrated_testing/src/bsp/device_driver.rs b/13_integrated_testing/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/13_integrated_testing/src/bsp/device_driver.rs +++ b/13_integrated_testing/src/bsp/device_driver.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::*; diff --git a/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b15ba818..20efe3a3 100644 --- a/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/13_integrated_testing/src/bsp/device_driver/common.rs b/13_integrated_testing/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/13_integrated_testing/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +} diff --git a/14_exceptions_part2_peripheral_IRQs/README.md b/14_exceptions_part2_peripheral_IRQs/README.md index 04715171..f26aeb22 100644 --- a/14_exceptions_part2_peripheral_IRQs/README.md +++ b/14_exceptions_part2_peripheral_IRQs/README.md @@ -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 + +//! 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; ++ ++//-------------------------------------------------------------------------------------------------- ++// 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; ++type SharedRegisters = MMIODerefWrapper; + +/// Abstraction for the banked parts of the associated MMIO registers. -+type BankedRegs = MMIODerefWrapper; ++type BankedRegisters = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// 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, ++ shared_registers: IRQSafeNullLock, + + /// 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 = ®s.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; - - //-------------------------------------------------------------------------------------------------- - // Public Definitions -@@ -80,30 +81,7 @@ +@@ -81,7 +81,7 @@ /// Representation of the GPIO HW. pub struct GPIO { -- inner: NullLock, --} -- --//-------------------------------------------------------------------------------------------------- --// 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, +- registers: NullLock, ++ registers: IRQSafeNullLock, } //-------------------------------------------------------------------------------------------------- -@@ -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; ++type WriteOnlyRegisters = MMIODerefWrapper; + +/// Abstraction for the ReadOnly parts of the associated MMIO registers. -+type ReadOnlyRegs = MMIODerefWrapper; ++type ReadOnlyRegisters = MMIODerefWrapper; + +type HandlerTable = + [Option; 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, ++ wo_registers: IRQSafeNullLock, + + /// 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, @@ -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 { + ®s.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), (0x2c => LCRH: WriteOnly), (0x30 => CR: WriteOnly), @@ -1931,7 +1870,20 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs (0x44 => ICR: WriteOnly), (0x48 => @END), } -@@ -145,7 +198,8 @@ +@@ -136,6 +181,12 @@ + /// Abstraction for the associated MMIO registers. + type Registers = MMIODerefWrapper; + ++#[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 { + // 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 -+ -+//! Common device driver code. -+ -+use core::{marker::PhantomData, ops}; -+ -+pub struct MMIODerefWrapper { -+ base_addr: usize, -+ phantom: PhantomData, -+} -+ -+impl MMIODerefWrapper { -+ /// 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 ops::Deref for MMIODerefWrapper { -+ 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::*; diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs index eaa60363..26c9f0b5 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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)); } } diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs index 25a6bdda..d2b6099f 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -64,10 +64,10 @@ register_structs! { } /// Abstraction for the non-banked parts of the associated MMIO registers. -type SharedRegs = MMIODerefWrapper; +type SharedRegisters = MMIODerefWrapper; /// Abstraction for the banked parts of the associated MMIO registers. -type BankedRegs = MMIODerefWrapper; +type BankedRegisters = MMIODerefWrapper; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -76,17 +76,17 @@ type BankedRegs = MMIODerefWrapper; /// Representation of the GIC Distributor. pub struct GICD { /// Access to shared registers is guarded with a lock. - shared_regs: IRQSafeNullLock, + shared_registers: IRQSafeNullLock, /// 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 = ®s.ISENABLER[enable_reg_index_shared]; enable_reg.set(enable_reg.get() | enable_bit); diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0e7384f3..b3301f8d 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -73,7 +73,7 @@ register_structs! { } /// Abstraction for the associated MMIO registers. -type Regs = MMIODerefWrapper; +type Registers = MMIODerefWrapper; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -81,7 +81,7 @@ type Regs = MMIODerefWrapper; /// Representation of the GPIO HW. pub struct GPIO { - inner: IRQSafeNullLock, + registers: IRQSafeNullLock, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index bd640216..851070bf 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -37,10 +37,10 @@ register_structs! { } /// Abstraction for the WriteOnly parts of the associated MMIO registers. -type WriteOnlyRegs = MMIODerefWrapper; +type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. -type ReadOnlyRegs = MMIODerefWrapper; +type ReadOnlyRegisters = MMIODerefWrapper; type HandlerTable = [Option; 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, + wo_registers: IRQSafeNullLock, /// 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, @@ -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 { ®s.ENABLE_1 diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 81d01643..b9889a85 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +#[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 { // 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) { diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index dc756ac7b827a0c3a074849e24ff06d5afc4caf9..59cba18d0198ceb0542ffba34ebb11a292f9770e 100755 GIT binary patch delta 256 zcmdmCzQcTi3}e(r*&EDE6J;iUXLe*fxY?4$fKmE@+{EMt`H6|F4M8mq3KJhOGfwPd zV3?x7pm1e!0=tf3_5c6VL7W53@z)p_7&b66HUu#&P?!kfKVX*E0?{D+|1jglf5r?y zyC$z?m0&8AnS7izmvPZ#Q?_Qt#>qR`)D<$R59W3cCm+qtE7*9PIp)4I~U0cT7%{P?^jt!7a)l!2z_Nfq@51GB5}MY2C?d g#jP2y0M-0ww3wVIDK5B&6{6}4l(yL1DXGr{0GJs}ng9R* delta 231 zcmdmCzQcTi4CBR(vNxES4oXk{&g{szWwRxV0i(+UxrxaOPwHUzaKC`^3B%s8=+ zfnkaQgTfUC28Iocj155y2jnImV2;1`fLUG(M8oj^!;BaI88iHxKKUW51k*z4$-h~1 z8P`wFWNT*ZoBWndo!1m@ki*Zy$%^d4j4vjevd2$uVb$Sa`Tu`9$db)d*hLr_?KiLF zVCUy>a`shl5AgJ#yg}T6an9t2;`)pnlLaNj!Tbf26D9sLvP@2t6c=n^HUKH<6ivVMDTm{6rQY-NK+S@ewoQ z#6;GHpk4-sDGCe-bmw|34kXIlvr$jRB~TAwgjxBV$7li2s0DUJFEn@c+Y% z7ylVE{Okm3Uckbz# IN>Yyr09p)F&j0`b delta 268 zcmZ2szQTNh4CA?tvKN?{8l@+{XSQYBvRRi!htX$&+(c#uh7HLH@)KErbc=$*#7E4G z6BAh*f_fPkrYJBdTwwr;Gc?FeWMpgzI=~!%?E$mA7Kn!7|A!eb{xfFyIc@SyRvD&) z(v!clW-_juoXFP9*gN?to4TwC)F7b2t2kI3Rz6_nSoMmDL4<+9;b+cdP4@W7HLN-u zEdT#c2U)kdgI$D?(P8sk4rYE1Cud&;_W)1-$qU2{7^h6WD6Y@=V=|+JIG8_Ua-hV2 etsiV0Ko>GFKu82#!wM1Ufzm(NHdjgNF#!Pfz)#lz diff --git a/X1_JTAG_boot/src/bsp/device_driver.rs b/X1_JTAG_boot/src/bsp/device_driver.rs index 4508e953..ce7396f2 100644 --- a/X1_JTAG_boot/src/bsp/device_driver.rs +++ b/X1_JTAG_boot/src/bsp/device_driver.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::*; diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0c17f498..e448392a 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -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; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -80,30 +81,7 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// 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, } //-------------------------------------------------------------------------------------------------- @@ -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); }) } } diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b15ba818..20efe3a3 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -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; + +//-------------------------------------------------------------------------------------------------- +// 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(); } }) } diff --git a/X1_JTAG_boot/src/bsp/device_driver/common.rs b/X1_JTAG_boot/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..8a83399a --- /dev/null +++ b/X1_JTAG_boot/src/bsp/device_driver/common.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +pub struct MMIODerefWrapper { + base_addr: usize, + phantom: PhantomData, +} + +impl MMIODerefWrapper { + /// 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 ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr() } + } +}