xref: /optee_os/core/drivers/imx_lpuart.c (revision 3639b55f101b2c3bba33740ec7bf5440b3125efc)
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
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 };
62*3639b55fSJerome Forissier DECLARE_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 }
74f1c2959fSClement Faure 
75f1c2959fSClement Faure #ifdef CFG_DT
76f1c2959fSClement Faure static struct serial_chip *imx_lpuart_dev_alloc(void)
77f1c2959fSClement Faure {
78f1c2959fSClement Faure 	struct imx_uart_data *pd = calloc(1, sizeof(*pd));
79f1c2959fSClement Faure 
80f1c2959fSClement Faure 	if (!pd)
81f1c2959fSClement Faure 		return NULL;
82f1c2959fSClement Faure 
83f1c2959fSClement Faure 	return &pd->chip;
84f1c2959fSClement Faure }
85f1c2959fSClement Faure 
86f1c2959fSClement Faure static int imx_lpuart_dev_init(struct serial_chip *chip, const void *fdt,
87f1c2959fSClement Faure 			       int offs, const char *parms)
88f1c2959fSClement Faure {
89f1c2959fSClement Faure 	struct imx_uart_data *pd =
90f1c2959fSClement Faure 		container_of(chip, struct imx_uart_data, chip);
91f1c2959fSClement Faure 	vaddr_t vbase = 0;
92f1c2959fSClement Faure 	paddr_t pbase = 0;
93f1c2959fSClement Faure 	size_t size = 0;
94f1c2959fSClement Faure 
95f1c2959fSClement Faure 	if (parms && parms[0])
96f1c2959fSClement Faure 		IMSG("imx_lpuart: device parameters ignored (%s)", parms);
97f1c2959fSClement Faure 
98f1c2959fSClement Faure 	if (dt_map_dev(fdt, offs, &vbase, &size) < 0)
99f1c2959fSClement Faure 		return -1;
100f1c2959fSClement Faure 
101f1c2959fSClement Faure 	pbase = virt_to_phys((void *)vbase);
102f1c2959fSClement Faure 	imx_uart_init(pd, pbase);
103f1c2959fSClement Faure 
104f1c2959fSClement Faure 	return 0;
105f1c2959fSClement Faure }
106f1c2959fSClement Faure 
107f1c2959fSClement Faure static void imx_lpuart_dev_free(struct serial_chip *chip)
108f1c2959fSClement Faure {
109f1c2959fSClement Faure 	struct imx_uart_data *pd =
110f1c2959fSClement Faure 		container_of(chip, struct imx_uart_data, chip);
111f1c2959fSClement Faure 
112f1c2959fSClement Faure 	free(pd);
113f1c2959fSClement Faure }
114f1c2959fSClement Faure 
115f1c2959fSClement Faure static const struct serial_driver imx_lpuart_driver = {
116f1c2959fSClement Faure 	.dev_alloc = imx_lpuart_dev_alloc,
117f1c2959fSClement Faure 	.dev_init = imx_lpuart_dev_init,
118f1c2959fSClement Faure 	.dev_free = imx_lpuart_dev_free,
119f1c2959fSClement Faure };
120f1c2959fSClement Faure 
121f1c2959fSClement Faure static const struct dt_device_match imx_match_table[] = {
122f1c2959fSClement Faure 	{ .compatible = "fsl,imx7ulp-lpuart" },
123f1c2959fSClement Faure 	{ .compatible = "fsl,imx8qm-lpuart" },
124f1c2959fSClement Faure 	{ 0 }
125f1c2959fSClement Faure };
126f1c2959fSClement Faure 
127f1c2959fSClement Faure const struct dt_driver imx_dt_driver __dt_driver = {
128f1c2959fSClement Faure 	.name = "imx_lpuart",
129f1c2959fSClement Faure 	.match_table = imx_match_table,
130f1c2959fSClement Faure 	.driver = &imx_lpuart_driver,
131f1c2959fSClement Faure };
132f1c2959fSClement Faure 
133f1c2959fSClement Faure #endif /* CFG_DT */
134