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