b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | commit 15e12c71ee848d275cf1f9ca8e1cf3676f0bb1af |
| 2 | Author: Yu Zhang <yuzhang@asrmicro.com> |
| 3 | Date: Tue Oct 10 04:28:07 2023 -0400 |
| 4 | |
| 5 | k-driver: uart: update uart clk and baudrate configuration |
| 6 | |
| 7 | Summary: |
| 8 | type: design change |
| 9 | |
| 10 | priority: normal |
| 11 | |
| 12 | impact: uart support more clock sources and baudrates |
| 13 | |
| 14 | details: |
| 15 | Use 58.5m clock source to derive 115200 and some other |
| 16 | baudrates, it's mainly used by AP UART to output logs. |
| 17 | Use 78m clock source to derive other high speed baudrates |
| 18 | for the UARTs which are used to connect peripherals. |
| 19 | This is for 1802s/1803/1828, 1826 use the old way. |
| 20 | |
| 21 | Test Plan: |
| 22 | AP UARTs can work with different clock sources |
| 23 | |
| 24 | dependency: None |
| 25 | |
| 26 | onto branches: master |
| 27 | |
| 28 | redmine: N/A |
| 29 | |
| 30 | Reviewers: lianghu, xhtan, gaoxhong, feilv, xuepingwang |
| 31 | |
| 32 | Reviewed By: xhtan |
| 33 | |
| 34 | Differential Revision: http://10.26.128.140/D10291 |
| 35 | |
| 36 | diff --git a/drivers/clk/mmp/clk-asr1802s.c b/drivers/clk/mmp/clk-asr1802s.c |
| 37 | old mode 100755 |
| 38 | new mode 100644 |
| 39 | index 0492fce33..167123913 |
| 40 | --- a/drivers/clk/mmp/clk-asr1802s.c |
| 41 | +++ b/drivers/clk/mmp/clk-asr1802s.c |
| 42 | @@ -115,10 +115,12 @@ static struct clk_factor_masks uart_factor_masks = { |
| 43 | |
| 44 | static struct clk_factor_tbl uart_factor_tbl[] = { |
| 45 | {.num = 8125, .den = 1536}, /*14.745MHZ */ |
| 46 | - {.num = 0x1f3e, .den = 0x600}, /*14.97MHZ */ |
| 47 | - {.num = 0x1fdc, .den = 0x689}, /*15.99MHZ */ |
| 48 | - {.num = 3250, .den = 2000}, /*48MHZ */ |
| 49 | + {.num = 7998, .den = 1536}, /*14.97MHZ */ |
| 50 | + {.num = 8156, .den = 1673}, /*15.99MHZ */ |
| 51 | + {.num = 3900, .den = 2000}, /*40 MHZ */ |
| 52 | + {.num = 3250, .den = 2000}, /*48 MHZ */ |
| 53 | {.num = 2100, .den = 1600}, /*59.429MHZ */ |
| 54 | + {.num = 2039, .den = 1673}, /*63.999MHZ */ |
| 55 | }; |
| 56 | |
| 57 | static struct clk_factor_masks isccr1_factor_masks = { |
| 58 | @@ -142,7 +144,8 @@ static const struct clk_div_table clk_ssp1_ref_table[] = { |
| 59 | { .val = 0, .div = 0 }, |
| 60 | }; |
| 61 | |
| 62 | -static const char *uart_parent[] = {"pll1_3_16", "uart_pll"}; |
| 63 | +static const char *uart_parent[] = {"pll1_3_32", "uart_pll"}; |
| 64 | +static const char *cpuart_parent[] = {"uart_pll", "pll1_3_32"}; |
| 65 | static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12", "pll1_192", "pll1_384", "pll1_768"}; |
| 66 | static const char *ssp1_parent[] = {"pll1_2", "vctcxo"}; |
| 67 | |
| 68 | @@ -284,9 +287,9 @@ void __init asr1802s_pll_init(void *mpmu_base, void *apbs_base, void *apmu_base) |
| 69 | CLK_SET_RATE_PARENT, 2, 3); |
| 70 | clk_register_clkdev(clk, "pll1_2_1_5", NULL); |
| 71 | |
| 72 | - clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1_624", |
| 73 | - CLK_SET_RATE_PARENT, 3, 16); |
| 74 | - clk_register_clkdev(clk, "pll1_3_16", NULL); |
| 75 | + clk = clk_register_fixed_factor(NULL, "pll1_3_32", "pll1_624", |
| 76 | + CLK_SET_RATE_PARENT, 3, 32); |
| 77 | + clk_register_clkdev(clk, "pll1_3_32", NULL); |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | @@ -1104,31 +1107,31 @@ void __init asr1802s_clk_init(void) |
| 82 | clk = clk_register_mux(NULL, "uart0_mux", uart_parent, |
| 83 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, |
| 84 | apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); |
| 85 | - clk_set_parent(clk, uart_pll); |
| 86 | + //clk_set_parent(clk, uart_pll); |
| 87 | clk_register_clkdev(clk, "uart_mux.0", NULL); |
| 88 | |
| 89 | clk = mmp_clk_register_apbc("uart0", "uart0_mux", |
| 90 | - apbc_base + APBC_UART0, 10, 0, &clk_lock); |
| 91 | + apbc_base + APBC_UART0, 10, APBC_MUX, &clk_lock); |
| 92 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); |
| 93 | |
| 94 | clk = clk_register_mux(NULL, "uart1_mux", uart_parent, |
| 95 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, |
| 96 | apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); |
| 97 | - clk_set_parent(clk, uart_pll); |
| 98 | + //clk_set_parent(clk, uart_pll); |
| 99 | clk_register_clkdev(clk, "uart_mux.1", NULL); |
| 100 | |
| 101 | clk = mmp_clk_register_apbc("uart1", "uart1_mux", |
| 102 | - apbc_base + APBC_UART1, 10, 0, &clk_lock); |
| 103 | + apbc_base + APBC_UART1, 10, APBC_MUX, &clk_lock); |
| 104 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); |
| 105 | |
| 106 | - clk = clk_register_mux(NULL, "uart2_mux", uart_parent, |
| 107 | - ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, |
| 108 | + clk = clk_register_mux(NULL, "uart2_mux", cpuart_parent, |
| 109 | + ARRAY_SIZE(cpuart_parent), CLK_SET_RATE_PARENT, |
| 110 | apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock); |
| 111 | - clk_set_parent(clk, uart_pll); |
| 112 | + //clk_set_parent(clk, uart_pll); |
| 113 | clk_register_clkdev(clk, "uart_mux.2", NULL); |
| 114 | |
| 115 | clk = mmp_clk_register_apbc("uart2", "uart2_mux", |
| 116 | - apbcp_base + APBCP_UART2, 10, 0, &clk_lock); |
| 117 | + apbcp_base + APBCP_UART2, 10, APBC_MUX, &clk_lock); |
| 118 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); |
| 119 | |
| 120 | clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, |
| 121 | diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c |
| 122 | index 1a173dbb5..5914f59d3 100644 |
| 123 | --- a/drivers/tty/serial/pxa.c |
| 124 | +++ b/drivers/tty/serial/pxa.c |
| 125 | @@ -1101,6 +1101,75 @@ static void serial_pxa_shutdown(struct uart_port *port) |
| 126 | serial_out(up, UART_FCR, 0); |
| 127 | } |
| 128 | |
| 129 | +#ifdef CONFIG_CPU_ASR1802S |
| 130 | +static int pxa_set_baudrate_clk(struct uart_port *port, unsigned int baud) |
| 131 | +{ |
| 132 | + struct uart_pxa_port *up = (struct uart_pxa_port *)port; |
| 133 | + unsigned long rate; |
| 134 | + int ret; |
| 135 | + struct clk *clk; |
| 136 | + |
| 137 | + switch (baud) { |
| 138 | + case 500000: |
| 139 | + case 1000000: |
| 140 | + case 1500000: |
| 141 | + case 3000000: |
| 142 | + rate = 48000000; /* from 78m, uart pll1 */ |
| 143 | + break; |
| 144 | + case 38400: |
| 145 | + case 57600: |
| 146 | + case 115200: |
| 147 | + case 576000: |
| 148 | + case 1152000: |
| 149 | + case 1842000: |
| 150 | + case 3500000: |
| 151 | + rate = 58500000; /* 58.5M, all SoCs have */ |
| 152 | + break; |
| 153 | + case 2000000: |
| 154 | + case 4000000: |
| 155 | + rate = 63999000; /* from 78m, uart pll1 */ |
| 156 | + break; |
| 157 | + case 2500000: |
| 158 | + rate = 40000000; /* from 78m, uart pll1 */ |
| 159 | + break; |
| 160 | + default: |
| 161 | + if (cpu_is_asr1803()) |
| 162 | + rate = 14970000; /* from 78m, uart pll1 */ |
| 163 | + else |
| 164 | + rate = 14740000; /* from 78m, uart pll1 */ |
| 165 | + break; |
| 166 | + } |
| 167 | + |
| 168 | + /* |
| 169 | + * It seems that the clock driver can not change uart clk to a frequency |
| 170 | + * supported by its M/N factor parent(uart_pll) from another pll1_3_32 parent. |
| 171 | + * Therefore, we workaround it through change its uart_pll parent directly here. |
| 172 | + * v2102 branch doesn't has such issue, need to debug in the furture. |
| 173 | + */ |
| 174 | + if(rate != 58500000) { /* 58.5 is from pll1_3_32 */ |
| 175 | + clk = clk_get(NULL, "uart_pll"); |
| 176 | + if (clk) |
| 177 | + clk_set_rate(clk, rate); |
| 178 | + } |
| 179 | + |
| 180 | + /* For one target baudrate, the quot is figured out |
| 181 | + * by formula [quot] = clk_rate / 16 / baudrate, and |
| 182 | + * choose the closest integral value above zero. |
| 183 | + * So for different clk source, the real baudrate is |
| 184 | + * baudrate = clk_rate / 16 / [quot]. */ |
| 185 | + ret = clk_set_rate(up->clk, rate); |
| 186 | + if (ret < 0) { |
| 187 | + dev_err(port->dev, |
| 188 | + "Failed to set clk rate %lu\n", rate); |
| 189 | + return ret; |
| 190 | + } |
| 191 | + |
| 192 | + up->port.uartclk = clk_get_rate(up->clk); |
| 193 | + |
| 194 | + return 0; |
| 195 | +} |
| 196 | +#endif |
| 197 | + |
| 198 | static void |
| 199 | serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| 200 | struct ktermios *old) |
| 201 | @@ -1110,6 +1179,9 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| 202 | unsigned long flags; |
| 203 | unsigned int baud, quot = 0; |
| 204 | unsigned int dll; |
| 205 | +#ifdef CONFIG_CPU_ASR1802S |
| 206 | + int ret; |
| 207 | +#endif |
| 208 | |
| 209 | switch (termios->c_cflag & CSIZE) { |
| 210 | case CS5: |
| 211 | @@ -1134,12 +1206,29 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| 212 | if (!(termios->c_cflag & PARODD)) |
| 213 | cval |= UART_LCR_EPAR; |
| 214 | |
| 215 | +#ifdef CONFIG_CPU_ASR1802S |
| 216 | + baud = uart_get_baud_rate(port, termios, old, 0, PXA_MAX_BAUD*16*4/16); |
| 217 | + if (!baud) |
| 218 | + baud = 115200; |
| 219 | + |
| 220 | + ret = pxa_set_baudrate_clk(port, baud); |
| 221 | + if (ret < 0) { |
| 222 | + dev_err(port->dev, "Failed to set baud rate clk: %d\n", ret); |
| 223 | + return; |
| 224 | + } |
| 225 | + |
| 226 | + quot = uart_get_divisor(port, baud); |
| 227 | +#else |
| 228 | up->clk = clk_get(up->port.dev, "uart_pll"); |
| 229 | if (unlikely(IS_ERR(up->clk))){ |
| 230 | return; |
| 231 | } |
| 232 | |
| 233 | baud = uart_get_baud_rate(port, termios, old, 0, PXA_MAX_BAUD*16*4/16); |
| 234 | + if (!baud) |
| 235 | + baud = 115200; |
| 236 | + |
| 237 | + /* 1826 keeps the old way */ |
| 238 | if (baud == 1842000 || baud > 3000000) { |
| 239 | clk_set_rate(up->clk, 59429000); |
| 240 | } else if (baud > 1000000) { |
| 241 | @@ -1147,10 +1236,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| 242 | } else if (baud > 921600) { |
| 243 | clk_set_rate(up->clk, 15990000); |
| 244 | }else{ |
| 245 | - if (cpu_is_asr1803()) |
| 246 | - clk_set_rate(up->clk, 14970000); |
| 247 | - else |
| 248 | - clk_set_rate(up->clk, 14740000); |
| 249 | + clk_set_rate(up->clk, 14740000); |
| 250 | } |
| 251 | |
| 252 | up->port.uartclk = clk_get_rate(up->clk); |
| 253 | @@ -1170,6 +1256,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, |
| 254 | } else { |
| 255 | quot = uart_get_divisor(port, baud); |
| 256 | } |
| 257 | +#endif |
| 258 | |
| 259 | if (up->dma_enable) { |
| 260 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32 | |