11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
28c4a5a9aSPeng Fan /*
38c4a5a9aSPeng Fan * Copyright (C) 2015 Freescale Semiconductor, Inc.
48c4a5a9aSPeng Fan * All rights reserved.
5f1c2959fSClement Faure * Copyright 2018-2019 NXP.
68c4a5a9aSPeng Fan *
78c4a5a9aSPeng Fan * Redistribution and use in source and binary forms, with or without
88c4a5a9aSPeng Fan * modification, are permitted provided that the following conditions are met:
98c4a5a9aSPeng Fan *
108c4a5a9aSPeng Fan * 1. Redistributions of source code must retain the above copyright notice,
118c4a5a9aSPeng Fan * this list of conditions and the following disclaimer.
128c4a5a9aSPeng Fan *
138c4a5a9aSPeng Fan * 2. Redistributions in binary form must reproduce the above copyright notice,
148c4a5a9aSPeng Fan * this list of conditions and the following disclaimer in the documentation
158c4a5a9aSPeng Fan * and/or other materials provided with the distribution.
168c4a5a9aSPeng Fan *
178c4a5a9aSPeng Fan * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
188c4a5a9aSPeng Fan * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
198c4a5a9aSPeng Fan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
208c4a5a9aSPeng Fan * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
218c4a5a9aSPeng Fan * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
228c4a5a9aSPeng Fan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
238c4a5a9aSPeng Fan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
248c4a5a9aSPeng Fan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
258c4a5a9aSPeng Fan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
268c4a5a9aSPeng Fan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
278c4a5a9aSPeng Fan * POSSIBILITY OF SUCH DAMAGE.
288c4a5a9aSPeng Fan */
298c4a5a9aSPeng Fan
3026267e82SJerome Forissier #include <assert.h>
318c4a5a9aSPeng Fan #include <drivers/imx_uart.h>
328c4a5a9aSPeng Fan #include <io.h>
338d94060aSEtienne Carriere #include <keep.h>
34f1c2959fSClement Faure #include <kernel/dt.h>
35*9e3c57c8SEtienne Carriere #include <kernel/dt_driver.h>
3626267e82SJerome Forissier #include <util.h>
378c4a5a9aSPeng Fan
388c4a5a9aSPeng Fan /* Register definitions */
398c4a5a9aSPeng Fan #define URXD 0x0 /* Receiver Register */
408c4a5a9aSPeng Fan #define UTXD 0x40 /* Transmitter Register */
418c4a5a9aSPeng Fan #define UCR1 0x80 /* Control Register 1 */
428c4a5a9aSPeng Fan #define UCR2 0x84 /* Control Register 2 */
438c4a5a9aSPeng Fan #define UCR3 0x88 /* Control Register 3 */
448c4a5a9aSPeng Fan #define UCR4 0x8c /* Control Register 4 */
458c4a5a9aSPeng Fan #define UFCR 0x90 /* FIFO Control Register */
468c4a5a9aSPeng Fan #define USR1 0x94 /* Status Register 1 */
478c4a5a9aSPeng Fan #define USR2 0x98 /* Status Register 2 */
488c4a5a9aSPeng Fan #define UESC 0x9c /* Escape Character Register */
498c4a5a9aSPeng Fan #define UTIM 0xa0 /* Escape Timer Register */
508c4a5a9aSPeng Fan #define UBIR 0xa4 /* BRM Incremental Register */
518c4a5a9aSPeng Fan #define UBMR 0xa8 /* BRM Modulator Register */
528c4a5a9aSPeng Fan #define UBRC 0xac /* Baud Rate Count Register */
538c4a5a9aSPeng Fan #define UTS 0xb4 /* UART Test Register (mx31) */
54c2e4eb43SAnton Rybakov #define USIZE 0xb8 /* UTS + sizeof(uint32_t) */
558c4a5a9aSPeng Fan
568c4a5a9aSPeng Fan /* UART Control Register Bit Fields.*/
578c4a5a9aSPeng Fan #define URXD_CHARRDY (1<<15)
588c4a5a9aSPeng Fan #define URXD_ERR (1<<14)
598c4a5a9aSPeng Fan #define URXD_OVRRUN (1<<13)
608c4a5a9aSPeng Fan #define URXD_FRMERR (1<<12)
618c4a5a9aSPeng Fan #define URXD_BRK (1<<11)
628c4a5a9aSPeng Fan #define URXD_PRERR (1<<10)
638c4a5a9aSPeng Fan #define URXD_RX_DATA (0xFF)
648c4a5a9aSPeng Fan #define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
658c4a5a9aSPeng Fan #define UCR1_ADBR (1<<14) /* Auto detect baud rate */
668c4a5a9aSPeng Fan #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
678c4a5a9aSPeng Fan #define UCR1_IDEN (1<<12) /* Idle condition interrupt */
688c4a5a9aSPeng Fan #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
698c4a5a9aSPeng Fan #define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
708c4a5a9aSPeng Fan #define UCR1_IREN (1<<7) /* Infrared interface enable */
718c4a5a9aSPeng Fan #define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
728c4a5a9aSPeng Fan #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
738c4a5a9aSPeng Fan #define UCR1_SNDBRK (1<<4) /* Send break */
748c4a5a9aSPeng Fan #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
758c4a5a9aSPeng Fan #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
768c4a5a9aSPeng Fan #define UCR1_DOZE (1<<1) /* Doze */
778c4a5a9aSPeng Fan #define UCR1_UARTEN (1<<0) /* UART enabled */
788c4a5a9aSPeng Fan
798c4a5a9aSPeng Fan #define UTS_FRCPERR (1<<13) /* Force parity error */
808c4a5a9aSPeng Fan #define UTS_LOOP (1<<12) /* Loop tx and rx */
818c4a5a9aSPeng Fan #define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
828c4a5a9aSPeng Fan #define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
838c4a5a9aSPeng Fan #define UTS_TXFULL (1<<4) /* TxFIFO full */
848c4a5a9aSPeng Fan #define UTS_RXFULL (1<<3) /* RxFIFO full */
858c4a5a9aSPeng Fan #define UTS_SOFTRST (1<<0) /* Software reset */
868c4a5a9aSPeng Fan
chip_to_base(struct serial_chip * chip)8726267e82SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip)
888c4a5a9aSPeng Fan {
8926267e82SJerome Forissier struct imx_uart_data *pd =
9026267e82SJerome Forissier container_of(chip, struct imx_uart_data, chip);
9126267e82SJerome Forissier
92c2e4eb43SAnton Rybakov return io_pa_or_va(&pd->base, USIZE);
938c4a5a9aSPeng Fan }
948c4a5a9aSPeng Fan
imx_uart_flush(struct serial_chip * chip)9526267e82SJerome Forissier static void imx_uart_flush(struct serial_chip *chip)
968c4a5a9aSPeng Fan {
9726267e82SJerome Forissier vaddr_t base = chip_to_base(chip);
9826267e82SJerome Forissier
9921145fe5SJordan Rhee
100918bb3a5SEtienne Carriere while (!(io_read32(base + UTS) & UTS_TXEMPTY))
101918bb3a5SEtienne Carriere if (!(io_read32(base + UCR1) & UCR1_UARTEN))
10221145fe5SJordan Rhee return;
1038c4a5a9aSPeng Fan }
1048c4a5a9aSPeng Fan
imx_uart_getchar(struct serial_chip * chip)10526267e82SJerome Forissier static int imx_uart_getchar(struct serial_chip *chip)
1068c4a5a9aSPeng Fan {
10726267e82SJerome Forissier vaddr_t base = chip_to_base(chip);
10826267e82SJerome Forissier
109918bb3a5SEtienne Carriere while (io_read32(base + UTS) & UTS_RXEMPTY)
1108c4a5a9aSPeng Fan ;
1118c4a5a9aSPeng Fan
112918bb3a5SEtienne Carriere return (io_read32(base + URXD) & URXD_RX_DATA);
1138c4a5a9aSPeng Fan }
1148c4a5a9aSPeng Fan
imx_uart_putc(struct serial_chip * chip,int ch)11526267e82SJerome Forissier static void imx_uart_putc(struct serial_chip *chip, int ch)
1168c4a5a9aSPeng Fan {
11726267e82SJerome Forissier vaddr_t base = chip_to_base(chip);
1188c4a5a9aSPeng Fan
1194c85b2cfSJordan Rhee /* Wait until there's space in the TX FIFO */
120918bb3a5SEtienne Carriere while (io_read32(base + UTS) & UTS_TXFULL)
121918bb3a5SEtienne Carriere if (!(io_read32(base + UCR1) & UCR1_UARTEN))
12221145fe5SJordan Rhee return;
1234c85b2cfSJordan Rhee
124918bb3a5SEtienne Carriere io_write32(base + UTXD, ch);
1258c4a5a9aSPeng Fan }
12626267e82SJerome Forissier
12726267e82SJerome Forissier static const struct serial_ops imx_uart_ops = {
12826267e82SJerome Forissier .flush = imx_uart_flush,
12926267e82SJerome Forissier .getchar = imx_uart_getchar,
13026267e82SJerome Forissier .putc = imx_uart_putc,
13126267e82SJerome Forissier };
1323639b55fSJerome Forissier DECLARE_KEEP_PAGER(imx_uart_ops);
13326267e82SJerome Forissier
imx_uart_init(struct imx_uart_data * pd,paddr_t base)13426267e82SJerome Forissier void imx_uart_init(struct imx_uart_data *pd, paddr_t base)
13526267e82SJerome Forissier {
13626267e82SJerome Forissier pd->base.pa = base;
13726267e82SJerome Forissier pd->chip.ops = &imx_uart_ops;
13826267e82SJerome Forissier
13926267e82SJerome Forissier /*
14026267e82SJerome Forissier * Do nothing, debug uart(uart0) share with normal world,
14126267e82SJerome Forissier * everything for uart0 initialization is done in bootloader.
14226267e82SJerome Forissier */
14326267e82SJerome Forissier }
144f1c2959fSClement Faure
145f1c2959fSClement Faure #ifdef CFG_DT
imx_uart_dev_alloc(void)146f1c2959fSClement Faure static struct serial_chip *imx_uart_dev_alloc(void)
147f1c2959fSClement Faure {
148f1c2959fSClement Faure struct imx_uart_data *pd = calloc(1, sizeof(*pd));
149f1c2959fSClement Faure
150f1c2959fSClement Faure if (!pd)
151f1c2959fSClement Faure return NULL;
152f1c2959fSClement Faure
153f1c2959fSClement Faure return &pd->chip;
154f1c2959fSClement Faure }
155f1c2959fSClement Faure
imx_uart_dev_init(struct serial_chip * chip,const void * fdt,int offs,const char * parms)156f1c2959fSClement Faure static int imx_uart_dev_init(struct serial_chip *chip, const void *fdt,
157f1c2959fSClement Faure int offs, const char *parms)
158f1c2959fSClement Faure {
159f1c2959fSClement Faure struct imx_uart_data *pd =
160f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip);
161f1c2959fSClement Faure vaddr_t vbase = 0;
162f1c2959fSClement Faure paddr_t pbase = 0;
163f1c2959fSClement Faure size_t size = 0;
164f1c2959fSClement Faure
165f1c2959fSClement Faure if (parms && parms[0])
166f1c2959fSClement Faure IMSG("imx_uart: device parameters ignored (%s)", parms);
167f1c2959fSClement Faure
168a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, offs, &vbase, &size, DT_MAP_AUTO) < 0)
169f1c2959fSClement Faure return -1;
170f1c2959fSClement Faure
171f1c2959fSClement Faure pbase = virt_to_phys((void *)vbase);
172f1c2959fSClement Faure imx_uart_init(pd, pbase);
173f1c2959fSClement Faure
174f1c2959fSClement Faure return 0;
175f1c2959fSClement Faure }
176f1c2959fSClement Faure
imx_uart_dev_free(struct serial_chip * chip)177f1c2959fSClement Faure static void imx_uart_dev_free(struct serial_chip *chip)
178f1c2959fSClement Faure {
179f1c2959fSClement Faure struct imx_uart_data *pd =
180f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip);
181f1c2959fSClement Faure
182f1c2959fSClement Faure free(pd);
183f1c2959fSClement Faure }
184f1c2959fSClement Faure
185f1c2959fSClement Faure static const struct serial_driver imx_uart_driver = {
186f1c2959fSClement Faure .dev_alloc = imx_uart_dev_alloc,
187f1c2959fSClement Faure .dev_init = imx_uart_dev_init,
188f1c2959fSClement Faure .dev_free = imx_uart_dev_free,
189f1c2959fSClement Faure };
190f1c2959fSClement Faure
191f1c2959fSClement Faure static const struct dt_device_match imx_match_table[] = {
192f1c2959fSClement Faure { .compatible = "fsl,imx6q-uart" },
193f1c2959fSClement Faure { 0 }
194f1c2959fSClement Faure };
195f1c2959fSClement Faure
19661bdedeaSJerome Forissier DEFINE_DT_DRIVER(imx_dt_driver) = {
197f1c2959fSClement Faure .name = "imx_uart",
1985e588771SClément Léger .type = DT_DRIVER_UART,
199f1c2959fSClement Faure .match_table = imx_match_table,
200f1c2959fSClement Faure .driver = &imx_uart_driver,
201f1c2959fSClement Faure };
202f1c2959fSClement Faure
203f1c2959fSClement Faure #endif /* CFG_DT */
204