[PATCH 7/8] serial: 8250/ingenic: Add support for the JZ4750/JZ4755 SoCs

Siarhei Volkau
2022-10-09T18:15:28Z

These SoCs are close to others but they have a clock divisor /2 for low
clock peripherals, thus to set up a proper baud rate we need to take
this into account.

The divisor bit is located in CGU area, unfortunately the clk framework
can't be used at early boot steps, so it's checked by direct readl()
call.

Signed-off-by: Siarhei Volkau <lis8215@gmail.com>
---
drivers/tty/serial/8250/8250_ingenic.c | 39 ++++++++++++++++++++++----
1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 2b2f5d8d2..f2662720d 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -70,7 +70,8 @@ static void ingenic_early_console_write(struct console *console,
ingenic_early_console_putc);
}

-static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev)
+static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev,
+ int clkdiv)
{
void *fdt = initial_boot_params;
const __be32 *prop;
@@ -84,11 +85,11 @@ static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev
if (!prop)
return;

- dev->port.uartclk = be32_to_cpup(prop);
+ dev->port.uartclk = be32_to_cpup(prop) / clkdiv;
}

-static int __init ingenic_early_console_setup(struct earlycon_device *dev,
- const char *opt)
+static int __init ingenic_earlycon_setup_common(struct earlycon_device *dev,
+ const char *opt, int clkdiv)
{
struct uart_port *port = &dev->port;
unsigned int divisor;
@@ -103,7 +104,7 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
uart_parse_options(opt, &baud, &parity, &bits, &flow);
}

- ingenic_early_console_setup_clock(dev);
+ ingenic_early_console_setup_clock(dev, clkdiv);

if (dev->baud)
baud = dev->baud;
@@ -129,9 +130,31 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
return 0;
}

+static int __init ingenic_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+ return ingenic_earlycon_setup_common(dev, opt, 1);
+}
+
+static int __init jz4750_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+#define CGU_REG_CPCCR ((void *)CKSEG1ADDR(0x10000000))
+#define CPCCR_ECS BIT(30)
+ u32 cpccr = readl(CGU_REG_CPCCR);
+ int clk_div = (cpccr & CPCCR_ECS) ? 2 : 1;
+#undef CGU_REG_CPCCR
+#undef CPCCR_ECS
+
+ return ingenic_earlycon_setup_common(dev, opt, clk_div);
+}
+
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
ingenic_early_console_setup);

+OF_EARLYCON_DECLARE(jz4750_uart, "ingenic,jz4750-uart",
+ jz4750_early_console_setup);
+
OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
ingenic_early_console_setup);

@@ -311,6 +334,11 @@ static const struct ingenic_uart_config jz4740_uart_config = {
.fifosize = 16,
};

+static const struct ingenic_uart_config jz4750_uart_config = {
+ .tx_loadsz = 16,
+ .fifosize = 32,
+};
+
static const struct ingenic_uart_config jz4760_uart_config = {
.tx_loadsz = 16,
.fifosize = 32,
@@ -328,6 +356,7 @@ static const struct ingenic_uart_config x1000_uart_config = {

static const struct of_device_id of_match[] = {
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
+ { .compatible = "ingenic,jz4750-uart", .data = &jz4750_uart_config },
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
--
2.36.1