arm64: Add apple,s5l UART driver

This is the debug UART found in Apple SoCs. Tested on M1 MacBook Air.

Registers definitions were taken from:
  - https://github.com/AsahiLinux/m1n1/blob/18eb02fa92789dfcdab8e00e8b1cace7ab002718/src/uart_regs.h
  - https://www.sistemasorp.es/blog/S3C2410%20-%20datasheet.pdf

Change-Id: I2e4c8b7927fc823cedca421e1a2623b91f5ef112
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10480
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Sam Roberts
2026-03-11 23:38:03 +00:00
committed by waddlesplash
parent 5bb69a0f33
commit d2819f9e83
4 changed files with 177 additions and 0 deletions
@@ -0,0 +1,41 @@
/*
* Copyright 2026 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Sam Roberts, [email protected]
*/
#ifndef __DEV_UART_SAMSUNG_H
#define __DEV_UART_SAMSUNG_H
#include <arch/generic/debug_uart.h>
#define UART_KIND_SAMSUNG "samsung"
class ArchUARTSamsung : public DebugUART {
public:
ArchUARTSamsung(addr_t base, int64 clock);
~ArchUARTSamsung();
void InitPort(uint32 baud);
void Enable();
void Disable();
int PutChar(char c);
int GetChar(bool wait);
void FlushTx();
void FlushRx();
private:
void Out32(int reg, uint32 data);
uint32 In32(int reg);
};
#endif
+1
View File
@@ -5,6 +5,7 @@ local platform ;
local kernelArchSources = local kernelArchSources =
arch_elf.cpp arch_elf.cpp
arch_uart_linflex.cpp arch_uart_linflex.cpp
arch_uart_samsung.cpp
; ;
local kernelArchReusableSources = local kernelArchReusableSources =
+2
View File
@@ -20,6 +20,7 @@
#elif defined(__aarch64__) #elif defined(__aarch64__)
# include <arch/arm/arch_uart_pl011.h> # include <arch/arm/arch_uart_pl011.h>
# include <arch/arm64/arch_uart_linflex.h> # include <arch/arm64/arch_uart_linflex.h>
# include <arch/arm64/arch_uart_samsung.h>
#endif #endif
@@ -83,6 +84,7 @@ const struct supported_uarts {
{ "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> }, { "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
{ "fsl,s32-linflexuart", UART_KIND_LINFLEX, &get_uart<ArchUARTlinflex> }, { "fsl,s32-linflexuart", UART_KIND_LINFLEX, &get_uart<ArchUARTlinflex> },
{ "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> }, { "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> },
{ "apple,s5l-uart", UART_KIND_SAMSUNG, &get_uart<ArchUARTSamsung> },
#endif #endif
}; };
@@ -0,0 +1,133 @@
/*
* Copyright 2026 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Sam Roberts, [email protected]
*/
#include <arch/generic/debug_uart.h>
#include <arch/arm64/arch_uart_samsung.h>
#define ULCON 0x00 // Line control
#define UCON 0x04 // Control
#define UFCON 0x08 // FIFO control
#define UTRSTAT 0x10 // Transmit status
#define UFSTAT 0x18 // FIFO status
#define UTXH 0x20 // Transmit holding
#define URXH 0x24 // Receive holding
#define UBRDIV 0x28 // Baud rate divider
#define UCON_TXTHRESH_ENA (1 << 13) // Transmit threshold enable
#define UCON_RXTHRESH_ENA (1 << 12) // Receive threshold enable
#define UCON_RXTO_ENA (1 << 9) // Receive timeout enable
#define UCON_TXMODE (3 << 2) // Transmit mode
#define UCON_RXMODE (3 << 0) // Receive mode
#define UCON_MODE_OFF 0
#define UCON_MODE_IRQ 1
#define UTRSTAT_RXTO (1 << 9) // Receive timeout status
#define UTRSTAT_TXTHRESH (1 << 5) // Transmit threshold status
#define UTRSTAT_RXTHRESH (1 << 4) // Receive threshold status
#define UTRSTAT_TXE (1 << 2) // Transmit empty status
#define UTRSTAT_TXBE (1 << 1) // Transmit buffer empty status
#define UTRSTAT_RXD (1 << 0) // Receive data status
#define UFSTAT_TXFULL (1 << 9) // Transmit FIFO full status
#define UFSTAT_RXFULL (1 << 8) // Receive FIFO full status
#define UFSTAT_TXCNT (15 << 4) // Transmit FIFO count
#define UFSTAT_RXCNT (15 << 0) // Receive FIFO count
ArchUARTSamsung::ArchUARTSamsung(addr_t base, int64 clock)
:
DebugUART(base, clock)
{
}
ArchUARTSamsung::~ArchUARTSamsung()
{
}
void
ArchUARTSamsung::Out32(int reg, uint32 data)
{
*(volatile uint32*)(Base() + reg) = data;
}
uint32
ArchUARTSamsung::In32(int reg)
{
return *(volatile uint32*)(Base() + reg);
}
void
ArchUARTSamsung::InitPort(uint32 baud)
{
uint32 ucon = In32(UCON);
// Disable TX and RX IRQ
Out32(UCON, ucon & !(UCON_RXMODE | UCON_TXMODE));
}
void
ArchUARTSamsung::Enable()
{
DebugUART::Enable();
}
void
ArchUARTSamsung::Disable()
{
DebugUART::Disable();
}
int
ArchUARTSamsung::PutChar(char c)
{
if (Enabled()) {
while ((In32(UFSTAT) & UFSTAT_TXFULL) != 0)
;
Out32(UTXH, c);
return 0;
}
return -1;
}
int
ArchUARTSamsung::GetChar(bool wait)
{
if (Enabled()) {
while (wait && ((In32(UFSTAT) & UFSTAT_RXCNT) == 0))
;
if ((In32(UFSTAT) & UFSTAT_RXCNT) == 0)
return -1;
return In32(URXH);
}
return -1;
}
void
ArchUARTSamsung::FlushTx()
{
}
void
ArchUARTSamsung::FlushRx()
{
}