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