xref: /optee_os/core/drivers/imx_lpuart.c (revision 039e02df2716a0ed886b56e1e07b7ac1d8597228)
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