system/kernel: Rework uart management
Change-Id: I6cb31760519c8ba4542d217d6e68439602eda558 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4356 Reviewed-by: Jessica Hamilton <[email protected]> Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
committed by
Alex von Gluck IV
parent
fbd2589b8c
commit
d637e0bec1
@@ -11,17 +11,19 @@
|
||||
|
||||
|
||||
#include <util/FixedWidthPointer.h>
|
||||
#include <boot/uart.h>
|
||||
|
||||
|
||||
#define _PACKED __attribute__((packed))
|
||||
|
||||
|
||||
// kernel args
|
||||
typedef struct {
|
||||
int cpu_type;
|
||||
int fpu_type;
|
||||
int mmu_type;
|
||||
int platform;
|
||||
int machine; // platform specific machine type
|
||||
int cpu_type;
|
||||
int fpu_type;
|
||||
int mmu_type;
|
||||
int platform;
|
||||
int machine; // platform specific machine type
|
||||
|
||||
// architecture specific
|
||||
uint32 phys_pgdir;
|
||||
@@ -31,6 +33,8 @@ typedef struct {
|
||||
// needed for UEFI, otherwise kernel acpi support can't find ACPI root
|
||||
FixedWidthPointer<void> acpi_root;
|
||||
FixedWidthPointer<void> fdt;
|
||||
|
||||
uart_info uart;
|
||||
} _PACKED arch_kernel_args;
|
||||
|
||||
#endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2012 Haiku, Inc. All rights reserved.
|
||||
* Copyright 2011-2021 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <arch/generic/debug_uart.h>
|
||||
|
||||
|
||||
#define UART_KIND_PL011 "pl011"
|
||||
|
||||
|
||||
class ArchUARTPL011 : public DebugUART {
|
||||
public:
|
||||
ArchUARTPL011(addr_t base, int64 clock);
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "debug_uart.h"
|
||||
|
||||
|
||||
#define UART_KIND_8250 "8250"
|
||||
|
||||
|
||||
class DebugUART8250 : public DebugUART {
|
||||
public:
|
||||
DebugUART8250(addr_t base, int64 clock);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
#include <util/FixedWidthPointer.h>
|
||||
#include <boot/uart.h>
|
||||
|
||||
|
||||
#define _PACKED __attribute__((packed))
|
||||
@@ -24,21 +25,6 @@ enum {
|
||||
kPlatformSbi,
|
||||
};
|
||||
|
||||
enum {
|
||||
kUartKindNone,
|
||||
kUartKind8250,
|
||||
kUartKindSifive,
|
||||
kUartKindPl011,
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32 kind;
|
||||
addr_range regs;
|
||||
uint32 irq;
|
||||
int64 clock;
|
||||
} _PACKED ArchUart;
|
||||
|
||||
|
||||
// kernel args
|
||||
typedef struct {
|
||||
@@ -62,7 +48,8 @@ typedef struct {
|
||||
addr_range htif;
|
||||
addr_range plic;
|
||||
addr_range clint;
|
||||
ArchUart uart;
|
||||
|
||||
uart_info uart;
|
||||
} _PACKED arch_kernel_args;
|
||||
|
||||
#endif /* KERNEL_ARCH_RISCV64_KERNEL_ARGS_H */
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include <arch/generic/debug_uart.h>
|
||||
|
||||
|
||||
#define UART_KIND_SIFIVE "sifive"
|
||||
|
||||
|
||||
// UARTSifiveRegs.ie, ip
|
||||
enum {
|
||||
kUartSifiveTxwm = 1 << 0,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2021 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef KERNEL_BOOT_UART_H
|
||||
#define KERNEL_BOOT_UART_H
|
||||
|
||||
|
||||
#include <boot/addr_range.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
char kind[32];
|
||||
addr_range regs;
|
||||
uint32 irq;
|
||||
int64 clock;
|
||||
} __attribute__((packed)) uart_info;
|
||||
|
||||
|
||||
#endif /* KERNEL_BOOT_UART_H */
|
||||
@@ -10,9 +10,9 @@
|
||||
#include <arch_kernel.h>
|
||||
#include <boot/platform.h>
|
||||
#include <boot/stage2.h>
|
||||
|
||||
#include <efi/types.h>
|
||||
#include <efi/boot-services.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mmu.h"
|
||||
#include "efi_platform.h"
|
||||
@@ -419,10 +419,12 @@ arch_mmu_generate_post_efi_page_tables(size_t memory_map_size,
|
||||
MapAddrRange(gKernelArgs.arch_args.clint, (1 << pteRead) | (1 << pteWrite));
|
||||
MapAddrRange(gKernelArgs.arch_args.htif, (1 << pteRead) | (1 << pteWrite));
|
||||
MapAddrRange(gKernelArgs.arch_args.plic, (1 << pteRead) | (1 << pteWrite));
|
||||
if (gKernelArgs.arch_args.uart.kind != kUartKindNone) {
|
||||
// !!!
|
||||
MapRange(gKernelArgs.arch_args.uart.regs.start, gKernelArgs.arch_args.uart.regs.start, gKernelArgs.arch_args.uart.regs.size, (1 << pteRead) | (1 << pteWrite));
|
||||
|
||||
if (strcmp(gKernelArgs.arch_args.uart.kind, "") != 0) {
|
||||
MapRange(gKernelArgs.arch_args.uart.regs.start,
|
||||
gKernelArgs.arch_args.uart.regs.start,
|
||||
gKernelArgs.arch_args.uart.regs.size,
|
||||
(1 << pteRead) | (1 << pteWrite));
|
||||
MapAddrRange(gKernelArgs.arch_args.uart.regs,
|
||||
(1 << pteRead) | (1 << pteWrite));
|
||||
}
|
||||
|
||||
@@ -7,13 +7,19 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <arch_smp.h>
|
||||
#include <arch/generic/debug_uart_8250.h>
|
||||
#if defined(__riscv)
|
||||
# include <arch/riscv64/arch_uart_sifive.h>
|
||||
#elif defined(__ARM__) || defined(__ARM64__)
|
||||
# include <arch/arm/arch_uart_pl011.h>
|
||||
#endif
|
||||
#include <boot/addr_range.h>
|
||||
#include <boot/platform.h>
|
||||
#include <boot/stage2.h>
|
||||
#include <boot/uart.h>
|
||||
#include <string.h>
|
||||
#include <kernel/kernel.h>
|
||||
#include <arch_smp.h>
|
||||
#include <arch/generic/debug_uart_8250.h>
|
||||
#include <arch/riscv64/arch_uart_sifive.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
@@ -37,7 +43,6 @@ static uint64 sTimerFrequency = 10000000;
|
||||
|
||||
static addr_range sPlic = {0};
|
||||
static addr_range sClint = {0};
|
||||
static ArchUart sUart = {.kind = kUartKindNone};
|
||||
|
||||
|
||||
static void WriteString(const char *str) {dprintf("%s", str);}
|
||||
@@ -46,6 +51,29 @@ static void WriteHex(uint64_t val, int n) {dprintf("%08" B_PRIx64, val);}
|
||||
static void WriteInt(int64_t val) {dprintf("%" B_PRId64, val);}
|
||||
|
||||
|
||||
template <typename T> DebugUART*
|
||||
get_uart(addr_t base, int64 clock) {
|
||||
static char buffer[sizeof(T)];
|
||||
return new(buffer) T(base, clock);
|
||||
}
|
||||
|
||||
|
||||
const struct supported_uarts {
|
||||
const char* dtb_compat;
|
||||
const char* kind;
|
||||
DebugUART* (*uart_driver_init)(addr_t base, int64 clock);
|
||||
} kSupportedUarts[] = {
|
||||
{ "ns16550a", UART_KIND_8250, &get_uart<DebugUART8250> },
|
||||
{ "ns16550", UART_KIND_8250, &get_uart<DebugUART8250> },
|
||||
#if defined(__riscv)
|
||||
{ "sifive,uart0", UART_KIND_SIFIVE, &get_uart<ArchUARTSifive> },
|
||||
#elif defined(__ARM__) || defined(__ARM64__)
|
||||
{ "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
|
||||
{ "arm,primecell", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static void WriteStringList(const char* prop, size_t size)
|
||||
{
|
||||
bool first = true;
|
||||
@@ -341,47 +369,48 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells,
|
||||
int compatibleLen;
|
||||
const char* compatible = (const char*)fdt_getprop(fdt, node,
|
||||
"compatible", &compatibleLen);
|
||||
if (compatible == NULL) return;
|
||||
|
||||
if (compatible == NULL)
|
||||
return;
|
||||
|
||||
if (HasFdtString(compatible, compatibleLen, "riscv,clint0")) {
|
||||
GetReg(fdt, node, addressCells, sizeCells, 0, sClint);
|
||||
} else if (
|
||||
HasFdtString(compatible, compatibleLen, "riscv,plic0") ||
|
||||
HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0")
|
||||
) {
|
||||
GetReg(fdt, node, addressCells, sizeCells, 0, sPlic);
|
||||
} else if (
|
||||
sUart.kind == kUartKindNone && (
|
||||
HasFdtString(compatible, compatibleLen, "ns16550a") ||
|
||||
HasFdtString(compatible, compatibleLen, "sifive,uart0") ||
|
||||
HasFdtString(compatible, compatibleLen, "arm,pl011")
|
||||
)
|
||||
) {
|
||||
if (HasFdtString(compatible, compatibleLen, "ns16550a"))
|
||||
sUart.kind = kUartKind8250;
|
||||
else if (HasFdtString(compatible, compatibleLen, "sifive,uart0"))
|
||||
sUart.kind = kUartKindSifive;
|
||||
else if (HasFdtString(compatible, compatibleLen, "arm,pl011"))
|
||||
sUart.kind = kUartKindPl011;
|
||||
|
||||
GetReg(fdt, node, addressCells, sizeCells, 0, sUart.regs);
|
||||
sUart.irq = GetInterrupt(fdt, node, interruptCells);
|
||||
const void* prop = fdt_getprop(fdt, node, "clock-frequency", NULL);
|
||||
sUart.clock = (prop == NULL) ? 0 : fdt32_to_cpu(*(uint32*)prop);
|
||||
|
||||
switch (sUart.kind) {
|
||||
case kUartKind8250:
|
||||
gUART = arch_get_uart_8250(sUart.regs.start, sUart.clock);
|
||||
break;
|
||||
case kUartKindSifive:
|
||||
gUART = arch_get_uart_sifive(sUart.regs.start, sUart.clock);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (gUART != NULL)
|
||||
gUART->InitEarly();
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasFdtString(compatible, compatibleLen, "riscv,plic0")
|
||||
|| HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0")) {
|
||||
GetReg(fdt, node, addressCells, sizeCells, 0, sPlic);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We should check for the "chosen" uart and prioritize that one
|
||||
|
||||
uart_info &uart = gKernelArgs.arch_args.uart;
|
||||
if (uart.kind[0] != 0)
|
||||
return;
|
||||
|
||||
// check for a uart if we don't have one
|
||||
for (uint32 i = 0; i < B_COUNT_OF(kSupportedUarts); i++) {
|
||||
if (HasFdtString(compatible, compatibleLen,
|
||||
kSupportedUarts[i].dtb_compat)) {
|
||||
|
||||
memcpy(uart.kind, kSupportedUarts[i].kind,
|
||||
sizeof(uart.kind));
|
||||
|
||||
GetReg(fdt, node, addressCells, sizeCells, 0, uart.regs);
|
||||
uart.irq = GetInterrupt(fdt, node, interruptCells);
|
||||
const void* prop = fdt_getprop(fdt, node, "clock-frequency", NULL);
|
||||
|
||||
uart.clock = (prop == NULL) ? 0 : fdt32_to_cpu(*(uint32*)prop);
|
||||
|
||||
gUART = kSupportedUarts[i].uart_driver_init(uart.regs.start,
|
||||
uart.clock);
|
||||
}
|
||||
}
|
||||
|
||||
if (gUART != NULL)
|
||||
gUART->InitEarly();
|
||||
}
|
||||
|
||||
|
||||
@@ -391,6 +420,9 @@ dtb_init()
|
||||
efi_configuration_table *table = kSystemTable->ConfigurationTable;
|
||||
size_t entries = kSystemTable->NumberOfTableEntries;
|
||||
|
||||
// Ensure uart is empty before we scan for one
|
||||
memset(&gKernelArgs.arch_args.uart, 0, sizeof(uart_info));
|
||||
|
||||
INFO("Probing for device trees from UEFI...\n");
|
||||
|
||||
// Try to find an FDT
|
||||
@@ -450,19 +482,16 @@ dtb_set_kernel_args()
|
||||
gKernelArgs.arch_args.clint = sClint;
|
||||
#endif
|
||||
#if defined(__ARM__) || defined(__riscv)
|
||||
gKernelArgs.arch_args.uart = sUart;
|
||||
dprintf("UART:\n");
|
||||
dprintf(" kind: ");
|
||||
switch (sUart.kind) {
|
||||
case kUartKindNone: dprintf("none"); break;
|
||||
case kUartKind8250: dprintf("8250"); break;
|
||||
case kUartKindSifive: dprintf("sifive"); break;
|
||||
case kUartKindPl011: dprintf("pl011"); break;
|
||||
default: ;
|
||||
uart_info &uart = gKernelArgs.arch_args.uart;
|
||||
dprintf("Chosen UART:\n");
|
||||
if (uart.kind[0] == 0) {
|
||||
dprintf("kind: None!\n");
|
||||
} else {
|
||||
dprintf(" kind: %s", uart.kind);
|
||||
dprintf("\n");
|
||||
dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", uart.regs.start, uart.regs.size);
|
||||
dprintf(" irq: %" B_PRIu32 "\n", uart.irq);
|
||||
dprintf(" clock: %" B_PRIu64 "\n", uart.clock);
|
||||
}
|
||||
dprintf("\n");
|
||||
dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", sUart.regs.start, sUart.regs.size);
|
||||
dprintf(" irq: %" B_PRIu32 "\n", sUart.irq);
|
||||
dprintf(" clock: %" B_PRIu64 "\n", sUart.clock);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -103,17 +103,14 @@ arch_debug_serial_early_boot_message(const char *string)
|
||||
status_t
|
||||
arch_debug_console_init(kernel_args *args)
|
||||
{
|
||||
switch (args->arch_args.uart.kind) {
|
||||
case kUartKind8250:
|
||||
sArchDebugUART = arch_get_uart_8250(args->arch_args.uart.regs.start,
|
||||
args->arch_args.uart.clock);
|
||||
break;
|
||||
case kUartKindSifive:
|
||||
sArchDebugUART = arch_get_uart_sifive(args->arch_args.uart.regs.start,
|
||||
args->arch_args.uart.clock);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
if (strncmp(args->arch_args.uart.kind, UART_KIND_8250,
|
||||
sizeof(args->arch_args.uart.kind)) == 0) {
|
||||
sArchDebugUART = arch_get_uart_8250(args->arch_args.uart.regs.start,
|
||||
args->arch_args.uart.clock);
|
||||
} else if (strncmp(args->arch_args.uart.kind, UART_KIND_SIFIVE,
|
||||
sizeof(args->arch_args.uart.kind)) == 0) {
|
||||
sArchDebugUART = arch_get_uart_sifive(args->arch_args.uart.regs.start,
|
||||
args->arch_args.uart.clock);
|
||||
}
|
||||
|
||||
if (sArchDebugUART != NULL)
|
||||
|
||||
Reference in New Issue
Block a user