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 <no-reply+buildbot@haiku-os.org>
Reviewed-by: David Karoly <karolyd577@gmail.com>
Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com>
This commit is contained in:
urnenfeld 2022-03-26 13:07:28 +01:00 committed by Fredrik Holmqvist
parent 955acf7e19
commit 476346ac62
10 changed files with 954 additions and 20 deletions

View File

@ -11,6 +11,7 @@
#include <util/FixedWidthPointer.h>
#include <boot/interrupt_controller.h>
#include <boot/uart.h>
@ -18,15 +19,16 @@
typedef struct {
// needed for UEFI, otherwise kernel acpi support can't find ACPI root
FixedWidthPointer<void> acpi_root;
// TODO: Deal with this later in the port
// FixedWidthPointer<void> 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<void> acpi_root;
FixedWidthPointer<void> fdt;
uart_info uart;
intc_info interrupt_controller;
} _PACKED arch_kernel_args;

View File

@ -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 <sys/types.h>
#include <ByteOrder.h>
#include <SupportDefs.h>
#include <arch/generic/debug_uart.h>
#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<typename REG>
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<typename TO, typename TA>
void Out(TA* reg, TO value) {
*(volatile TO*)(reg) = value;
}
template<typename TI, typename TA>
TI In(TA* reg) {
return *(volatile TI*)(reg);
}
virtual void Barrier();
LINFlexRegisters::LINFlex* LinflexCell() {
return reinterpret_cast<LINFlexRegisters::LINFlex*>(Base());
}
};
ArchUARTlinflex *arch_get_uart_linflex(addr_t base, int64 clock);
#endif

View File

@ -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) ]

View File

@ -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 ;
}

View File

@ -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 :

View File

@ -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 <kallisti5@unixzen.com>
*/
#include <arch_cpu_defs.h>
#include <arch_dtb.h>
#include <arch_smp.h>
#include <boot/platform.h>
#include <boot/stage2.h>
extern "C" {
#include <libfdt.h>
}
#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);
}
}

View File

@ -15,9 +15,14 @@
#include <arch/generic/debug_uart_8250.h>
#if defined(__riscv)
# include <arch/riscv64/arch_uart_sifive.h>
#elif defined(__ARM__) || defined(__aarch64__)
#elif defined(__ARM__)
# include <arch/arm/arch_uart_pl011.h>
#elif defined(__aarch64__)
# include <arch/arm/arch_uart_pl011.h>
# include <arch/arm64/arch_uart_linflex.h>
#endif
#include <boot/addr_range.h>
#include <boot/platform.h>
#include <boot/stage2.h>
@ -64,10 +69,14 @@ const struct supported_uarts {
{ "ns16550", UART_KIND_8250, &get_uart<DebugUART8250> },
#if defined(__riscv)
{ "sifive,uart0", UART_KIND_SIFIVE, &get_uart<ArchUARTSifive> },
#elif defined(__ARM__) || defined(__aarch64__)
#elif defined(__ARM__)
{ "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
{ "snps,dw-apb-uart", UART_KIND_8250, &get_uart<DebugUART8250> },
{ "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> },
{ "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> }
#elif defined(__aarch64__)
{ "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
{ "fsl,s32-linflexuart", UART_KIND_LINFLEX, &get_uart<ArchUARTlinflex> },
{ "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> }
#endif
};

View File

@ -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
:

View File

@ -4,12 +4,19 @@
*/
#include <arch/debug_console.h>
#include <arch/generic/debug_uart.h>
// #include <arch/generic/debug_uart_8250.h>
// #include <arch/arm/arch_uart_8250_omap.h>
#include <arch/arm/arch_uart_pl011.h>
#include <arch/arm64/arch_uart_linflex.h>
#include <boot/kernel_args.h>
#include <kernel.h>
#include <vm/vm.h>
#include <string.h>
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;
}

View File

@ -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 <debug.h>
#include <arch/arm/reg.h>
#include <arch/generic/debug_uart.h>
#include <arch/arm64/arch_uart_linflex.h>
#include <new>
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<uint8, vuint32>(&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_register>();
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<uint8, vuint32>(&LinflexCell()->BDRM.R);
// Clear status
auto uartsr = BitfieldRegister<UARTSR_register>();
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;
}