Skip to content

Commit 4bebd64

Browse files
jcmvbkbcgregkh
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 22088bb commit 4bebd64

File tree

1 file changed

+46
-3
lines changed

1 file changed

+46
-3
lines changed

drivers/tty/serial/esp32_uart.c

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,26 @@
6767
#define ESP32S3_UART_TXFIFO_EMPTY_THRHD_SHIFT 10
6868
#define ESP32_UART_RX_FLOW_EN BIT(23)
6969
#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))
7090

7191
struct esp32_port {
7292
struct uart_port port;
@@ -80,6 +100,7 @@ struct esp32_uart_variant {
80100
u32 txfifo_empty_thrhd_shift;
81101
u32 rx_flow_en;
82102
const char *type;
103+
bool has_clkconf;
83104
};
84105

85106
static const struct esp32_uart_variant esp32_variant = {
@@ -98,6 +119,7 @@ static const struct esp32_uart_variant esp32s3_variant = {
98119
.txfifo_empty_thrhd_shift = ESP32S3_UART_TXFIFO_EMPTY_THRHD_SHIFT,
99120
.rx_flow_en = ESP32S3_UART_RX_FLOW_EN,
100121
.type = "ESP32S3 UART",
122+
.has_clkconf = true,
101123
};
102124

103125
static const struct of_device_id esp32_uart_dt_ids[] = {
@@ -314,6 +336,9 @@ static int esp32_uart_startup(struct uart_port *port)
314336
}
315337

316338
spin_lock_irqsave(&port->lock, flags);
339+
if (port_variant(port)->has_clkconf)
340+
esp32_uart_write(port, ESP32S3_UART_CLK_CONF_REG,
341+
ESP32S3_UART_CLK_CONF_DEFAULT);
317342
esp32_uart_write(port, UART_CONF1_REG,
318343
(1 << UART_RXFIFO_FULL_THRHD_SHIFT) |
319344
(1 << port_variant(port)->txfifo_empty_thrhd_shift));
@@ -335,10 +360,24 @@ static void esp32_uart_shutdown(struct uart_port *port)
335360

336361
static bool esp32_uart_set_baud(struct uart_port *port, u32 baud)
337362
{
338-
u32 div = port->uartclk / baud;
339-
u32 frag = (port->uartclk * 16) / baud - div * 16;
363+
u32 sclk = port->uartclk;
364+
u32 div = sclk / baud;
365+
366+
if (port_variant(port)->has_clkconf) {
367+
u32 sclk_div = div / port_variant(port)->clkdiv_mask;
368+
369+
if (div > port_variant(port)->clkdiv_mask) {
370+
sclk /= (sclk_div + 1);
371+
div = sclk / baud;
372+
}
373+
esp32_uart_write(port, ESP32S3_UART_CLK_CONF_REG,
374+
FIELD_PREP(ESP32S3_UART_SCLK_DIV_NUM, sclk_div) |
375+
ESP32S3_UART_CLK_CONF_DEFAULT);
376+
}
340377

341378
if (div <= port_variant(port)->clkdiv_mask) {
379+
u32 frag = (sclk * 16) / baud - div * 16;
380+
342381
esp32_uart_write(port, UART_CLKDIV_REG,
343382
div | FIELD_PREP(UART_CLKDIV_FRAG, frag));
344383
return true;
@@ -355,11 +394,15 @@ static void esp32_uart_set_termios(struct uart_port *port,
355394
u32 conf0, conf1;
356395
u32 baud;
357396
const u32 rx_flow_en = port_variant(port)->rx_flow_en;
397+
u32 max_div = port_variant(port)->clkdiv_mask;
358398

359399
termios->c_cflag &= ~CMSPAR;
360400

401+
if (port_variant(port)->has_clkconf)
402+
max_div *= FIELD_MAX(ESP32S3_UART_SCLK_DIV_NUM);
403+
361404
baud = uart_get_baud_rate(port, termios, old,
362-
port->uartclk / port_variant(port)->clkdiv_mask,
405+
port->uartclk / max_div,
363406
port->uartclk / 16);
364407

365408
spin_lock_irqsave(&port->lock, flags);

0 commit comments

Comments
 (0)