blob: 663957e18ffb3d0143f610af60effe6ff0ca001f [file] [log] [blame]
#pragma once
#pragma push_macro("CHERIOT_PLATFORM_CUSTOM_UART")
#define CHERIOT_PLATFORM_CUSTOM_UART
#include_next <platform-uart.hh>
#pragma pop_macro("CHERIOT_PLATFORM_CUSTOM_UART")
/**
* OpenTitan UART
*
* This peripheral's source and documentation can be found at:
* https://github.com/lowRISC/opentitan/tree/ab878b5d3578939a04db72d4ed966a56a869b2ed/hw/ip/uart
*
* Rendered register documentation is served at:
* https://opentitan.org/book/hw/ip/uart/doc/registers.html
*/
struct OpenTitanUart
{
/**
* Interrupt State Register.
*/
uint32_t interruptState;
/**
* Interrupt Enable Register.
*/
uint32_t interruptEnable;
/**
* Interrupt Test Register.
*/
uint32_t interruptTest;
/**
* Alert Test Register (unused).
*/
uint32_t alertTest;
/**
* Control Register.
*/
uint32_t control;
/**
* Status Register.
*/
uint32_t status;
/**
* UART Read Data.
*/
uint32_t readData;
/**
* UART Write Data.
*/
uint32_t writeData;
/**
* UART FIFO Control Register.
*/
uint32_t fifoCtrl;
/**
* UART FIFO Status Register.
*/
uint32_t fifoStatus;
/**
* Transmit Pin Override Control.
*
* Gives direct software control over the transmit pin state.
*/
uint32_t override;
/**
* UART Oversampled Values.
*/
uint32_t values;
/**
* UART Receive Timeout Control.
*/
uint32_t timeoutControl;
/// Control Register Fields
enum : uint32_t
{
/// Sets the BAUD clock rate from the numerically controlled oscillator.
ControlNco = 0xff << 16,
/// Set the number of character times the line must be low
/// which will be interpreted as a break.
ControlReceiveBreakLevel = 0b11 << 8,
/// When set, odd parity is used, otherwise even parity is used.
ControlParityOdd = 1 << 7,
/// Enable party on both transmit and receive lines.
ControlParityEnable = 1 << 6,
/// When set, incoming received bits are forwarded to the transmit line.
ControlLineLoopback = 1 << 5,
/// When set, outgoing transmitted bits are routed back the receiving
/// line.
ControlSystemLoopback = 1 << 4,
/// Enable the noise filter on the receiving line.
ControlNoiseFilter = 1 << 2,
/// Enable receiving bits.
ControlReceiveEnable = 1 << 1,
/// Enable transmitting bits.
ControlTransmitEnable = 1 << 0,
};
void init(unsigned baudRate = 115'200) volatile
{
// Nco = 2^20 * baud rate / cpu frequency
const uint32_t Nco =
((static_cast<uint64_t>(baudRate) << 20) / CPU_TIMER_HZ);
// Set the baud rate and enable transmit & receive
control = (Nco << 16) | ControlTransmitEnable | ControlReceiveEnable;
}
[[gnu::always_inline]] uint16_t transmit_fifo_level() volatile
{
return fifoStatus & 0xff;
}
[[gnu::always_inline]] uint16_t receive_fifo_level() volatile
{
return ((fifoStatus >> 16) & 0xff);
}
bool can_write() volatile
{
return transmit_fifo_level() < 32;
}
bool can_read() volatile
{
return receive_fifo_level() > 0;
}
/**
* Write one byte, blocking until the byte is written.
*/
void blocking_write(uint8_t byte) volatile
{
while (!can_write()) {}
writeData = byte;
}
/**
* Read one byte, blocking until a byte is available.
*/
uint8_t blocking_read() volatile
{
while (!can_read()) {}
return readData;
}
};
#ifndef CHERIOT_PLATFORM_CUSTOM_UART
using Uart = OpenTitanUart;
static_assert(IsUart<Uart>);
#endif