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