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