[sq] add console
This commit is contained in:
parent
12b01105f4
commit
58be472573
5
Makefile
5
Makefile
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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() })
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue