Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial/esp32_uart: use prescaler when available

esp32s3 variant of the esp32 UART has limited baudrate divisor range
that does not allow it to use 9600 and lower rates with 40MHz input
clock. Use clock prescaler present in this UART variant to help with
that.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Link: https://lore.kernel.org/r/20231018191252.1551972-1-jcmvbkbc@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Max Filippov and committed by
Greg Kroah-Hartman
4bebd644 22088bbb

+46 -3
+46 -3
drivers/tty/serial/esp32_uart.c
··· 67 67 #define ESP32S3_UART_TXFIFO_EMPTY_THRHD_SHIFT 10 68 68 #define ESP32_UART_RX_FLOW_EN BIT(23) 69 69 #define ESP32S3_UART_RX_FLOW_EN BIT(22) 70 + #define ESP32S3_UART_CLK_CONF_REG 0x78 71 + #define ESP32S3_UART_SCLK_DIV_B GENMASK(5, 0) 72 + #define ESP32S3_UART_SCLK_DIV_A GENMASK(11, 6) 73 + #define ESP32S3_UART_SCLK_DIV_NUM GENMASK(19, 12) 74 + #define ESP32S3_UART_SCLK_SEL GENMASK(21, 20) 75 + #define APB_CLK 1 76 + #define RC_FAST_CLK 2 77 + #define XTAL_CLK 3 78 + #define ESP32S3_UART_SCLK_EN BIT(22) 79 + #define ESP32S3_UART_RST_CORE BIT(23) 80 + #define ESP32S3_UART_TX_SCLK_EN BIT(24) 81 + #define ESP32S3_UART_RX_SCLK_EN BIT(25) 82 + #define ESP32S3_UART_TX_RST_CORE BIT(26) 83 + #define ESP32S3_UART_RX_RST_CORE BIT(27) 84 + 85 + #define ESP32S3_UART_CLK_CONF_DEFAULT \ 86 + (ESP32S3_UART_RX_SCLK_EN | \ 87 + ESP32S3_UART_TX_SCLK_EN | \ 88 + ESP32S3_UART_SCLK_EN | \ 89 + FIELD_PREP(ESP32S3_UART_SCLK_SEL, XTAL_CLK)) 70 90 71 91 struct esp32_port { 72 92 struct uart_port port; ··· 100 80 u32 txfifo_empty_thrhd_shift; 101 81 u32 rx_flow_en; 102 82 const char *type; 83 + bool has_clkconf; 103 84 }; 104 85 105 86 static const struct esp32_uart_variant esp32_variant = { ··· 119 98 .txfifo_empty_thrhd_shift = ESP32S3_UART_TXFIFO_EMPTY_THRHD_SHIFT, 120 99 .rx_flow_en = ESP32S3_UART_RX_FLOW_EN, 121 100 .type = "ESP32S3 UART", 101 + .has_clkconf = true, 122 102 }; 123 103 124 104 static const struct of_device_id esp32_uart_dt_ids[] = { ··· 336 314 } 337 315 338 316 spin_lock_irqsave(&port->lock, flags); 317 + if (port_variant(port)->has_clkconf) 318 + esp32_uart_write(port, ESP32S3_UART_CLK_CONF_REG, 319 + ESP32S3_UART_CLK_CONF_DEFAULT); 339 320 esp32_uart_write(port, UART_CONF1_REG, 340 321 (1 << UART_RXFIFO_FULL_THRHD_SHIFT) | 341 322 (1 << port_variant(port)->txfifo_empty_thrhd_shift)); ··· 360 335 361 336 static bool esp32_uart_set_baud(struct uart_port *port, u32 baud) 362 337 { 363 - u32 div = port->uartclk / baud; 364 - u32 frag = (port->uartclk * 16) / baud - div * 16; 338 + u32 sclk = port->uartclk; 339 + u32 div = sclk / baud; 340 + 341 + if (port_variant(port)->has_clkconf) { 342 + u32 sclk_div = div / port_variant(port)->clkdiv_mask; 343 + 344 + if (div > port_variant(port)->clkdiv_mask) { 345 + sclk /= (sclk_div + 1); 346 + div = sclk / baud; 347 + } 348 + esp32_uart_write(port, ESP32S3_UART_CLK_CONF_REG, 349 + FIELD_PREP(ESP32S3_UART_SCLK_DIV_NUM, sclk_div) | 350 + ESP32S3_UART_CLK_CONF_DEFAULT); 351 + } 365 352 366 353 if (div <= port_variant(port)->clkdiv_mask) { 354 + u32 frag = (sclk * 16) / baud - div * 16; 355 + 367 356 esp32_uart_write(port, UART_CLKDIV_REG, 368 357 div | FIELD_PREP(UART_CLKDIV_FRAG, frag)); 369 358 return true; ··· 394 355 u32 conf0, conf1; 395 356 u32 baud; 396 357 const u32 rx_flow_en = port_variant(port)->rx_flow_en; 358 + u32 max_div = port_variant(port)->clkdiv_mask; 397 359 398 360 termios->c_cflag &= ~CMSPAR; 399 361 362 + if (port_variant(port)->has_clkconf) 363 + max_div *= FIELD_MAX(ESP32S3_UART_SCLK_DIV_NUM); 364 + 400 365 baud = uart_get_baud_rate(port, termios, old, 401 - port->uartclk / port_variant(port)->clkdiv_mask, 366 + port->uartclk / max_div, 402 367 port->uartclk / 16); 403 368 404 369 spin_lock_irqsave(&port->lock, flags);