From: Samuel Holland <[email protected]> D1 needs its DesignWare UART clocks enabled before register access. Select this behavior through the existing snps,dw-apb-uart compatible. Keep other UART variants unchanged. Allow fixed-clock devices without a clocks property. Propagate clock provider and enable errors.
Tested on MangoPi MQ Pro. Link: https://github.com/smaeul/u-boot/commit/0617377a2555031f02a459b3451fa33ce53e9b74 Suggested-by: Yao Zi <[email protected]> Signed-off-by: Samuel Holland <[email protected]> Co-developed-by: khaliforce <[email protected]> Signed-off-by: khaliforce <[email protected]> --- Changes in v2: - Select clock enabling through snps,dw-apb-uart match data. - Remove the proposed NS16550_CLK_ENABLE Kconfig option. - Preserve fixed-clock UARTs without a clocks property. - Propagate clock provider and enable errors. Validation: - U-Boot CI Docker builds pass: MQ Pro, RISC-V QEMU, x96q, MQ R, and AM335x EVM. - QEMU console tests pass: ns16550a and snps,dw-apb-uart without clocks. - MQ Pro UART input/output, clock gate, SD, GRUB, Linux, SSH, and repeated boots pass. - Other physical boards are not tested. drivers/serial/ns16550.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 10271f46aa6..c631d9628ea 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -492,6 +492,14 @@ static int ns16550_serial_assign_base(struct ns16550_plat *plat, return 0; } +#if CONFIG_IS_ENABLED(OF_CONTROL) +enum { + PORT_NS16550 = 0, + PORT_JZ4780, + PORT_DW_APB, +}; +#endif + int ns16550_serial_probe(struct udevice *dev) { struct ns16550_plat *plat = dev_get_plat(dev); @@ -516,19 +524,28 @@ int ns16550_serial_probe(struct udevice *dev) if (!ret) reset_deassert_bulk(&reset_bulk); +#if CONFIG_IS_ENABLED(OF_REAL) + if (CONFIG_IS_ENABLED(CLK) && + dev_get_driver_data(dev) == PORT_DW_APB) { + struct clk_bulk clk_bulk; + + ret = clk_get_bulk(dev, &clk_bulk); + if (!ret) { + ret = clk_enable_bulk(&clk_bulk); + if (ret) + return ret; + } else if (ret != -ENOENT && ret != -ENOSYS) { + return ret; + } + } +#endif + com_port->plat = dev_get_plat(dev); ns16550_init(com_port, -1); return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -enum { - PORT_NS16550 = 0, - PORT_JZ4780, -}; -#endif - #if CONFIG_IS_ENABLED(OF_REAL) int ns16550_serial_of_to_plat(struct udevice *dev) { @@ -598,7 +615,7 @@ static const struct udevice_id ns16550_serial_ids[] = { { .compatible = "ns16550a", .data = PORT_NS16550 }, { .compatible = "ingenic,jz4780-uart", .data = PORT_JZ4780 }, { .compatible = "nvidia,tegra20-uart", .data = PORT_NS16550 }, - { .compatible = "snps,dw-apb-uart", .data = PORT_NS16550 }, + { .compatible = "snps,dw-apb-uart", .data = PORT_DW_APB }, { .compatible = "intel,xscale-uart", .data = PORT_NS16550 }, {} }; -- 2.53.0
