1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2017-2019 NXP 4 */ 5 6 #include <assert.h> 7 #include <drivers/imx_uart.h> 8 #include <io.h> 9 #include <keep.h> 10 #include <kernel/dt.h> 11 #include <util.h> 12 13 #define STAT 0x14 14 #define DATA 0x1C 15 #define STAT_TDRE BIT(23) 16 #define STAT_RDRF BIT(21) 17 #define STAT_OR BIT(19) 18 19 static vaddr_t chip_to_base(struct serial_chip *chip) 20 { 21 struct imx_uart_data *pd = 22 container_of(chip, struct imx_uart_data, chip); 23 24 return io_pa_or_va(&pd->base); 25 } 26 27 static void imx_lpuart_flush(struct serial_chip *chip __unused) 28 { 29 } 30 31 static int imx_lpuart_getchar(struct serial_chip *chip) 32 { 33 int ch = 0; 34 vaddr_t base = chip_to_base(chip); 35 36 while (io_read32(base + STAT) & STAT_RDRF) 37 ; 38 39 ch = io_read32(base + DATA) & 0x3ff; 40 41 if (io_read32(base + STAT) & STAT_OR) 42 io_write32(base + STAT, STAT_OR); 43 44 return ch; 45 } 46 47 static void imx_lpuart_putc(struct serial_chip *chip, int ch) 48 { 49 vaddr_t base = chip_to_base(chip); 50 51 while (!(io_read32(base + STAT) & STAT_TDRE)) 52 ; 53 54 io_write32(base + DATA, ch); 55 } 56 57 static const struct serial_ops imx_lpuart_ops = { 58 .flush = imx_lpuart_flush, 59 .getchar = imx_lpuart_getchar, 60 .putc = imx_lpuart_putc, 61 }; 62 KEEP_PAGER(imx_lpuart_ops); 63 64 void imx_uart_init(struct imx_uart_data *pd, paddr_t base) 65 { 66 pd->base.pa = base; 67 pd->chip.ops = &imx_lpuart_ops; 68 69 /* 70 * Do nothing, debug uart(sc lpuart) shared with normal world, 71 * everything for uart initialization is done in bootloader. 72 */ 73 } 74 75 #ifdef CFG_DT 76 static struct serial_chip *imx_lpuart_dev_alloc(void) 77 { 78 struct imx_uart_data *pd = calloc(1, sizeof(*pd)); 79 80 if (!pd) 81 return NULL; 82 83 return &pd->chip; 84 } 85 86 static int imx_lpuart_dev_init(struct serial_chip *chip, const void *fdt, 87 int offs, const char *parms) 88 { 89 struct imx_uart_data *pd = 90 container_of(chip, struct imx_uart_data, chip); 91 vaddr_t vbase = 0; 92 paddr_t pbase = 0; 93 size_t size = 0; 94 95 if (parms && parms[0]) 96 IMSG("imx_lpuart: device parameters ignored (%s)", parms); 97 98 if (dt_map_dev(fdt, offs, &vbase, &size) < 0) 99 return -1; 100 101 pbase = virt_to_phys((void *)vbase); 102 imx_uart_init(pd, pbase); 103 104 return 0; 105 } 106 107 static void imx_lpuart_dev_free(struct serial_chip *chip) 108 { 109 struct imx_uart_data *pd = 110 container_of(chip, struct imx_uart_data, chip); 111 112 free(pd); 113 } 114 115 static const struct serial_driver imx_lpuart_driver = { 116 .dev_alloc = imx_lpuart_dev_alloc, 117 .dev_init = imx_lpuart_dev_init, 118 .dev_free = imx_lpuart_dev_free, 119 }; 120 121 static const struct dt_device_match imx_match_table[] = { 122 { .compatible = "fsl,imx7ulp-lpuart" }, 123 { .compatible = "fsl,imx8qm-lpuart" }, 124 { 0 } 125 }; 126 127 const struct dt_driver imx_dt_driver __dt_driver = { 128 .name = "imx_lpuart", 129 .match_table = imx_match_table, 130 .driver = &imx_lpuart_driver, 131 }; 132 133 #endif /* CFG_DT */ 134