| commit 15e12c71ee848d275cf1f9ca8e1cf3676f0bb1af |
| Author: Yu Zhang <yuzhang@asrmicro.com> |
| Date: Tue Oct 10 04:28:07 2023 -0400 |
| |
| k-driver: uart: update uart clk and baudrate configuration |
| |
| Summary: |
| type: design change |
| |
| priority: normal |
| |
| impact: uart support more clock sources and baudrates |
| |
| details: |
| Use 58.5m clock source to derive 115200 and some other |
| baudrates, it's mainly used by AP UART to output logs. |
| Use 78m clock source to derive other high speed baudrates |
| for the UARTs which are used to connect peripherals. |
| This is for 1802s/1803/1828, 1826 use the old way. |
| |
| Test Plan: |
| AP UARTs can work with different clock sources |
| |
| dependency: None |
| |
| onto branches: master |
| |
| redmine: N/A |
| |
| Reviewers: lianghu, xhtan, gaoxhong, feilv, xuepingwang |
| |
| Reviewed By: xhtan |
| |
| Differential Revision: http://10.26.128.140/D10291 |
| |
| diff --git a/drivers/clk/mmp/clk-asr1802s.c b/drivers/clk/mmp/clk-asr1802s.c |
| old mode 100755 |
| new mode 100644 |
| index 0492fce33..167123913 |
| --- a/drivers/clk/mmp/clk-asr1802s.c |
| +++ b/drivers/clk/mmp/clk-asr1802s.c |
| @@ -115,10 +115,12 @@ static struct clk_factor_masks uart_factor_masks = { |
| |
| static struct clk_factor_tbl uart_factor_tbl[] = { |
| {.num = 8125, .den = 1536}, /*14.745MHZ */ |
| - {.num = 0x1f3e, .den = 0x600}, /*14.97MHZ */ |
| - {.num = 0x1fdc, .den = 0x689}, /*15.99MHZ */ |
| - {.num = 3250, .den = 2000}, /*48MHZ */ |
| + {.num = 7998, .den = 1536}, /*14.97MHZ */ |
| + {.num = 8156, .den = 1673}, /*15.99MHZ */ |
| + {.num = 3900, .den = 2000}, /*40 MHZ */ |
| + {.num = 3250, .den = 2000}, /*48 MHZ */ |
| {.num = 2100, .den = 1600}, /*59.429MHZ */ |
| + {.num = 2039, .den = 1673}, /*63.999MHZ */ |
| }; |
| |
| static struct clk_factor_masks isccr1_factor_masks = { |
| @@ -142,7 +144,8 @@ static const struct clk_div_table clk_ssp1_ref_table[] = { |
| { .val = 0, .div = 0 }, |
| }; |
| |
| -static const char *uart_parent[] = {"pll1_3_16", "uart_pll"}; |
| +static const char *uart_parent[] = {"pll1_3_32", "uart_pll"}; |
| +static const char *cpuart_parent[] = {"uart_pll", "pll1_3_32"}; |
| static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12", "pll1_192", "pll1_384", "pll1_768"}; |
| static const char *ssp1_parent[] = {"pll1_2", "vctcxo"}; |
| |
| @@ -284,9 +287,9 @@ void __init asr1802s_pll_init(void *mpmu_base, void *apbs_base, void *apmu_base) |
| CLK_SET_RATE_PARENT, 2, 3); |
| clk_register_clkdev(clk, "pll1_2_1_5", NULL); |
| |
| - clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1_624", |
| - CLK_SET_RATE_PARENT, 3, 16); |
| - clk_register_clkdev(clk, "pll1_3_16", NULL); |
| + clk = clk_register_fixed_factor(NULL, "pll1_3_32", "pll1_624", |
| + CLK_SET_RATE_PARENT, 3, 32); |
| + clk_register_clkdev(clk, "pll1_3_32", NULL); |
| } |
| |
| /* |
| @@ -1104,31 +1107,31 @@ void __init asr1802s_clk_init(void) |
| clk = clk_register_mux(NULL, "uart0_mux", uart_parent, |
| ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, |
| apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); |
| - clk_set_parent(clk, uart_pll); |
| + //clk_set_parent(clk, uart_pll); |
| clk_register_clkdev(clk, "uart_mux.0", NULL); |
| |
| clk = mmp_clk_register_apbc("uart0", "uart0_mux", |
| - apbc_base + APBC_UART0, 10, 0, &clk_lock); |
| + apbc_base + APBC_UART0, 10, APBC_MUX, &clk_lock); |
| clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); |
| |
| clk = clk_register_mux(NULL, "uart1_mux", uart_parent, |
| ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, |
| apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); |
| - clk_set_parent(clk, uart_pll); |
| + //clk_set_parent(clk, uart_pll); |
| clk_register_clkdev(clk, "uart_mux.1", NULL); |
| |
| clk = mmp_clk_register_apbc("uart1", "uart1_mux", |
| - apbc_base + APBC_UART1, 10, 0, &clk_lock); |
| + apbc_base + APBC_UART1, 10, APBC_MUX, &clk_lock); |
| clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); |
| |
| - clk = clk_register_mux(NULL, "uart2_mux", uart_parent, |
| - ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, |
| + clk = clk_register_mux(NULL, "uart2_mux", cpuart_parent, |
| + ARRAY_SIZE(cpuart_parent), CLK_SET_RATE_PARENT, |
| apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock); |
| - clk_set_parent(clk, uart_pll); |
| + //clk_set_parent(clk, uart_pll); |
| clk_register_clkdev(clk, "uart_mux.2", NULL); |
| |
| clk = mmp_clk_register_apbc("uart2", "uart2_mux", |
| - apbcp_base + APBCP_UART2, 10, 0, &clk_lock); |
| + apbcp_base + APBCP_UART2, 10, APBC_MUX, &clk_lock); |
| clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); |
| |
| clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, |
| diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c |
| index 1a173dbb5..5914f59d3 100644 |
| --- a/drivers/tty/serial/pxa.c |
| +++ b/drivers/tty/serial/pxa.c |
| @@ -1101,6 +1101,75 @@ static void serial_pxa_shutdown(struct uart_port *port) |
| serial_out(up, UART_FCR, 0); |
| } |
| |
| +#ifdef CONFIG_CPU_ASR1802S |
| +static int pxa_set_baudrate_clk(struct uart_port *port, unsigned int baud) |
| +{ |
| + struct uart_pxa_port *up = (struct uart_pxa_port *)port; |
| + unsigned long rate; |
| + int ret; |
| + struct clk *clk; |
| + |
| + switch (baud) { |
| + case 500000: |
| + case 1000000: |
| + case 1500000: |
| + case 3000000: |
| + rate = 48000000; /* from 78m, uart pll1 */ |
| + break; |
| + case 38400: |
| + case 57600: |
| + case 115200: |
| + case 576000: |
| + case 1152000: |
| + case 1842000: |
| + case 3500000: |
| + rate = 58500000; /* 58.5M, all SoCs have */ |
| + break; |
| + case 2000000: |
| + case 4000000: |
| + rate = 63999000; /* from 78m, uart pll1 */ |
| + break; |
| + case 2500000: |
| + rate = 40000000; /* from 78m, uart pll1 */ |
| + break; |
| + default: |
| + if (cpu_is_asr1803()) |
| + rate = 14970000; /* from 78m, uart pll1 */ |
| + else |
| + rate = 14740000; /* from 78m, uart pll1 */ |
| + break; |
| + } |
| + |
| + /* |
| + * It seems that the clock driver can not change uart clk to a frequency |
| + * supported by its M/N factor parent(uart_pll) from another pll1_3_32 parent. |
| + * Therefore, we workaround it through change its uart_pll parent directly here. |
| + * v2102 branch doesn't has such issue, need to debug in the furture. |
| + */ |
| + if(rate != 58500000) { /* 58.5 is from pll1_3_32 */ |
| + clk = clk_get(NULL, "uart_pll"); |
| + if (clk) |
| + clk_set_rate(clk, rate); |
| + } |
| + |
| + /* For one target baudrate, the quot is figured out |
| + * by formula [quot] = clk_rate / 16 / baudrate, and |
| + * choose the closest integral value above zero. |
| + * So for different clk source, the real baudrate is |
| + * baudrate = clk_rate / 16 / [quot]. */ |
| + ret = clk_set_rate(up->clk, rate); |
| + if (ret < 0) { |
| + dev_err(port->dev, |
| + "Failed to set clk rate %lu\n", rate); |
| + return ret; |
| + } |
| + |
| + up->port.uartclk = clk_get_rate(up->clk); |
| + |
| + return 0; |
| +} |
| +#endif |
| + |
| static void |
| serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| struct ktermios *old) |
| @@ -1110,6 +1179,9 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| unsigned long flags; |
| unsigned int baud, quot = 0; |
| unsigned int dll; |
| +#ifdef CONFIG_CPU_ASR1802S |
| + int ret; |
| +#endif |
| |
| switch (termios->c_cflag & CSIZE) { |
| case CS5: |
| @@ -1134,12 +1206,29 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| if (!(termios->c_cflag & PARODD)) |
| cval |= UART_LCR_EPAR; |
| |
| +#ifdef CONFIG_CPU_ASR1802S |
| + baud = uart_get_baud_rate(port, termios, old, 0, PXA_MAX_BAUD*16*4/16); |
| + if (!baud) |
| + baud = 115200; |
| + |
| + ret = pxa_set_baudrate_clk(port, baud); |
| + if (ret < 0) { |
| + dev_err(port->dev, "Failed to set baud rate clk: %d\n", ret); |
| + return; |
| + } |
| + |
| + quot = uart_get_divisor(port, baud); |
| +#else |
| up->clk = clk_get(up->port.dev, "uart_pll"); |
| if (unlikely(IS_ERR(up->clk))){ |
| return; |
| } |
| |
| baud = uart_get_baud_rate(port, termios, old, 0, PXA_MAX_BAUD*16*4/16); |
| + if (!baud) |
| + baud = 115200; |
| + |
| + /* 1826 keeps the old way */ |
| if (baud == 1842000 || baud > 3000000) { |
| clk_set_rate(up->clk, 59429000); |
| } else if (baud > 1000000) { |
| @@ -1147,10 +1236,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| } else if (baud > 921600) { |
| clk_set_rate(up->clk, 15990000); |
| }else{ |
| - if (cpu_is_asr1803()) |
| - clk_set_rate(up->clk, 14970000); |
| - else |
| - clk_set_rate(up->clk, 14740000); |
| + clk_set_rate(up->clk, 14740000); |
| } |
| |
| up->port.uartclk = clk_get_rate(up->clk); |
| @@ -1170,6 +1256,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| } else { |
| quot = uart_get_divisor(port, baud); |
| } |
| +#endif |
| |
| if (up->dma_enable) { |
| fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32 | |