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

serial: stm32: get FIFO size from hwcfg register

Since STM32MP25, FIFO size could vary regarding the STM32MPxx version.
So we get this size from "hwcfgr1" register and compute threshold values
corresponding to the ratio given by reference manual.

As STM32MP1x, STM32MP25 and STM32H7 share the same compatible and STM32H7
doesn't have a register to get FIFO size, we force FIFO size to 16 in case
of zero read from hwcfgr1 register.

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

authored by

Valentin Caron and committed by
Greg Kroah-Hartman
5d207f62 7be985bd

+94 -70
+89 -69
drivers/tty/serial/stm32-usart.c
··· 40 40 /* Register offsets */ 41 41 static struct stm32_usart_info __maybe_unused stm32f4_info = { 42 42 .ofs = { 43 - .isr = 0x00, 44 - .rdr = 0x04, 45 - .tdr = 0x04, 46 - .brr = 0x08, 47 - .cr1 = 0x0c, 48 - .cr2 = 0x10, 49 - .cr3 = 0x14, 50 - .gtpr = 0x18, 51 - .rtor = UNDEF_REG, 52 - .rqr = UNDEF_REG, 53 - .icr = UNDEF_REG, 54 - .presc = UNDEF_REG, 43 + .isr = 0x00, 44 + .rdr = 0x04, 45 + .tdr = 0x04, 46 + .brr = 0x08, 47 + .cr1 = 0x0c, 48 + .cr2 = 0x10, 49 + .cr3 = 0x14, 50 + .gtpr = 0x18, 51 + .rtor = UNDEF_REG, 52 + .rqr = UNDEF_REG, 53 + .icr = UNDEF_REG, 54 + .presc = UNDEF_REG, 55 + .hwcfgr1 = UNDEF_REG, 55 56 }, 56 57 .cfg = { 57 58 .uart_enable_bit = 13, 58 59 .has_7bits_data = false, 59 - .fifosize = 1, 60 60 } 61 61 }; 62 62 63 63 static struct stm32_usart_info __maybe_unused stm32f7_info = { 64 64 .ofs = { 65 - .cr1 = 0x00, 66 - .cr2 = 0x04, 67 - .cr3 = 0x08, 68 - .brr = 0x0c, 69 - .gtpr = 0x10, 70 - .rtor = 0x14, 71 - .rqr = 0x18, 72 - .isr = 0x1c, 73 - .icr = 0x20, 74 - .rdr = 0x24, 75 - .tdr = 0x28, 76 - .presc = UNDEF_REG, 65 + .cr1 = 0x00, 66 + .cr2 = 0x04, 67 + .cr3 = 0x08, 68 + .brr = 0x0c, 69 + .gtpr = 0x10, 70 + .rtor = 0x14, 71 + .rqr = 0x18, 72 + .isr = 0x1c, 73 + .icr = 0x20, 74 + .rdr = 0x24, 75 + .tdr = 0x28, 76 + .presc = UNDEF_REG, 77 + .hwcfgr1 = UNDEF_REG, 77 78 }, 78 79 .cfg = { 79 80 .uart_enable_bit = 0, 80 81 .has_7bits_data = true, 81 82 .has_swap = true, 82 - .fifosize = 1, 83 83 } 84 84 }; 85 85 86 86 static struct stm32_usart_info __maybe_unused stm32h7_info = { 87 87 .ofs = { 88 - .cr1 = 0x00, 89 - .cr2 = 0x04, 90 - .cr3 = 0x08, 91 - .brr = 0x0c, 92 - .gtpr = 0x10, 93 - .rtor = 0x14, 94 - .rqr = 0x18, 95 - .isr = 0x1c, 96 - .icr = 0x20, 97 - .rdr = 0x24, 98 - .tdr = 0x28, 99 - .presc = 0x2c, 88 + .cr1 = 0x00, 89 + .cr2 = 0x04, 90 + .cr3 = 0x08, 91 + .brr = 0x0c, 92 + .gtpr = 0x10, 93 + .rtor = 0x14, 94 + .rqr = 0x18, 95 + .isr = 0x1c, 96 + .icr = 0x20, 97 + .rdr = 0x24, 98 + .tdr = 0x28, 99 + .presc = 0x2c, 100 + .hwcfgr1 = 0x3f0, 100 101 }, 101 102 .cfg = { 102 103 .uart_enable_bit = 0, ··· 105 104 .has_swap = true, 106 105 .has_wakeup = true, 107 106 .has_fifo = true, 108 - .fifosize = 16, 109 107 } 110 108 }; 111 109 ··· 1498 1498 #endif /* CONFIG_CONSOLE_POLL */ 1499 1499 }; 1500 1500 1501 - /* 1502 - * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG) 1503 - * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case, 1504 - * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE. 1505 - * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1. 1506 - */ 1507 - static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 }; 1501 + struct stm32_usart_thresh_ratio { 1502 + int mul; 1503 + int div; 1504 + }; 1508 1505 1509 - static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p, 1510 - int *ftcfg) 1506 + static const struct stm32_usart_thresh_ratio stm32h7_usart_fifo_thresh_cfg[] = { 1507 + {1, 8}, {1, 4}, {1, 2}, {3, 4}, {7, 8}, {1, 1} }; 1508 + 1509 + static int stm32_usart_get_thresh_value(u32 fifo_size, int index) 1511 1510 { 1512 - u32 bytes, i; 1511 + return fifo_size * stm32h7_usart_fifo_thresh_cfg[index].mul / 1512 + stm32h7_usart_fifo_thresh_cfg[index].div; 1513 + } 1513 1514 1514 - /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */ 1515 + static int stm32_usart_get_ftcfg(struct platform_device *pdev, struct stm32_port *stm32port, 1516 + const char *p, int *ftcfg) 1517 + { 1518 + const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; 1519 + u32 bytes, i, cfg8; 1520 + int fifo_size; 1521 + 1522 + if (WARN_ON(ofs->hwcfgr1 == UNDEF_REG)) 1523 + return 1; 1524 + 1525 + cfg8 = FIELD_GET(USART_HWCFGR1_CFG8, 1526 + readl_relaxed(stm32port->port.membase + ofs->hwcfgr1)); 1527 + 1528 + /* On STM32H7, hwcfgr is not present, so returned value will be 0 */ 1529 + fifo_size = cfg8 ? 1 << cfg8 : STM32H7_USART_FIFO_SIZE; 1530 + 1531 + /* DT option to get RX & TX FIFO threshold (default to half fifo size) */ 1515 1532 if (of_property_read_u32(pdev->dev.of_node, p, &bytes)) 1516 - bytes = 8; 1533 + bytes = fifo_size / 2; 1517 1534 1518 - for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) 1519 - if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes) 1535 + if (bytes < stm32_usart_get_thresh_value(fifo_size, 0)) { 1536 + *ftcfg = -EINVAL; 1537 + return fifo_size; 1538 + } 1539 + 1540 + for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) { 1541 + if (stm32_usart_get_thresh_value(fifo_size, i) >= bytes) 1520 1542 break; 1543 + } 1521 1544 if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg)) 1522 1545 i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1; 1523 1546 1524 - dev_dbg(&pdev->dev, "%s set to %d bytes\n", p, 1525 - stm32h7_usart_fifo_thresh_cfg[i]); 1547 + dev_dbg(&pdev->dev, "%s set to %d/%d bytes\n", p, 1548 + stm32_usart_get_thresh_value(fifo_size, i), fifo_size); 1526 1549 1527 - /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */ 1528 - if (i) 1529 - *ftcfg = i - 1; 1530 - else 1531 - *ftcfg = -EINVAL; 1550 + *ftcfg = i; 1551 + return fifo_size; 1532 1552 } 1533 1553 1534 1554 static void stm32_usart_deinit_port(struct stm32_port *stm32port) ··· 1578 1558 port->flags = UPF_BOOT_AUTOCONF; 1579 1559 port->ops = &stm32_uart_ops; 1580 1560 port->dev = &pdev->dev; 1581 - port->fifosize = stm32port->info->cfg.fifosize; 1582 1561 port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); 1583 1562 port->irq = irq; 1584 1563 port->rs485_config = stm32_usart_config_rs485; ··· 1592 1573 1593 1574 stm32port->swap = stm32port->info->cfg.has_swap && 1594 1575 of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"); 1595 - 1596 - stm32port->fifoen = stm32port->info->cfg.has_fifo; 1597 - if (stm32port->fifoen) { 1598 - stm32_usart_get_ftcfg(pdev, "rx-threshold", 1599 - &stm32port->rxftcfg); 1600 - stm32_usart_get_ftcfg(pdev, "tx-threshold", 1601 - &stm32port->txftcfg); 1602 - } 1603 1576 1604 1577 port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 1605 1578 if (IS_ERR(port->membase)) ··· 1613 1602 if (!stm32port->port.uartclk) { 1614 1603 ret = -EINVAL; 1615 1604 goto err_clk; 1605 + } 1606 + 1607 + stm32port->fifoen = stm32port->info->cfg.has_fifo; 1608 + if (stm32port->fifoen) { 1609 + stm32_usart_get_ftcfg(pdev, stm32port, "rx-threshold", &stm32port->rxftcfg); 1610 + port->fifosize = stm32_usart_get_ftcfg(pdev, stm32port, "tx-threshold", 1611 + &stm32port->txftcfg); 1612 + } else { 1613 + port->fifosize = 1; 1616 1614 } 1617 1615 1618 1616 stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0);
+5 -1
drivers/tty/serial/stm32-usart.h
··· 21 21 u16 rdr; 22 22 u16 tdr; 23 23 u16 presc; 24 + u16 hwcfgr1; 24 25 }; 25 26 26 27 struct stm32_usart_config { ··· 30 29 bool has_swap; 31 30 bool has_wakeup; 32 31 bool has_fifo; 33 - int fifosize; 34 32 }; 35 33 36 34 struct stm32_usart_info { ··· 182 182 #define USART_PRESC GENMASK(3, 0) /* H7 */ 183 183 #define USART_PRESC_MAX 0b1011 184 184 185 + /* USART_HWCFCR1 */ 186 + #define USART_HWCFGR1_CFG8 GENMASK(31, 28) /* MP1 */ 187 + 185 188 #define STM32_SERIAL_NAME "ttySTM" 186 189 #define STM32_MAX_PORTS 9 190 + #define STM32H7_USART_FIFO_SIZE 16 187 191 188 192 #define RX_BUF_L 4096 /* dma rx buffer length */ 189 193 #define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */