diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index da5bd79fa53..c7357d076f1 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -4,7 +4,7 @@ /* * Copyright (c) 2010, 2012-2015 Wind River Systems, Inc. - * Copyright (c) 2020-2022 Intel Corp. + * Copyright (c) 2020-2023 Intel Corp. * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,9 @@ #endif #include +#include + +LOG_MODULE_REGISTER(uart_ns16550, CONFIG_UART_LOG_LEVEL); #define INST_HAS_PCP_HELPER(inst) DT_INST_NODE_HAS_PROP(inst, pcp) || #define INST_HAS_DLF_HELPER(inst) DT_INST_NODE_HAS_PROP(inst, dlf) || @@ -53,6 +56,13 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #include #endif +/* Is UART module 'resets' line property defined */ +#define UART_NS16550_RESET_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + +#if UART_NS16550_RESET_ENABLED +#include +#endif + /* register definitions */ #define REG_THR 0x00 /* Transmitter holding reg. */ @@ -247,6 +257,9 @@ struct uart_ns16550_device_config { #if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS) bool io_map; #endif +#if UART_NS16550_RESET_ENABLED + struct reset_dt_spec reset_spec; +#endif }; /** Device data structure */ @@ -580,6 +593,35 @@ static int uart_ns16550_config_get(const struct device *dev, } #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#if UART_NS16550_RESET_ENABLED +/** + * @brief Toggle the reset UART line + * + * This routine is called to bring UART IP out of reset state. + * + * @param reset_spec Reset controller device configuration struct + * + * @return 0 if successful, failed otherwise + */ +static int uart_reset_config(const struct reset_dt_spec *reset_spec) +{ + int ret; + + if (!device_is_ready(reset_spec->dev)) { + LOG_ERR("Reset controller device is not ready"); + return -ENODEV; + } + + ret = reset_line_toggle(reset_spec->dev, reset_spec->id); + if (ret != 0) { + LOG_ERR("UART toggle reset line failed"); + return ret; + } + + return 0; +} +#endif /* UART_NS16550_RESET_ENABLED */ + /** * @brief Initialize individual UART port * @@ -597,6 +639,16 @@ static int uart_ns16550_init(const struct device *dev) ARG_UNUSED(dev_cfg); +#if UART_NS16550_RESET_ENABLED + /* Assert the UART reset line if it is defined. */ + if (dev_cfg->reset_spec.dev != NULL) { + ret = uart_reset_config(&(dev_cfg->reset_spec)); + if (ret != 0) { + return ret; + } + } +#endif + #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) if (dev_cfg->pcie) { struct pcie_bar mbar; @@ -1285,6 +1337,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #else #define BOOT_LEVEL(n) PRE_KERNEL_1 #endif +#define UART_RESET_FUNC_INIT(n) \ + .reset_spec = RESET_DT_SPEC_INST_GET(n), #define UART_NS16550_DEVICE_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ @@ -1310,6 +1364,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { DEV_CONFIG_PCIE_INIT(n) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ (.pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)),)) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, resets), \ + (UART_RESET_FUNC_INIT(n))) \ }; \ static struct uart_ns16550_dev_data uart_ns16550_dev_data_##n = { \ .uart_config.baudrate = DT_INST_PROP_OR(n, current_speed, 0), \ diff --git a/dts/bindings/serial/ns16550.yaml b/dts/bindings/serial/ns16550.yaml index 04766ea117b..da315af4271 100644 --- a/dts/bindings/serial/ns16550.yaml +++ b/dts/bindings/serial/ns16550.yaml @@ -2,7 +2,7 @@ description: ns16550 UART compatible: "ns16550" -include: [uart-controller.yaml, pcie-device.yaml, pinctrl-device.yaml] +include: [uart-controller.yaml, pcie-device.yaml, pinctrl-device.yaml, reset-device.yaml] properties: reg-shift: