2023-07-18 18:03:45 +03:00
|
|
|
//! ARM PL011 driver
|
2023-07-27 16:24:52 +03:00
|
|
|
use abi::{error::Error, io::DeviceRequest};
|
2023-08-13 21:23:58 +03:00
|
|
|
use alloc::boxed::Box;
|
2023-08-21 17:26:44 +03:00
|
|
|
use device_api::{interrupt::InterruptHandler, serial::SerialDevice, Device};
|
|
|
|
use kernel_util::util::OneTimeInit;
|
2023-07-18 18:03:45 +03:00
|
|
|
use tock_registers::{
|
|
|
|
interfaces::{ReadWriteable, Readable, Writeable},
|
|
|
|
register_bitfields, register_structs,
|
|
|
|
registers::{ReadOnly, ReadWrite, WriteOnly},
|
|
|
|
};
|
|
|
|
use vfs::CharDevice;
|
|
|
|
|
|
|
|
use crate::{
|
2023-08-21 17:26:44 +03:00
|
|
|
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
|
2023-11-16 00:16:38 +02:00
|
|
|
block,
|
2023-08-13 21:23:58 +03:00
|
|
|
debug::{self, DebugSink, LogLevel},
|
2023-08-21 17:26:44 +03:00
|
|
|
device::{
|
|
|
|
devtree::{self, DevTreeIndexPropExt},
|
2023-11-16 00:16:38 +02:00
|
|
|
tty::{TtyContext, TtyDevice},
|
2023-08-21 17:26:44 +03:00
|
|
|
},
|
2023-08-13 21:23:58 +03:00
|
|
|
device_tree_driver,
|
|
|
|
fs::devfs::{self, CharDeviceType},
|
2023-11-16 00:16:38 +02:00
|
|
|
mem::{address::FromRaw, device::DeviceMemoryIo, PhysicalAddress},
|
2023-07-18 18:03:45 +03:00
|
|
|
sync::IrqSafeSpinlock,
|
2023-11-21 14:16:18 +02:00
|
|
|
task::process::ProcessId,
|
2023-07-18 18:03:45 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
register_bitfields! {
|
|
|
|
u32,
|
|
|
|
FR [
|
|
|
|
TXFF OFFSET(5) NUMBITS(1) [],
|
|
|
|
RXFE OFFSET(4) NUMBITS(1) [],
|
|
|
|
BUSY OFFSET(3) NUMBITS(1) [],
|
|
|
|
],
|
|
|
|
CR [
|
|
|
|
RXE OFFSET(9) NUMBITS(1) [],
|
|
|
|
TXE OFFSET(8) NUMBITS(1) [],
|
|
|
|
UARTEN OFFSET(0) NUMBITS(1) [],
|
|
|
|
],
|
|
|
|
ICR [
|
|
|
|
ALL OFFSET(0) NUMBITS(11) [],
|
|
|
|
],
|
|
|
|
IMSC [
|
|
|
|
RXIM OFFSET(4) NUMBITS(1) [],
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
register_structs! {
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
Regs {
|
|
|
|
/// Transmit/receive data register
|
|
|
|
(0x00 => DR: ReadWrite<u32>),
|
|
|
|
(0x04 => _0),
|
|
|
|
(0x18 => FR: ReadOnly<u32, FR::Register>),
|
|
|
|
(0x1C => _1),
|
|
|
|
(0x2C => LCR_H: ReadWrite<u32>),
|
|
|
|
(0x30 => CR: ReadWrite<u32, CR::Register>),
|
|
|
|
(0x34 => IFLS: ReadWrite<u32>),
|
|
|
|
(0x38 => IMSC: ReadWrite<u32, IMSC::Register>),
|
|
|
|
(0x3C => _2),
|
|
|
|
(0x44 => ICR: WriteOnly<u32, ICR::Register>),
|
|
|
|
(0x48 => @END),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Pl011Inner {
|
2023-11-16 00:16:38 +02:00
|
|
|
regs: DeviceMemoryIo<'static, Regs>,
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// PL011 device instance
|
|
|
|
pub struct Pl011 {
|
|
|
|
inner: OneTimeInit<IrqSafeSpinlock<Pl011Inner>>,
|
2023-11-16 00:16:38 +02:00
|
|
|
base: PhysicalAddress,
|
2023-07-18 18:03:45 +03:00
|
|
|
irq: IrqNumber,
|
2023-11-16 00:16:38 +02:00
|
|
|
context: TtyContext,
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Pl011Inner {
|
|
|
|
fn send_byte(&mut self, b: u8) -> Result<(), Error> {
|
|
|
|
while self.regs.FR.matches_all(FR::TXFF::SET) {
|
|
|
|
core::hint::spin_loop();
|
|
|
|
}
|
|
|
|
self.regs.DR.set(b as u32);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn init(&mut self) {
|
|
|
|
self.regs.CR.set(0);
|
|
|
|
self.regs.ICR.write(ICR::ALL::CLEAR);
|
|
|
|
self.regs
|
|
|
|
.CR
|
|
|
|
.write(CR::UARTEN::SET + CR::TXE::SET + CR::RXE::SET);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-03 13:01:30 +03:00
|
|
|
impl DebugSink for Pl011 {
|
|
|
|
fn putc(&self, byte: u8) -> Result<(), Error> {
|
|
|
|
self.send(byte)
|
|
|
|
}
|
2023-08-22 10:00:56 +03:00
|
|
|
|
|
|
|
fn supports_control_sequences(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2023-08-03 13:01:30 +03:00
|
|
|
}
|
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
impl TtyDevice for Pl011 {
|
|
|
|
fn context(&self) -> &TtyContext {
|
|
|
|
&self.context
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CharDevice for Pl011 {
|
|
|
|
fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
|
|
|
assert!(blocking);
|
|
|
|
self.line_write(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
|
|
|
|
assert!(blocking);
|
2023-11-16 00:16:38 +02:00
|
|
|
match block! {
|
|
|
|
self.line_read(data).await
|
|
|
|
} {
|
|
|
|
Ok(res) => res,
|
|
|
|
Err(err) => Err(err),
|
|
|
|
}
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
2023-07-27 16:24:52 +03:00
|
|
|
|
|
|
|
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
|
|
|
match req {
|
|
|
|
&mut DeviceRequest::SetTerminalGroup(id) => {
|
2023-11-21 14:16:18 +02:00
|
|
|
self.set_signal_group(ProcessId::from(id));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
DeviceRequest::SetTerminalOptions(config) => self.context.set_config(config),
|
|
|
|
DeviceRequest::GetTerminalOptions(config) => {
|
|
|
|
config.write(self.context.config());
|
2023-07-27 16:24:52 +03:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => Err(Error::InvalidArgument),
|
|
|
|
}
|
|
|
|
}
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SerialDevice for Pl011 {
|
|
|
|
fn send(&self, byte: u8) -> Result<(), Error> {
|
|
|
|
self.inner.get().lock().send_byte(byte)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
impl InterruptHandler for Pl011 {
|
|
|
|
fn handle_irq(&self) -> bool {
|
2023-07-18 18:03:45 +03:00
|
|
|
let inner = self.inner.get().lock();
|
|
|
|
inner.regs.ICR.write(ICR::ALL::CLEAR);
|
|
|
|
|
|
|
|
let byte = inner.regs.DR.get();
|
|
|
|
drop(inner);
|
|
|
|
|
2023-11-21 14:16:18 +02:00
|
|
|
// if byte == b'\x1b' as u32 {
|
|
|
|
// use crate::task::sched::CpuQueue;
|
|
|
|
|
|
|
|
// for (i, queue) in CpuQueue::all().enumerate() {
|
|
|
|
// log_print_raw!(LogLevel::Fatal, "queue{}:\n", i);
|
|
|
|
// let lock = unsafe { queue.grab() };
|
|
|
|
// for item in lock.iter() {
|
|
|
|
// log_print_raw!(
|
|
|
|
// LogLevel::Fatal,
|
|
|
|
// "* {} {:?} {:?}\n",
|
|
|
|
// item.id(),
|
|
|
|
// item.name(),
|
|
|
|
// item.state()
|
|
|
|
// );
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// } else {
|
|
|
|
self.recv_byte(byte as u8);
|
|
|
|
// }
|
2023-07-18 18:03:45 +03:00
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
true
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
impl Device for Pl011 {
|
|
|
|
fn display_name(&self) -> &'static str {
|
|
|
|
"Primecell PL011 UART"
|
|
|
|
}
|
2023-08-04 10:07:21 +03:00
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
unsafe fn init(&'static self) -> Result<(), Error> {
|
2023-07-18 18:03:45 +03:00
|
|
|
let mut inner = Pl011Inner {
|
2023-11-16 00:16:38 +02:00
|
|
|
regs: DeviceMemoryIo::map(self.base)?,
|
2023-07-18 18:03:45 +03:00
|
|
|
};
|
|
|
|
inner.init();
|
|
|
|
|
|
|
|
self.inner.init(IrqSafeSpinlock::new(inner));
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2023-11-26 15:05:16 +02:00
|
|
|
debug::add_sink(self, LogLevel::Debug);
|
2023-08-13 21:23:58 +03:00
|
|
|
devfs::add_char_device(self, CharDeviceType::TtySerial)?;
|
|
|
|
|
2023-07-18 18:03:45 +03:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
unsafe fn init_irq(&'static self) -> Result<(), Error> {
|
|
|
|
let intc = ARCHITECTURE.external_interrupt_controller();
|
|
|
|
|
|
|
|
intc.register_irq(self.irq, Default::default(), self)?;
|
|
|
|
self.inner.get().lock().regs.IMSC.modify(IMSC::RXIM::SET);
|
|
|
|
intc.enable_irq(self.irq)?;
|
|
|
|
|
|
|
|
Ok(())
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
device_tree_driver! {
|
|
|
|
compatible: ["arm,pl011"],
|
|
|
|
probe(of) => {
|
|
|
|
let reg = devtree::find_prop(&of.node, "reg")?;
|
|
|
|
let (base, _) = reg.cell2_array_item(0, of.address_cells, of.size_cells)?;
|
|
|
|
|
|
|
|
Some(Box::new(Pl011 {
|
2023-07-18 18:03:45 +03:00
|
|
|
inner: OneTimeInit::new(),
|
2023-08-13 21:23:58 +03:00
|
|
|
// TODO obtain IRQ from dt
|
|
|
|
irq: IrqNumber::Shared(1),
|
2023-11-16 00:16:38 +02:00
|
|
|
context: TtyContext::new(),
|
|
|
|
base: PhysicalAddress::from_raw(base)
|
2023-08-13 21:23:58 +03:00
|
|
|
}))
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
}
|