kernel: add SiFive UART driver for riscv64

Change-Id: I37a909b5bcdb18b3fa062961eca9ff2f5187867c
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4305
Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
X512
2021-08-06 16:56:21 +00:00
committed by Alex von Gluck IV
parent 64bc301951
commit ec1174b442
3 changed files with 211 additions and 0 deletions
@@ -0,0 +1,100 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _ARCH_UART_SIFIVE_H_
#define _ARCH_UART_SIFIVE_H_
#include <arch/generic/debug_uart.h>
// UARTSifiveRegs.ie, ip
enum {
kUartSifiveTxwm = 1 << 0,
kUartSifiveRxwm = 1 << 1,
};
struct UARTSifiveRegs {
union Txdata {
struct {
uint32 data: 8;
uint32 reserved: 23;
uint32 isFull: 1;
};
uint32 val;
} txdata;
union Rxdata {
struct {
uint32 data: 8;
uint32 reserved: 23;
uint32 isEmpty: 1;
};
uint32 val;
} rxdata;
union Txctrl {
struct {
uint32 enable: 1;
uint32 nstop: 1;
uint32 reserved1: 14;
uint32 cnt: 3;
uint32 reserved2: 13;
};
uint32 val;
} txctrl;
union Rxctrl {
struct {
uint32 enable: 1;
uint32 reserved1: 15;
uint32 cnt: 3;
uint32 reserved2: 13;
};
uint32 val;
} rxctrl;
uint32 ie; // interrupt enable
uint32 ip; // interrupt pending
uint32 div;
uint32 unused;
};
class ArchUARTSifive : public DebugUART {
public:
ArchUARTSifive(addr_t base, int64 clock);
~ArchUARTSifive();
virtual void InitEarly();
virtual void Init();
virtual void InitPort(uint32 baud);
virtual void Enable();
virtual void Disable();
virtual int PutChar(char ch);
virtual int GetChar(bool wait);
virtual void FlushTx();
virtual void FlushRx();
protected:
virtual void Barrier();
inline volatile UARTSifiveRegs*
Regs();
};
volatile UARTSifiveRegs*
ArchUARTSifive::Regs()
{
return (volatile UARTSifiveRegs*)Base();
}
#endif // _ARCH_UART_SIFIVE_H_
+5
View File
@@ -3,6 +3,8 @@ SubDir HAIKU_TOP src system kernel arch riscv64 ;
SubDirHdrs $(SUBDIR) $(DOTDOT) generic ; SubDirHdrs $(SUBDIR) $(DOTDOT) generic ;
UsePrivateKernelHeaders ; UsePrivateKernelHeaders ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
KernelMergeObject kernel_arch_riscv64.o : KernelMergeObject kernel_arch_riscv64.o :
arch_asm.S arch_asm.S
arch_commpage.cpp arch_commpage.cpp
@@ -23,6 +25,9 @@ KernelMergeObject kernel_arch_riscv64.o :
RISCV64VMTranslationMap.cpp RISCV64VMTranslationMap.cpp
Htif.cpp Htif.cpp
sbi_syscalls.S sbi_syscalls.S
debug_uart_8250.cpp
arch_uart_sifive.cpp
: :
$(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
: :
@@ -0,0 +1,106 @@
/*
* Copyright 2021, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <arch/riscv64/arch_uart_sifive.h>
ArchUARTSifive::ArchUARTSifive(addr_t base, int64 clock)
:
DebugUART(base, clock)
{
}
ArchUARTSifive::~ArchUARTSifive()
{
}
void
ArchUARTSifive::InitEarly()
{
//Regs()->ie = 0;
//Enable();
}
void
ArchUARTSifive::Init()
{
}
void
ArchUARTSifive::InitPort(uint32 baud)
{
uint64 quotient = (Clock() + baud - 1) / baud;
if (quotient == 0)
Regs()->div = 0;
else
Regs()->div = (uint32)(quotient - 1);
}
void
ArchUARTSifive::Enable()
{
//Regs()->txctrl.enable = 1;
//Regs()->rxctrl.enable = 1;
DebugUART::Enable();
}
void
ArchUARTSifive::Disable()
{
//Regs()->txctrl.enable = 0;
//Regs()->rxctrl.enable = 0;
DebugUART::Disable();
}
int
ArchUARTSifive::PutChar(char ch)
{
// TODO: Needs to be more atomic?
// Character drop will happen if there is one space left
// in the FIFO and two harts race. atomic_fetch_or of
// register, retrying if isFull.
while (Regs()->txdata.isFull) {}
Regs()->txdata.val = ch;
return 0;
}
int
ArchUARTSifive::GetChar(bool wait)
{
UARTSifiveRegs::Rxdata data;
do {
data = { .val = Regs()->rxdata.val };
} while (!wait || data.isEmpty);
return data.isEmpty ? -1 : data.data;
}
void
ArchUARTSifive::FlushTx()
{
}
void
ArchUARTSifive::FlushRx()
{
}
void
ArchUARTSifive::Barrier()
{
asm volatile ("" : : : "memory");
}