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