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