tock: Migrate to using an opentitan UART driver

This brings in the uart driver from lowrisc::uart, but updates it to
use offsets from the opentitan-upstream tree in an effort to get us
off the old tree.

Bug: 228243751
Change-Id: If3b9ce99ee107303d37de46dee591f120577be34
diff --git a/chips/opentitan/Cargo.toml b/chips/opentitan/Cargo.toml
new file mode 100644
index 0000000..a7ef8ba
--- /dev/null
+++ b/chips/opentitan/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "opentitan"
+version = "0.1.0"
+authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
+
+[dependencies]
+rv32i = { path = "../../../tock/arch/rv32i" }
+kernel = { path = "../../../tock/kernel" }
+tock-rt0 = { path = "../../../tock/libraries/tock-rt0" }
diff --git a/chips/opentitan/src/lib.rs b/chips/opentitan/src/lib.rs
new file mode 100644
index 0000000..9622367
--- /dev/null
+++ b/chips/opentitan/src/lib.rs
@@ -0,0 +1,8 @@
+//! Implementations for generic OpenTitan peripherals.
+
+#![feature(const_fn)]
+#![no_std]
+#![crate_name = "opentitan"]
+#![crate_type = "rlib"]
+
+pub mod uart;
diff --git a/chips/opentitan/src/uart.rs b/chips/opentitan/src/uart.rs
new file mode 100644
index 0000000..0c21cad
--- /dev/null
+++ b/chips/opentitan/src/uart.rs
@@ -0,0 +1,348 @@
+//! UART driver.
+
+use core::cell::Cell;
+
+use kernel::common::cells::OptionalCell;
+use kernel::common::cells::TakeCell;
+use kernel::common::registers::{
+    register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
+};
+use kernel::common::StaticRef;
+use kernel::hil;
+use kernel::hil::uart;
+use kernel::ReturnCode;
+
+// BIG FAT NOTE: if the UART registers change, we're going to have to fix the
+// dprintf hack in dprintf_hal.rs as well, since it bypasses these register
+// definitions. If you fix this, please fix b/239714445 as well.
+register_structs! {
+    pub UartRegisters {
+        (0x000 => intr_state: ReadWrite<u32, intr::Register>),
+        (0x004 => intr_enable: ReadWrite<u32, intr::Register>),
+        (0x008 => intr_test: ReadWrite<u32, intr::Register>),
+        (0x00c => alert_test: ReadWrite<u32, intr::Register>),
+        /// UART control register
+        (0x010 => ctrl: ReadWrite<u32, ctrl::Register>),
+        /// UART live status register
+        (0x014 => status: ReadOnly<u32, status::Register>),
+        /// UART read data)
+        (0x018 => rdata: ReadOnly<u32, rdata::Register>),
+        /// UART write data
+        (0x01c => wdata: WriteOnly<u32, wdata::Register>),
+        /// UART FIFO control register")
+        (0x020 => fifo_ctrl: ReadWrite<u32, fifo_ctrl::Register>),
+        /// UART FIFO status register
+        (0x024 => fifo_status: ReadWrite<u32, fifo_status::Register>),
+        /// TX pin override control. Gives direct SW control over TX pin state
+        (0x028 => ovrd: ReadWrite<u32, ovrd::Register>),
+        /// UART oversampled values
+        (0x02c => val: ReadWrite<u32, val::Register>),
+        /// UART RX timeout control
+        (0x030 => timeout_ctrl: ReadWrite<u32, timeout_ctrl::Register>),
+        (0x034 => @END),
+    }
+}
+
+register_bitfields![u32,
+    intr [
+        tx_watermark OFFSET(0) NUMBITS(1) [],
+        rx_watermark OFFSET(1) NUMBITS(1) [],
+        tx_empty OFFSET(2) NUMBITS(1) [],
+        rx_overflow OFFSET(3) NUMBITS(1) [],
+        rx_frame_err OFFSET(4) NUMBITS(1) [],
+        rx_break_err OFFSET(5) NUMBITS(1) [],
+        rx_timeout OFFSET(6) NUMBITS(1) [],
+        rx_parity_err OFFSET(7) NUMBITS(1) []
+    ],
+    ctrl [
+        tx OFFSET(0) NUMBITS(1) [],
+        rx OFFSET(1) NUMBITS(1) [],
+        nf OFFSET(2) NUMBITS(1) [],
+        slpbk OFFSET(4) NUMBITS(1) [],
+        llpbk OFFSET(5) NUMBITS(1) [],
+        parity_en OFFSET(6) NUMBITS(1) [],
+        parity_odd OFFSET(7) NUMBITS(1) [],
+        rxblvl OFFSET(8) NUMBITS(2) [],
+        nco OFFSET(16) NUMBITS(16) []
+    ],
+    status [
+        txfull OFFSET(0) NUMBITS(1) [],
+        rxfull OFFSET(1) NUMBITS(1) [],
+        txempty OFFSET(2) NUMBITS(1) [],
+        txidle OFFSET(3) NUMBITS(1) [],
+        rxidle OFFSET(4) NUMBITS(1) [],
+        rxempty OFFSET(5) NUMBITS(1) []
+    ],
+    rdata [
+        data OFFSET(0) NUMBITS(8) []
+    ],
+    wdata [
+        data OFFSET(0) NUMBITS(8) []
+    ],
+    fifo_ctrl [
+        rxrst OFFSET(0) NUMBITS(1) [],
+        txrst OFFSET(1) NUMBITS(1) [],
+        rxilvl OFFSET(2) NUMBITS(2) [],
+        txilvl OFFSET(5) NUMBITS(2) []
+    ],
+    fifo_status [
+        txlvl OFFSET(0) NUMBITS(5) [],
+        rxlvl OFFSET(16) NUMBITS(5) []
+    ],
+    ovrd [
+        txen OFFSET(0) NUMBITS(1) [],
+        txval OFFSET(1) NUMBITS(1) []
+    ],
+    val [
+        rx OFFSET(0) NUMBITS(16) []
+    ],
+    timeout_ctrl [
+        val OFFSET(0) NUMBITS(23) [],
+        en OFFSET(31) NUMBITS(1) []
+    ]
+];
+
+pub struct Uart<'a> {
+    registers: StaticRef<UartRegisters>,
+    clock_frequency: u32,
+    tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
+    rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,
+
+    tx_buffer: TakeCell<'static, [u8]>,
+    tx_len: Cell<usize>,
+    tx_index: Cell<usize>,
+
+    rx_buffer: TakeCell<'static, [u8]>,
+    rx_len: Cell<usize>,
+}
+
+#[derive(Copy, Clone)]
+pub struct UartParams {
+    pub baud_rate: u32,
+}
+
+impl<'a> Uart<'a> {
+    pub const fn new(base: StaticRef<UartRegisters>, clock_frequency: u32) -> Uart<'a> {
+        Uart {
+            registers: base,
+            clock_frequency: clock_frequency,
+            tx_client: OptionalCell::empty(),
+            rx_client: OptionalCell::empty(),
+            tx_buffer: TakeCell::empty(),
+            tx_len: Cell::new(0),
+            tx_index: Cell::new(0),
+            rx_buffer: TakeCell::empty(),
+            rx_len: Cell::new(0),
+        }
+    }
+
+    fn set_baud_rate(&self, baud_rate: u32) {
+        let regs = self.registers;
+        let uart_ctrl_nco = ((baud_rate as u64) << 20) / self.clock_frequency as u64;
+
+        regs.ctrl
+            .write(ctrl::nco.val((uart_ctrl_nco & 0xffff) as u32));
+        regs.ctrl.modify(ctrl::tx::SET + ctrl::rx::SET);
+
+        regs.fifo_ctrl
+            .write(fifo_ctrl::rxrst::SET + fifo_ctrl::txrst::SET);
+    }
+
+    fn enable_tx_interrupt(&self) {
+        let regs = self.registers;
+
+        regs.intr_enable.modify(intr::tx_empty::SET);
+    }
+
+    fn disable_tx_interrupt(&self) {
+        let regs = self.registers;
+
+        regs.intr_enable.modify(intr::tx_empty::CLEAR);
+        // Clear the interrupt bit (by writing 1), if it happens to be set
+        regs.intr_state.write(intr::tx_empty::SET);
+    }
+
+    fn enable_rx_interrupt(&self) {
+        let regs = self.registers;
+
+        // Generate an interrupt if we get any value in the RX buffer
+        regs.intr_enable.modify(intr::rx_watermark::SET);
+        regs.fifo_ctrl.write(fifo_ctrl::rxilvl.val(0 as u32));
+    }
+
+    fn disable_rx_interrupt(&self) {
+        let regs = self.registers;
+
+        // Generate an interrupt if we get any value in the RX buffer
+        regs.intr_enable.modify(intr::rx_watermark::CLEAR);
+
+        // Clear the interrupt bit (by writing 1), if it happens to be set
+        regs.intr_state.write(intr::rx_watermark::SET);
+    }
+
+    fn tx_progress(&self) {
+        let regs = self.registers;
+        let idx = self.tx_index.get();
+        let len = self.tx_len.get();
+
+        if idx < len {
+            // If we are going to transmit anything, we first need to enable the
+            // TX interrupt. This ensures that we will get an interrupt, where
+            // we can either call the callback from, or continue transmitting
+            // bytes.
+            self.enable_tx_interrupt();
+
+            // Read from the transmit buffer and send bytes to the UART hardware
+            // until either the buffer is empty or the UART hardware is full.
+            self.tx_buffer.map(|tx_buf| {
+                let tx_len = len - idx;
+
+                for i in 0..tx_len {
+                    if regs.status.is_set(status::txfull) {
+                        break;
+                    }
+                    let tx_idx = idx + i;
+                    regs.wdata.write(wdata::data.val(tx_buf[tx_idx] as u32));
+                    self.tx_index.set(tx_idx + 1)
+                }
+            });
+        }
+    }
+
+    pub fn handle_interrupt(&self) {
+        let regs = self.registers;
+        let intrs = regs.intr_state.extract();
+
+        if intrs.is_set(intr::tx_empty) {
+            self.disable_tx_interrupt();
+
+            if self.tx_index.get() == self.tx_len.get() {
+                // We sent everything to the UART hardware, now from an
+                // interrupt callback we can issue the callback.
+                self.tx_client.map(|client| {
+                    self.tx_buffer.take().map(|tx_buf| {
+                        client.transmitted_buffer(tx_buf, self.tx_len.get(), ReturnCode::SUCCESS);
+                    });
+                });
+            } else {
+                // We have more to transmit, so continue in tx_progress().
+                self.tx_progress();
+            }
+        } else if intrs.is_set(intr::rx_watermark) {
+            self.disable_rx_interrupt();
+
+            self.rx_client.map(|client| {
+                self.rx_buffer.take().map(|rx_buf| {
+                    let mut len = 0;
+                    let mut return_code = ReturnCode::SUCCESS;
+
+                    for i in 0..self.rx_len.get() {
+                        rx_buf[i] = regs.rdata.get() as u8;
+                        len = i + 1;
+
+                        if regs.status.is_set(status::rxempty) {
+                            /* RX is empty */
+                            return_code = ReturnCode::ESIZE;
+                            break;
+                        }
+                    }
+
+                    client.received_buffer(rx_buf, len, return_code, uart::Error::None);
+                });
+            });
+        }
+    }
+
+    pub fn transmit_sync(&self, bytes: &[u8]) {
+        let regs = self.registers;
+        for b in bytes.iter() {
+            while regs.status.is_set(status::txfull) {}
+            regs.wdata.write(wdata::data.val(*b as u32));
+        }
+    }
+}
+
+impl<'a> hil::uart::UartData<'a> for Uart<'a> {}
+impl<'a> hil::uart::Uart<'a> for Uart<'a> {}
+
+impl hil::uart::Configure for Uart<'_> {
+    fn configure(&self, params: hil::uart::Parameters) -> ReturnCode {
+        let regs = self.registers;
+        // We can set the baud rate.
+        self.set_baud_rate(params.baud_rate);
+
+        regs.fifo_ctrl
+            .write(fifo_ctrl::rxrst::SET + fifo_ctrl::txrst::SET);
+
+        // Disable all interrupts for now
+        regs.intr_enable.set(0 as u32);
+
+        ReturnCode::SUCCESS
+    }
+}
+
+impl<'a> hil::uart::Transmit<'a> for Uart<'a> {
+    fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
+        self.tx_client.set(client);
+    }
+
+    fn transmit_buffer(
+        &self,
+        tx_data: &'static mut [u8],
+        tx_len: usize,
+    ) -> (ReturnCode, Option<&'static mut [u8]>) {
+        if tx_len == 0 || tx_len > tx_data.len() {
+            (ReturnCode::ESIZE, Some(tx_data))
+        } else if self.tx_buffer.is_some() {
+            (ReturnCode::EBUSY, Some(tx_data))
+        } else {
+            // Save the buffer so we can keep sending it.
+            self.tx_buffer.replace(tx_data);
+            self.tx_len.set(tx_len);
+            self.tx_index.set(0);
+
+            self.tx_progress();
+            (ReturnCode::SUCCESS, None)
+        }
+    }
+
+    fn transmit_abort(&self) -> ReturnCode {
+        ReturnCode::FAIL
+    }
+
+    fn transmit_word(&self, _word: u32) -> ReturnCode {
+        ReturnCode::FAIL
+    }
+}
+
+/* UART receive is not implemented yet, mostly due to a lack of tests avaliable */
+impl<'a> hil::uart::Receive<'a> for Uart<'a> {
+    fn set_receive_client(&self, client: &'a dyn hil::uart::ReceiveClient) {
+        self.rx_client.set(client);
+    }
+
+    fn receive_buffer(
+        &self,
+        rx_buffer: &'static mut [u8],
+        rx_len: usize,
+    ) -> (ReturnCode, Option<&'static mut [u8]>) {
+        if rx_len == 0 || rx_len > rx_buffer.len() {
+            return (ReturnCode::ESIZE, Some(rx_buffer));
+        }
+
+        self.enable_rx_interrupt();
+
+        self.rx_buffer.replace(rx_buffer);
+        self.rx_len.set(rx_len);
+
+        (ReturnCode::SUCCESS, None)
+    }
+
+    fn receive_abort(&self) -> ReturnCode {
+        ReturnCode::FAIL
+    }
+
+    fn receive_word(&self) -> ReturnCode {
+        ReturnCode::FAIL
+    }
+}
diff --git a/config/src/lib.rs b/config/src/lib.rs
index f7a74cc..83a4ecf 100644
--- a/config/src/lib.rs
+++ b/config/src/lib.rs
@@ -32,4 +32,6 @@
 pub const MAILBOX_BASE: u32 = 0x40800000; // TOP_MATCHA_MAILBOX_SEC_BASE_ADDR
 pub const MAILBOX_WTIRQ: u32 = 181;       // kTopMatchaPlicIrqIdMailboxSecWtirq
 pub const MAILBOX_RTIRQ: u32 = 182;       // kTopMatchaPlicIrqIdMailboxSecRtirq
-pub const MAILBOX_EIRQ: u32 = 183;        // kTopMatchaPlicIrqIdMailboxSecEirq
\ No newline at end of file
+pub const MAILBOX_EIRQ: u32 = 183;        // kTopMatchaPlicIrqIdMailboxSecEirq
+
+pub const UART0_BASE_ADDRESS: u32 = 0x40000000;
diff --git a/hal/src/dprintf_hal.rs b/hal/src/dprintf_hal.rs
index d6e5ffb..848a76f 100644
--- a/hal/src/dprintf_hal.rs
+++ b/hal/src/dprintf_hal.rs
@@ -3,12 +3,21 @@
 use core2::io::{Cursor, Write};
 use core::fmt;
 
-pub const TX_BUSY: *const u32 = 0x4000_0010 as *const u32;
-pub const TX_PORT: *mut u32 = 0x4000_0018 as *mut u32;
+// TODO(jtgans|aappleby): b/239714445. Use the actual UART registers defined in
+// opentitan/uart.rs instead of hardcoding them here. Or better: get rid of this
+// gross hack and replace with something less gross. :P
+pub const TX_BUSY: *const u32 = 0x4000_0014 as *const u32;
+pub const TX_PORT: *mut u32 = 0x4000_001c as *mut u32;
 
 pub fn send_sync(buf: &[u8], len: usize) {
     unsafe {
         for i in 0..len {
+            // TODO(jtgans|aappleby): b/239714445. This is a gross hack to
+            // ensure we don't buffer dprintf output for diagnosing early boot
+            // of the system.
+            //
+            // NOTE: if the UART registers change, we're going to have to fix
+            // this here as well!
             while (TX_BUSY.read_volatile() & 1) != 0 {}
             TX_PORT.write_volatile(buf[i] as u32);
         }
diff --git a/platform/Cargo.toml b/platform/Cargo.toml
index e3c1b04..a0ee2e4 100644
--- a/platform/Cargo.toml
+++ b/platform/Cargo.toml
@@ -11,6 +11,7 @@
 capsules   = { path = "../../tock/capsules" }
 kernel     = { path = "../../tock/kernel" }
 lowrisc    = { path = "../../tock/chips/lowrisc" }
+opentitan  = { path = "../chips/opentitan" }
 
 blob_fs         = { path = "../blob_fs" }
 matcha_capsules = { path = "../capsules" }
diff --git a/platform/src/uart.rs b/platform/src/uart.rs
index f9acb19..5ebe18c 100644
--- a/platform/src/uart.rs
+++ b/platform/src/uart.rs
@@ -1,10 +1,10 @@
-//use crate::chip_config::CONFIG;
 use kernel::common::StaticRef;
-use lowrisc::uart::{Uart, UartRegisters};
+use opentitan::uart::{Uart, UartRegisters};
+use matcha_config::*;
 
 pub const UART0_BAUDRATE: u32 = crate::chip::CHIP_UART_BPS;
 
 pub static mut UART0: Uart = Uart::new(UART0_BASE, crate::chip::CHIP_PERIPH_FREQ);
 
 const UART0_BASE: StaticRef<UartRegisters> =
-    unsafe { StaticRef::new(0x4000_0000 as *const UartRegisters) };
+    unsafe { StaticRef::new(UART0_BASE_ADDRESS as *const UartRegisters) };