Skip to content

Commit

Permalink
libplatsupport: separate drivers from platforms
Browse files Browse the repository at this point in the history
Signed-off-by: Axel Heider <axel.heider@hensoldt.net>
  • Loading branch information
Axel Heider committed Jan 11, 2024
1 parent 970c79d commit 6e1c59d
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 194 deletions.
117 changes: 117 additions & 0 deletions libplatsupport/include/platsupport/driver/uart_ns16550.h
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);
}
128 changes: 128 additions & 0 deletions libplatsupport/include/platsupport/driver/uart_pl011.h
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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
* Copyright 2022, HENSOLDT Cyber GmbH
*
* SPDX-License-Identifier: BSD-2-Clause
*
*
* QEMU RISC-V virt emulates a 16550 compatible UART.
*
*/

#pragma once

#include <autoconf.h>

/* This information is taken from the device tree. */
#define UART0_PADDR 0x10000000
#define UART0_IRQ 10
Expand All @@ -22,40 +24,3 @@ enum chardev_id {

#define DEFAULT_SERIAL_PADDR UART0_PADDR
#define DEFAULT_SERIAL_INTERRUPT UART0_IRQ

/* QEMU RISC-V virt emulates a 16550 compatible UART. */

#define UART_IER_ERBFI BIT(0) /* Enable Received Data Available Interrupt */
#define UART_IER_ETBEI BIT(1) /* Enable Transmitter Holding Register Empty Interrupt */
#define UART_IER_ELSI BIT(2) /* Enable Receiver Line Status Interrupt */
#define UART_IER_EDSSI BIT(3) /* Enable MODEM Status Interrupt */

#define UART_FCR_ENABLE_FIFOS BIT(0)
#define UART_FCR_RESET_RX_FIFO BIT(1)
#define UART_FCR_RESET_TX_FIFO BIT(2)
#define UART_FCR_TRIGGER_1 (0u << 6)
#define UART_FCR_TRIGGER_4 (1u << 6)
#define UART_FCR_TRIGGER_8 (2u << 6)
#define UART_FCR_TRIGGER_14 (3u << 6)

#define UART_LCR_DLAB BIT(7) /* Divisor Latch Access */

#define UART_LSR_DR BIT(0) /* Data Ready */
#define UART_LSR_THRE BIT(5) /* Transmitter Holding Register Empty */

typedef volatile struct {
uint8_t rbr_dll_thr; /* 0x00 Receiver Buffer Register (Read Only)
* Divisor Latch (LSB)
* Transmitter Holding Register (Write Only)
*/
uint8_t dlm_ier; /* 0x04 Divisor Latch (MSB)
* Interrupt Enable Register
*/
uint8_t iir_fcr; /* 0x08 Interrupt Identification Register (Read Only)
* FIFO Control Register (Write Only)
*/
uint8_t lcr; /* 0xC Line Control Register */
uint8_t mcr; /* 0x10 MODEM Control Register */
uint8_t lsr; /* 0x14 Line Status Register */
uint8_t msr; /* 0x18 MODEM Status Register */
} uart_regs_t;
Loading

0 comments on commit 6e1c59d

Please sign in to comment.