| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_UART_H_ |
| #define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_UART_H_ |
| |
| /** |
| * @file |
| * @brief <a href="/hw/ip/uart/doc/">UART</a> Device Interface Functions |
| */ |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/dif/dif_warn_unused_result.h" |
| |
| // Header Extern Guard (so header can be used from C and C++) |
| #ifdef __cplusplus |
| extern "C" { |
| #endif // __cplusplus |
| |
| // The size of UART TX and RX FIFOs in bytes. |
| extern const uint32_t kDifUartFifoSizeBytes; |
| |
| /** |
| * UART interrupt configuration. |
| * |
| * Enumeration used to enable, disable, test and query the UART interrupts. |
| * Please see the comportability specification for more information: |
| * https://docs.opentitan.org/doc/rm/comportability_specification/ |
| */ |
| typedef enum dif_uart_interrupt { |
| kDifUartInterruptTxWatermark = 0, /**< TX FIFO dipped below watermark */ |
| kDifUartInterruptRxWatermark, /**< RX FIFO reached high watermark */ |
| kDifUartInterruptTxEmpty, /**< TX FIFO empty */ |
| kDifUartInterruptRxOverflow, /**< RX FIFO overflow */ |
| kDifUartInterruptRxFrameErr, /**< RX framing error */ |
| kDifUartInterruptRxBreakErr, /**< RX break condition */ |
| kDifUartInterruptRxTimeout, /**< RX FIFO timeout (not empty in a set time) */ |
| kDifUartInterruptRxParityErr, /**< RX parity error detection */ |
| kDifUartInterruptLast = |
| kDifUartInterruptRxParityErr, /**< \internal Final UART interrupt */ |
| } dif_uart_interrupt_t; |
| |
| /** |
| * TX and RX FIFO depth configuration. |
| * |
| * Enumeration used to set the upper limit of bytes to queue. |
| */ |
| typedef enum dif_uart_watermark { |
| kDifUartWatermarkByte1 = 0, /**< 1 byte. */ |
| kDifUartWatermarkByte4, /**< 4 bytes. */ |
| kDifUartWatermarkByte8, /**< 8 bytes. */ |
| kDifUartWatermarkByte16, /**< 16 bytes. */ |
| kDifUartWatermarkByte30, /**< 30 bytes. */ |
| kDifUartWatermarkLast = |
| kDifUartWatermarkByte30, /**< \internal Final UART watermark. */ |
| } dif_uart_watermark_t; |
| |
| /** |
| * UART TX/RX FIFO reset enumeration. |
| */ |
| typedef enum dif_uart_fifo_reset { |
| kDifUartFifoResetRx = 0, /**< Reset RX FIFO. */ |
| kDifUartFifoResetTx, /**< Reset TX FIFO. */ |
| kDifUartFifoResetAll, /**< All above. */ |
| } dif_uart_fifo_reset_t; |
| |
| /** |
| * UART System/Line loopback enumeration. |
| */ |
| typedef enum dif_uart_loopback { |
| kDifUartLoopbackSystem = 0, /**< Outgoing TX bits received through RX. */ |
| kDifUartLoopbackLine, /**< Incoming RX bits are forwarded to TX. */ |
| } dif_uart_loopback_t; |
| |
| /** |
| * Generic enable/disable enumeration. |
| * |
| * Enumeration used to enable/disable bits, flags, ... |
| */ |
| typedef enum dif_uart_enable { |
| kDifUartDisable = 0, /**< disable. */ |
| kDifUartEnable, /**< enable. */ |
| } dif_uart_enable_t; |
| |
| /** |
| * UART parity enumeration |
| * |
| * Enumeration used to convey parity information |
| */ |
| typedef enum dif_uart_parity { |
| kDifUartParityOdd = 0, /**< odd. */ |
| kDifUartParityEven, /**< even. */ |
| } dif_uart_parity_t; |
| |
| /** |
| * UART configuration data. |
| * |
| * The fundamental data used to configure an UART instance. |
| */ |
| typedef struct dif_uart_config { |
| uint32_t baudrate; /**< Requested baudrate. */ |
| uint32_t clk_freq_hz; /**< Input clock frequency. */ |
| dif_uart_enable_t parity_enable; /**< Enable parity check. */ |
| dif_uart_parity_t parity; /**< Set parity (even by default). */ |
| } dif_uart_config_t; |
| |
| /** |
| * UART instance state. |
| * |
| * UART persistent data that is required by all UART API. `base_address` must |
| * be initialised by the caller, before passing into the UART DIF init routine. |
| */ |
| typedef struct dif_uart { |
| mmio_region_t base_addr; /**< UART base address. */ |
| } dif_uart_t; |
| |
| /** |
| * Uart generic status codes. |
| * |
| * These error codes can be used by any function. However if a function |
| * requires additional status codes, it must define a set of status codes to |
| * be used exclusicvely by such function. |
| */ |
| typedef enum dif_uart_result { |
| kDifUartOk = 0, /**< Success. */ |
| kDifUartError, /**< General error. */ |
| kDifUartBadArg, /**< Input parameter is not valid. */ |
| } dif_uart_result_t; |
| |
| /** |
| * Uart initialisation routine status codes. |
| */ |
| typedef enum dif_uart_config_result { |
| kDifUartConfigOk = 0, /**< Success. */ |
| kDifUartConfigError, /**< General error. */ |
| kDifUartConfigBadArg, /**< Input parameter is not valid. */ |
| kDifUartConfigBadConfig, /**< Configuration is not valid. */ |
| kDifUartConfigBadNco, /**< Calculated NCO is not valid. */ |
| } dif_uart_config_result_t; |
| |
| /** |
| * Initialise an instance of UART. |
| * |
| * Initialise UART instance using the configuration data in `config`. |
| * Information that must be retained, and is required to program UART must be |
| * stored in `uart`. |
| * @param base_addr Base address of an instance of UART IP block. |
| * @param config UART configuration data. |
| * @param uart UART state data. |
| * @return `dif_uart_config_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_config_result_t dif_uart_init(mmio_region_t base_addr, |
| const dif_uart_config_t *config, |
| dif_uart_t *uart); |
| |
| /** |
| * Configure an instance of UART. |
| * |
| * Configure UART using the configuration data in `config`. This operation |
| * performs fundamental configuration. |
| * |
| * @param uart UART state data. |
| * @param config UART configuration data. |
| * @return `dif_uart_config_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_config_result_t dif_uart_configure(const dif_uart_t *uart, |
| const dif_uart_config_t *config); |
| |
| /** |
| * Set the RX FIFO watermark. |
| * |
| * Set the RX FIFO watermark, is only useful when the corresponding interrupt |
| * is enabled. When the queued RX FIFO number of bytes rises to or above this |
| * level, the RX watermark interrupt is raised. |
| * |
| * @param uart UART state data. |
| * @param watermark RX FIFO watermark. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_watermark_rx_set(const dif_uart_t *uart, |
| dif_uart_watermark_t watermark); |
| |
| /** |
| * Set the TX FIFO watermark. |
| * |
| * Set the TX FIFO watermark, is only useful when the corresponding interrupt |
| * is enabled. When the queued TX FIFO number of bytes falls to or below this |
| * level, the TX watermark interrupt is raised. |
| * |
| * @param uart UART state data. |
| * @param watermark TX FIFO watermark. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_watermark_tx_set(const dif_uart_t *uart, |
| dif_uart_watermark_t watermark); |
| |
| /** |
| * UART send bytes. |
| * |
| * Non-blocking UART send bytes routine. Can be used from inside an UART ISR. |
| * This function attempts to write `bytes_requested` number of bytes to the |
| * UART TX FIFO from `bytes_requested`, and passes `bytes_written` back to |
| * the caller. `bytes_written` is optional, NULL should be passed in if the |
| * value is not needed. |
| * |
| * @param uart UART state data. |
| * @param data Data to be written. |
| * @param bytes_requested Number of bytes requested to be written by the caller. |
| * @param bytes_written Number of bytes written (optional). |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_bytes_send(const dif_uart_t *uart, |
| const uint8_t *data, |
| size_t bytes_requested, |
| size_t *bytes_written); |
| |
| /** |
| * UART receive bytes. |
| * |
| * Non-blocking UART receive bytes routine. Can be used from inside an UART ISR. |
| * This function attempts to read `bytes_requested` number of bytes from the |
| * UART RX FIFO into `data`, and passes `bytes_read` back to the caller. |
| * `bytes_read` is optional, NULL should be passed in if the value is not |
| * needed. |
| * |
| * @param uart UART state data. |
| * @param bytes_requested Number of bytes requested to be read by the caller. |
| * @param data Data to be read. |
| * @param bytes_read Number of bytes read (optional). |
| * @return `dif_uart_result_t` |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_bytes_receive(const dif_uart_t *uart, |
| size_t bytes_requested, uint8_t *data, |
| size_t *bytes_read); |
| |
| /** |
| * Transmit a single UART byte (polled). |
| * |
| * Transmit a single UART byte `byte`. This operation is polled, and will busy |
| * wait until a byte has been sent. Must not be used inside an ISR. |
| * |
| * @param uart UART state data. |
| * @param byte Byte to be transmitted. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_byte_send_polled(const dif_uart_t *uart, |
| uint8_t byte); |
| |
| /** |
| * Receive a single UART byte (polled). |
| * |
| * Receive a single UART byte and store it in `byte`. This operation is polled, |
| * and will busy wait until a byte has been read. Must not be used inside an |
| * ISR. |
| * |
| * @param uart UART state data. |
| * @param byte Received byte. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_byte_receive_polled(const dif_uart_t *uart, |
| uint8_t *byte); |
| |
| /** |
| * UART get requested IRQ state. |
| * |
| * Get the state of the requested IRQ in `irq_type`. |
| * |
| * @param uart UART state data. |
| * @param irq_type IRQ to get the state of. |
| * @param state IRQ state passed back to the caller. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_irq_state_get(const dif_uart_t *uart, |
| dif_uart_interrupt_t irq_type, |
| dif_uart_enable_t *state); |
| /** |
| * UART clear requested IRQ state. |
| * |
| * Clear the state of the requested IRQ in `irq_type`. Primary use of this |
| * function is to de-assert the interrupt after it has been serviced. |
| * |
| * @param uart UART state data. |
| * @param irq_type IRQ to be de-asserted. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_irq_state_clear(const dif_uart_t *uart, |
| dif_uart_interrupt_t irq_type); |
| |
| /** |
| * UART disable interrupts. |
| * |
| * Disable generation of all UART interrupts, and pass previous interrupt state |
| * in `state` back to the caller. Parameter `state` is ignored if NULL. |
| * |
| * @param uart UART state data. |
| * @param state IRQ state passed back to the caller. |
| * @return 'dif_uart_result_t'. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_irqs_disable(const dif_uart_t *uart, |
| uint32_t *state); |
| |
| /** |
| * UART restore IRQ state. |
| * |
| * Restore previous UART IRQ state. This function is used to restore the |
| * UART interrupt state prior to `dif_uart_irqs_disable` function call. |
| * |
| * @param uart UART state data. |
| * @param state IRQ state to restore. |
| * @return 'dif_uart_result_t'. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_irqs_restore(const dif_uart_t *uart, uint32_t state); |
| |
| /** |
| * UART interrupt control. |
| * |
| * Enable/disable an UART interrupt specified in `enable`. |
| * |
| * @param uart UART state data. |
| * @param irq_type UART interrupt type. |
| * @param enable enable or disable the interrupt. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_irq_enable(const dif_uart_t *uart, |
| dif_uart_interrupt_t irq_type, |
| dif_uart_enable_t enable); |
| |
| /** |
| * UART interrupt force. |
| * |
| * Force interrupt specified in `irq_type`. |
| * |
| * @param uart UART state data. |
| * @param irq_type UART interrupt type to be forced. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_irq_force(const dif_uart_t *uart, |
| dif_uart_interrupt_t irq_type); |
| |
| /** |
| * UART RX bytes available. |
| * |
| * Get the number of bytes available to be read from the UART RX FIFO. This |
| * function can be used to check FIFO full and empty conditions. |
| * |
| * @param uart UART state data. |
| * @param num_bytes Number of bytes available to be read. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_rx_bytes_available(const dif_uart_t *uart, |
| size_t *num_bytes); |
| |
| /** |
| * UART TX bytes available. |
| * |
| * Get the number of bytes available to be written to the UART TX FIFO. This |
| * function can be used to check FIFO full and empty conditions. |
| * |
| * @param uart UART state data. |
| * @param num_bytes Number of bytes available to be written. |
| * @return `dif_uart_result_t`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| dif_uart_result_t dif_uart_tx_bytes_available(const dif_uart_t *uart, |
| size_t *num_bytes); |
| /** |
| * UART TX reset RX/TX FIFO. |
| * |
| * Reset both FIFOs, or the requested one. |
| * |
| * @param uart UART state data. |
| * @param reset FIFO to reset (RX or TX). |
| * @return `dif_uart_result_t`. |
| */ |
| dif_uart_result_t dif_uart_fifo_reset(const dif_uart_t *uart, |
| dif_uart_fifo_reset_t reset); |
| |
| /** |
| * UART enable/disable transmit/receive loopback. |
| * |
| * This API can be used for testing purpose. For example, to validate transmit |
| * and receive routines. |
| * |
| * Loopback should only be enabled when device is in the IDLE state to prevent |
| * data loss/coruption. Behaviour depends on the `loopback` parameter: |
| * - `kDifUartLoopbackSystem`: |
| * Receives the data that is being transmitted. No external data can be |
| * received (from the RX line). When enabled the TX line goes high. |
| * - `kDifUartLoopbackLine`: |
| * Transmits the data that is being received. No internal data can be |
| * sent out (from the TX FIFO). When enabled the RX line goes high. |
| * |
| * @param uart UART state data. |
| * @param loopback Loopback type (transmit/receive). |
| * @param enable Enable/disable control flag. |
| * @return `dif_uart_result_t`. |
| */ |
| dif_uart_result_t dif_uart_loopback_set(const dif_uart_t *uart, |
| dif_uart_loopback_t loopback, |
| dif_uart_enable_t enable); |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| #endif // __cplusplus |
| |
| #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_UART_H_ |