feat!: Add shared MMIODerefWrapper instead of per-module ones

This commit is contained in:
Berkus Decker 2021-12-18 23:09:13 +02:00
parent 1e17e03a8d
commit 33dbf79041
7 changed files with 297 additions and 287 deletions

View File

@ -3,6 +3,7 @@
#![feature(decl_macro)] #![feature(decl_macro)]
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(format_args_nl)] #![feature(format_args_nl)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(nonnull_slice_from_raw_parts)] #![feature(nonnull_slice_from_raw_parts)]
#![feature(custom_test_frameworks)] #![feature(custom_test_frameworks)]
#![test_runner(crate::tests::test_runner)] #![test_runner(crate::tests::test_runner)]

View File

@ -2,4 +2,51 @@
* SPDX-License-Identifier: BlueOak-1.0.0 * SPDX-License-Identifier: BlueOak-1.0.0
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems> * Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
*/ */
use core::{marker::PhantomData, ops};
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
pub mod rpi3; pub mod rpi3;
pub struct MMIODerefWrapper<T> {
base_addr: usize,
phantom: PhantomData<fn() -> T>,
}
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
impl<T> MMIODerefWrapper<T> {
/// Create an instance.
///
/// # Safety
///
/// Unsafe, duh!
pub const unsafe fn new(start_addr: usize) -> Self {
Self {
base_addr: start_addr,
phantom: PhantomData,
}
}
}
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.GPPUD.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*GPIO::ptr()).GPPUD.read() }
/// ```
impl<T> ops::Deref for MMIODerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.base_addr as *const _) }
}
}

View File

@ -7,12 +7,12 @@
use { use {
super::BcmHost, super::BcmHost,
crate::arch::loop_delay, crate::{arch::loop_delay, platform::MMIODerefWrapper},
core::{marker::PhantomData, ops}, core::marker::PhantomData,
tock_registers::{ tock_registers::{
fields::FieldValue, fields::FieldValue,
interfaces::{ReadWriteable, Readable, Writeable}, interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly}, registers::{ReadOnly, ReadWrite, WriteOnly},
}, },
}; };
@ -48,102 +48,107 @@ states! {
Uninitialized, Input, Output, Alt Uninitialized, Input, Output, Alt
} }
/// A wrapper type that prevents reads or writes to its value. register_structs! {
/// /// The offsets for each register.
/// This type implements no methods. It is meant to make the inner type /// From <https://wiki.osdev.org/Raspberry_Pi_Bare_Bones> and
/// inaccessible to prevent accidental reads or writes. /// <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
#[repr(C)] #[allow(non_snake_case)]
pub struct Reserved<T>(T); RegisterBlock {
(0x00 => pub FSEL: [ReadWrite<u32>; 6]), // function select
/// The offsets for reach register. (0x18 => __reserved_1),
/// From <https://wiki.osdev.org/Raspberry_Pi_Bare_Bones> and (0x1c => pub SET: [WriteOnly<u32>; 2]), // set output pin
/// <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf> (0x24 => __reserved_2),
#[allow(non_snake_case)] (0x28 => pub CLR: [WriteOnly<u32>; 2]), // clear output pin
#[repr(C)] (0x30 => __reserved_3),
pub struct RegisterBlock { (0x34 => pub LEV: [ReadOnly<u32>; 2]), // get input pin level
pub FSEL: [ReadWrite<u32>; 6], // 0x00-0x14 function select (0x3c => __reserved_4),
__reserved_0: Reserved<u32>, // 0x18 (0x40 => pub EDS: [ReadWrite<u32>; 2]),
pub SET: [WriteOnly<u32>; 2], // 0x1c-0x20 set output pin (0x48 => __reserved_5),
__reserved_1: Reserved<u32>, // 0x24 (0x4c => pub REN: [ReadWrite<u32>; 2]),
pub CLR: [WriteOnly<u32>; 2], // 0x28-0x2c clear output pin (0x54 => __reserved_6),
__reserved_2: Reserved<u32>, // 0x30 (0x58 => pub FEN: [ReadWrite<u32>; 2]),
pub LEV: [ReadOnly<u32>; 2], // 0x34-0x38 get input pin level (0x60 => __reserved_7),
__reserved_3: Reserved<u32>, // 0x3C (0x64 => pub HEN: [ReadWrite<u32>; 2]),
pub EDS: [ReadWrite<u32>; 2], // 0x40-0x44 (0x6c => __reserved_8),
__reserved_4: Reserved<u32>, // 0x48 (0x70 => pub LEN: [ReadWrite<u32>; 2]),
pub REN: [ReadWrite<u32>; 2], // 0x4c-0x50 (0x78 => __reserved_9),
__reserved_5: Reserved<u32>, // 0x54 (0x7c => pub AREN: [ReadWrite<u32>; 2]),
pub FEN: [ReadWrite<u32>; 2], // 0x58-0x5c (0x84 => __reserved_10),
__reserved_6: Reserved<u32>, // 0x60 (0x88 => pub AFEN: [ReadWrite<u32>; 2]),
pub HEN: [ReadWrite<u32>; 2], // 0x64-0x68 (0x90 => __reserved_11),
__reserved_7: Reserved<u32>, // 0x6c (0x94 => pub PUD: ReadWrite<u32>), // pull up down
pub LEN: [ReadWrite<u32>; 2], // 0x70-0x74 (0x98 => pub PUDCLK: [ReadWrite<u32, PUDCLK0::Register>; 2]), // 0x98-0x9C -- TODO: remove this register?
__reserved_8: Reserved<u32>, // 0x78 // (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite<u32, GPIO_PUP_PDN_CNTRL_REG0::Register>), -- ??
pub AREN: [ReadWrite<u32>; 2], // 0x7c-0x80 (0xa0 => __reserved_12),
__reserved_9: Reserved<u32>, // 0x84 (0xE8 => @END),
pub AFEN: [ReadWrite<u32>; 2], // 0x88-0x8c }
__reserved_10: Reserved<u32>, // 0x90
pub PUD: ReadWrite<u32>, // 0x94 pull up down
pub PUDCLK: [ReadWrite<u32, PUDCLK0::Register>; 2], // 0x98-0x9C -- @todo remove this register
} }
// Hide RegisterBlock from public api.
type Registers = MMIODerefWrapper<RegisterBlock>;
/// Public interface to the GPIO MMIO area /// Public interface to the GPIO MMIO area
pub struct GPIO { pub struct GPIO {
base_addr: usize, registers: Registers,
} }
/// Deref to RegisterBlock pub const GPIO_START: usize = 0x20_0000;
///
/// Allows writing
/// ```
/// self.GPPUD.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*GPIO::ptr()).GPPUD.read() }
/// ```
impl ops::Deref for GPIO {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl Default for GPIO { impl Default for GPIO {
fn default() -> GPIO { fn default() -> GPIO {
// Default RPi3 GPIO base address // Default RPi3 GPIO base address
const GPIO_BASE: usize = BcmHost::get_peripheral_address() + 0x20_0000; const GPIO_BASE: usize = BcmHost::get_peripheral_address() + GPIO_START;
GPIO::new(GPIO_BASE) unsafe { GPIO::new(GPIO_BASE) }
} }
} }
impl GPIO { impl GPIO {
pub fn new(base_addr: usize) -> GPIO { /// # Safety
GPIO { base_addr } ///
} /// Unsafe, duh!
pub const unsafe fn new(base_addr: usize) -> GPIO {
/// Returns a pointer to the register block GPIO {
fn ptr(&self) -> *const RegisterBlock { registers: Registers::new(base_addr),
self.base_addr as *const _ }
} }
pub fn get_pin(&self, pin: usize) -> Pin<Uninitialized> { pub fn get_pin(&self, pin: usize) -> Pin<Uninitialized> {
Pin::new(pin, self.base_addr) unsafe { Pin::new(pin, self.registers.base_addr) }
} }
}
pub fn enable_uart_pins(gpio: &GPIO) { pub fn enable_uart_pins(&self) {
gpio.PUD.set(0); self.registers.PUD.set(0);
loop_delay(150); loop_delay(2000);
// enable pins 14 and 15 // enable pins 14 and 15
gpio.PUDCLK[0].write(PUDCLK0::PUDCLK14::AssertClock + PUDCLK0::PUDCLK15::AssertClock); self.registers.PUDCLK[0]
.write(PUDCLK0::PUDCLK14::AssertClock + PUDCLK0::PUDCLK15::AssertClock);
loop_delay(150); loop_delay(2000);
gpio.PUDCLK[0].set(0); self.registers.PUDCLK[0].set(0);
}
pub fn power_off(&self) {
// power off gpio pins (but not VCC pins)
for bank in 0..5 {
self.registers.FSEL[bank].set(0);
}
self.registers.PUD.set(0);
loop_delay(2000);
self.registers.PUDCLK[0].set(0xffff_ffff);
self.registers.PUDCLK[1].set(0xffff_ffff);
loop_delay(2000);
// flush GPIO setup
self.registers.PUDCLK[0].set(0);
self.registers.PUDCLK[1].set(0);
}
} }
/// An alternative GPIO function. /// An alternative GPIO function.
@ -174,7 +179,7 @@ impl ::core::convert::From<Function> for u32 {
/// `into_alt` methods before it can be used. /// `into_alt` methods before it can be used.
pub struct Pin<State> { pub struct Pin<State> {
pin: usize, pin: usize,
base_addr: usize, registers: Registers,
_state: PhantomData<State>, _state: PhantomData<State>,
} }
@ -186,34 +191,10 @@ impl<State> Pin<State> {
fn transition<NewState>(self) -> Pin<NewState> { fn transition<NewState>(self) -> Pin<NewState> {
Pin { Pin {
pin: self.pin, pin: self.pin,
base_addr: self.base_addr, registers: self.registers,
_state: PhantomData, _state: PhantomData,
} }
} }
/// Returns a pointer to the register block
#[inline(always)]
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
}
/// Deref to Pin's Registers
///
/// Allows writing
/// ```
/// self.PUD.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*Pin::ptr()).PUD.read() }
/// ```
impl<State> ops::Deref for Pin<State> {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
} }
impl Pin<Uninitialized> { impl Pin<Uninitialized> {
@ -222,13 +203,13 @@ impl Pin<Uninitialized> {
/// # Panics /// # Panics
/// ///
/// Panics if `pin` > `53`. /// Panics if `pin` > `53`.
fn new(pin: usize, base_addr: usize) -> Pin<Uninitialized> { unsafe fn new(pin: usize, base_addr: usize) -> Pin<Uninitialized> {
if pin > 53 { if pin > 53 {
panic!("gpio::Pin::new(): pin {} exceeds maximum of 53", pin); panic!("gpio::Pin::new(): pin {} exceeds maximum of 53", pin);
} }
Pin { Pin {
base_addr, registers: Registers::new(base_addr),
pin, pin,
_state: PhantomData, _state: PhantomData,
} }
@ -239,7 +220,11 @@ impl Pin<Uninitialized> {
pub fn into_alt(self, function: Function) -> Pin<Alt> { pub fn into_alt(self, function: Function) -> Pin<Alt> {
let bank = self.pin / 10; let bank = self.pin / 10;
let off = self.pin % 10; let off = self.pin % 10;
self.FSEL[bank].modify(FieldValue::<u32, ()>::new(0b111, off * 3, function.into())); self.registers.FSEL[bank].modify(FieldValue::<u32, ()>::new(
0b111,
off * 3,
function.into(),
));
self.transition() self.transition()
} }
@ -262,7 +247,7 @@ impl Pin<Output> {
// Guarantees: pin number is between [0; 53] by construction. // Guarantees: pin number is between [0; 53] by construction.
let bank = self.pin / 32; let bank = self.pin / 32;
let shift = self.pin % 32; let shift = self.pin % 32;
self.SET[bank].set(1 << shift); self.registers.SET[bank].set(1 << shift);
} }
/// Clears (turns off) this pin. /// Clears (turns off) this pin.
@ -270,7 +255,7 @@ impl Pin<Output> {
// Guarantees: pin number is between [0; 53] by construction. // Guarantees: pin number is between [0; 53] by construction.
let bank = self.pin / 32; let bank = self.pin / 32;
let shift = self.pin % 32; let shift = self.pin % 32;
self.CLR[bank].set(1 << shift); self.registers.CLR[bank].set(1 << shift);
} }
} }
@ -283,7 +268,7 @@ impl Pin<Input> {
// Guarantees: pin number is between [0; 53] by construction. // Guarantees: pin number is between [0; 53] by construction.
let bank = self.pin / 32; let bank = self.pin / 32;
let off = self.pin % 32; let off = self.pin % 32;
self.LEV[bank].matches_all(FieldValue::<u32, ()>::new(1, off, 1)) self.registers.LEV[bank].matches_all(FieldValue::<u32, ()>::new(1, off, 1))
} }
} }
@ -294,7 +279,7 @@ mod tests {
#[test_case] #[test_case]
fn test_pin_transitions() { fn test_pin_transitions() {
let mut reg = [0u32; 40]; let mut reg = [0u32; 40];
let gpio = GPIO::new(&mut reg as *mut _ as usize); let gpio = unsafe { GPIO::new(&mut reg as *mut _ as usize) };
let _out = gpio.get_pin(1).into_output(); let _out = gpio.get_pin(1).into_output();
assert_eq!(reg[0], 0b001_000); assert_eq!(reg[0], 0b001_000);
@ -307,7 +292,7 @@ mod tests {
#[test_case] #[test_case]
fn test_pin_outputs() { fn test_pin_outputs() {
let mut reg = [0u32; 40]; let mut reg = [0u32; 40];
let gpio = GPIO::new(&mut reg as *mut _ as usize); let gpio = unsafe { GPIO::new(&mut reg as *mut _ as usize) };
let pin = gpio.get_pin(1); let pin = gpio.get_pin(1);
let mut out = pin.into_output(); let mut out = pin.into_output();
@ -327,7 +312,7 @@ mod tests {
#[test_case] #[test_case]
fn test_pin_inputs() { fn test_pin_inputs() {
let mut reg = [0u32; 40]; let mut reg = [0u32; 40];
let gpio = GPIO::new(&mut reg as *mut _ as usize); let gpio = unsafe { GPIO::new(&mut reg as *mut _ as usize) };
let pin = gpio.get_pin(1); let pin = gpio.get_pin(1);
let inp = pin.into_input(); let inp = pin.into_input();

View File

@ -9,12 +9,12 @@
use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::interfaces::{Readable, Writeable};
use { use {
super::{gpio, BcmHost}, super::{gpio, BcmHost},
crate::devices::ConsoleOps, crate::{devices::ConsoleOps, platform::MMIODerefWrapper},
cfg_if::cfg_if, cfg_if::cfg_if,
core::{convert::From, fmt, ops}, core::{convert::From, fmt},
tock_registers::{ tock_registers::{
interfaces::ReadWriteable, interfaces::ReadWriteable,
register_bitfields, register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly}, registers::{ReadOnly, ReadWrite, WriteOnly},
}, },
}; };
@ -88,33 +88,41 @@ register_bitfields! {
] ]
], ],
/// Mini Uart Baudrate /// Mini Uart Baud rate
AUX_MU_BAUD [ AUX_MU_BAUD [
/// Mini UART baudrate counter /// Mini UART baud rate counter
RATE OFFSET(0) NUMBITS(16) [] RATE OFFSET(0) NUMBITS(16) []
] ]
} }
#[allow(non_snake_case)] register_structs! {
#[repr(C)] #[allow(non_snake_case)]
pub struct RegisterBlock { RegisterBlock {
__reserved_0: u32, // 0x00 - AUX_IRQ? // 0x00 - AUX_IRQ?
AUX_ENABLES: ReadWrite<u32, AUX_ENABLES::Register>, // 0x04 (0x00 => __reserved_1),
__reserved_1: [u32; 14], // 0x08 (0x04 => AUX_ENABLES: ReadWrite<u32, AUX_ENABLES::Register>),
AUX_MU_IO: ReadWrite<u32>, // 0x40 - Mini Uart I/O Data (0x08 => __reserved_2),
AUX_MU_IER: WriteOnly<u32>, // 0x44 - Mini Uart Interrupt Enable (0x40 => AUX_MU_IO: ReadWrite<u32>),//Mini Uart I/O Data
AUX_MU_IIR: WriteOnly<u32, AUX_MU_IIR::Register>, // 0x48 (0x44 => AUX_MU_IER: WriteOnly<u32>),//Mini Uart Interrupt Enable
AUX_MU_LCR: WriteOnly<u32, AUX_MU_LCR::Register>, // 0x4C (0x48 => AUX_MU_IIR: WriteOnly<u32, AUX_MU_IIR::Register>),
AUX_MU_MCR: WriteOnly<u32>, // 0x50 (0x4c => AUX_MU_LCR: WriteOnly<u32, AUX_MU_LCR::Register>),
AUX_MU_LSR: ReadOnly<u32, AUX_MU_LSR::Register>, // 0x54 (0x50 => AUX_MU_MCR: WriteOnly<u32>),
__reserved_2: [u32; 2], // 0x58 - AUX_MU_MSR, AUX_MU_SCRATCH (0x54 => AUX_MU_LSR: ReadOnly<u32, AUX_MU_LSR::Register>),
AUX_MU_CNTL: WriteOnly<u32, AUX_MU_CNTL::Register>, // 0x60 // 0x58 - AUX_MU_MSR
__reserved_3: u32, // 0x64 - AUX_MU_STAT // 0x5c - AUX_MU_SCRATCH
AUX_MU_BAUD: WriteOnly<u32, AUX_MU_BAUD::Register>, // 0x68 (0x58 => __reserved_3),
(0x60 => AUX_MU_CNTL: WriteOnly<u32, AUX_MU_CNTL::Register>),
// 0x64 - AUX_MU_STAT
(0x64 => __reserved_4),
(0x68 => AUX_MU_BAUD: WriteOnly<u32, AUX_MU_BAUD::Register>),
(0x6c => @END),
}
} }
type Registers = MMIODerefWrapper<RegisterBlock>;
pub struct MiniUart { pub struct MiniUart {
base_addr: usize, registers: Registers,
} }
pub struct PreparedMiniUart(MiniUart); pub struct PreparedMiniUart(MiniUart);
@ -130,41 +138,24 @@ impl From<Rate> for u32 {
} }
} }
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.MU_IER.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*MiniUart::ptr()).MU_IER.read() }
/// ```
impl ops::Deref for MiniUart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
// [temporary] Used in mmu.rs to set up local paging // [temporary] Used in mmu.rs to set up local paging
pub const UART1_BASE: usize = BcmHost::get_peripheral_address() + 0x21_5000; pub const UART1_START: usize = 0x21_5000;
impl Default for MiniUart { impl Default for MiniUart {
fn default() -> MiniUart { fn default() -> Self {
MiniUart::new(UART1_BASE) const UART1_BASE: usize = BcmHost::get_peripheral_address() + UART1_START;
unsafe { MiniUart::new(UART1_BASE) }
} }
} }
impl MiniUart { impl MiniUart {
pub fn new(base_addr: usize) -> MiniUart { /// # Safety
MiniUart { base_addr } ///
} /// Unsafe, duh!
pub const unsafe fn new(base_addr: usize) -> MiniUart {
/// Returns a pointer to the register block MiniUart {
fn ptr(&self) -> *const RegisterBlock { registers: Registers::new(base_addr),
self.base_addr as *const _ }
} }
} }
@ -174,14 +165,14 @@ impl MiniUart {
/// Set baud rate and characteristics (115200 8N1) and map to GPIO /// Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn prepare(self, gpio: &gpio::GPIO) -> PreparedMiniUart { pub fn prepare(self, gpio: &gpio::GPIO) -> PreparedMiniUart {
// initialize UART // initialize UART
self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); self.registers.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET);
self.AUX_MU_IER.set(0); self.registers.AUX_MU_IER.set(0);
self.AUX_MU_CNTL.set(0); self.registers.AUX_MU_CNTL.set(0);
self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); self.registers.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit);
self.AUX_MU_MCR.set(0); self.registers.AUX_MU_MCR.set(0);
self.AUX_MU_IER.set(0); self.registers.AUX_MU_IER.set(0);
self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); self.registers.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All);
self.AUX_MU_BAUD self.registers.AUX_MU_BAUD
.write(AUX_MU_BAUD::RATE.val(Rate::Baud115200.into())); .write(AUX_MU_BAUD::RATE.val(Rate::Baud115200.into()));
// Pin 14 // Pin 14
@ -193,13 +184,13 @@ impl MiniUart {
gpio.get_pin(14).into_alt(MINI_UART_TXD); gpio.get_pin(14).into_alt(MINI_UART_TXD);
gpio.get_pin(15).into_alt(MINI_UART_RXD); gpio.get_pin(15).into_alt(MINI_UART_RXD);
gpio::enable_uart_pins(gpio); gpio.enable_uart_pins();
self.AUX_MU_CNTL self.registers.AUX_MU_CNTL
.write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled);
// Clear FIFOs before using the device // Clear FIFOs before using the device
self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); self.registers.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All);
PreparedMiniUart(self) PreparedMiniUart(self)
} }
@ -214,6 +205,7 @@ impl MiniUart {
impl Drop for PreparedMiniUart { impl Drop for PreparedMiniUart {
fn drop(&mut self) { fn drop(&mut self) {
self.0 self.0
.registers
.AUX_ENABLES .AUX_ENABLES
.modify(AUX_ENABLES::MINI_UART_ENABLE::CLEAR); .modify(AUX_ENABLES::MINI_UART_ENABLE::CLEAR);
// @todo disable gpio.PUD ? // @todo disable gpio.PUD ?
@ -226,10 +218,10 @@ impl ConsoleOps for PreparedMiniUart {
/// Send a character /// Send a character
fn putc(&self, c: char) { fn putc(&self, c: char) {
// wait until we can send // wait until we can send
crate::arch::loop_until(|| self.0.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY)); crate::arch::loop_until(|| self.0.registers.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY));
// write the character to the buffer // write the character to the buffer
self.0.AUX_MU_IO.set(c as u32); self.0.registers.AUX_MU_IO.set(c as u32);
} }
/// Display a string /// Display a string
@ -247,10 +239,10 @@ impl ConsoleOps for PreparedMiniUart {
/// Receive a character /// Receive a character
fn getc(&self) -> char { fn getc(&self) -> char {
// wait until something is in the buffer // wait until something is in the buffer
crate::arch::loop_until(|| self.0.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY)); crate::arch::loop_until(|| self.0.registers.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY));
// read it and return // read it and return
let mut ret = self.0.AUX_MU_IO.get() as u8 as char; let mut ret = self.0.registers.AUX_MU_IO.get() as u8 as char;
// convert carriage return to newline // convert carriage return to newline
if ret == '\r' { if ret == '\r' {
@ -263,7 +255,7 @@ impl ConsoleOps for PreparedMiniUart {
/// Wait until the TX FIFO is empty, aka all characters have been put on the /// Wait until the TX FIFO is empty, aka all characters have been put on the
/// line. /// line.
fn flush(&self) { fn flush(&self) {
crate::arch::loop_until(|| self.0.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_IDLE)); crate::arch::loop_until(|| self.0.registers.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_IDLE));
} }
} else { } else {
fn putc(&self, _c: char) {} fn putc(&self, _c: char) {}

View File

@ -14,12 +14,11 @@ use {
mailbox::{self, MailboxOps}, mailbox::{self, MailboxOps},
BcmHost, BcmHost,
}, },
crate::{arch::loop_until, devices::ConsoleOps}, crate::{arch::loop_until, devices::ConsoleOps, platform::MMIODerefWrapper},
core::ops,
snafu::Snafu, snafu::Snafu,
tock_registers::{ tock_registers::{
interfaces::{Readable, Writeable}, interfaces::{Readable, Writeable},
register_bitfields, register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly}, registers::{ReadOnly, ReadWrite, WriteOnly},
}, },
}; };
@ -111,29 +110,31 @@ register_bitfields! {
] ]
} }
#[allow(non_snake_case)] register_structs! {
#[repr(C)] #[allow(non_snake_case)]
pub struct RegisterBlock { RegisterBlock {
DR: ReadWrite<u32>, // 0x00 (0x00 => DR: ReadWrite<u32>),
__reserved_0: [u32; 5], // 0x04 (UART0_RSRECR=0x04) (0x04 => __reserved_1), // (UART0_RSRECR=0x04)
FR: ReadOnly<u32, FR::Register>, // 0x18 (0x18 => FR: ReadOnly<u32, FR::Register>),
__reserved_1: [u32; 1], // 0x1c (0x1c => __reserved_2),
ILPR: u32, // 0x20 (0x20 => ILPR: u32),
IBRD: WriteOnly<u32, IBRD::Register>, // 0x24 (0x24 => IBRD: WriteOnly<u32, IBRD::Register>),
FBRD: WriteOnly<u32, FBRD::Register>, // 0x28 (0x28 => FBRD: WriteOnly<u32, FBRD::Register>),
LCRH: WriteOnly<u32, LCRH::Register>, // 0x2C (0x2c => LCRH: WriteOnly<u32, LCRH::Register>),
CR: WriteOnly<u32, CR::Register>, // 0x30 (0x30 => CR: WriteOnly<u32, CR::Register>),
IFLS: u32, // 0x34 (0x34 => IFLS: u32),
IMSC: u32, // 0x38 (0x38 => IMSC: u32),
RIS: u32, // 0x3C (0x3c => RIS: u32),
MIS: u32, // 0x40 (0x40 => MIS: u32),
ICR: WriteOnly<u32, ICR::Register>, // 0x44 (0x44 => ICR: WriteOnly<u32, ICR::Register>),
DMACR: u32, // 0x48 (0x48 => DMACR: u32),
__reserved_2: [u32; 14], // 0x4c-0x7c (0x4c => __reserved_3),
ITCR: u32, // 0x80 (0x80 => ITCR: u32),
ITIP: u32, // 0x84 (0x84 => ITIP: u32),
ITOP: u32, // 0x88 (0x88 => ITOP: u32),
TDR: u32, // 0x8C (0x8c => TDR: u32),
(0x90 => @END),
}
} }
#[derive(Debug, Snafu)] #[derive(Debug, Snafu)]
@ -141,10 +142,13 @@ pub enum PL011UartError {
#[snafu(display("PL011 UART setup failed in mailbox operation"))] #[snafu(display("PL011 UART setup failed in mailbox operation"))]
MailboxError, MailboxError,
} }
pub type Result<T> = ::core::result::Result<T, PL011UartError>; pub type Result<T> = ::core::result::Result<T, PL011UartError>;
type Registers = MMIODerefWrapper<RegisterBlock>;
pub struct PL011Uart { pub struct PL011Uart {
base_addr: usize, registers: Registers,
} }
pub struct PreparedPL011Uart(PL011Uart); pub struct PreparedPL011Uart(PL011Uart);
@ -160,37 +164,23 @@ impl From<Rate> for u32 {
} }
} }
impl ops::Deref for PL011Uart { pub const UART_START: usize = 0x20_1000;
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl ops::Deref for PreparedPL011Uart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0.ptr() }
}
}
impl Default for PL011Uart { impl Default for PL011Uart {
fn default() -> Self { fn default() -> Self {
const UART0_BASE: usize = BcmHost::get_peripheral_address() + 0x20_1000; const UART0_BASE: usize = BcmHost::get_peripheral_address() + UART_START;
PL011Uart::new(UART0_BASE) unsafe { PL011Uart::new(UART0_BASE) }
} }
} }
impl PL011Uart { impl PL011Uart {
pub fn new(base_addr: usize) -> PL011Uart { /// # Safety
PL011Uart { base_addr } ///
} /// Unsafe, duh!
pub const unsafe fn new(base_addr: usize) -> PL011Uart {
/// Returns a pointer to the register block PL011Uart {
fn ptr(&self) -> *const RegisterBlock { registers: Registers::new(base_addr),
self.base_addr as *const _ }
} }
/// Set baud rate and characteristics (115200 8N1) and map to GPIO /// Set baud rate and characteristics (115200 8N1) and map to GPIO
@ -200,7 +190,7 @@ impl PL011Uart {
gpio: &gpio::GPIO, gpio: &gpio::GPIO,
) -> Result<PreparedPL011Uart> { ) -> Result<PreparedPL011Uart> {
// turn off UART0 // turn off UART0
self.CR.set(0); self.registers.CR.set(0);
// set up clock for consistent divisor values // set up clock for consistent divisor values
let index = mbox.request(); let index = mbox.request();
@ -220,15 +210,18 @@ impl PL011Uart {
gpio.get_pin(14).into_alt(UART_TXD); gpio.get_pin(14).into_alt(UART_TXD);
gpio.get_pin(15).into_alt(UART_RXD); gpio.get_pin(15).into_alt(UART_RXD);
gpio::enable_uart_pins(gpio); gpio.enable_uart_pins();
self.ICR.write(ICR::ALL::CLEAR); self.registers.ICR.write(ICR::ALL::CLEAR);
// @todo Configure divisors more sanely // @todo Configure divisors more sanely
self.IBRD.write(IBRD::IBRD.val(Rate::Baud115200.into())); self.registers
self.FBRD.write(FBRD::FBRD.val(0xB)); // Results in 115200 baud .IBRD
self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 .write(IBRD::IBRD.val(Rate::Baud115200.into()));
self.registers.FBRD.write(FBRD::FBRD.val(0xB)); // Results in 115200 baud
self.registers.LCRH.write(LCRH::WLEN::EightBit); // 8N1
self.CR self.registers
.CR
.write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
Ok(PreparedPL011Uart(self)) Ok(PreparedPL011Uart(self))
@ -237,7 +230,9 @@ impl PL011Uart {
impl Drop for PreparedPL011Uart { impl Drop for PreparedPL011Uart {
fn drop(&mut self) { fn drop(&mut self) {
self.CR self.0
.registers
.CR
.write(CR::UARTEN::Disabled + CR::TXE::Disabled + CR::RXE::Disabled); .write(CR::UARTEN::Disabled + CR::TXE::Disabled + CR::RXE::Disabled);
} }
} }
@ -246,10 +241,10 @@ impl ConsoleOps for PreparedPL011Uart {
/// Send a character /// Send a character
fn putc(&self, c: char) { fn putc(&self, c: char) {
// wait until we can send // wait until we can send
loop_until(|| !self.FR.is_set(FR::TXFF)); loop_until(|| !self.0.registers.FR.is_set(FR::TXFF));
// write the character to the buffer // write the character to the buffer
self.DR.set(c as u32); self.0.registers.DR.set(c as u32);
} }
/// Display a string /// Display a string
@ -267,10 +262,10 @@ impl ConsoleOps for PreparedPL011Uart {
/// Receive a character /// Receive a character
fn getc(&self) -> char { fn getc(&self) -> char {
// wait until something is in the buffer // wait until something is in the buffer
loop_until(|| !self.FR.is_set(FR::RXFE)); loop_until(|| !self.0.registers.FR.is_set(FR::RXFE));
// read it and return // read it and return
let mut ret = self.DR.get() as u8 as char; let mut ret = self.0.registers.DR.get() as u8 as char;
// convert carriage return to newline // convert carriage return to newline
if ret == '\r' { if ret == '\r' {

View File

@ -11,23 +11,24 @@ use {
mailbox::{channel, Mailbox, MailboxOps}, mailbox::{channel, Mailbox, MailboxOps},
BcmHost, BcmHost,
}, },
crate::arch::loop_delay, crate::platform::MMIODerefWrapper,
core::ops,
snafu::Snafu, snafu::Snafu,
tock_registers::{ tock_registers::{
interfaces::{Readable, Writeable}, interfaces::{Readable, Writeable},
register_structs,
registers::ReadWrite, registers::ReadWrite,
}, },
}; };
const POWER_BASE: usize = BcmHost::get_peripheral_address() + 0x0010_001C; register_structs! {
#[allow(non_snake_case)]
#[allow(non_snake_case)] RegisterBlock {
#[repr(C)] (0x00 => __reserved_1),
pub struct RegisterBlock { (0x1c => PM_RSTC: ReadWrite<u32>),
PM_RSTC: ReadWrite<u32>, // 0x1C (0x20 => PM_RSTS: ReadWrite<u32>),
PM_RSTS: ReadWrite<u32>, // 0x20 (0x24 => PM_WDOG: ReadWrite<u32>),
PM_WDOG: ReadWrite<u32>, // 0x24 (0x28 => @END),
}
} }
const PM_PASSWORD: u32 = 0x5a00_0000; const PM_PASSWORD: u32 = 0x5a00_0000;
@ -50,28 +51,33 @@ pub enum PowerError {
#[snafu(display("Power setup failed in mailbox operation"))] #[snafu(display("Power setup failed in mailbox operation"))]
MailboxError, MailboxError,
} }
pub type Result<T> = ::core::result::Result<T, PowerError>; pub type Result<T> = ::core::result::Result<T, PowerError>;
type Registers = MMIODerefWrapper<RegisterBlock>;
const POWER_START: usize = 0x0010_0000;
/// Public interface to the Power subsystem /// Public interface to the Power subsystem
pub struct Power; pub struct Power {
registers: Registers,
}
impl ops::Deref for Power { impl Default for Power {
type Target = RegisterBlock; fn default() -> Power {
const POWER_BASE: usize = BcmHost::get_peripheral_address() + POWER_START;
fn deref(&self) -> &Self::Target { unsafe { Power::new(POWER_BASE) }
unsafe { &*Self::ptr() }
} }
} }
impl Power { impl Power {
#[allow(clippy::new_without_default)] /// # Safety
pub fn new() -> Power { ///
Power /// Unsafe, duh!
} pub const unsafe fn new(base_addr: usize) -> Power {
Power {
/// Returns a pointer to the register block registers: Registers::new(base_addr),
fn ptr() -> *const RegisterBlock { }
POWER_BASE as *const _
} }
/// Shutdown the board /// Shutdown the board
@ -88,30 +94,14 @@ impl Power {
.map_err(|_| PowerError::MailboxError)?; .map_err(|_| PowerError::MailboxError)?;
} }
// power off gpio pins (but not VCC pins) gpio.power_off();
for bank in 0..5 {
gpio.FSEL[bank].set(0);
}
gpio.PUD.set(0);
loop_delay(150);
gpio.PUDCLK[0].set(0xffff_ffff);
gpio.PUDCLK[1].set(0xffff_ffff);
loop_delay(150);
// flush GPIO setup
gpio.PUDCLK[0].set(0);
gpio.PUDCLK[1].set(0);
// We set the watchdog hard reset bit here to distinguish this // We set the watchdog hard reset bit here to distinguish this
// reset from the normal (full) reset. bootcode.bin will not // reset from the normal (full) reset. bootcode.bin will not
// reboot after a hard reset. // reboot after a hard reset.
let mut val = self.PM_RSTS.get(); let mut val = self.registers.PM_RSTS.get();
val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT; val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT;
self.PM_RSTS.set(val); self.registers.PM_RSTS.set(val);
// Continue with normal reset mechanism // Continue with normal reset mechanism
self.reset(); self.reset();
@ -120,11 +110,11 @@ impl Power {
/// Reboot /// Reboot
pub fn reset(&self) -> ! { pub fn reset(&self) -> ! {
// use a timeout of 10 ticks (~150us) // use a timeout of 10 ticks (~150us)
self.PM_WDOG.set(PM_PASSWORD | 10); self.registers.PM_WDOG.set(PM_PASSWORD | 10);
let mut val = self.PM_RSTC.get(); let mut val = self.registers.PM_RSTC.get();
val &= PM_RSTC_WRCFG_CLR; val &= PM_RSTC_WRCFG_CLR;
val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
self.PM_RSTC.set(val); self.registers.PM_RSTC.set(val);
crate::endless_sleep() crate::endless_sleep()
} }

View File

@ -192,7 +192,7 @@ fn reboot() -> ! {
use machine::platform::rpi3::power::Power; use machine::platform::rpi3::power::Power;
println!("Bye, going to reset now"); println!("Bye, going to reset now");
Power::new().reset() Power::default().reset()
} }
} }
} }