Re: [PATCH 4/4] serial: 8250: Add Airoha SoC UART and HSUART support
From: Benjamin Larsson
Date: Tue Jul 14 2026 - 10:55:46 EST
On 10/07/2026 09:13, Jiri Slaby wrote:
+static void airoha_set_termios(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old)
+{
+ const struct airoha_8250_clk_div_info *clk_div_info;
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned int xyd_x, nom, denom;
+ unsigned int baud;
+ int i;
+
+ serial8250_do_set_termios(port, termios, old);
+
+ baud = serial8250_get_baud_rate(port, termios, old);
+
+ /* 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 (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 (i = 0 ; i < ARRAY_SIZE(airoha_clk_div_info) ; i++) {
+ clk_div_info = &airoha_clk_div_info[i];
+
+ denom = (XINDIV_CLOCK / 40) / clk_div_info->div;
+ nom = baud * (XYD_Y / 40);
Are these "/ 40" to avoid overflow? Add a comment.
Yes, this is to keep it in 32bits.
+ xyd_x = ((nom / denom) << 4);
* don't you want to round to closest instead of down?
* I don't understand the purpose of the shift though.
IIRC this is the vendor calculation logic scaled to fit 32bits. With this rounding/calculation we hit the baud rate exactly for the baud rates that people actually use.
+ /* For the HSUART xyd_x needs to be scaled by a factor of 2 */
+ if (port->type == UART_PORT_AIROHA_HS)
+ xyd_x = xyd_x >> 1;
Do not use shifts for div/mul.
+ if (xyd_x < XYD_Y)
+ break;
+ }
+
+ serial_port_out(port, UART_AIROHA_XINCLKDR, clk_div_info->mask);
+ serial_port_out(port, UART_AIROHA_XYD, (xyd_x << 16) | XYD_Y);
+
+ /* unset DLAB */
+ serial_port_out(port, UART_LCR, up->lcr);
+}
thanks,
--
js
suse labs
MvH
Benjamin Larsson