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(allocator_api)]
#![feature(format_args_nl)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(custom_test_frameworks)]
#![test_runner(crate::tests::test_runner)]

View File

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

View File

@ -9,12 +9,12 @@
use tock_registers::interfaces::{Readable, Writeable};
use {
super::{gpio, BcmHost},
crate::devices::ConsoleOps,
crate::{devices::ConsoleOps, platform::MMIODerefWrapper},
cfg_if::cfg_if,
core::{convert::From, fmt, ops},
core::{convert::From, fmt},
tock_registers::{
interfaces::ReadWriteable,
register_bitfields,
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
},
};
@ -88,33 +88,41 @@ register_bitfields! {
]
],
/// Mini Uart Baudrate
/// Mini Uart Baud rate
AUX_MU_BAUD [
/// Mini UART baudrate counter
/// Mini UART baud rate counter
RATE OFFSET(0) NUMBITS(16) []
]
}
#[allow(non_snake_case)]
#[repr(C)]
pub struct RegisterBlock {
__reserved_0: u32, // 0x00 - AUX_IRQ?
AUX_ENABLES: ReadWrite<u32, AUX_ENABLES::Register>, // 0x04
__reserved_1: [u32; 14], // 0x08
AUX_MU_IO: ReadWrite<u32>, // 0x40 - Mini Uart I/O Data
AUX_MU_IER: WriteOnly<u32>, // 0x44 - Mini Uart Interrupt Enable
AUX_MU_IIR: WriteOnly<u32, AUX_MU_IIR::Register>, // 0x48
AUX_MU_LCR: WriteOnly<u32, AUX_MU_LCR::Register>, // 0x4C
AUX_MU_MCR: WriteOnly<u32>, // 0x50
AUX_MU_LSR: ReadOnly<u32, AUX_MU_LSR::Register>, // 0x54
__reserved_2: [u32; 2], // 0x58 - AUX_MU_MSR, AUX_MU_SCRATCH
AUX_MU_CNTL: WriteOnly<u32, AUX_MU_CNTL::Register>, // 0x60
__reserved_3: u32, // 0x64 - AUX_MU_STAT
AUX_MU_BAUD: WriteOnly<u32, AUX_MU_BAUD::Register>, // 0x68
register_structs! {
#[allow(non_snake_case)]
RegisterBlock {
// 0x00 - AUX_IRQ?
(0x00 => __reserved_1),
(0x04 => AUX_ENABLES: ReadWrite<u32, AUX_ENABLES::Register>),
(0x08 => __reserved_2),
(0x40 => AUX_MU_IO: ReadWrite<u32>),//Mini Uart I/O Data
(0x44 => AUX_MU_IER: WriteOnly<u32>),//Mini Uart Interrupt Enable
(0x48 => AUX_MU_IIR: WriteOnly<u32, AUX_MU_IIR::Register>),
(0x4c => AUX_MU_LCR: WriteOnly<u32, AUX_MU_LCR::Register>),
(0x50 => AUX_MU_MCR: WriteOnly<u32>),
(0x54 => AUX_MU_LSR: ReadOnly<u32, AUX_MU_LSR::Register>),
// 0x58 - AUX_MU_MSR
// 0x5c - AUX_MU_SCRATCH
(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 {
base_addr: usize,
registers: Registers,
}
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
pub const UART1_BASE: usize = BcmHost::get_peripheral_address() + 0x21_5000;
pub const UART1_START: usize = 0x21_5000;
impl Default for MiniUart {
fn default() -> MiniUart {
MiniUart::new(UART1_BASE)
fn default() -> Self {
const UART1_BASE: usize = BcmHost::get_peripheral_address() + UART1_START;
unsafe { MiniUart::new(UART1_BASE) }
}
}
impl MiniUart {
pub fn new(base_addr: usize) -> MiniUart {
MiniUart { base_addr }
}
/// Returns a pointer to the register block
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
/// # Safety
///
/// Unsafe, duh!
pub const unsafe fn new(base_addr: usize) -> MiniUart {
MiniUart {
registers: Registers::new(base_addr),
}
}
}
@ -174,14 +165,14 @@ impl MiniUart {
/// Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn prepare(self, gpio: &gpio::GPIO) -> PreparedMiniUart {
// initialize UART
self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET);
self.AUX_MU_IER.set(0);
self.AUX_MU_CNTL.set(0);
self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit);
self.AUX_MU_MCR.set(0);
self.AUX_MU_IER.set(0);
self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All);
self.AUX_MU_BAUD
self.registers.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET);
self.registers.AUX_MU_IER.set(0);
self.registers.AUX_MU_CNTL.set(0);
self.registers.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit);
self.registers.AUX_MU_MCR.set(0);
self.registers.AUX_MU_IER.set(0);
self.registers.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All);
self.registers.AUX_MU_BAUD
.write(AUX_MU_BAUD::RATE.val(Rate::Baud115200.into()));
// Pin 14
@ -193,13 +184,13 @@ impl MiniUart {
gpio.get_pin(14).into_alt(MINI_UART_TXD);
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);
// 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)
}
@ -214,6 +205,7 @@ impl MiniUart {
impl Drop for PreparedMiniUart {
fn drop(&mut self) {
self.0
.registers
.AUX_ENABLES
.modify(AUX_ENABLES::MINI_UART_ENABLE::CLEAR);
// @todo disable gpio.PUD ?
@ -226,10 +218,10 @@ impl ConsoleOps for PreparedMiniUart {
/// Send a character
fn putc(&self, c: char) {
// 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
self.0.AUX_MU_IO.set(c as u32);
self.0.registers.AUX_MU_IO.set(c as u32);
}
/// Display a string
@ -247,10 +239,10 @@ impl ConsoleOps for PreparedMiniUart {
/// Receive a character
fn getc(&self) -> char {
// 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
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
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
/// line.
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 {
fn putc(&self, _c: char) {}

View File

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

View File

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

View File

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