sys: Simplify enabling EARLY_PRINTF uarts

Support selecting the early uart with "options EARLY_PRINTF=foo" in
the kernel configuration file. This allows us to not have to change
source files when enabling EARLY_PRINTF, simplifying enabling it.

New uart drivers can be enabled by defining a new early_printf_foo
value to be unique, then using "#if CHECK_EARLY_PRINTF(foo)" to decide
when to enable the uart.

While here add pl011 early printf support.

Reviewed by:	imp (earlier version)
Sponsored by:	Arm Ltd
Differential Revision:	https://reviews.freebsd.org/D43360
This commit is contained in:
Andrew Turner 2024-01-08 14:45:51 +00:00
parent 639a626b40
commit 202890922e
6 changed files with 51 additions and 21 deletions

View file

@ -104,18 +104,15 @@
/*
* For debugging purposes
*/
#if 0
#ifdef EARLY_PRINTF
#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
#define UART_REG_OFFSET 0x12000
#if CHECK_EARLY_PRINTF(mvebu)
static void
uart_mvebu_early_putc(int c)
{
volatile uint32_t *tsh;
volatile uint32_t *stat;
tsh = (uint32_t *)(SOCDEV_VA + UART_REG_OFFSET + UART_TSH);
stat = (uint32_t *)(SOCDEV_VA + UART_REG_OFFSET + UART_STAT);
tsh = (uint32_t *)(socdev_va + UART_REG_OFFSET + UART_TSH);
stat = (uint32_t *)(socdev_va + UART_REG_OFFSET + UART_STAT);
while(!(*stat & STAT_TX_RDY))
;
@ -125,8 +122,6 @@ uart_mvebu_early_putc(int c)
early_putc_t *early_putc = uart_mvebu_early_putc;
#endif
#endif
#endif
/*
* Low-level UART interface.

View file

@ -81,9 +81,12 @@ SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RWTUN,
* To use early printf on x86, add the following to your kernel config:
*
* options UART_NS8250_EARLY_PORT=0x3f8
* options EARLY_PRINTF
* options EARLY_PRINTF=ns8250
*/
#if defined(EARLY_PRINTF) && (defined(__amd64__) || defined(__i386__))
#if CHECK_EARLY_PRINTF(ns8250)
#if !(defined(__amd64__) || defined(__i386__))
#error ns8250 early putc is x86 specific as it uses inb/outb
#endif
static void
uart_ns8250_early_putc(int c)
{

View file

@ -249,6 +249,20 @@ uart_pl011_term(struct uart_bas *bas)
{
}
#if CHECK_EARLY_PRINTF(pl011)
static void
uart_pl011_early_putc(int c)
{
volatile uint32_t *fr = (uint32_t *)(socdev_va + UART_FR * 4);
volatile uint32_t *dr = (uint32_t *)(socdev_va + UART_DR * 4);
while ((*fr & FR_TXFF) != 0)
;
*dr = c & 0xff;
}
early_putc_t *early_putc = uart_pl011_early_putc;
#endif /* CHECK_EARLY_PRINTF */
static void
uart_pl011_putc(struct uart_bas *bas, int c)
{

View file

@ -54,18 +54,16 @@ struct snps_softc {
/*
* To use early printf on 64 bits Allwinner SoC, add to kernel config
* options SOCDEV_PA=0x0
* options SOCDEV_VA=0x40000000
* options EARLY_PRINTF
* options EARLY_PRINTF=snps
*
* To use early printf on 32 bits Allwinner SoC, add to kernel config
* options SOCDEV_PA=0x01C00000
* options SOCDEV_VA=0x10000000
* options EARLY_PRINTF
* options EARLY_PRINTF=snps
*
* remove the if 0
*/
#if 0
#ifdef EARLY_PRINTF
#if CHECK_EARLY_PRINTF(snps)
static void
uart_snps_early_putc(int c)
{
@ -73,12 +71,12 @@ uart_snps_early_putc(int c)
volatile uint32_t *tx;
#ifdef ALLWINNER_64
stat = (uint32_t *) (SOCDEV_VA + 0x1C2807C);
tx = (uint32_t *) (SOCDEV_VA + 0x1C28000);
stat = (uint32_t *) (socdev_va + 0x1C2807C);
tx = (uint32_t *) (socdev_va + 0x1C28000);
#endif
#ifdef ALLWINNER_32
stat = (uint32_t *) (SOCDEV_VA + 0x2807C);
tx = (uint32_t *) (SOCDEV_VA + 0x28000);
stat = (uint32_t *) (socdev_va + 0x2807C);
tx = (uint32_t *) (socdev_va + 0x28000);
#endif
while ((*stat & (1 << 2)) == 0)
@ -86,8 +84,7 @@ uart_snps_early_putc(int c)
*tx = c;
}
early_putc_t *early_putc = uart_snps_early_putc;
#endif /* EARLY_PRINTF */
#endif
#endif /* CHECK_EARLY_PRINTF */
static kobj_method_t snps_methods[] = {
KOBJMETHOD(uart_probe, ns8250_bus_probe),

View file

@ -72,6 +72,18 @@
#include <machine/cpu.h>
#include <machine/clock.h>
/*
* Check for 'options EARLY_PRINTF' that may have been used in old kernel
* config files. If you are hitting this error you should update your
* config to use 'options EARLY_PRINTF=<device name>', e.g. with the
* Arm pl011 use:
*
* options EARLY_PRINTF=pl011
*/
#if CHECK_EARLY_PRINTF(1)
#error Update your config to use 'options EARLY_PRINTF=<device name>'
#endif
static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling");
struct cn_device {

View file

@ -208,6 +208,15 @@ critical_exit(void)
#ifdef EARLY_PRINTF
typedef void early_putc_t(int ch);
extern early_putc_t *early_putc;
#define CHECK_EARLY_PRINTF(x) \
__CONCAT(early_printf_, EARLY_PRINTF) == __CONCAT(early_printf_, x)
#define early_printf_1 1
#define early_printf_mvebu 2
#define early_printf_ns8250 3
#define early_printf_pl011 4
#define early_printf_snps 5
#else
#define CHECK_EARLY_PRINTF(x) 0
#endif
int kvprintf(char const *, void (*)(int, void*), void *, int,
__va_list) __printflike(1, 0);