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

serial: stm32: implement prescaler tuning to compute low baudrate

In the case of high USART input clock and low baud rate, BRR value
is not enough to get correct baud rate. So here we use USART prescaler to
divide USART input clock to get the correct baud rate.

PRESC register is only available since stm32h7.

Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
Link: https://lore.kernel.org/r/20240112095300.2004878-2-valentin.caron@foss.st.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Valentin Caron and committed by
Greg Kroah-Hartman
ec240f88 5c49b6a4

+56 -21
+50 -21
drivers/tty/serial/stm32-usart.c
··· 9 9 * Inspired by st-asc.c from STMicroelectronics (c) 10 10 */ 11 11 12 + #include <linux/bitfield.h> 12 13 #include <linux/clk.h> 13 14 #include <linux/console.h> 14 15 #include <linux/delay.h> ··· 51 50 .rtor = UNDEF_REG, 52 51 .rqr = UNDEF_REG, 53 52 .icr = UNDEF_REG, 53 + .presc = UNDEF_REG, 54 54 }, 55 55 .cfg = { 56 56 .uart_enable_bit = 13, ··· 73 71 .icr = 0x20, 74 72 .rdr = 0x24, 75 73 .tdr = 0x28, 74 + .presc = UNDEF_REG, 76 75 }, 77 76 .cfg = { 78 77 .uart_enable_bit = 0, ··· 96 93 .icr = 0x20, 97 94 .rdr = 0x24, 98 95 .tdr = 0x28, 96 + .presc = 0x2c, 99 97 }, 100 98 .cfg = { 101 99 .uart_enable_bit = 0, ··· 1149 1145 free_irq(port->irq, port); 1150 1146 } 1151 1147 1148 + static const unsigned int stm32_usart_presc_val[] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256}; 1149 + 1152 1150 static void stm32_usart_set_termios(struct uart_port *port, 1153 1151 struct ktermios *termios, 1154 1152 const struct ktermios *old) ··· 1159 1153 const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; 1160 1154 const struct stm32_usart_config *cfg = &stm32_port->info->cfg; 1161 1155 struct serial_rs485 *rs485conf = &port->rs485; 1162 - unsigned int baud, bits; 1156 + unsigned int baud, bits, uart_clk, uart_clk_pres; 1163 1157 u32 usartdiv, mantissa, fraction, oversampling; 1164 1158 tcflag_t cflag = termios->c_cflag; 1165 - u32 cr1, cr2, cr3, isr; 1159 + u32 cr1, cr2, cr3, isr, brr, presc; 1166 1160 unsigned long flags; 1167 1161 int ret; 1168 1162 1169 1163 if (!stm32_port->hw_flow_control) 1170 1164 cflag &= ~CRTSCTS; 1171 1165 1172 - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); 1166 + uart_clk = clk_get_rate(stm32_port->clk); 1167 + 1168 + baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8); 1173 1169 1174 1170 uart_port_lock_irqsave(port, &flags); 1175 1171 ··· 1273 1265 cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; 1274 1266 } 1275 1267 1276 - usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); 1268 + for (presc = 0; presc <= USART_PRESC_MAX; presc++) { 1269 + uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]); 1270 + usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud); 1277 1271 1278 - /* 1279 - * The USART supports 16 or 8 times oversampling. 1280 - * By default we prefer 16 times oversampling, so that the receiver 1281 - * has a better tolerance to clock deviations. 1282 - * 8 times oversampling is only used to achieve higher speeds. 1283 - */ 1284 - if (usartdiv < 16) { 1285 - oversampling = 8; 1286 - cr1 |= USART_CR1_OVER8; 1287 - stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); 1288 - } else { 1289 - oversampling = 16; 1290 - cr1 &= ~USART_CR1_OVER8; 1291 - stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); 1272 + /* 1273 + * The USART supports 16 or 8 times oversampling. 1274 + * By default we prefer 16 times oversampling, so that the receiver 1275 + * has a better tolerance to clock deviations. 1276 + * 8 times oversampling is only used to achieve higher speeds. 1277 + */ 1278 + if (usartdiv < 16) { 1279 + oversampling = 8; 1280 + cr1 |= USART_CR1_OVER8; 1281 + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); 1282 + } else { 1283 + oversampling = 16; 1284 + cr1 &= ~USART_CR1_OVER8; 1285 + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); 1286 + } 1287 + 1288 + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; 1289 + fraction = usartdiv % oversampling; 1290 + brr = mantissa | fraction; 1291 + 1292 + if (FIELD_FIT(USART_BRR_MASK, brr)) { 1293 + if (ofs->presc != UNDEF_REG) { 1294 + port->uartclk = uart_clk_pres; 1295 + writel_relaxed(presc, port->membase + ofs->presc); 1296 + } else if (presc) { 1297 + /* We need a prescaler but we don't have it (STM32F4, STM32F7) */ 1298 + dev_err(port->dev, 1299 + "unable to set baudrate, input clock is too high"); 1300 + } 1301 + break; 1302 + } else if (presc == USART_PRESC_MAX) { 1303 + /* Even with prescaler and brr at max value we can't set baudrate */ 1304 + dev_err(port->dev, "unable to set baudrate, input clock is too high"); 1305 + break; 1306 + } 1292 1307 } 1293 1308 1294 - mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; 1295 - fraction = usartdiv % oversampling; 1296 - writel_relaxed(mantissa | fraction, port->membase + ofs->brr); 1309 + writel_relaxed(brr, port->membase + ofs->brr); 1297 1310 1298 1311 uart_update_timeout(port, cflag, baud); 1299 1312
+6
drivers/tty/serial/stm32-usart.h
··· 20 20 u8 icr; 21 21 u8 rdr; 22 22 u8 tdr; 23 + u8 presc; 23 24 }; 24 25 25 26 struct stm32_usart_config { ··· 72 71 #define USART_BRR_DIV_M_MASK GENMASK(15, 4) 73 72 #define USART_BRR_DIV_M_SHIFT 4 74 73 #define USART_BRR_04_R_SHIFT 1 74 + #define USART_BRR_MASK (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK) 75 75 76 76 /* USART_CR1 */ 77 77 #define USART_CR1_SBK BIT(0) ··· 177 175 #define USART_ICR_EOBCF BIT(12) /* F7 */ 178 176 #define USART_ICR_CMCF BIT(17) /* F7 */ 179 177 #define USART_ICR_WUCF BIT(20) /* H7 */ 178 + 179 + /* USART_PRESC */ 180 + #define USART_PRESC GENMASK(3, 0) /* H7 */ 181 + #define USART_PRESC_MAX 0b1011 180 182 181 183 #define STM32_SERIAL_NAME "ttySTM" 182 184 #define STM32_MAX_PORTS 8