feat!: ✨ Add shared MMIODerefWrapper instead of per-module ones
This commit is contained in:
parent
1e17e03a8d
commit
33dbf79041
|
@ -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)]
|
||||
|
|
|
@ -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 _) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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' {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ fn reboot() -> ! {
|
|||
use machine::platform::rpi3::power::Power;
|
||||
|
||||
println!("Bye, going to reset now");
|
||||
Power::new().reset()
|
||||
Power::default().reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue