8250: microchip: Add 4 Mbps support in PCI1XXXX UART
authorRengarajan S <rengarajan.s@microchip.com>
Thu, 25 Jan 2024 10:06:19 +0000 (15:36 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 28 Jan 2024 03:05:54 +0000 (19:05 -0800)
The current clock input is set to 62.5 MHz for supporting fractional
divider, which enables generation of an acceptable baud rate from any
frequency. With the current clock input the baud rate range is limited
to 3.9 Mbps. Hence, the current range is extended to support 4 Mbps
with Burst mode operation. Divisor calculation for a given baud rate is
updated as the sampling rate is reduced from 16 to 8 for 4 Mbps.

Signed-off-by: Rengarajan S <rengarajan.s@microchip.com>
Link: https://lore.kernel.org/r/20240125100619.154873-1-rengarajan.s@microchip.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_pci1xxxx.c
drivers/tty/serial/8250/8250_port.c

index d53605bf908d61c639f2373d843284b156e2f8fe..6cfeba058dba768baa0923124eeeed791c05357b 100644 (file)
@@ -82,7 +82,8 @@
 #define ADCL_CFG_PIN_SEL                       BIT(1)
 #define ADCL_CFG_EN                            BIT(0)
 
-#define UART_BIT_SAMPLE_CNT                    16
+#define UART_BIT_SAMPLE_CNT_8                  8
+#define UART_BIT_SAMPLE_CNT_16                 16
 #define BAUD_CLOCK_DIV_INT_MSK                 GENMASK(31, 8)
 #define ADCL_CFG_RTS_DELAY_MASK                        GENMASK(11, 8)
 #define UART_CLOCK_DEFAULT                     (62500 * HZ_PER_KHZ)
@@ -96,6 +97,7 @@
        (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
 
 #define UART_BAUD_CLK_DIVISOR_REG              0x54
+#define FRAC_DIV_CFG_REG                       0x58
 
 #define UART_RESET_REG                         0x94
 #define UART_RESET_D3_RESET_DISABLE            BIT(16)
 #define UART_TX_BURST_FIFO                     0xA0
 #define UART_RX_BURST_FIFO                     0xA4
 
+#define UART_BIT_DIVISOR_8                     0x26731000
+#define UART_BIT_DIVISOR_16                    0x6ef71000
+#define UART_BAUD_4MBPS                                4000000
+
 #define MAX_PORTS                              4
 #define PORT_OFFSET                            0x100
 #define RX_BUF_SIZE                            512
@@ -210,15 +216,24 @@ static int pci1xxxx_get_num_ports(struct pci_dev *dev)
 static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
                                         unsigned int baud, unsigned int *frac)
 {
+       unsigned int uart_sample_cnt;
        unsigned int quot;
 
+       if (baud >= UART_BAUD_4MBPS) {
+               uart_sample_cnt = UART_BIT_SAMPLE_CNT_8;
+               writel(UART_BIT_DIVISOR_8, (port->membase + FRAC_DIV_CFG_REG));
+       } else {
+               uart_sample_cnt = UART_BIT_SAMPLE_CNT_16;
+               writel(UART_BIT_DIVISOR_16, (port->membase + FRAC_DIV_CFG_REG));
+       }
+
        /*
         * Calculate baud rate sampling period in nanoseconds.
         * Fractional part x denotes x/255 parts of a nanosecond.
         */
-       quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
-       *frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
-                 255 / UART_BIT_SAMPLE_CNT / baud;
+       quot = NSEC_PER_SEC / (baud * uart_sample_cnt);
+       *frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) *
+                 255 / uart_sample_cnt / baud;
 
        return quot;
 }
@@ -237,7 +252,16 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
        u32 delay_in_baud_periods;
        u32 baud_period_in_ns;
        u32 mode_cfg = 0;
+       u32 sample_cnt;
        u32 clock_div;
+       u32 frac_div;
+
+       frac_div = readl(port->membase + FRAC_DIV_CFG_REG);
+
+       if (frac_div == UART_BIT_DIVISOR_16)
+               sample_cnt = UART_BIT_SAMPLE_CNT_16;
+       else
+               sample_cnt = UART_BIT_SAMPLE_CNT_8;
 
        /*
         * pci1xxxx's uart hardware supports only RTS delay after
@@ -253,7 +277,7 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
                        clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
                        baud_period_in_ns =
                                FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
-                               UART_BIT_SAMPLE_CNT;
+                               sample_cnt;
                        delay_in_baud_periods =
                                rs485->delay_rts_after_send * NSEC_PER_MSEC /
                                baud_period_in_ns;
index 8ca061d3bbb9215d04a4381a84f07b09147f2c8a..c37905ea3cae64b9a3e3116d2389544030a25dd3 100644 (file)
@@ -2681,6 +2681,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
                                             struct ktermios *termios,
                                             const struct ktermios *old)
 {
+       struct uart_8250_port *up = up_to_u8250p(port);
        unsigned int tolerance = port->uartclk / 100;
        unsigned int min;
        unsigned int max;
@@ -2698,6 +2699,12 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
                max = (port->uartclk + tolerance) / 16;
        }
 
+       /*
+        * Microchip PCI1XXXX UART supports maximum baud rate up to 4 Mbps
+        */
+       if (up->port.type == PORT_MCHP16550A)
+               max = 4000000;
+
        /*
         * Ask the core to calculate the divisor for us.
         * Allow 1% tolerance at the upper limit so uart clks marginally