From 476346ac62ce45d15462ac08a10f59389e3dc2c3 Mon Sep 17 00:00:00 2001 From: urnenfeld Date: Sat, 26 Mar 2022 13:07:28 +0100 Subject: [PATCH] arm64: Enable DTB handling, Introduce LINFlex UART driver Change-Id: Ib643545271700e6ff4a4037d0e797355194927e7 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5149 Tested-by: Commit checker robot Reviewed-by: David Karoly Reviewed-by: Fredrik Holmqvist --- .../kernel/arch/arm64/arch_kernel_args.h | 18 +- .../kernel/arch/arm64/arch_uart_linflex.h | 554 ++++++++++++++++++ src/system/boot/arch/arm64/Jamfile | 19 +- src/system/boot/platform/efi/Jamfile | 6 +- .../boot/platform/efi/arch/arm64/Jamfile | 3 + .../boot/platform/efi/arch/arm64/arch_dtb.cpp | 97 +++ src/system/boot/platform/efi/dtb.cpp | 15 +- src/system/kernel/arch/arm64/Jamfile | 12 +- .../kernel/arch/arm64/arch_debug_console.cpp | 50 +- .../kernel/arch/arm64/arch_uart_linflex.cpp | 200 +++++++ 10 files changed, 954 insertions(+), 20 deletions(-) create mode 100644 headers/private/kernel/arch/arm64/arch_uart_linflex.h create mode 100644 src/system/boot/platform/efi/arch/arm64/arch_dtb.cpp create mode 100644 src/system/kernel/arch/arm64/arch_uart_linflex.cpp diff --git a/headers/private/kernel/arch/arm64/arch_kernel_args.h b/headers/private/kernel/arch/arm64/arch_kernel_args.h index c8f644eb95..dfeb8bc037 100644 --- a/headers/private/kernel/arch/arm64/arch_kernel_args.h +++ b/headers/private/kernel/arch/arm64/arch_kernel_args.h @@ -11,6 +11,7 @@ #include +#include #include @@ -18,15 +19,16 @@ typedef struct { - // needed for UEFI, otherwise kernel acpi support can't find ACPI root - FixedWidthPointer acpi_root; -// TODO: Deal with this later in the port -// FixedWidthPointer fdt; -// uart_info uart; + uint64 phys_pgdir; + uint64 vir_pgdir; + uint64 next_pagetable; - uint64 phys_pgdir; - uint64 vir_pgdir; - uint64 next_pagetable; + // needed for UEFI, otherwise kernel acpi support can't find ACPI root + FixedWidthPointer acpi_root; + FixedWidthPointer fdt; + + uart_info uart; + intc_info interrupt_controller; } _PACKED arch_kernel_args; diff --git a/headers/private/kernel/arch/arm64/arch_uart_linflex.h b/headers/private/kernel/arch/arm64/arch_uart_linflex.h new file mode 100644 index 0000000000..f3314c2b52 --- /dev/null +++ b/headers/private/kernel/arch/arm64/arch_uart_linflex.h @@ -0,0 +1,554 @@ +/* + * Copyright 2022 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Ruiz Dorantes, oliver.ruiz.dorantes@gmail.com + */ +#ifndef __DEV_UART_LINFLEX_H +#define __DEV_UART_LINFLEX_H + + +#include +#include +#include + +#include + + +#define UART_KIND_LINFLEX "linflex" + +namespace LINFlexRegisters { + typedef union { /* LINFLEX LIN Control 1 (Base+0x0000) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32 CCD:1; + vuint32 CFD:1; + vuint32 LASE:1; + vuint32 AWUM:1; + vuint32 MBL:4; + vuint32 BF:1; + vuint32 SFTM:1; + vuint32 LBKM:1; + vuint32 MME:1; + vuint32 SBDT:1; + vuint32 RBLM:1; + vuint32 SLEEP:1; + vuint32 INIT:1; + #endif + #if __BYTE_ORDER == __LITTLE_ENDIAN + vuint32 INIT:1; + vuint32 SLEEP:1; + vuint32 RBLM:1; + vuint32 SBDT:1; + vuint32 MME:1; + vuint32 LBKM:1; + vuint32 SFTM:1; + vuint32 BF:1; + vuint32 MBL:4; + vuint32 AWUM:1; + vuint32 LASE:1; + vuint32 CFD:1; + vuint32 CCD:1; + vuint32 :16; + #endif + } B; + } LINCR1_register; + + + typedef union { /* LINFLEX LIN Interrupt Enable (Base+0x0004) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32 SZIE:1; + vuint32 OCIE:1; + vuint32 BEIE:1; + vuint32 CEIE:1; + vuint32 HEIE:1; + vuint32:2; + vuint32 FEIE:1; + vuint32 BOIE:1; + vuint32 LSIE:1; + vuint32 WUIE:1; + vuint32 DBFIE:1; + vuint32 DBEIE:1; + vuint32 DRIE:1; + vuint32 DTIE:1; + vuint32 HRIE:1; + #endif + } B; + } LINIER_register; + + + typedef union { /* LINFLEX LIN Status (Base+0x0008) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32 LINS:4; + vuint32:2; + vuint32 RMB:1; + vuint32:1; + vuint32 RBSY:1; + vuint32 RPS:1; + vuint32 WUF:1; + vuint32 DBFF:1; + vuint32 DBEF:1; + vuint32 DRF:1; + vuint32 DTF:1; + vuint32 HRF:1; + #endif + } B; + } LINSR_register; + + + typedef union { /* LINFLEX LIN Error Status (Base+0x000C) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32 SZF:1; + vuint32 OCF:1; + vuint32 BEF:1; + vuint32 CEF:1; + vuint32 SFEF:1; + vuint32 BDEF:1; + vuint32 IDPEF:1; + vuint32 FEF:1; + vuint32 BOF:1; + vuint32:6; + vuint32 NF:1; + #endif + } B; + } LINESR_register; + + + typedef union { /* LINFLEX UART Mode Control (Base+0x0010) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32:1; + vuint32 TDFL:2; + vuint32:1; + vuint32 RDFL:2; + vuint32 RFBM:1; + vuint32 TFBM:1; + vuint32 WL1:1; + vuint32 PC1:1; + vuint32 RXEN:1; + vuint32 TXEN:1; + vuint32 PC0:1; + vuint32 PCE:1; + vuint32 WL:1; + vuint32 UART:1; + #endif + #if __BYTE_ORDER == __LITTLE_ENDIAN + vuint32 UART:1; + vuint32 WL:1; + vuint32 PCE:1; + vuint32 PC0:1; + vuint32 TXEN:1; + vuint32 RXEN:1; + vuint32 PC1:1; + vuint32 WL1:1; + vuint32 TFBM:1; + vuint32 RFBM:1; + vuint32 RDFL:2; + vuint32:1; + vuint32 TDFL:2; + vuint32:1; + vuint32 :16; + #endif + } B; + } UARTCR_register; + + + typedef union { /* LINFLEX UART Mode Status (Base+0x0014) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32 SZF:1; + vuint32 OCF:1; + vuint32 PE:4; /*Can check all 4 RX'd bytes at once with array*/ + vuint32 RMB:1; + vuint32 FEF:1; + vuint32 BOF:1; + vuint32 RPS:1; + vuint32 WUF:1; + vuint32:2; + vuint32 DRF:1; + vuint32 DTF:1; + vuint32 NF:1; + #endif + #if __BYTE_ORDER == __LITTLE_ENDIAN + vuint32 NF:1; + vuint32 DTF:1; + vuint32 DRF:1; + vuint32:2; + vuint32 WUF:1; + vuint32 RPS:1; + vuint32 BOF:1; + vuint32 FEF:1; + vuint32 RMB:1; + vuint32 PE:4; /*Can check all 4 RX'd bytes at once with array*/ + vuint32 OCF:1; + vuint32 SZF:1; + vuint32 :16; + #endif + } B; + } UARTSR_register; + + + typedef union { /* LINFLEX TimeOut Control Status ((Base+0x0018)*/ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32:5; + vuint32 LTOM:1; + vuint32 IOT:1; + vuint32 TOCE:1; + vuint32 CNT:8; + #endif + } B; + } LINTCSR_register; + + + typedef union { /* LINFLEX LIN Output Compare (Base+0x001C) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :16; + vuint32 OC2:8; + vuint32 OC1:8; + #endif + } B; + } LINOCR_register; + + + typedef union { /* LINFLEX LIN Timeout Control (Base+0x0020) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 :20; + vuint32 RTO:4; + vuint32:1; + vuint32 HTO:7; + #endif + } B; + } LINTOCR_register; + + + typedef union { /* LINFLEX LIN Fractional Baud Rate (+0x0024) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:28; + vuint32 DIV_F:4; + #endif + } B; + } LINFBRR_register; + + + typedef union { /* LINFLEX LIN Integer Baud Rate (Base+0x0028) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:19; + vuint32 DIV_M:13; + #endif + } B; + } LINIBRR_register; + + + typedef union { /* LINFLEX LIN Checksum Field (Base+0x002C) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:24; + vuint32 CF:8; + #endif + } B; + } LINCFR_register; + + + typedef union { /* LINFLEX LIN Control 2 (Base+0x0030) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:17; + vuint32 IOBE:1; + vuint32 IOPE:1; + vuint32 WURQ:1; + vuint32 DDRQ:1; + vuint32 DTRQ:1; + vuint32 ABRQ:1; + vuint32 HTRQ:1; + vuint32:8; + #endif + } B; + } LINCR2_register; + + + typedef union { /* LINFLEX Buffer Identifier (Base+0x0034) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:16; + vuint32 DFL:6; + vuint32 DIR:1; + vuint32 CCS:1; + vuint32:2; + vuint32 ID:6; + #endif + } B; + } BIDR_register; + + + typedef union { /* LINFLEX Buffer Data LSB (Base+0x0038) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 DATA3:8; + vuint32 DATA2:8; + vuint32 DATA1:8; + vuint32 DATA0:8; + #endif + } B; + } BDRL_register; + + + typedef union { /* LINFLEX Buffer Data MSB (Base+0x003C */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32 DATA7:8; + vuint32 DATA6:8; + vuint32 DATA5:8; + vuint32 DATA4:8; + #endif + } B; + } BDRM_register; + + + typedef union { /* LINFLEX Identifier Filter Enable (+0x0040) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:24; + vuint32 FACT:8; + #endif + } B; + } IFER_register; + + + typedef union { /* LINFLEX Identifier Filter Match Index (+0x0044)*/ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:28; + vuint32 IFMI:4; + #endif + } B; + } IFMI_register; + + + typedef union { /* LINFLEX Identifier Filter Mode (Base+0x0048) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:28; + vuint32 IFM:4; + #endif + } B; + } IFMR_register; + + + typedef union { /* LINFLEX Identifier Filter Control 0..15 (+0x004C-0x0088)*/ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:16; + vuint32:3; + vuint32 DFL:3; + vuint32 DIR:1; + vuint32 CCS:1; + vuint32:2; + vuint32 ID:6; + #endif + } B; + } IFCR_register; + + + typedef union { /* LINFLEX Global Counter (+0x008C) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:26; + vuint32 TDFBM:1; + vuint32 RDFBM:1; + vuint32 TDLIS:1; + vuint32 RDLIS:1; + vuint32 STOP:1; + vuint32 SR:1; + #endif + } B; + } GCR_register; + + + typedef union { /* LINFLEX UART preset timeout (+0x0090) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:20; + vuint32 PTO:12; + #endif + } B; + } UARTPTO_register; + + + typedef union { /* LINFLEX UART current timeout (+0x0094) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:20; + vuint32 CTO:12; + #endif + } B; + } UARTCTO_register; + + + typedef union { /* LINFLEX DMA Tx Enable (+0x0098) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:16; + vuint32 DTE15:1; + vuint32 DTE14:1; + vuint32 DTE13:1; + vuint32 DTE12:1; + vuint32 DTE11:1; + vuint32 DTE10:1; + vuint32 DTE9:1; + vuint32 DTE8:1; + vuint32 DTE7:1; + vuint32 DTE6:1; + vuint32 DTE5:1; + vuint32 DTE4:1; + vuint32 DTE3:1; + vuint32 DTE2:1; + vuint32 DTE1:1; + vuint32 DTE0:1; + #endif + } B; + } DMATXE_register; + + + typedef union { /* LINFLEX DMA RX Enable (+0x009C) */ + vuint32 R; + struct { + #if __BYTE_ORDER == __BIG_ENDIAN + vuint32:16; + vuint32 DRE15:1; + vuint32 DRE14:1; + vuint32 DRE13:1; + vuint32 DRE12:1; + vuint32 DRE11:1; + vuint32 DRE10:1; + vuint32 DRE9:1; + vuint32 DRE8:1; + vuint32 DRE7:1; + vuint32 DRE6:1; + vuint32 DRE5:1; + vuint32 DRE4:1; + vuint32 DRE3:1; + vuint32 DRE2:1; + vuint32 DRE1:1; + vuint32 DRE0:1; + #endif + } B; + } DMARXE_register; + + // Helper to deal with w1c (Write 1 to clear) register fields + template + REG BitfieldRegister() { + REG reg; + reg.R = 0; + return reg; + } + + typedef struct { + LINCR1_register LINCR1; /* LINFLEX LIN Control 1 (Base+0x0000) */ + LINIER_register LINIER; /* LINFLEX LIN Interrupt Enable (Base+0x0004) */ + LINSR_register LINSR; /* LINFLEX LIN Status (Base+0x0008) */ + LINESR_register LINESR; /* LINFLEX LIN Error Status (Base+0x000C) */ + UARTCR_register UARTCR; /* LINFLEX UART Mode Control (Base+0x0010) */ + UARTSR_register UARTSR; /* LINFLEX UART Mode Status (Base+0x0014) */ + LINTCSR_register LINTCSR; /* LINFLEX TimeOut Control Status ((Base+0x0018)*/ + LINOCR_register LINOCR; /* LINFLEX LIN Output Compare (Base+0x001C) */ + LINTOCR_register LINTOCR; /* LINFLEX LIN Timeout Control (Base+0x0020) */ + LINFBRR_register LINFBRR; /* LINFLEX LIN Fractional Baud Rate (+0x0024) */ + LINIBRR_register LINIBRR; /* LINFLEX LIN Integer Baud Rate (Base+0x0028) */ + LINCFR_register LINCFR; /* LINFLEX LIN Checksum Field (Base+0x002C) */ + LINCR2_register LINCR2; /* LINFLEX LIN Control 2 (Base+0x0030) */ + BIDR_register BIDR; /* LINFLEX Buffer Identifier (Base+0x0034) */ + BDRL_register BDRL; /* LINFLEX Buffer Data LSB (Base+0x0038) */ + BDRM_register BDRM; /* LINFLEX Buffer Data MSB (Base+0x003C */ + IFER_register IFER; /* LINFLEX Identifier Filter Enable (+0x0040) */ + IFMI_register IFMI; /* LINFLEX Identifier Filter Match Index (+0x0044)*/ + IFMR_register IFMR; /* LINFLEX Identifier Filter Mode (Base+0x0048) */ + IFCR_register IFCR[16]; /* LINFLEX Identifier Filter Control 0..15 (+0x004C-0x0088)*/ + GCR_register GCR; /* LINFLEX Global Counter (+0x008C) */ + UARTPTO_register UARTPTO; /* LINFLEX UART preset timeout (+0x0090) */ + UARTCTO_register UARTCTO; /* LINFLEX UART current timeout (+0x0094) */ + DMATXE_register DMATXE; /* LINFLEX DMA Tx Enable (+0x0098) */ + DMARXE_register DMARXE; /* LINFLEX DMA RX Enable (+0x009C) */ + } LINFlex; +} + + +class ArchUARTlinflex : public DebugUART { + +public: + ArchUARTlinflex(addr_t base, int64 clock); + ~ArchUARTlinflex(); + + void InitEarly(); + void InitPort(uint32 baud); + + void Enable(); + void Disable(); + + int PutChar(char c); + int GetChar(bool wait); + + void FlushTx(); + void FlushRx(); + +private: + template + void Out(TA* reg, TO value) { + *(volatile TO*)(reg) = value; + } + + template + TI In(TA* reg) { + return *(volatile TI*)(reg); + } + + virtual void Barrier(); + LINFlexRegisters::LINFlex* LinflexCell() { + return reinterpret_cast(Base()); + } +}; + + +ArchUARTlinflex *arch_get_uart_linflex(addr_t base, int64 clock); + + +#endif diff --git a/src/system/boot/arch/arm64/Jamfile b/src/system/boot/arch/arm64/Jamfile index 339df36d8b..f906ad7ed5 100644 --- a/src/system/boot/arch/arm64/Jamfile +++ b/src/system/boot/arch/arm64/Jamfile @@ -4,6 +4,16 @@ local platform ; local kernelArchSources = arch_elf.cpp + arch_uart_linflex.cpp +; + +local kernelArchReusableSources = + arch_uart_pl011.cpp +; + +local kernelGenericDriverSources = + debug_uart.cpp + debug_uart_8250.cpp ; kernelLibGenericSources = @@ -23,16 +33,23 @@ for platform in [ MultiBootSubDirSetup efi ] { BootMergeObject [ FGristFiles boot_arch_$(TARGET_KERNEL_ARCH).o ] : + $(kernelGenericDriverSources) $(kernelArchSources) + $(kernelArchReusableSources) $(kernelLibArchSources) $(kernelLibGenericSources) $(librootOsArchSources) + arch_cpu.cpp : # additional flags ; + SEARCH on [ FGristFiles $(kernelGenericDriverSources) ] + = [ FDirName $(HAIKU_TOP) src system kernel arch generic ] ; SEARCH on [ FGristFiles $(kernelArchSources) ] - = [ FDirName $(HAIKU_TOP) src system kernel arch arm64 ] ; + = [ FDirName $(HAIKU_TOP) src system kernel arch $(TARGET_KERNEL_ARCH_DIR) ] ; + SEARCH on [ FGristFiles $(kernelArchReusableSources) ] + = [ FDirName $(HAIKU_TOP) src system kernel arch arm ] ; SEARCH on [ FGristFiles $(kernelLibGenericSources) ] = [ FDirName $(HAIKU_TOP) src system libroot posix string arch generic ] ; SEARCH on [ FGristFiles $(kernelLibArchSources) ] diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index d1c016aec8..6ee2846a93 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -5,7 +5,7 @@ UsePrivateHeaders [ FDirName kernel platform ] ; UsePrivateHeaders [ FDirName kernel boot platform efi ] ; UsePrivateHeaders [ FDirName kernel boot arch $(TARGET_KERNEL_ARCH_DIR) ] ; -if $(TARGET_ARCH) != x86_64 && $(TARGET_ARCH) != x86 && $(TARGET_ARCH) != arm64 { +if $(TARGET_ARCH) != x86_64 && $(TARGET_ARCH) != x86 { UseLibraryHeaders [ FDirName libfdt ] ; } @@ -14,7 +14,7 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel partitioning_systems gpt ; { local defines = _BOOT_MODE _BOOT_PLATFORM_EFI ; - if $(TARGET_ARCH) != x86_64 && $(TARGET_ARCH) != x86 && $(TARGET_ARCH) != arm64 { + if $(TARGET_ARCH) != x86_64 && $(TARGET_ARCH) != x86 { defines += _BOOT_FDT_SUPPORT ; } @@ -42,7 +42,7 @@ local platform_src = local support_libs ; -if $(TARGET_ARCH) != x86_64 && $(TARGET_ARCH) != x86 && $(TARGET_ARCH) != arm64 { +if $(TARGET_ARCH) != x86_64 && $(TARGET_ARCH) != x86 { support_libs += boot_fdt.a ; platform_src += dtb.cpp ; } diff --git a/src/system/boot/platform/efi/arch/arm64/Jamfile b/src/system/boot/platform/efi/arch/arm64/Jamfile index 105b3593f5..06db6b312d 100644 --- a/src/system/boot/platform/efi/arch/arm64/Jamfile +++ b/src/system/boot/platform/efi/arch/arm64/Jamfile @@ -2,6 +2,8 @@ SubDir HAIKU_TOP src system boot platform efi arch arm64 ; SubDirHdrs $(HAIKU_TOP) src system boot platform efi ; +UseLibraryHeaders [ FDirName libfdt ] ; + UsePrivateHeaders [ FDirName kernel platform ] ; UsePrivateHeaders [ FDirName kernel boot platform efi ] ; @@ -27,6 +29,7 @@ for platform in [ MultiBootSubDirSetup efi ] { arch_start.cpp arch_timer.cpp arch_cache.cpp + arch_dtb.cpp ; BootMergeObject boot_platform_efi_arm64.o : diff --git a/src/system/boot/platform/efi/arch/arm64/arch_dtb.cpp b/src/system/boot/platform/efi/arch/arm64/arch_dtb.cpp new file mode 100644 index 0000000000..5f7f4ca6cf --- /dev/null +++ b/src/system/boot/platform/efi/arch/arm64/arch_dtb.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2019-2021 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck IV + */ + +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +#include "dtb.h" + +/* TODO: Code taken from ARM port just for building purposes */ + +/* The potential interrupt controoller would be present in the dts as: + * compatible = "arm,gic-v3"; + */ +const struct supported_interrupt_controllers { + const char* dtb_compat; + const char* kind; +} kSupportedInterruptControllers[] = { + { "arm,cortex-a9-gic", INTC_KIND_GICV1 }, + { "arm,cortex-a15-gic", INTC_KIND_GICV2 }, + { "ti,omap3-intc", INTC_KIND_OMAP3 }, + { "marvell,pxa-intc", INTC_KIND_PXA }, +}; + + +void +arch_handle_fdt(const void* fdt, int node) +{ + const char* deviceType = (const char*)fdt_getprop(fdt, node, + "device_type", NULL); + + if (deviceType != NULL) { + if (strcmp(deviceType, "cpu") == 0) { + platform_cpu_info* info = NULL; + arch_smp_register_cpu(&info); + if (info == NULL) + return; + info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node, + "reg", NULL)); + dprintf("cpu\n"); + dprintf(" id: %" B_PRIu32 "\n", info->id); + + } + } + + int compatibleLen; + const char* compatible = (const char*)fdt_getprop(fdt, node, + "compatible", &compatibleLen); + + if (compatible == NULL) + return; + + intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller; + if (interrupt_controller.kind[0] == 0) { + for (uint32 i = 0; i < B_COUNT_OF(kSupportedInterruptControllers); i++) { + if (dtb_has_fdt_string(compatible, compatibleLen, + kSupportedInterruptControllers[i].dtb_compat)) { + + memcpy(interrupt_controller.kind, kSupportedInterruptControllers[i].kind, + sizeof(interrupt_controller.kind)); + + dtb_get_reg(fdt, node, 0, interrupt_controller.regs1); + dtb_get_reg(fdt, node, 1, interrupt_controller.regs2); + } + } + } +} + + +void +arch_dtb_set_kernel_args(void) +{ + intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller; + dprintf("Chosen interrupt controller:\n"); + if (interrupt_controller.kind[0] == 0) { + dprintf("kind: None!\n"); + } else { + dprintf(" kind: %s\n", interrupt_controller.kind); + dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", + interrupt_controller.regs1.start, + interrupt_controller.regs1.size); + dprintf(" %#" B_PRIx64 ", %#" B_PRIx64 "\n", + interrupt_controller.regs2.start, + interrupt_controller.regs2.size); + } +} diff --git a/src/system/boot/platform/efi/dtb.cpp b/src/system/boot/platform/efi/dtb.cpp index a297a0369d..fa49022e7a 100644 --- a/src/system/boot/platform/efi/dtb.cpp +++ b/src/system/boot/platform/efi/dtb.cpp @@ -15,9 +15,14 @@ #include #if defined(__riscv) # include -#elif defined(__ARM__) || defined(__aarch64__) +#elif defined(__ARM__) # include +#elif defined(__aarch64__) +# include +# include #endif + + #include #include #include @@ -64,10 +69,14 @@ const struct supported_uarts { { "ns16550", UART_KIND_8250, &get_uart }, #if defined(__riscv) { "sifive,uart0", UART_KIND_SIFIVE, &get_uart }, -#elif defined(__ARM__) || defined(__aarch64__) +#elif defined(__ARM__) { "arm,pl011", UART_KIND_PL011, &get_uart }, { "snps,dw-apb-uart", UART_KIND_8250, &get_uart }, - { "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart }, + { "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart } +#elif defined(__aarch64__) + { "arm,pl011", UART_KIND_PL011, &get_uart }, + { "fsl,s32-linflexuart", UART_KIND_LINFLEX, &get_uart }, + { "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart } #endif }; diff --git a/src/system/kernel/arch/arm64/Jamfile b/src/system/kernel/arch/arm64/Jamfile index eab0f7f9c8..30f1845cf0 100644 --- a/src/system/kernel/arch/arm64/Jamfile +++ b/src/system/kernel/arch/arm64/Jamfile @@ -3,6 +3,9 @@ SubDir HAIKU_TOP src system kernel arch arm64 ; SubDirHdrs $(SUBDIR) $(DOTDOT) generic ; UsePrivateKernelHeaders ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) arm ] ; + KernelMergeObject kernel_arch_arm64.o : arch_elf.cpp arch_int.cpp @@ -20,7 +23,14 @@ KernelMergeObject kernel_arch_arm64.o : arch_real_time_clock.cpp arch_platform.cpp arch_asm.S - + + # Serial UART and drivers + debug_uart.cpp +# debug_uart_8250.cpp +# arch_uart_8250_omap.cpp + arch_uart_pl011.cpp + arch_uart_linflex.cpp + : $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused : diff --git a/src/system/kernel/arch/arm64/arch_debug_console.cpp b/src/system/kernel/arch/arm64/arch_debug_console.cpp index c1e841b75a..07b72c76d5 100644 --- a/src/system/kernel/arch/arm64/arch_debug_console.cpp +++ b/src/system/kernel/arch/arm64/arch_debug_console.cpp @@ -4,12 +4,19 @@ */ #include #include +// #include +// #include +#include +#include #include #include #include #include +static DebugUART *sArchDebugUART = NULL; + + void arch_debug_remove_interrupt_handler(uint32 line) { @@ -25,34 +32,43 @@ arch_debug_install_interrupt_handlers(void) int arch_debug_blue_screen_try_getchar(void) { - return -1; + // TODO: Implement correctly! + return arch_debug_blue_screen_getchar(); } char arch_debug_blue_screen_getchar(void) { - return -1; + return arch_debug_serial_getchar(); } int arch_debug_serial_try_getchar(void) { - return -1; + // TODO: Implement correctly! + return arch_debug_serial_getchar(); } char arch_debug_serial_getchar(void) { - return -1; + if (sArchDebugUART == NULL) + return '\0'; + + return sArchDebugUART->GetChar(false); } void arch_debug_serial_putchar(const char c) { + if (sArchDebugUART == NULL) + return; + + sArchDebugUART->PutChar(c); } @@ -74,12 +90,38 @@ arch_debug_serial_puts(const char *s) void arch_debug_serial_early_boot_message(const char *string) { + // this function will only be called in fatal situations + arch_debug_serial_puts(string); } status_t arch_debug_console_init(kernel_args *args) { + if (strncmp(args->arch_args.uart.kind, UART_KIND_PL011, + sizeof(args->arch_args.uart.kind)) == 0) { + sArchDebugUART = arch_get_uart_pl011(args->arch_args.uart.regs.start, + args->arch_args.uart.clock); + } else if (strncmp(args->arch_args.uart.kind, UART_KIND_LINFLEX, + sizeof(args->arch_args.uart.kind)) == 0) { + sArchDebugUART = arch_get_uart_linflex(args->arch_args.uart.regs.start, + args->arch_args.uart.clock); + }/* else if (strncmp(args->arch_args.uart.kind, UART_KIND_8250_OMAP, + sizeof(args->arch_args.uart.kind)) == 0) { + sArchDebugUART = arch_get_uart_8250_omap(args->arch_args.uart.regs.start, + args->arch_args.uart.clock); + } else 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); + }*/ + + // Oh well. + if (sArchDebugUART == NULL) + return B_ERROR; + + sArchDebugUART->InitEarly(); + return B_OK; } diff --git a/src/system/kernel/arch/arm64/arch_uart_linflex.cpp b/src/system/kernel/arch/arm64/arch_uart_linflex.cpp new file mode 100644 index 0000000000..b9af34426f --- /dev/null +++ b/src/system/kernel/arch/arm64/arch_uart_linflex.cpp @@ -0,0 +1,200 @@ +/* + * Copyright 2022 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Ruiz Dorantes, oliver.ruiz.dorantes@gmail.com + */ + +#include +#include +#include +#include +#include + + +using namespace LINFlexRegisters; + + +ArchUARTlinflex::ArchUARTlinflex(addr_t base, int64 clock) + : + DebugUART(base, clock) +{ + Barrier(); + + if (LinflexCell()->LINCR1.B.SLEEP == 0) { + // This periperal is initialized + if ((LinflexCell()->UARTCR.B.TXEN == 1) + && (LinflexCell()->UARTCR.B.RXEN == 1) + && (LinflexCell()->UARTCR.B.UART == 1)) { + // LinFlex already configured as UART mode + // TODO: good to go + } else { + + } + } +} + + +ArchUARTlinflex::~ArchUARTlinflex() +{ +} + + +void +ArchUARTlinflex::Barrier() +{ + asm volatile ("" : : : "memory"); +} + + +void +ArchUARTlinflex::InitPort(uint32 baud) +{ + // Calculate baud divisor + uint32 baudDivisor = Clock() / (16 * baud); + uint32 remainder = Clock() % (16 * baud); + uint32 baudFractional = ((8 * remainder) / baud >> 1) + + ((8 * remainder) / baud & 1); + + // Disable UART + Disable(); + + // Set baud divisor + + // Set LCR 8n1, enable fifo + + // Set FIFO levels + + // Enable UART + Enable(); +} + + +void +ArchUARTlinflex::InitEarly() +{ + // Perform special hardware UART configuration +} + + +void +ArchUARTlinflex::Enable() +{ + + DebugUART::Enable(); +} + + +void +ArchUARTlinflex::Disable() +{ + + DebugUART::Disable(); +} + + +int +ArchUARTlinflex::PutChar(char c) +{ + if (Enabled() == true) { + // Wait until there is room in fifo + bool fifo = LinflexCell()->UARTCR.B.TFBM == 1; + + if (fifo) { + // TFF is set by hardware in UART FIFO mode (TFBM = 1) when TX FIFO is full. + while (LinflexCell()->UARTSR.B.DTF == 1) { + Barrier(); + } + } + + Out(&LinflexCell()->BDRL.R, c); + + if (!fifo) { + // DTF is set by hardware in UART buffer mode (TFBM = 0) and + // indicates that data transmission is completed. DTF should be cleared by software. + while (LinflexCell()->UARTSR.B.DTF == 0) { + Barrier(); + } + + auto uartsr = BitfieldRegister(); + uartsr.B.DTF = 1; + LinflexCell()->UARTSR.R = uartsr.R; + } + + return 0; + } + + return -1; +} + + +int +ArchUARTlinflex::GetChar(bool wait) +{ + int character; + + if (Enabled() == true) { + bool fifo = LinflexCell()->UARTCR.B.RFBM == 1; + + if (fifo) { + // RFE is set by hardware in UART FIFO mode (RFBM = 1) when the RX FIFO is empty. + if (wait) { + // Wait until a character is received + while (LinflexCell()->UARTSR.B.DRF == 1) { + Barrier(); + } + } else { + if (LinflexCell()->UARTSR.B.DRF == 1) + return -1; + } + } else { + // DRF is set by hardware in UART buffer mode (RFBM = 0) and + // indicates that the number of bytes programmed in RDFL have been received. + // DRF should be cleared by software. + if (wait) { + while (LinflexCell()->UARTSR.B.DRF == 0) { + Barrier(); + } + } else { + if (LinflexCell()->UARTSR.B.DRF == 0) + return -1; + } + } + + character = In(&LinflexCell()->BDRM.R); + + // Clear status + auto uartsr = BitfieldRegister(); + uartsr.B.RMB = 1; + uartsr.B.DRF = 1; + LinflexCell()->UARTSR.R = uartsr.R; + + return character; + } + + return -1; +} + + +void +ArchUARTlinflex::FlushTx() +{ + // Wait until transmit fifo empty +} + + +void +ArchUARTlinflex::FlushRx() +{ + // Wait until receive fifo empty +} + + +ArchUARTlinflex* +arch_get_uart_linflex(addr_t base, int64 clock) +{ + static char buffer[sizeof(ArchUARTlinflex)]; + ArchUARTlinflex *uart = new(buffer) ArchUARTlinflex(base, clock); + return uart; +}