blob: 48fb6ad32ce7a944e3b4c304aa8f185de8a0226c [file] [log] [blame]
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 |