diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 4d30c40..5743117 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -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)] diff --git a/machine/src/platform/mod.rs b/machine/src/platform/mod.rs index 5926078..dfd3731 100644 --- a/machine/src/platform/mod.rs +++ b/machine/src/platform/mod.rs @@ -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 _) } + } +} diff --git a/machine/src/platform/rpi3/gpio.rs b/machine/src/platform/rpi3/gpio.rs index 3fc0625..656a14e 100644 --- a/machine/src/platform/rpi3/gpio.rs +++ b/machine/src/platform/rpi3/gpio.rs @@ -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(); diff --git a/machine/src/platform/rpi3/mini_uart.rs b/machine/src/platform/rpi3/mini_uart.rs index b47097b..c59a42e 100644 --- a/machine/src/platform/rpi3/mini_uart.rs +++ b/machine/src/platform/rpi3/mini_uart.rs @@ -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) {} diff --git a/machine/src/platform/rpi3/pl011_uart.rs b/machine/src/platform/rpi3/pl011_uart.rs index 557c3cb..cd1e04c 100644 --- a/machine/src/platform/rpi3/pl011_uart.rs +++ b/machine/src/platform/rpi3/pl011_uart.rs @@ -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' { diff --git a/machine/src/platform/rpi3/power.rs b/machine/src/platform/rpi3/power.rs index 279b901..4d0d3b9 100644 --- a/machine/src/platform/rpi3/power.rs +++ b/machine/src/platform/rpi3/power.rs @@ -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() } diff --git a/nucleus/src/main.rs b/nucleus/src/main.rs index 8a60006..7f651ef 100644 --- a/nucleus/src/main.rs +++ b/nucleus/src/main.rs @@ -192,7 +192,7 @@ fn reboot() -> ! { use machine::platform::rpi3::power::Power; println!("Bye, going to reset now"); - Power::new().reset() + Power::default().reset() } } }