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