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