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

Reply via email to