1601976a5SPeng Fan // SPDX-License-Identifier: BSD-2-Clause 2601976a5SPeng Fan /* 3601976a5SPeng Fan * Copyright 2017-2019 NXP 4601976a5SPeng Fan */ 5601976a5SPeng Fan 6601976a5SPeng Fan #include <assert.h> 7601976a5SPeng Fan #include <drivers/imx_uart.h> 8601976a5SPeng Fan #include <io.h> 9601976a5SPeng Fan #include <keep.h> 10f1c2959fSClement Faure #include <kernel/dt.h> 11601976a5SPeng Fan #include <util.h> 12601976a5SPeng Fan 13601976a5SPeng Fan #define STAT 0x14 14601976a5SPeng Fan #define DATA 0x1C 15*c2e4eb43SAnton Rybakov #define UART_SIZE 0x20 16601976a5SPeng Fan #define STAT_TDRE BIT(23) 17601976a5SPeng Fan #define STAT_RDRF BIT(21) 18601976a5SPeng Fan #define STAT_OR BIT(19) 19601976a5SPeng Fan 20601976a5SPeng Fan static vaddr_t chip_to_base(struct serial_chip *chip) 21601976a5SPeng Fan { 22601976a5SPeng Fan struct imx_uart_data *pd = 23601976a5SPeng Fan container_of(chip, struct imx_uart_data, chip); 24601976a5SPeng Fan 25*c2e4eb43SAnton Rybakov return io_pa_or_va(&pd->base, UART_SIZE); 26601976a5SPeng Fan } 27601976a5SPeng Fan 28601976a5SPeng Fan static void imx_lpuart_flush(struct serial_chip *chip __unused) 29601976a5SPeng Fan { 30601976a5SPeng Fan } 31601976a5SPeng Fan 32601976a5SPeng Fan static int imx_lpuart_getchar(struct serial_chip *chip) 33601976a5SPeng Fan { 34601976a5SPeng Fan int ch = 0; 35601976a5SPeng Fan vaddr_t base = chip_to_base(chip); 36601976a5SPeng Fan 37601976a5SPeng Fan while (io_read32(base + STAT) & STAT_RDRF) 38601976a5SPeng Fan ; 39601976a5SPeng Fan 40601976a5SPeng Fan ch = io_read32(base + DATA) & 0x3ff; 41601976a5SPeng Fan 42601976a5SPeng Fan if (io_read32(base + STAT) & STAT_OR) 43601976a5SPeng Fan io_write32(base + STAT, STAT_OR); 44601976a5SPeng Fan 45601976a5SPeng Fan return ch; 46601976a5SPeng Fan } 47601976a5SPeng Fan 48601976a5SPeng Fan static void imx_lpuart_putc(struct serial_chip *chip, int ch) 49601976a5SPeng Fan { 50601976a5SPeng Fan vaddr_t base = chip_to_base(chip); 51601976a5SPeng Fan 52601976a5SPeng Fan while (!(io_read32(base + STAT) & STAT_TDRE)) 53601976a5SPeng Fan ; 54601976a5SPeng Fan 55601976a5SPeng Fan io_write32(base + DATA, ch); 56601976a5SPeng Fan } 57601976a5SPeng Fan 58601976a5SPeng Fan static const struct serial_ops imx_lpuart_ops = { 59601976a5SPeng Fan .flush = imx_lpuart_flush, 60601976a5SPeng Fan .getchar = imx_lpuart_getchar, 61601976a5SPeng Fan .putc = imx_lpuart_putc, 62601976a5SPeng Fan }; 633639b55fSJerome Forissier DECLARE_KEEP_PAGER(imx_lpuart_ops); 64601976a5SPeng Fan 65601976a5SPeng Fan void imx_uart_init(struct imx_uart_data *pd, paddr_t base) 66601976a5SPeng Fan { 67601976a5SPeng Fan pd->base.pa = base; 68601976a5SPeng Fan pd->chip.ops = &imx_lpuart_ops; 69601976a5SPeng Fan 70601976a5SPeng Fan /* 71601976a5SPeng Fan * Do nothing, debug uart(sc lpuart) shared with normal world, 72601976a5SPeng Fan * everything for uart initialization is done in bootloader. 73601976a5SPeng Fan */ 74601976a5SPeng Fan } 75f1c2959fSClement Faure 76f1c2959fSClement Faure #ifdef CFG_DT 77f1c2959fSClement Faure static struct serial_chip *imx_lpuart_dev_alloc(void) 78f1c2959fSClement Faure { 79f1c2959fSClement Faure struct imx_uart_data *pd = calloc(1, sizeof(*pd)); 80f1c2959fSClement Faure 81f1c2959fSClement Faure if (!pd) 82f1c2959fSClement Faure return NULL; 83f1c2959fSClement Faure 84f1c2959fSClement Faure return &pd->chip; 85f1c2959fSClement Faure } 86f1c2959fSClement Faure 87f1c2959fSClement Faure static int imx_lpuart_dev_init(struct serial_chip *chip, const void *fdt, 88f1c2959fSClement Faure int offs, const char *parms) 89f1c2959fSClement Faure { 90f1c2959fSClement Faure struct imx_uart_data *pd = 91f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip); 92f1c2959fSClement Faure vaddr_t vbase = 0; 93f1c2959fSClement Faure paddr_t pbase = 0; 94f1c2959fSClement Faure size_t size = 0; 95f1c2959fSClement Faure 96f1c2959fSClement Faure if (parms && parms[0]) 97f1c2959fSClement Faure IMSG("imx_lpuart: device parameters ignored (%s)", parms); 98f1c2959fSClement Faure 99f1c2959fSClement Faure if (dt_map_dev(fdt, offs, &vbase, &size) < 0) 100f1c2959fSClement Faure return -1; 101f1c2959fSClement Faure 102f1c2959fSClement Faure pbase = virt_to_phys((void *)vbase); 103f1c2959fSClement Faure imx_uart_init(pd, pbase); 104f1c2959fSClement Faure 105f1c2959fSClement Faure return 0; 106f1c2959fSClement Faure } 107f1c2959fSClement Faure 108f1c2959fSClement Faure static void imx_lpuart_dev_free(struct serial_chip *chip) 109f1c2959fSClement Faure { 110f1c2959fSClement Faure struct imx_uart_data *pd = 111f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip); 112f1c2959fSClement Faure 113f1c2959fSClement Faure free(pd); 114f1c2959fSClement Faure } 115f1c2959fSClement Faure 116f1c2959fSClement Faure static const struct serial_driver imx_lpuart_driver = { 117f1c2959fSClement Faure .dev_alloc = imx_lpuart_dev_alloc, 118f1c2959fSClement Faure .dev_init = imx_lpuart_dev_init, 119f1c2959fSClement Faure .dev_free = imx_lpuart_dev_free, 120f1c2959fSClement Faure }; 121f1c2959fSClement Faure 122f1c2959fSClement Faure static const struct dt_device_match imx_match_table[] = { 123f1c2959fSClement Faure { .compatible = "fsl,imx7ulp-lpuart" }, 124f1c2959fSClement Faure { .compatible = "fsl,imx8qm-lpuart" }, 125f1c2959fSClement Faure { 0 } 126f1c2959fSClement Faure }; 127f1c2959fSClement Faure 128f1c2959fSClement Faure const struct dt_driver imx_dt_driver __dt_driver = { 129f1c2959fSClement Faure .name = "imx_lpuart", 130f1c2959fSClement Faure .match_table = imx_match_table, 131f1c2959fSClement Faure .driver = &imx_lpuart_driver, 132f1c2959fSClement Faure }; 133f1c2959fSClement Faure 134f1c2959fSClement Faure #endif /* CFG_DT */ 135