xref: /optee_os/core/drivers/imx_lpuart.c (revision f1c2959f711761aab52aa24a3a34c7b7c4a057db)
1601976a5SPeng Fan // SPDX-License-Identifier: BSD-2-Clause
2601976a5SPeng Fan /*
3601976a5SPeng Fan  * Copyright 2017-2019 NXP
4601976a5SPeng Fan  */
5601976a5SPeng Fan 
6601976a5SPeng Fan #include <assert.h>
7601976a5SPeng Fan #include <drivers/imx_uart.h>
8601976a5SPeng Fan #include <io.h>
9601976a5SPeng Fan #include <keep.h>
10*f1c2959fSClement Faure #include <kernel/dt.h>
11601976a5SPeng Fan #include <util.h>
12601976a5SPeng Fan 
13601976a5SPeng Fan #define STAT		0x14
14601976a5SPeng Fan #define DATA		0x1C
15601976a5SPeng Fan #define STAT_TDRE	BIT(23)
16601976a5SPeng Fan #define STAT_RDRF	BIT(21)
17601976a5SPeng Fan #define STAT_OR		BIT(19)
18601976a5SPeng Fan 
19601976a5SPeng Fan static vaddr_t chip_to_base(struct serial_chip *chip)
20601976a5SPeng Fan {
21601976a5SPeng Fan 	struct imx_uart_data *pd =
22601976a5SPeng Fan 		container_of(chip, struct imx_uart_data, chip);
23601976a5SPeng Fan 
24601976a5SPeng Fan 	return io_pa_or_va(&pd->base);
25601976a5SPeng Fan }
26601976a5SPeng Fan 
27601976a5SPeng Fan static void imx_lpuart_flush(struct serial_chip *chip __unused)
28601976a5SPeng Fan {
29601976a5SPeng Fan }
30601976a5SPeng Fan 
31601976a5SPeng Fan static int imx_lpuart_getchar(struct serial_chip *chip)
32601976a5SPeng Fan {
33601976a5SPeng Fan 	int ch = 0;
34601976a5SPeng Fan 	vaddr_t base = chip_to_base(chip);
35601976a5SPeng Fan 
36601976a5SPeng Fan 	while (io_read32(base + STAT) & STAT_RDRF)
37601976a5SPeng Fan 		;
38601976a5SPeng Fan 
39601976a5SPeng Fan 	ch = io_read32(base + DATA) & 0x3ff;
40601976a5SPeng Fan 
41601976a5SPeng Fan 	if (io_read32(base + STAT) & STAT_OR)
42601976a5SPeng Fan 		io_write32(base + STAT, STAT_OR);
43601976a5SPeng Fan 
44601976a5SPeng Fan 	return ch;
45601976a5SPeng Fan }
46601976a5SPeng Fan 
47601976a5SPeng Fan static void imx_lpuart_putc(struct serial_chip *chip, int ch)
48601976a5SPeng Fan {
49601976a5SPeng Fan 	vaddr_t base = chip_to_base(chip);
50601976a5SPeng Fan 
51601976a5SPeng Fan 	while (!(io_read32(base + STAT) & STAT_TDRE))
52601976a5SPeng Fan 		;
53601976a5SPeng Fan 
54601976a5SPeng Fan 	io_write32(base + DATA, ch);
55601976a5SPeng Fan }
56601976a5SPeng Fan 
57601976a5SPeng Fan static const struct serial_ops imx_lpuart_ops = {
58601976a5SPeng Fan 	.flush = imx_lpuart_flush,
59601976a5SPeng Fan 	.getchar = imx_lpuart_getchar,
60601976a5SPeng Fan 	.putc = imx_lpuart_putc,
61601976a5SPeng Fan };
62601976a5SPeng Fan KEEP_PAGER(imx_lpuart_ops);
63601976a5SPeng Fan 
64601976a5SPeng Fan void imx_uart_init(struct imx_uart_data *pd, paddr_t base)
65601976a5SPeng Fan {
66601976a5SPeng Fan 	pd->base.pa = base;
67601976a5SPeng Fan 	pd->chip.ops = &imx_lpuart_ops;
68601976a5SPeng Fan 
69601976a5SPeng Fan 	/*
70601976a5SPeng Fan 	 * Do nothing, debug uart(sc lpuart) shared with normal world,
71601976a5SPeng Fan 	 * everything for uart initialization is done in bootloader.
72601976a5SPeng Fan 	 */
73601976a5SPeng Fan }
74*f1c2959fSClement Faure 
75*f1c2959fSClement Faure #ifdef CFG_DT
76*f1c2959fSClement Faure static struct serial_chip *imx_lpuart_dev_alloc(void)
77*f1c2959fSClement Faure {
78*f1c2959fSClement Faure 	struct imx_uart_data *pd = calloc(1, sizeof(*pd));
79*f1c2959fSClement Faure 
80*f1c2959fSClement Faure 	if (!pd)
81*f1c2959fSClement Faure 		return NULL;
82*f1c2959fSClement Faure 
83*f1c2959fSClement Faure 	return &pd->chip;
84*f1c2959fSClement Faure }
85*f1c2959fSClement Faure 
86*f1c2959fSClement Faure static int imx_lpuart_dev_init(struct serial_chip *chip, const void *fdt,
87*f1c2959fSClement Faure 			       int offs, const char *parms)
88*f1c2959fSClement Faure {
89*f1c2959fSClement Faure 	struct imx_uart_data *pd =
90*f1c2959fSClement Faure 		container_of(chip, struct imx_uart_data, chip);
91*f1c2959fSClement Faure 	vaddr_t vbase = 0;
92*f1c2959fSClement Faure 	paddr_t pbase = 0;
93*f1c2959fSClement Faure 	size_t size = 0;
94*f1c2959fSClement Faure 
95*f1c2959fSClement Faure 	if (parms && parms[0])
96*f1c2959fSClement Faure 		IMSG("imx_lpuart: device parameters ignored (%s)", parms);
97*f1c2959fSClement Faure 
98*f1c2959fSClement Faure 	if (dt_map_dev(fdt, offs, &vbase, &size) < 0)
99*f1c2959fSClement Faure 		return -1;
100*f1c2959fSClement Faure 
101*f1c2959fSClement Faure 	pbase = virt_to_phys((void *)vbase);
102*f1c2959fSClement Faure 	imx_uart_init(pd, pbase);
103*f1c2959fSClement Faure 
104*f1c2959fSClement Faure 	return 0;
105*f1c2959fSClement Faure }
106*f1c2959fSClement Faure 
107*f1c2959fSClement Faure static void imx_lpuart_dev_free(struct serial_chip *chip)
108*f1c2959fSClement Faure {
109*f1c2959fSClement Faure 	struct imx_uart_data *pd =
110*f1c2959fSClement Faure 		container_of(chip, struct imx_uart_data, chip);
111*f1c2959fSClement Faure 
112*f1c2959fSClement Faure 	free(pd);
113*f1c2959fSClement Faure }
114*f1c2959fSClement Faure 
115*f1c2959fSClement Faure static const struct serial_driver imx_lpuart_driver = {
116*f1c2959fSClement Faure 	.dev_alloc = imx_lpuart_dev_alloc,
117*f1c2959fSClement Faure 	.dev_init = imx_lpuart_dev_init,
118*f1c2959fSClement Faure 	.dev_free = imx_lpuart_dev_free,
119*f1c2959fSClement Faure };
120*f1c2959fSClement Faure 
121*f1c2959fSClement Faure static const struct dt_device_match imx_match_table[] = {
122*f1c2959fSClement Faure 	{ .compatible = "fsl,imx7ulp-lpuart" },
123*f1c2959fSClement Faure 	{ .compatible = "fsl,imx8qm-lpuart" },
124*f1c2959fSClement Faure 	{ 0 }
125*f1c2959fSClement Faure };
126*f1c2959fSClement Faure 
127*f1c2959fSClement Faure const struct dt_driver imx_dt_driver __dt_driver = {
128*f1c2959fSClement Faure 	.name = "imx_lpuart",
129*f1c2959fSClement Faure 	.match_table = imx_match_table,
130*f1c2959fSClement Faure 	.driver = &imx_lpuart_driver,
131*f1c2959fSClement Faure };
132*f1c2959fSClement Faure 
133*f1c2959fSClement Faure #endif /* CFG_DT */
134