Message ID | 20240111152712.1842790-2-valentin.caron@foss.st.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | serial: stm32: improve driver for stm32mp25 | expand |
Hi Valentin, kernel test robot noticed the following build errors: [auto build test ERROR on atorgue-stm32/stm32-next] [also build test ERROR on tty/tty-testing tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v6.7 next-20240111] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Valentin-Caron/serial-stm32-implement-prescaler-tuning-to-compute-low-baudrate/20240111-233406 base: https://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next patch link: https://lore.kernel.org/r/20240111152712.1842790-2-valentin.caron%40foss.st.com patch subject: [PATCH 1/4] serial: stm32: implement prescaler tuning to compute low baudrate config: i386-buildonly-randconfig-003-20240112 (https://download.01.org/0day-ci/archive/20240112/202401121426.pnTJrQes-lkp@intel.com/config) compiler: ClangBuiltLinux clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240112/202401121426.pnTJrQes-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202401121426.pnTJrQes-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/tty/serial/stm32-usart.c:1303:7: error: call to undeclared function 'FIELD_FIT'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 1303 | if (FIELD_FIT(USART_BRR_MASK, brr)) { | ^ 1 error generated. vim +/FIELD_FIT +1303 drivers/tty/serial/stm32-usart.c 1156 1157 static void stm32_usart_set_termios(struct uart_port *port, 1158 struct ktermios *termios, 1159 const struct ktermios *old) 1160 { 1161 struct stm32_port *stm32_port = to_stm32_port(port); 1162 const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; 1163 const struct stm32_usart_config *cfg = &stm32_port->info->cfg; 1164 struct serial_rs485 *rs485conf = &port->rs485; 1165 unsigned int baud, bits, uart_clk, uart_clk_pres; 1166 u32 usartdiv, mantissa, fraction, oversampling; 1167 tcflag_t cflag = termios->c_cflag; 1168 u32 cr1, cr2, cr3, isr, brr, presc; 1169 unsigned long flags; 1170 int ret; 1171 1172 if (!stm32_port->hw_flow_control) 1173 cflag &= ~CRTSCTS; 1174 1175 uart_clk = clk_get_rate(stm32_port->clk); 1176 1177 baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8); 1178 1179 uart_port_lock_irqsave(port, &flags); 1180 1181 ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, 1182 isr, 1183 (isr & USART_SR_TC), 1184 10, 100000); 1185 1186 /* Send the TC error message only when ISR_TC is not set. */ 1187 if (ret) 1188 dev_err(port->dev, "Transmission is not complete\n"); 1189 1190 /* Stop serial port and reset value */ 1191 writel_relaxed(0, port->membase + ofs->cr1); 1192 1193 /* flush RX & TX FIFO */ 1194 if (ofs->rqr != UNDEF_REG) 1195 writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, 1196 port->membase + ofs->rqr); 1197 1198 cr1 = USART_CR1_TE | USART_CR1_RE; 1199 if (stm32_port->fifoen) 1200 cr1 |= USART_CR1_FIFOEN; 1201 cr2 = stm32_port->swap ? USART_CR2_SWAP : 0; 1202 1203 /* Tx and RX FIFO configuration */ 1204 cr3 = readl_relaxed(port->membase + ofs->cr3); 1205 cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; 1206 if (stm32_port->fifoen) { 1207 if (stm32_port->txftcfg >= 0) 1208 cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT; 1209 if (stm32_port->rxftcfg >= 0) 1210 cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT; 1211 } 1212 1213 if (cflag & CSTOPB) 1214 cr2 |= USART_CR2_STOP_2B; 1215 1216 bits = tty_get_char_size(cflag); 1217 stm32_port->rdr_mask = (BIT(bits) - 1); 1218 1219 if (cflag & PARENB) { 1220 bits++; 1221 cr1 |= USART_CR1_PCE; 1222 } 1223 1224 /* 1225 * Word length configuration: 1226 * CS8 + parity, 9 bits word aka [M1:M0] = 0b01 1227 * CS7 or (CS6 + parity), 7 bits word aka [M1:M0] = 0b10 1228 * CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00 1229 * M0 and M1 already cleared by cr1 initialization. 1230 */ 1231 if (bits == 9) { 1232 cr1 |= USART_CR1_M0; 1233 } else if ((bits == 7) && cfg->has_7bits_data) { 1234 cr1 |= USART_CR1_M1; 1235 } else if (bits != 8) { 1236 dev_dbg(port->dev, "Unsupported data bits config: %u bits\n" 1237 , bits); 1238 cflag &= ~CSIZE; 1239 cflag |= CS8; 1240 termios->c_cflag = cflag; 1241 bits = 8; 1242 if (cflag & PARENB) { 1243 bits++; 1244 cr1 |= USART_CR1_M0; 1245 } 1246 } 1247 1248 if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || 1249 (stm32_port->fifoen && 1250 stm32_port->rxftcfg >= 0))) { 1251 if (cflag & CSTOPB) 1252 bits = bits + 3; /* 1 start bit + 2 stop bits */ 1253 else 1254 bits = bits + 2; /* 1 start bit + 1 stop bit */ 1255 1256 /* RX timeout irq to occur after last stop bit + bits */ 1257 stm32_port->cr1_irq = USART_CR1_RTOIE; 1258 writel_relaxed(bits, port->membase + ofs->rtor); 1259 cr2 |= USART_CR2_RTOEN; 1260 /* 1261 * Enable fifo threshold irq in two cases, either when there is no DMA, or when 1262 * wake up over usart, from low power until the DMA gets re-enabled by resume. 1263 */ 1264 stm32_port->cr3_irq = USART_CR3_RXFTIE; 1265 } 1266 1267 cr1 |= stm32_port->cr1_irq; 1268 cr3 |= stm32_port->cr3_irq; 1269 1270 if (cflag & PARODD) 1271 cr1 |= USART_CR1_PS; 1272 1273 port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); 1274 if (cflag & CRTSCTS) { 1275 port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; 1276 cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; 1277 } 1278 1279 for (presc = 0; presc <= USART_PRESC_MAX; presc++) { 1280 uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]); 1281 usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud); 1282 1283 /* 1284 * The USART supports 16 or 8 times oversampling. 1285 * By default we prefer 16 times oversampling, so that the receiver 1286 * has a better tolerance to clock deviations. 1287 * 8 times oversampling is only used to achieve higher speeds. 1288 */ 1289 if (usartdiv < 16) { 1290 oversampling = 8; 1291 cr1 |= USART_CR1_OVER8; 1292 stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); 1293 } else { 1294 oversampling = 16; 1295 cr1 &= ~USART_CR1_OVER8; 1296 stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); 1297 } 1298 1299 mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; 1300 fraction = usartdiv % oversampling; 1301 brr = mantissa | fraction; 1302 > 1303 if (FIELD_FIT(USART_BRR_MASK, brr)) { 1304 if (ofs->presc != UNDEF_REG) { 1305 port->uartclk = uart_clk_pres; 1306 writel_relaxed(presc, port->membase + ofs->presc); 1307 } else if (presc) { 1308 /* We need a prescaler but we don't have it (STM32F4, STM32F7) */ 1309 dev_err(port->dev, 1310 "unable to set baudrate, input clock is too high"); 1311 } 1312 break; 1313 } else if (presc == USART_PRESC_MAX) { 1314 /* Even with prescaler and brr at max value we can't set baudrate */ 1315 dev_err(port->dev, "unable to set baudrate, input clock is too high"); 1316 break; 1317 } 1318 } 1319 1320 writel_relaxed(brr, port->membase + ofs->brr); 1321 1322 uart_update_timeout(port, cflag, baud); 1323 1324 port->read_status_mask = USART_SR_ORE; 1325 if (termios->c_iflag & INPCK) 1326 port->read_status_mask |= USART_SR_PE | USART_SR_FE; 1327 if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 1328 port->read_status_mask |= USART_SR_FE; 1329 1330 /* Characters to ignore */ 1331 port->ignore_status_mask = 0; 1332 if (termios->c_iflag & IGNPAR) 1333 port->ignore_status_mask = USART_SR_PE | USART_SR_FE; 1334 if (termios->c_iflag & IGNBRK) { 1335 port->ignore_status_mask |= USART_SR_FE; 1336 /* 1337 * If we're ignoring parity and break indicators, 1338 * ignore overruns too (for real raw support). 1339 */ 1340 if (termios->c_iflag & IGNPAR) 1341 port->ignore_status_mask |= USART_SR_ORE; 1342 } 1343 1344 /* Ignore all characters if CREAD is not set */ 1345 if ((termios->c_cflag & CREAD) == 0) 1346 port->ignore_status_mask |= USART_SR_DUMMY_RX; 1347 1348 if (stm32_port->rx_ch) { 1349 /* 1350 * Setup DMA to collect only valid data and enable error irqs. 1351 * This also enables break reception when using DMA. 1352 */ 1353 cr1 |= USART_CR1_PEIE; 1354 cr3 |= USART_CR3_EIE; 1355 cr3 |= USART_CR3_DMAR; 1356 cr3 |= USART_CR3_DDRE; 1357 } 1358 1359 if (stm32_port->tx_ch) 1360 cr3 |= USART_CR3_DMAT; 1361 1362 if (rs485conf->flags & SER_RS485_ENABLED) { 1363 stm32_usart_config_reg_rs485(&cr1, &cr3, 1364 rs485conf->delay_rts_before_send, 1365 rs485conf->delay_rts_after_send, 1366 baud); 1367 if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { 1368 cr3 &= ~USART_CR3_DEP; 1369 rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; 1370 } else { 1371 cr3 |= USART_CR3_DEP; 1372 rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; 1373 } 1374 1375 } else { 1376 cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP); 1377 cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); 1378 } 1379 1380 /* Configure wake up from low power on start bit detection */ 1381 if (stm32_port->wakeup_src) { 1382 cr3 &= ~USART_CR3_WUS_MASK; 1383 cr3 |= USART_CR3_WUS_START_BIT; 1384 } 1385 1386 writel_relaxed(cr3, port->membase + ofs->cr3); 1387 writel_relaxed(cr2, port->membase + ofs->cr2); 1388 writel_relaxed(cr1, port->membase + ofs->cr1); 1389 1390 stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); 1391 uart_port_unlock_irqrestore(port, flags); 1392 1393 /* Handle modem control interrupts */ 1394 if (UART_ENABLE_MS(port, termios->c_cflag)) 1395 stm32_usart_enable_ms(port); 1396 else 1397 stm32_usart_disable_ms(port); 1398 } 1399
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 794b77512740..e8ab5efad945 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -50,6 +50,7 @@ static struct stm32_usart_info __maybe_unused stm32f4_info = { .rtor = UNDEF_REG, .rqr = UNDEF_REG, .icr = UNDEF_REG, + .presc = UNDEF_REG, }, .cfg = { .uart_enable_bit = 13, @@ -71,6 +72,7 @@ static struct stm32_usart_info __maybe_unused stm32f7_info = { .icr = 0x20, .rdr = 0x24, .tdr = 0x28, + .presc = UNDEF_REG, }, .cfg = { .uart_enable_bit = 0, @@ -93,6 +95,7 @@ static struct stm32_usart_info __maybe_unused stm32h7_info = { .icr = 0x20, .rdr = 0x24, .tdr = 0x28, + .presc = 0x2c, }, .cfg = { .uart_enable_bit = 0, @@ -1145,6 +1148,8 @@ static void stm32_usart_shutdown(struct uart_port *port) free_irq(port->irq, port); } +static const unsigned int stm32_usart_presc_val[] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256}; + static void stm32_usart_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) @@ -1153,17 +1158,19 @@ static void stm32_usart_set_termios(struct uart_port *port, const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_config *cfg = &stm32_port->info->cfg; struct serial_rs485 *rs485conf = &port->rs485; - unsigned int baud, bits; + unsigned int baud, bits, uart_clk, uart_clk_pres; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; - u32 cr1, cr2, cr3, isr; + u32 cr1, cr2, cr3, isr, brr, presc; unsigned long flags; int ret; if (!stm32_port->hw_flow_control) cflag &= ~CRTSCTS; - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); + uart_clk = clk_get_rate(stm32_port->clk); + + baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8); uart_port_lock_irqsave(port, &flags); @@ -1265,27 +1272,48 @@ static void stm32_usart_set_termios(struct uart_port *port, cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } - usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + for (presc = 0; presc <= USART_PRESC_MAX; presc++) { + uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]); + usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud); - /* - * The USART supports 16 or 8 times oversampling. - * By default we prefer 16 times oversampling, so that the receiver - * has a better tolerance to clock deviations. - * 8 times oversampling is only used to achieve higher speeds. - */ - if (usartdiv < 16) { - oversampling = 8; - cr1 |= USART_CR1_OVER8; - stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); - } else { - oversampling = 16; - cr1 &= ~USART_CR1_OVER8; - stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + /* + * The USART supports 16 or 8 times oversampling. + * By default we prefer 16 times oversampling, so that the receiver + * has a better tolerance to clock deviations. + * 8 times oversampling is only used to achieve higher speeds. + */ + if (usartdiv < 16) { + oversampling = 8; + cr1 |= USART_CR1_OVER8; + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); + } else { + oversampling = 16; + cr1 &= ~USART_CR1_OVER8; + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + } + + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; + fraction = usartdiv % oversampling; + brr = mantissa | fraction; + + if (FIELD_FIT(USART_BRR_MASK, brr)) { + if (ofs->presc != UNDEF_REG) { + port->uartclk = uart_clk_pres; + writel_relaxed(presc, port->membase + ofs->presc); + } else if (presc) { + /* We need a prescaler but we don't have it (STM32F4, STM32F7) */ + dev_err(port->dev, + "unable to set baudrate, input clock is too high"); + } + break; + } else if (presc == USART_PRESC_MAX) { + /* Even with prescaler and brr at max value we can't set baudrate */ + dev_err(port->dev, "unable to set baudrate, input clock is too high"); + break; + } } - mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; - fraction = usartdiv % oversampling; - writel_relaxed(mantissa | fraction, port->membase + ofs->brr); + writel_relaxed(brr, port->membase + ofs->brr); uart_update_timeout(port, cflag, baud); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index f59f831b2a10..8cecfdce9386 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -20,6 +20,7 @@ struct stm32_usart_offsets { u8 icr; u8 rdr; u8 tdr; + u8 presc; }; struct stm32_usart_config { @@ -71,6 +72,7 @@ struct stm32_usart_info { #define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_SHIFT 4 #define USART_BRR_04_R_SHIFT 1 +#define USART_BRR_MASK (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK) /* USART_CR1 */ #define USART_CR1_SBK BIT(0) @@ -176,6 +178,10 @@ struct stm32_usart_info { #define USART_ICR_CMCF BIT(17) /* F7 */ #define USART_ICR_WUCF BIT(20) /* H7 */ +/* USART_PRESC */ +#define USART_PRESC GENMASK(3, 0) /* H7 */ +#define USART_PRESC_MAX 0b1011 + #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8
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> --- drivers/tty/serial/stm32-usart.c | 70 ++++++++++++++++++++++---------- drivers/tty/serial/stm32-usart.h | 6 +++ 2 files changed, 55 insertions(+), 21 deletions(-)