mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: add sifive serial driver
This commit is contained in:
parent
5032711022
commit
ea15acb8f6
@ -3,4 +3,8 @@ use crate::plat::console::ConsoleDevice;
|
||||
|
||||
pub trait SerialDriver: Driver + ConsoleDevice {}
|
||||
|
||||
pub mod uart16550;
|
||||
mod sifive;
|
||||
mod uart16550;
|
||||
|
||||
pub use sifive::UartSifive;
|
||||
pub use uart16550::Uart16550;
|
||||
|
172
kernel/src/drivers/serial/sifive.rs
Normal file
172
kernel/src/drivers/serial/sifive.rs
Normal file
@ -0,0 +1,172 @@
|
||||
use crate::drivers::serial::SerialDriver;
|
||||
use crate::drivers::Driver;
|
||||
use crate::plat::console::ConsoleDevice;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use fdt::node::FdtNode;
|
||||
|
||||
// https://static.dev.sifive.com/FU540-C000-v1.0.pdf
|
||||
|
||||
pub struct UartSifive
|
||||
where UartSifive: SerialDriver
|
||||
{
|
||||
tx_data: AtomicPtr<u32>,
|
||||
rx_data: AtomicPtr<u32>,
|
||||
tx_ctrl: AtomicPtr<u32>,
|
||||
rx_ctrl: AtomicPtr<u32>,
|
||||
ie: AtomicPtr<u32>,
|
||||
ip: AtomicPtr<u32>,
|
||||
div: AtomicPtr<u32>,
|
||||
}
|
||||
|
||||
impl UartSifive {
|
||||
fn tx_write(&self, val: u8) {
|
||||
unsafe { self.tx_data.load(Ordering::Relaxed).write(val as u32) }
|
||||
}
|
||||
|
||||
fn tx_full(&self) -> bool {
|
||||
unsafe { (self.tx_data.load(Ordering::Relaxed).read() >> 31) == 1 }
|
||||
}
|
||||
|
||||
fn rx_read(&self) -> u8 {
|
||||
unsafe { self.rx_data.load(Ordering::Relaxed).read() as u8 }
|
||||
}
|
||||
|
||||
fn rx_full(&self) -> bool {
|
||||
unsafe { (self.rx_data.load(Ordering::Relaxed).read() >> 31) == 0 }
|
||||
}
|
||||
|
||||
fn rx_try_read(&self) -> Option<u8> {
|
||||
unsafe {
|
||||
let val = self.rx_data.load(Ordering::Relaxed).read();
|
||||
if (val >> 31) == 0 {
|
||||
Some(val as u8)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tx_ctrl_enable(&self, enable: bool) {
|
||||
unsafe {
|
||||
let ctrl = self.tx_ctrl.load(Ordering::Relaxed);
|
||||
let val = ctrl.read() & !1 | (enable as u32);
|
||||
ctrl.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn tx_ctrl_stop_bit(&self, two: bool) {
|
||||
unsafe {
|
||||
let ctrl = self.tx_ctrl.load(Ordering::Relaxed);
|
||||
let val = ctrl.read() & !2 | (two as u32) << 1;
|
||||
ctrl.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn tx_ctrl_watermark(&self, watermark: u8) {
|
||||
unsafe {
|
||||
let ctrl = self.tx_ctrl.load(Ordering::Relaxed);
|
||||
let val = ctrl.read() & !(0b111 << 16) | ((watermark as u32 & 0b111) << 16);
|
||||
ctrl.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn rx_ctrl_enable(&self, enable: bool) {
|
||||
unsafe {
|
||||
let ctrl = self.rx_ctrl.load(Ordering::Relaxed);
|
||||
let val = ctrl.read() & !1 | (enable as u32);
|
||||
ctrl.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn rx_ctrl_watermark(&self, watermark: u8) {
|
||||
unsafe {
|
||||
let ctrl = self.rx_ctrl.load(Ordering::Relaxed);
|
||||
let val = ctrl.read() & !(0b111 << 16) | ((watermark as u32 & 0b111) << 16);
|
||||
ctrl.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn interrupt_tx_enable(&self, enable: bool) {
|
||||
unsafe {
|
||||
let ie = self.ie.load(Ordering::Relaxed);
|
||||
let val = ie.read() & !1 | (enable as u32);
|
||||
ie.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn interrupt_rx_enable(&self, enable: bool) {
|
||||
unsafe {
|
||||
let ie = self.ie.load(Ordering::Relaxed);
|
||||
let val = ie.read() & !2 | (enable as u32) << 1;
|
||||
ie.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
fn interrupt_tx_pending(&self) -> bool {
|
||||
unsafe { (self.ip.load(Ordering::Relaxed).read() & 1) == 1 }
|
||||
}
|
||||
|
||||
fn interrupt_rx_pending(&self) -> bool {
|
||||
unsafe { (self.ip.load(Ordering::Relaxed).read() & 2) == 2 }
|
||||
}
|
||||
|
||||
fn div_write(&self, val: u32) {
|
||||
unsafe { self.div.load(Ordering::Relaxed).write(val & 0xffff) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Driver for UartSifive {
|
||||
fn compatible() -> &'static [&'static str] {
|
||||
&["sifive,uart0"]
|
||||
}
|
||||
|
||||
fn setup(fdt: FdtNode) -> Self {
|
||||
let addr = fdt.reg().unwrap().next().unwrap().starting_address as *mut u32;
|
||||
let uart = unsafe {
|
||||
UartSifive {
|
||||
tx_data: AtomicPtr::new(addr),
|
||||
rx_data: AtomicPtr::new(addr.add(1)),
|
||||
tx_ctrl: AtomicPtr::new(addr.add(2)),
|
||||
rx_ctrl: AtomicPtr::new(addr.add(3)),
|
||||
ie: AtomicPtr::new(addr.add(4)),
|
||||
ip: AtomicPtr::new(addr.add(5)),
|
||||
div: AtomicPtr::new(addr.add(6)),
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: no interrupt & baud rate support now
|
||||
uart.interrupt_tx_enable(false);
|
||||
uart.interrupt_rx_enable(false);
|
||||
uart.tx_ctrl_stop_bit(false);
|
||||
|
||||
// Enable TX, RX
|
||||
uart.tx_ctrl_enable(true);
|
||||
uart.rx_ctrl_enable(true);
|
||||
|
||||
uart
|
||||
}
|
||||
}
|
||||
|
||||
impl ConsoleDevice for UartSifive {
|
||||
fn read(&mut self) -> u8 {
|
||||
loop {
|
||||
if let Some(ch) = self.rx_try_read() {
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_read(&mut self) -> Option<u8> {
|
||||
self.rx_try_read()
|
||||
}
|
||||
|
||||
fn write(&mut self, n: u8) {
|
||||
while self.tx_full() {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
self.tx_write(n);
|
||||
}
|
||||
}
|
||||
|
||||
impl SerialDriver for UartSifive {}
|
@ -1,7 +1,8 @@
|
||||
use crate::arch::EarlyConsole;
|
||||
use crate::drivers::serial::uart16550::Uart16550;
|
||||
use crate::drivers::serial::{Uart16550, UartSifive};
|
||||
use crate::drivers::Driver;
|
||||
use fdt::node::FdtNode;
|
||||
use log::debug;
|
||||
use spin::Mutex;
|
||||
|
||||
macro_rules! create_console_driver {
|
||||
@ -20,6 +21,7 @@ macro_rules! create_console_driver {
|
||||
.all()
|
||||
.any(|s| $dynamic_driver::compatible().contains(&s))
|
||||
{
|
||||
debug!("Console: Using driver: {}", stringify!($dynamic_driver));
|
||||
return Some(ConsoleDriver::$dynamic_driver($dynamic_driver::setup(fdt)))
|
||||
}
|
||||
)+
|
||||
@ -60,7 +62,7 @@ macro_rules! create_console_driver {
|
||||
};
|
||||
}
|
||||
|
||||
create_console_driver!((Uart16550), (SilenceConsole, EarlyConsole));
|
||||
create_console_driver!((Uart16550, UartSifive), (SilenceConsole, EarlyConsole));
|
||||
|
||||
impl core::fmt::Write for ConsoleDriver {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
|
Loading…
Reference in New Issue
Block a user