-
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
Separate serial drivers Signed-off-by: Axel Heider <axel.heider@hensoldt.net>
- Loading branch information
Axel Heider
committed
Aug 21, 2023
1 parent
ee69769
commit 2bdf04e
Showing
7 changed files
with
334 additions
and
184 deletions.
There are no files selected for viewing
118 changes: 118 additions & 0 deletions
118
libplatsupport/include/platsupport/driver/ns16550/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,118 @@ | ||
/* | ||
* 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 stated 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); | ||
} |
115 changes: 115 additions & 0 deletions
115
libplatsupport/include/platsupport/driver/pl011/pl011.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,115 @@ | ||
/* | ||
* 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_TXFF BIT(5) | ||
#define PL011_FR_RXFE BIT(4) | ||
|
||
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_write_char(pl011_regs_t *regs, uint8_t c) | ||
{ | ||
/* Caller has to ensure TX FIFO has space */ | ||
regs->dr = c; | ||
} | ||
|
||
static uint8_t pl011_read_char(pl011_regs_t *regs) | ||
{ | ||
return (uint8_t)(regs->dr & 0xFF); | ||
} | ||
|
||
static void pl011_clear_interrupt(pl011_regs_t *regs) | ||
{ | ||
regs->icr = 0x7f0; | ||
} | ||
|
||
static void pl011_init(pl011_regs_t *regs) | ||
{ | ||
regs->imsc = 0x50; | ||
} | ||
|
||
|
||
/* | ||
******************************************************************************* | ||
* UART access helpers | ||
******************************************************************************* | ||
*/ | ||
|
||
/* | ||
* Returns a char from the TX FIFO or EOF if the FIFO is empty. | ||
*/ | ||
int pl011_get_char_or_EOF(pl011_regs_t *regs) | ||
{ | ||
return pl011_is_rx_fifo_empty(regs) ? EOF : pl011_read_char(regs); | ||
} | ||
|
||
/* | ||
* 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 terminal use case. | ||
*/ | ||
void pl011_put_char_blocking(pl011_regs_t *regs, uint8_t c, bool is_auto_cr) | ||
{ | ||
|
||
/* output CR (\r) before LF (\n) automatically if UART is a terminal */ | ||
if ((c == '\n') && is_auto_cr) { | ||
while (pl011_is_tx_fifo_full(regs)) { | ||
/* busy loop */ | ||
} | ||
pl011_write_char(regs, '\r'); | ||
} | ||
|
||
while (pl011_is_tx_fifo_full(regs)) { | ||
/* busy loop */ | ||
} | ||
pl011_write_char(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
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.