-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libplatsupport: separate drivers from platforms
Signed-off-by: Axel Heider <axel.heider@hensoldt.net>
- Loading branch information
Axel Heider
committed
Jan 11, 2024
1 parent
970c79d
commit 8fc8520
Showing
7 changed files
with
358 additions
and
194 deletions.
There are no files selected for viewing
117 changes: 117 additions & 0 deletions
117
libplatsupport/include/platsupport/driver/uart_ns16550.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Copyright 2022, HENSOLDT Cyber GmbH | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
* | ||
* Driver for a 16550 compatible UART. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <stdio.h> | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <utils/arith.h> | ||
|
||
#define NS16550_IER_ERBFI BIT(0) /* Enable Received Data Available Interrupt */ | ||
#define NS16550_IER_ETBEI BIT(1) /* Enable Transmitter Holding Register Empty Interrupt */ | ||
#define NS16550_IER_ELSI BIT(2) /* Enable Receiver Line Status Interrupt */ | ||
#define NS16550_IER_EDSSI BIT(3) /* Enable MODEM Status Interrupt */ | ||
|
||
#define NS16550_FCR_ENABLE_FIFOS BIT(0) | ||
#define NS16550_FCR_RESET_RX_FIFO BIT(1) | ||
#define NS16550_FCR_RESET_TX_FIFO BIT(2) | ||
#define NS16550_FCR_TRIGGER_1 (0u << 6) | ||
#define NS16550_FCR_TRIGGER_4 (1u << 6) | ||
#define NS16550_FCR_TRIGGER_8 (2u << 6) | ||
#define NS16550_FCR_TRIGGER_14 (3u << 6) | ||
|
||
#define NS16550_LCR_DLAB BIT(7) /* Divisor Latch Access */ | ||
|
||
#define NS16550_LSR_DR BIT(0) /* Data Ready */ | ||
#define NS16550_LSR_THRE BIT(5) /* Transmitter Holding Register Empty */ | ||
|
||
/* There are different NS16550 hardware implementations. The classic size of | ||
* each register is just one byte, but some implementations started to use | ||
* 32-bit registers, as this fits better with the natural alignment. | ||
*/ | ||
#if defined(NS16550_WITH_REG32) | ||
typedef volatile uint32_t ns16550_reg_t; | ||
#elif defined(NS16550_WITH_REG8) | ||
typedef volatile uint8_t ns16550_reg_t; | ||
#else | ||
#error "define NS16550_WITH_REG[8|32]" | ||
#endif | ||
|
||
typedef struct { | ||
/* 0x00 */ | ||
ns16550_reg_t rbr_dll_thr; /* Receiver Buffer Register (Read Only) | ||
* Divisor Latch (LSB) | ||
* Transmitter Holding Register (Write Only) | ||
*/ | ||
/* 0x01 or 0x04 */ | ||
ns16550_reg_t dlm_ier; /* Divisor Latch (MSB) | ||
* Interrupt Enable Register | ||
*/ | ||
/* 0x02 or 0x08 */ | ||
ns16550_reg_t iir_fcr; /* Interrupt Identification Register (Read Only) | ||
* FIFO Control Register (Write Only) | ||
*/ | ||
/* 0x03 or 0x0c */ | ||
ns16550_reg_t lcr; /* Line Control Register */ | ||
/* 0x04 or 0x10 */ | ||
ns16550_reg_t mcr; /* MODEM Control Register */ | ||
/* 0x05 or 0x14 */ | ||
ns16550_reg_t lsr; /* Line Status Register */ | ||
/* 0x06 or 0x18 */ | ||
ns16550_reg_t msr; /* MODEM Status Register */ | ||
/* 0x07 or 0x1c */ | ||
} ns16550_regs_t; | ||
|
||
|
||
/* | ||
******************************************************************************* | ||
* UART access primitives | ||
******************************************************************************* | ||
*/ | ||
|
||
static bool ns16550_is_tx_empty(ns16550_regs_t *regs) | ||
{ | ||
/* The THRE bit is set when the FIFO is fully empty. There seems no way to | ||
* detect if the FIFO is partially empty only, so we can't implement a | ||
* "tx_ready" check. | ||
*/ | ||
return (0 != (regs->lsr & NS16550_LSR_THRE)); | ||
} | ||
|
||
static void ns16550_tx_byte(ns16550_regs_t *regs, uint8_t byte) | ||
{ | ||
/* Caller has to ensure TX FIFO is ready */ | ||
regs->rbr_dll_thr = byte; | ||
} | ||
|
||
static bool ns16550_is_rx_empty(ns16550_regs_t *regs) | ||
{ | ||
return (0 == (regs->lsr & NS16550_LSR_DR)); | ||
} | ||
|
||
static int ns16550_rx_byte(ns16550_regs_t *regs) | ||
{ | ||
/* Caller has to ensure RX FIFO has data */ | ||
return regs->rbr_dll_thr; | ||
} | ||
|
||
|
||
/* | ||
******************************************************************************* | ||
* UART access helpers | ||
******************************************************************************* | ||
*/ | ||
|
||
/* | ||
* Returns a char from the TX FIFO or EOF if the FIFO is empty. | ||
*/ | ||
static int ns16550_get_char_or_EOF(ns16550_regs_t *regs) | ||
{ | ||
return ns16550_is_rx_empty(regs) ? EOF : ns16550_rx_byte(regs); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Copyright 2022, HENSOLDT Cyber GmbH | ||
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
* | ||
* Driver for a ARM PL011 UART. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <stdio.h> | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <utils/arith.h> | ||
|
||
#define PL011_FR_BUSY BIT(3) /* UART busy */ | ||
#define PL011_FR_RXFE BIT(4) /* Receive FIFO empty */ | ||
#define PL011_FR_TXFF BIT(5) /* Transmit FIFO full */ | ||
#define PL011_FR_RXFF BIT(6) /* Receive FIFO full */ | ||
#define PL011_FR_TXFE BIT(7) /* Transmit FIFO empty */ | ||
|
||
#define PL011_IMSC_RXIM BIT(4) /* RX interrupt */ | ||
#define PL011_IMSC_TXIM BIT(5) /* TX interrupt */ | ||
#define PL011_IMSC_RTIM BIT(6) /* RX timeout interrupt */ | ||
#define PL011_IMSC_OEIM BIT(10) /* Overrun timeout */ | ||
|
||
#define PL011_CR_UARTEN BIT(0) /* UART enable */ | ||
#define PL011_CR_TXE BIT(8) /* Transmit enable */ | ||
#define PL011_CR_RXE BIT(9) /* Receive enable */ | ||
|
||
// 0111 1111 0000 | ||
#define PL011_ICR_RXIC BIT(4) | ||
#define PL011_ICR_TXIC BIT(5) | ||
|
||
typedef volatile struct { | ||
uint32_t dr; /* 0x00 */ | ||
uint32_t _rfu_04; /* 0x04 */ | ||
uint32_t _rfu_08; /* 0x08 */ | ||
uint32_t _rfu_0c; /* 0x0c */ | ||
uint32_t _rfu_10; /* 0x10 */ | ||
uint32_t _rfu_14; /* 0x14 */ | ||
uint32_t fr; /* 0x18 */ | ||
uint32_t _rfu_1c; /* 0x1c */ | ||
uint32_t _rfu_20; /* 0x20 */ | ||
uint32_t _rfu_24; /* 0x24 */ | ||
uint32_t _rfu_28; /* 0x28 */ | ||
uint32_t _rfu_2c; /* 0x2c */ | ||
uint32_t _rfu_30; /* 0x30 */ | ||
uint32_t _rfu_34; /* 0x34 */ | ||
uint32_t imsc; /* 0x38 */ | ||
uint32_t _rfu_3c; /* 0x3c */ | ||
uint32_t _rfu_40; /* 0x40 */ | ||
uint32_t icr; /* 0x44 */ | ||
uint32_t _rfu_48; /* 0x48 */ | ||
uint32_t _rfu_4c; /* 0x4c */ | ||
} pl011_regs_t; | ||
|
||
|
||
/* | ||
******************************************************************************* | ||
* UART access primitives | ||
******************************************************************************* | ||
*/ | ||
|
||
static bool pl011_is_rx_fifo_empty(pl011_regs_t *regs) | ||
{ | ||
return (0 != (regs->fr & PL011_FR_RXFE)); | ||
} | ||
|
||
static bool pl011_is_tx_fifo_full(pl011_regs_t *regs) | ||
{ | ||
return (0 != (regs->fr & PL011_FR_TXFF)); | ||
} | ||
|
||
static void pl011_tx_byte(pl011_regs_t *regs, uint8_t c) | ||
{ | ||
/* Caller has to ensure TX FIFO has space */ | ||
regs->dr = c; | ||
} | ||
|
||
static uint8_t pl011_rx_byte(pl011_regs_t *regs) | ||
{ | ||
return (uint8_t)(regs->dr & 0xFF); | ||
} | ||
|
||
static void pl011_clear_interrupt(pl011_regs_t *regs) | ||
{ | ||
regs->icr = 0x7f0; | ||
} | ||
|
||
/* | ||
******************************************************************************* | ||
* UART access helpers | ||
******************************************************************************* | ||
*/ | ||
|
||
/* | ||
* Returns a char from the TX FIFO or EOF if the FIFO is empty. | ||
*/ | ||
static int pl011_get_char_or_EOF(pl011_regs_t *regs) | ||
{ | ||
return pl011_is_rx_fifo_empty(regs) ? EOF : pl011_rx_byte(regs); | ||
} | ||
|
||
/* | ||
* Block until there is space in the TX FIFO, then outputs the char. | ||
*/ | ||
static void pl011_put_char_blocking(pl011_regs_t *regs, uint8_t c) | ||
{ | ||
while (pl011_is_tx_fifo_full(regs)) { | ||
/* busy loop */ | ||
} | ||
pl011_tx_byte(regs, c); | ||
} | ||
|
||
/* | ||
* Block until there is space in the TX FIFO, then outputs the char. Optionally | ||
* output a CR (\r) first in case of LF (\n) to support the terminal use case. | ||
*/ | ||
static void pl011_put_char_blocking_auto_cr(pl011_regs_t *regs, uint8_t c, | ||
bool is_auto_cr) | ||
{ | ||
if ((c == '\n') && is_auto_cr) { | ||
pl011_put_char_blocking(regs, '\r'); | ||
} | ||
pl011_put_char_blocking(regs, c); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.