#![no_std]
use processor::cpu_relax;
use simink_serial::{self, Serial, SerialInstance};
use simink_spinlock::{self, SpinLock};
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_bitfields! {
u32,
Data [
IO OFFSET(0) NUMBITS(32) []
],
Flags [
FR OFFSET(0) NUMBITS(32) [
TXFE = 0x80,
RXFF = 0x40,
TXFF = 0x20,
RXFE = 0x10,
BUSY = 0x08,
]
],
Baud [
BAUD OFFSET(0) NUMBITS(32) []
],
LineControl [
BRK OFFSET(0) NUMBITS(1) [],
PEN OFFSET(1) NUMBITS(1) [],
EPS OFFSET(2) NUMBITS(1) [],
STP2 OFFSET(3) NUMBITS(1) [],
FEN OFFSET(4) NUMBITS(1) [],
WLEN OFFSET(5) NUMBITS(2) [
WLEN_5 = 0,
WLEN_6 = 1,
WLEN_7 = 2,
WLEN_8 = 3,
],
SPS OFFSET(7) NUMBITS(1) [],
],
Control [
UARTEN OFFSET(0) NUMBITS(1) [],
SIREN OFFSET(1) NUMBITS(1) [],
IIRLP OFFSET(2) NUMBITS(1) [],
LPE OFFSET(7) NUMBITS(1) [],
TXE OFFSET(8) NUMBITS(1) [],
RXE OFFSET(9) NUMBITS(1) [],
DTR OFFSET(10) NUMBITS(1) [],
RTS OFFSET(11) NUMBITS(1) [],
OUT1 OFFSET(12) NUMBITS(1) [],
OUT2 OFFSET(13) NUMBITS(1) [],
RTSEN OFFSET(14) NUMBITS(1) [],
CTSEN OFFSET(15) NUMBITS(1) [],
]
}
register_structs! {
Pl011Registers {
(0x00 => dr: WriteOnly<u32, Data::Register>),
(0x04 => _reserved),
(0x18 => fr: ReadOnly<u32, Flags::Register>),
(0x1c => _reserved2),
(0x24 => ibrd: ReadWrite<u32, Baud::Register>),
(0x28 => fbrd: ReadWrite<u32, Baud::Register>),
(0x2c => lcrh: ReadWrite<u32, LineControl::Register>),
(0x30 => cr: ReadWrite<u32, Control::Register>),
(0x34 => @END),
}
}
pub struct Pl011State {
val: SpinLock<*mut Pl011Registers>,
}
impl Default for Pl011State {
fn default() -> Self {
Self::new()
}
}
impl Pl011State {
pub fn new() -> Self {
Self::default()
}
#[inline]
fn putc(reg: &Pl011Registers, c: u8) {
while reg.fr.matches_any(Flags::FR::TXFF) {
cpu_relax();
}
reg.dr.set(c as u32);
while reg.fr.matches_any(Flags::FR::BUSY) {
cpu_relax();
}
}
}
impl<S> SerialInstance<S> for Pl011State {
fn init(&self, serial: &Serial<S>) {
let reg;
unsafe {
let mut val = self.val.lock();
*val = serial.virtbase as *mut Pl011Registers;
reg = val.as_ref().unwrap();
}
reg.cr.set(0);
let mut temp = 16 * serial.baud;
let divider = serial.clk / temp;
let remainder = serial.clk % temp;
temp = (8 * remainder) / serial.baud;
let fraction = (temp >> 1) + (temp & 1);
reg.ibrd.set(divider);
reg.fbrd.set(fraction);
reg.lcrh
.write(LineControl::WLEN::WLEN_8 + LineControl::FEN::SET);
reg.cr.write(
Control::UARTEN::SET + Control::TXE::SET + Control::RXE::SET + Control::RTS::SET,
);
}
fn write(&self, s: &str) {
let reg;
unsafe {
reg = self.val.lock().as_ref().unwrap();
}
for c in s.bytes() {
if c == b'\n' {
Pl011State::putc(reg, b'\r');
}
Pl011State::putc(reg, c);
}
}
}