[sq] add console

This commit is contained in:
Berkus Decker 2019-02-23 23:03:21 +02:00
parent 12b01105f4
commit 58be472573
8 changed files with 589 additions and 219 deletions

View File

@ -2,6 +2,7 @@
# MIT License # MIT License
# #
# Copyright (c) 2018 Andre Richter <andre.o.richter@gmail.com> # Copyright (c) 2018 Andre Richter <andre.o.richter@gmail.com>
# Copyright (c) 2019 Berkus Decker <berkus+github@metta.systems>
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
@ -44,14 +45,14 @@ QEMU = /usr/local/Cellar/qemu/HEAD-3365de01b5-custom/bin/qemu-system-aarch64
all: kernel8.img all: kernel8.img
target/$(TARGET)/release/vesper: $(SOURCES) target/$(TARGET)/release/vesper: $(SOURCES)
cargo xbuild --target=$(TARGET_JSON) --release --features "noserial" cargo xbuild --target=$(TARGET_JSON) --release
kernel8.img: target/$(TARGET)/release/vesper $(SOURCES) kernel8.img: target/$(TARGET)/release/vesper $(SOURCES)
cp $< ./kernel8 cp $< ./kernel8
$(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img
docker_qemu: all docker_qemu: all
$(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) $(QEMU_OPTS) -kernel kernel8.img $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) $(QEMU_OPTS) -serial stdio -kernel kernel8.img
qemu: all qemu: all
$(QEMU) $(QEMU_OPTS) $(QEMU_SERIAL) -kernel kernel8.img $(QEMU) $(QEMU_OPTS) $(QEMU_SERIAL) -kernel kernel8.img

View File

@ -7,6 +7,7 @@
#![feature(lang_items)] #![feature(lang_items)]
#![feature(ptr_internals)] // until we mark with PhantomData instead? #![feature(ptr_internals)] // until we mark with PhantomData instead?
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(try_from)]
#![doc(html_root_url = "https://docs.metta.systems/")] #![doc(html_root_url = "https://docs.metta.systems/")]
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_assignments)] #![allow(unused_assignments)]
@ -27,14 +28,17 @@ extern crate rlibc;
#[macro_use] #[macro_use]
pub mod arch; pub mod arch;
pub use arch::*; pub use arch::*;
mod devices;
pub mod macros; pub mod macros;
pub use macros::*; pub use macros::*;
pub mod platform; pub mod platform;
mod sync;
mod write_to; mod write_to;
// use core::fmt::Write; // use core::fmt::Write;
use platform::{ use platform::{
display::{Color, Size2d}, display::{Color, Size2d},
gpio::GPIO,
// uart::MiniUart, // uart::MiniUart,
vc::VC, vc::VC,
}; };

View File

@ -1,8 +1,7 @@
use crate::arch::*; use crate::{
use crate::platform::{ arch::*,
display::Size2d, platform::{display::Size2d, rpi3::BcmHost},
rpi3::BcmHost, println,
// uart::MiniUart,
}; };
use core::ops::Deref; use core::ops::Deref;
use register::mmio::*; use register::mmio::*;
@ -115,6 +114,7 @@ pub mod tag {
pub const GetPowerState: u32 = 0x0002_0001; pub const GetPowerState: u32 = 0x0002_0001;
pub const SetPowerState: u32 = 0x0002_8001; pub const SetPowerState: u32 = 0x0002_8001;
pub const GetClockRate: u32 = 0x0003_0002; pub const GetClockRate: u32 = 0x0003_0002;
pub const SetClockRate: u32 = 0x0003_8002;
pub const AllocateBuffer: u32 = 0x0004_0001; pub const AllocateBuffer: u32 = 0x0004_0001;
pub const ReleaseBuffer: u32 = 0x0004_8001; pub const ReleaseBuffer: u32 = 0x0004_8001;
pub const BlankScreen: u32 = 0x0004_0002; pub const BlankScreen: u32 = 0x0004_0002;
@ -192,11 +192,7 @@ pub mod alpha_mode {
fn write(regs: &RegisterBlock, buf_ptr: u32, channel: u32) -> Result<()> { fn write(regs: &RegisterBlock, buf_ptr: u32, channel: u32) -> Result<()> {
let mut count: u32 = 0; let mut count: u32 = 0;
// { println!("Mailbox::write {:x}/{:x}", buf_ptr, channel);
// let mut uart = MiniUart::new();
// uart.init();
// writeln!(uart, "Mailbox::write {:x}/{:x}", buf_ptr, channel);
// }
while regs.STATUS.is_set(STATUS::FULL) { while regs.STATUS.is_set(STATUS::FULL) {
count += 1; count += 1;
@ -213,9 +209,6 @@ fn write(regs: &RegisterBlock, buf_ptr: u32, channel: u32) -> Result<()> {
fn read(regs: &RegisterBlock, expected: u32, channel: u32) -> Result<()> { fn read(regs: &RegisterBlock, expected: u32, channel: u32) -> Result<()> {
let mut count: u32 = 0; let mut count: u32 = 0;
// let mut uart = MiniUart::new();
// uart.init();
loop { loop {
while regs.STATUS.is_set(STATUS::EMPTY) { while regs.STATUS.is_set(STATUS::EMPTY) {
count += 1; count += 1;
@ -288,20 +281,17 @@ impl Mailbox {
pub fn read(&self, channel: u32) -> Result<()> { pub fn read(&self, channel: u32) -> Result<()> {
read(self, self.buffer.as_ptr() as u32, channel)?; read(self, self.buffer.as_ptr() as u32, channel)?;
// let mut uart = MiniUart::new();
// uart.init();
match self.buffer[1] { match self.buffer[1] {
response::SUCCESS => { response::SUCCESS => {
// writeln!(uart, "\n######\nMailbox::returning SUCCESS"); println!("\n######\nMailbox::returning SUCCESS");
Ok(()) Ok(())
} }
response::ERROR => { response::ERROR => {
// writeln!(uart, "\n######\nMailbox::returning ResponseError"); println!("\n######\nMailbox::returning ResponseError");
Err(MboxError::ResponseError) Err(MboxError::ResponseError)
} }
_ => { _ => {
// writeln!(uart, "\n######\nMailbox::returning UnknownError"); println!("\n######\nMailbox::returning UnknownError");
Err(MboxError::UnknownError) Err(MboxError::UnknownError)
} }
} }

279
src/platform/mini_uart.rs Normal file
View File

@ -0,0 +1,279 @@
/*
* MIT License
*
* Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
* Copyright (c) 2019 Berkus Decker <berkus+github@metta.systems>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::arch::{loop_delay, loop_until};
use crate::devices::ConsoleOps;
use crate::platform::{gpio, rpi3::BcmHost};
use core::{convert::TryFrom, fmt, ops};
use register::{mmio::*, register_bitfields};
/// Auxilary mini UART registers
//
// Descriptions taken from
// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf
register_bitfields! {
u32,
/// Auxiliary enables
AUX_ENABLES [
/// If set the mini UART is enabled. The UART will immediately
/// start receiving data, especially if the UART1_RX line is
/// low.
/// If clear the mini UART is disabled. That also disables any
/// mini UART register access
MINI_UART_ENABLE OFFSET(0) NUMBITS(1) []
],
/// Mini Uart Interrupt Identify
AUX_MU_IIR [
/// Writing with bit 1 set will clear the receive FIFO
/// Writing with bit 2 set will clear the transmit FIFO
FIFO_CLEAR OFFSET(1) NUMBITS(2) [
Rx = 0b01,
Tx = 0b10,
All = 0b11
]
],
/// Mini Uart Line Control
AUX_MU_LCR [
/// Mode the UART works in
DATA_SIZE OFFSET(0) NUMBITS(2) [
SevenBit = 0b00,
EightBit = 0b11
]
],
/// Mini Uart Line Status
AUX_MU_LSR [
/// This bit is set if the transmit FIFO is empty and the transmitter is
/// idle. (Finished shifting out the last bit).
TX_IDLE OFFSET(6) NUMBITS(1) [],
/// This bit is set if the transmit FIFO can accept at least
/// one byte.
TX_EMPTY OFFSET(5) NUMBITS(1) [],
/// This bit is set if the receive FIFO holds at least 1
/// symbol.
DATA_READY OFFSET(0) NUMBITS(1) []
],
/// Mini Uart Extra Control
AUX_MU_CNTL [
/// If this bit is set the mini UART transmitter is enabled.
/// If this bit is clear the mini UART transmitter is disabled.
TX_EN OFFSET(1) NUMBITS(1) [
Disabled = 0,
Enabled = 1
],
/// If this bit is set the mini UART receiver is enabled.
/// If this bit is clear the mini UART receiver is disabled.
RX_EN OFFSET(0) NUMBITS(1) [
Disabled = 0,
Enabled = 1
]
],
/// Mini Uart Baudrate
AUX_MU_BAUD [
/// Mini UART baudrate 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
}
pub struct MiniUart {
base_addr: usize,
}
/// 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: u32 = BcmHost::get_peripheral_address() + 0x21_5000;
impl MiniUart {
pub fn new_default() -> MiniUart {
MiniUart {
base_addr: usize::try_from(UART1_BASE).unwrap(),
}
}
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 _
}
///Set baud rate and characteristics (115200 8N1) and map to GPIO
#[cfg(not(feature = "noserial"))]
pub fn init(&self, gpio: &gpio::GPIO) {
// 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.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud
// map UART1 to GPIO pins
gpio.GPFSEL1
.modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1);
gpio.GPPUD.set(0); // enable pins 14 and 15
loop_delay(150);
gpio.GPPUDCLK0
.write(gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock);
loop_delay(150);
gpio.GPPUDCLK0.set(0);
self.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);
}
#[cfg(feature = "noserial")]
pub fn init(&self, _gpio: &gpio::GPIO) {}
#[cfg(not(feature = "noserial"))]
pub fn wait_tx_fifo_empty(&self) {
loop_until(|| self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_IDLE));
}
#[cfg(feature = "noserial")]
pub fn wait_tx_fifo_empty(&self) {}
}
impl Drop for MiniUart {
fn drop(&mut self) {
self.AUX_ENABLES
.modify(AUX_ENABLES::MINI_UART_ENABLE::CLEAR);
}
}
impl ConsoleOps for MiniUart {
/// Send a character
#[cfg(not(feature = "noserial"))]
fn putc(&self, c: char) {
// wait until we can send
loop_until(|| self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY));
// write the character to the buffer
self.AUX_MU_IO.set(c as u32);
}
#[cfg(feature = "noserial")]
fn putc(&self, c: char) {}
/// Display a string
fn puts(&self, string: &str) {
for c in string.chars() {
// convert newline to carrige return + newline
if c == '\n' {
self.putc('\r')
}
self.putc(c);
}
}
/// Receive a character
#[cfg(not(feature = "noserial"))]
fn getc(&self) -> char {
// wait until something is in the buffer
loop_until(|| self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY));
// read it and return
let mut ret = self.AUX_MU_IO.get() as u8 as char;
// convert carrige return to newline
if ret == '\r' {
ret = '\n'
}
ret
}
#[cfg(feature = "noserial")]
pub fn getc(&self) -> char {
'\n'
}
/// Wait until the TX FIFO is empty, aka all characters have been put on the
/// line.
fn flush(&self) {
self.wait_tx_fifo_empty();
}
}
impl fmt::Write for MiniUart {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.puts(s);
Ok(())
}
}

View File

@ -1,6 +1,10 @@
pub mod display; pub mod display;
pub mod gpio; pub mod gpio;
pub mod mailbox; pub mod mailbox;
pub mod mini_uart;
pub mod rpi3; pub mod rpi3;
pub mod uart; pub mod uart;
pub mod vc; pub mod vc;
pub use mini_uart::MiniUart;
pub use uart::PL011Uart;

View File

@ -1,240 +1,269 @@
use crate::arch::*; /*
* MIT License
*
* Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
* Copyright (c) 2019 Berkus Decker <berkus+github@metta.systems>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use super::mailbox;
use crate::arch::{loop_delay, loop_until};
use crate::devices::ConsoleOps;
use crate::platform::{gpio, rpi3::BcmHost}; use crate::platform::{gpio, rpi3::BcmHost};
use core::{fmt, ops}; use core::{convert::TryFrom, ops};
use register::mmio::*; use register::{mmio::*, register_bitfields};
// The base address for UART. // PL011 UART registers.
const UART0_BASE: u32 = BcmHost::get_peripheral_address() + 0x20_1000;
// The offsets for reach register for the UART.
const UART0_DR: u32 = UART0_BASE + 0x00;
const UART0_RSRECR: u32 = UART0_BASE + 0x04;
const UART0_FR: u32 = UART0_BASE + 0x18;
const UART0_ILPR: u32 = UART0_BASE + 0x20;
const UART0_IBRD: u32 = UART0_BASE + 0x24;
const UART0_FBRD: u32 = UART0_BASE + 0x28;
const UART0_LCRH: u32 = UART0_BASE + 0x2C;
const UART0_CR: u32 = UART0_BASE + 0x30;
const UART0_IFLS: u32 = UART0_BASE + 0x34;
const UART0_IMSC: u32 = UART0_BASE + 0x38;
const UART0_RIS: u32 = UART0_BASE + 0x3C;
const UART0_MIS: u32 = UART0_BASE + 0x40;
const UART0_ICR: u32 = UART0_BASE + 0x44;
const UART0_DMACR: u32 = UART0_BASE + 0x48;
const UART0_ITCR: u32 = UART0_BASE + 0x80;
const UART0_ITIP: u32 = UART0_BASE + 0x84;
const UART0_ITOP: u32 = UART0_BASE + 0x88;
const UART0_TDR: u32 = UART0_BASE + 0x8C;
// Mini UART
pub const UART1_BASE: u32 = BcmHost::get_peripheral_address() + 0x21_5000;
#[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
}
// Auxiliary mini UART registers
// //
// Descriptions taken from // Descriptions taken from
// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf // https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf
register_bitfields! { register_bitfields! {
u32, u32,
/// Auxiliary enables /// Flag Register
AUX_ENABLES [ FR [
/// If set the mini UART is enabled. The UART will immediately /// Transmit FIFO full. The meaning of this bit depends on the
/// start receiving data, especially if the UART1_RX line is /// state of the FEN bit in the UARTLCR_ LCRH Register. If the
/// low. /// FIFO is disabled, this bit is set when the transmit
/// If clear the mini UART is disabled. That also disables any /// holding register is full. If the FIFO is enabled, the TXFF
/// mini UART register access /// bit is set when the transmit FIFO is full.
MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] TXFF OFFSET(5) NUMBITS(1) [],
/// Receive FIFO empty. The meaning of this bit depends on the
/// state of the FEN bit in the UARTLCR_H Register. If the
/// FIFO is disabled, this bit is set when the receive holding
/// register is empty. If the FIFO is enabled, the RXFE bit is
/// set when the receive FIFO is empty.
RXFE OFFSET(4) NUMBITS(1) []
], ],
/// Mini Uart Interrupt Identify /// Integer Baud rate divisor
AUX_MU_IIR [ IBRD [
/// Writing with bit 1 set will clear the receive FIFO /// Integer Baud rate divisor
/// Writing with bit 2 set will clear the transmit FIFO IBRD OFFSET(0) NUMBITS(16) []
FIFO_CLEAR OFFSET(1) NUMBITS(2) [
Rx = 0b01,
Tx = 0b10,
All = 0b11
]
], ],
/// Mini Uart Line Control /// Fractional Baud rate divisor
AUX_MU_LCR [ FBRD [
/// Mode the UART works in /// Fractional Baud rate divisor
DATA_SIZE OFFSET(0) NUMBITS(2) [ FBRD OFFSET(0) NUMBITS(6) []
SevenBit = 0b00, ],
/// Line Control register
LCRH [
/// Word length. These bits indicate the number of data bits
/// transmitted or received in a frame.
WLEN OFFSET(5) NUMBITS(2) [
FiveBit = 0b00,
SixBit = 0b01,
SevenBit = 0b10,
EightBit = 0b11 EightBit = 0b11
] ]
], ],
/// Mini Uart Line Status /// Control Register
AUX_MU_LSR [ CR [
/// This bit is set if the transmit FIFO can accept at least /// Receive enable. If this bit is set to 1, the receive
/// one byte. /// section of the UART is enabled. Data reception occurs for
TX_EMPTY OFFSET(5) NUMBITS(1) [], /// UART signals. When the UART is disabled in the middle of
/// reception, it completes the current character before
/// This bit is set if the receive FIFO holds at least 1 /// stopping.
/// symbol. RXE OFFSET(9) NUMBITS(1) [
DATA_READY OFFSET(0) NUMBITS(1) []
],
/// Mini Uart Extra Control
AUX_MU_CNTL [
/// If this bit is set the mini UART transmitter is enabled.
/// If this bit is clear the mini UART transmitter is disabled.
TX_EN OFFSET(1) NUMBITS(1) [
Disabled = 0, Disabled = 0,
Enabled = 1 Enabled = 1
], ],
/// If this bit is set the mini UART receiver is enabled. /// Transmit enable. If this bit is set to 1, the transmit
/// If this bit is clear the mini UART receiver is disabled. /// section of the UART is enabled. Data transmission occurs
RX_EN OFFSET(0) NUMBITS(1) [ /// for UART signals. When the UART is disabled in the middle
/// of transmission, it completes the current character before
/// stopping.
TXE OFFSET(8) NUMBITS(1) [
Disabled = 0,
Enabled = 1
],
/// UART enable
UARTEN OFFSET(0) NUMBITS(1) [
/// If the UART is disabled in the middle of transmission
/// or reception, it completes the current character
/// before stopping.
Disabled = 0, Disabled = 0,
Enabled = 1 Enabled = 1
] ]
], ],
/// Mini Uart Baudrate /// Interupt Clear Register
AUX_MU_BAUD [ ICR [
/// Mini UART baudrate counter /// Meta field for all pending interrupts
RATE OFFSET(0) NUMBITS(16) [] ALL OFFSET(0) NUMBITS(11) []
] ]
} }
pub struct MiniUart; #[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
}
/// Deref to RegisterBlock pub enum PL011UartError {
/// MailboxError,
/// Allows writing }
/// ``` pub type Result<T> = ::core::result::Result<T, PL011UartError>;
/// self.MU_IER.read()
/// ``` pub struct PL011Uart {
/// instead of something along the lines of base_addr: usize,
/// ``` }
/// unsafe { (*MiniUart::ptr()).MU_IER.read() }
/// ``` impl ops::Deref for PL011Uart {
impl ops::Deref for MiniUart {
type Target = RegisterBlock; type Target = RegisterBlock;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() } unsafe { &*self.ptr() }
} }
} }
impl MiniUart { impl PL011Uart {
pub fn new() -> MiniUart { pub fn new_default() -> PL011Uart {
MiniUart const UART0_BASE: u32 = BcmHost::get_peripheral_address() + 0x20_1000;
PL011Uart {
base_addr: usize::try_from(UART0_BASE).unwrap(),
}
}
pub fn new(base_addr: usize) -> PL011Uart {
PL011Uart { base_addr }
} }
/// Returns a pointer to the register block /// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock { fn ptr(&self) -> *const RegisterBlock {
UART1_BASE as *const _ 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
#[cfg(not(feature = "noserial"))] pub fn init(&self, mbox: &mut mailbox::Mailbox, gpio: &gpio::GPIO) -> Result<()> {
pub fn init(&self) { // turn off UART0
// initialize UART self.CR.set(0);
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.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud
// map UART1 to GPIO pins // set up clock for consistent divisor values
unsafe { mbox.buffer[0] = 9 * 4;
(*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); mbox.buffer[1] = mailbox::REQUEST;
mbox.buffer[2] = mailbox::tag::SetClockRate;
mbox.buffer[3] = 12;
mbox.buffer[4] = 8;
mbox.buffer[5] = mailbox::clock::UART; // UART clock
mbox.buffer[6] = 4_000_000; // 4Mhz
mbox.buffer[7] = 0; // skip turbo setting
mbox.buffer[8] = mailbox::tag::End;
(*gpio::GPPUD).set(0); // enable pins 14 and 15 if mbox.call(mailbox::channel::PropertyTagsArmToVc).is_err() {
loop_delay(150); return Err(PL011UartError::MailboxError); // Abort if UART clocks couldn't be set
};
(*gpio::GPPUDCLK0).write( // map UART0 to GPIO pins
gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, gpio.GPFSEL1
); .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0);
loop_delay(150);
(*gpio::GPPUDCLK0).set(0); gpio.GPPUD.set(0); // enable pins 14 and 15
} loop_delay(150);
self.AUX_MU_CNTL gpio.GPPUDCLK0.modify(
.write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock,
} );
loop_delay(150);
#[cfg(feature = "noserial")] gpio.GPPUDCLK0.set(0);
pub fn init(&self) {}
/// Send a character self.ICR.write(ICR::ALL::CLEAR);
#[cfg(not(feature = "noserial"))] self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud
pub fn send(&self, c: char) { self.FBRD.write(FBRD::FBRD.val(0xB));
// wait until we can send self.LCRH.write(LCRH::WLEN::EightBit); // 8N1
loop_until(|| self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY));
// write the character to the buffer self.CR
self.AUX_MU_IO.set(c as u32); .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
}
#[cfg(feature = "noserial")]
pub fn send(&self, _c: char) {}
/// Receive a character
#[cfg(not(feature = "noserial"))]
pub fn getc(&self) -> char {
// wait until something is in the buffer
loop_until(|| self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY));
// read it and return
let ret = self.AUX_MU_IO.get() as u8 as char;
// convert carriage return to newline
if ret == '\r' {
'\n'
} else {
ret
}
}
#[cfg(feature = "noserial")]
pub fn getc(&self) -> char {
'\n'
}
/// Display a string
pub fn puts(&self, string: &str) {
for c in string.chars() {
// convert newline to carriage return + newline
if c == '\n' {
self.send('\r')
}
self.send(c);
}
}
}
impl fmt::Write for MiniUart {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.puts(s);
Ok(()) Ok(())
} }
} }
impl Drop for PL011Uart {
fn drop(&mut self) {
self.CR
.write(CR::UARTEN::Disabled + CR::TXE::Disabled + CR::RXE::Disabled);
}
}
impl ConsoleOps for PL011Uart {
/// Send a character
fn putc(&self, c: char) {
// wait until we can send
loop_until(|| !self.FR.is_set(FR::TXFF));
// write the character to the buffer
self.DR.set(c as u32);
}
/// Display a string
fn puts(&self, string: &str) {
for c in string.chars() {
// convert newline to carrige return + newline
if c == '\n' {
self.putc('\r')
}
self.putc(c);
}
}
/// Receive a character
fn getc(&self) -> char {
// wait until something is in the buffer
loop_until(|| !self.FR.is_set(FR::RXFE));
// read it and return
let mut ret = self.DR.get() as u8 as char;
// convert carrige return to newline
if ret == '\r' {
ret = '\n'
}
ret
}
}

View File

@ -1,23 +1,24 @@
use crate::platform::{ use crate::{
display::{Display, PixelOrder, Size2d, CHARSIZE_X, CHARSIZE_Y}, platform::{
mailbox::{self, channel, response::VAL_LEN_FLAG, tag, GpuFb, Mailbox}, display::{Display, PixelOrder, Size2d, CHARSIZE_X, CHARSIZE_Y},
mailbox::{self, channel, response::VAL_LEN_FLAG, tag, GpuFb, Mailbox},
},
println,
}; };
// use core::fmt::Write;
// use platform::uart::MiniUart;
pub struct VC; pub struct VC;
impl VC { impl VC {
// Use mailbox framebuffer interface to initialize // Use mailbox framebuffer interface to initialize
pub fn init_fb(size: Size2d /*, uart: &mut MiniUart*/) -> Option<Display> { pub fn init_fb(size: Size2d) -> Option<Display> {
let mut fb_info = GpuFb::new(size, 32); let mut fb_info = GpuFb::new(size, 32);
// writeln!(uart, "initing fb_info"); println!("initing fb_info");
fb_info.call().map_err(|_| { fb_info.call().map_err(|_| {
// writeln!(uart, "fb_info error"); println!("fb_info error");
}); });
// writeln!(uart, "inited fb_info: {}", fb_info); println!("inited fb_info: {}", fb_info);
let mut mbox = Mailbox::new(); let mut mbox = Mailbox::new();
@ -62,7 +63,7 @@ impl VC {
/* Need to set up max_x/max_y before using Display::write */ /* Need to set up max_x/max_y before using Display::write */
let max_x = fb_info.vwidth / CHARSIZE_X; let max_x = fb_info.vwidth / CHARSIZE_X;
let max_y = fb_info.vheight / CHARSIZE_Y; let max_y = fb_info.vheight / CHARSIZE_Y;
// writeln!(uart, "inited fb_info #2"); println!("inited fb_info #2");
Some(Display::new( Some(Display::new(
fb_info.pointer & 0x3fff_ffff, fb_info.pointer & 0x3fff_ffff,

62
src/sync.rs Normal file
View File

@ -0,0 +1,62 @@
/*
* MIT License
*
* Copyright (c) 2019 Andre Richter <andre.o.richter@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use core::cell::UnsafeCell;
pub struct NullLock<T> {
data: UnsafeCell<T>,
}
// Since we are instantiating this struct as a static variable, which could
// potentially be shared between different threads, we need to tell the compiler
// that sharing of this struct is safe by marking it with the Sync trait.
//
// At this point in time, we can do so without worrying, because the kernel
// anyways runs on a single core and interrupts are disabled. In short, multiple
// threads don't exist yet in our code.
//
// Literature:
// https://doc.rust-lang.org/beta/nomicon/send-and-sync.html
// https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html
unsafe impl<T> Sync for NullLock<T> {}
impl<T> NullLock<T> {
pub const fn new(data: T) -> NullLock<T> {
NullLock {
data: UnsafeCell::new(data),
}
}
}
impl<T> NullLock<T> {
pub fn lock<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
// In a real lock, there would be code around this line that ensures
// that this mutable reference will ever only be given out to one thread
// at a time.
f(unsafe { &mut *self.data.get() })
}
}