serial: Airoha SoC UART and HSUART support

Support for Airoha AN7581 SoC UART and HSUART baud rate
calculation routine.

Signed-off-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Link: https://lore.kernel.org/r/20250119130105.2833517-3-benjamin.larsson@genexis.eu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Benjamin Larsson
2025-01-19 14:01:05 +01:00
committed by Greg Kroah-Hartman
parent ed333392bd
commit e12ebf14fa
6 changed files with 135 additions and 0 deletions
+15
View File
@@ -314,6 +314,21 @@ static inline int serial8250_in_MCR(struct uart_8250_port *up)
return mctrl;
}
/* uart_config[] table port type defines */
/* Airoha UART */
#define PORT_AIROHA 124
/* Airoha HSUART */
#define PORT_AIROHA_HS 125
#ifdef CONFIG_SERIAL_8250_AIROHA
void airoha8250_set_baud_rate(struct uart_port *port,
unsigned int baud, unsigned int hs);
#else
static inline void airoha8250_set_baud_rate(struct uart_port *port,
unsigned int baud, unsigned int hs) { }
#endif
#ifdef CONFIG_SERIAL_8250_PNP
int serial8250_pnp_init(void);
void serial8250_pnp_exit(void);
+81
View File
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Airoha UART baud rate calculation function
*
* Copyright (c) 2025 Genexis Sweden AB
* Author: Benjamin Larsson <benjamin.larsson@genexis.eu>
*/
#include "8250.h"
/* The Airoha UART is 16550-compatible except for the baud rate calculation. */
/* Airoha UART registers */
#define UART_AIROHA_BRDL 0
#define UART_AIROHA_BRDH 1
#define UART_AIROHA_XINCLKDR 10
#define UART_AIROHA_XYD 11
#define XYD_Y 65000
#define XINDIV_CLOCK 20000000
#define UART_BRDL_20M 0x01
#define UART_BRDH_20M 0x00
static const int clock_div_tab[] = { 10, 4, 2};
static const int clock_div_reg[] = { 4, 2, 1};
/**
* airoha8250_set_baud_rate() - baud rate calculation routine
* @port: uart port
* @baud: requested uart baud rate
* @hs: uart type selector, 0 for regular uart and 1 for high-speed uart
*
* crystal_clock = 20 MHz (fixed frequency)
* xindiv_clock = crystal_clock / clock_div
* (x/y) = XYD, 32 bit register with 16 bits of x and then 16 bits of y
* clock_div = XINCLK_DIVCNT (default set to 10 (0x4)),
* - 3 bit register [ 1, 2, 4, 8, 10, 12, 16, 20 ]
*
* baud_rate = ((xindiv_clock) * (x/y)) / ([BRDH,BRDL] * 16)
*
* Selecting divider needs to fulfill
* 1.8432 MHz <= xindiv_clk <= APB clock / 2
* The clocks are unknown but a divider of value 1 did not result in a valid
* waveform.
*
* XYD_y seems to need to be larger then XYD_x for proper waveform generation.
* Setting [BRDH,BRDL] to [0,1] and XYD_y to 65000 gives even values
* for usual baud rates.
*/
void airoha8250_set_baud_rate(struct uart_port *port,
unsigned int baud, unsigned int hs)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int xyd_x, nom, denom;
int i;
/* set DLAB to access the baud rate divider registers (BRDH, BRDL) */
serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
/* set baud rate calculation defaults */
/* set BRDIV ([BRDH,BRDL]) to 1 */
serial_port_out(port, UART_AIROHA_BRDL, UART_BRDL_20M);
serial_port_out(port, UART_AIROHA_BRDH, UART_BRDH_20M);
/* calculate XYD_x and XINCLKDR register by searching
* through a table of crystal_clock divisors
*
* for the HSUART xyd_x needs to be scaled by a factor of 2
*/
for (i = 0 ; i < ARRAY_SIZE(clock_div_tab) ; i++) {
denom = (XINDIV_CLOCK/40) / clock_div_tab[i];
nom = baud * (XYD_Y/40);
xyd_x = ((nom/denom) << 4) >> hs;
if (xyd_x < XYD_Y)
break;
}
serial_port_out(port, UART_AIROHA_XINCLKDR, clock_div_reg[i]);
serial_port_out(port, UART_AIROHA_XYD, (xyd_x<<16) | XYD_Y);
/* unset DLAB */
serial_port_out(port, UART_LCR, up->lcr);
}
+2
View File
@@ -341,6 +341,8 @@ static const struct of_device_id of_platform_serial_table[] = {
{ .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },
{ .compatible = "nuvoton,wpcm450-uart", .data = (void *)PORT_NPCM, },
{ .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, },
{ .compatible = "airoha,airoha-uart", .data = (void *)PORT_AIROHA, },
{ .compatible = "airoha,airoha-hsuart", .data = (void *)PORT_AIROHA_HS, },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
+26
View File
@@ -319,6 +319,24 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {1, 8, 16, 30},
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
/* From here on after additional uart config port defines are placed in 8250.h
*/
[PORT_AIROHA] = {
.name = "Airoha UART",
.fifo_size = 8,
.tx_loadsz = 1,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_CLEAR_RCVR,
.rxtrig_bytes = {1, 4},
.flags = UART_CAP_FIFO,
},
[PORT_AIROHA_HS] = {
.name = "Airoha HSUART",
.fifo_size = 128,
.tx_loadsz = 128,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_CLEAR_RCVR,
.rxtrig_bytes = {1, 4},
.flags = UART_CAP_FIFO,
},
};
/* Uart divisor latch read */
@@ -2865,6 +2883,14 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial8250_set_divisor(port, baud, quot, frac);
/*
* Airoha SoCs have custom registers for baud rate settings
*/
if (port->type == PORT_AIROHA)
airoha8250_set_baud_rate(port, baud, 0);
if (port->type == PORT_AIROHA_HS)
airoha8250_set_baud_rate(port, baud, 1);
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
* is written without DLAB set, this mode will be disabled.
+10
View File
@@ -356,6 +356,16 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
config SERIAL_8250_AIROHA
tristate "Airoha UART support"
depends on (ARCH_AIROHA || COMPILE_TEST) && OF && SERIAL_8250
help
Selecting this option enables an Airoha SoC specific baud rate
calculation routine on an otherwise 16550 compatible UART hardware.
If you have an Airoha based board and want to use the serial port,
say Y to this option. If unsure, say N.
config SERIAL_8250_BCM2835AUX
tristate "BCM2835 auxiliar mini UART support"
depends on ARCH_BCM2835 || COMPILE_TEST
+1
View File
@@ -20,6 +20,7 @@ obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
obj-$(CONFIG_SERIAL_8250_AIROHA) += 8250_airoha.o
obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o