11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 28c4a5a9aSPeng Fan /* 38c4a5a9aSPeng Fan * Copyright (C) 2015 Freescale Semiconductor, Inc. 48c4a5a9aSPeng Fan * All rights reserved. 5*f1c2959fSClement 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> 34*f1c2959fSClement Faure #include <kernel/dt.h> 3526267e82SJerome Forissier #include <util.h> 368c4a5a9aSPeng Fan 378c4a5a9aSPeng Fan /* Register definitions */ 388c4a5a9aSPeng Fan #define URXD 0x0 /* Receiver Register */ 398c4a5a9aSPeng Fan #define UTXD 0x40 /* Transmitter Register */ 408c4a5a9aSPeng Fan #define UCR1 0x80 /* Control Register 1 */ 418c4a5a9aSPeng Fan #define UCR2 0x84 /* Control Register 2 */ 428c4a5a9aSPeng Fan #define UCR3 0x88 /* Control Register 3 */ 438c4a5a9aSPeng Fan #define UCR4 0x8c /* Control Register 4 */ 448c4a5a9aSPeng Fan #define UFCR 0x90 /* FIFO Control Register */ 458c4a5a9aSPeng Fan #define USR1 0x94 /* Status Register 1 */ 468c4a5a9aSPeng Fan #define USR2 0x98 /* Status Register 2 */ 478c4a5a9aSPeng Fan #define UESC 0x9c /* Escape Character Register */ 488c4a5a9aSPeng Fan #define UTIM 0xa0 /* Escape Timer Register */ 498c4a5a9aSPeng Fan #define UBIR 0xa4 /* BRM Incremental Register */ 508c4a5a9aSPeng Fan #define UBMR 0xa8 /* BRM Modulator Register */ 518c4a5a9aSPeng Fan #define UBRC 0xac /* Baud Rate Count Register */ 528c4a5a9aSPeng Fan #define UTS 0xb4 /* UART Test Register (mx31) */ 538c4a5a9aSPeng Fan 548c4a5a9aSPeng Fan /* UART Control Register Bit Fields.*/ 558c4a5a9aSPeng Fan #define URXD_CHARRDY (1<<15) 568c4a5a9aSPeng Fan #define URXD_ERR (1<<14) 578c4a5a9aSPeng Fan #define URXD_OVRRUN (1<<13) 588c4a5a9aSPeng Fan #define URXD_FRMERR (1<<12) 598c4a5a9aSPeng Fan #define URXD_BRK (1<<11) 608c4a5a9aSPeng Fan #define URXD_PRERR (1<<10) 618c4a5a9aSPeng Fan #define URXD_RX_DATA (0xFF) 628c4a5a9aSPeng Fan #define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ 638c4a5a9aSPeng Fan #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ 648c4a5a9aSPeng Fan #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ 658c4a5a9aSPeng Fan #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ 668c4a5a9aSPeng Fan #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ 678c4a5a9aSPeng Fan #define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ 688c4a5a9aSPeng Fan #define UCR1_IREN (1<<7) /* Infrared interface enable */ 698c4a5a9aSPeng Fan #define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ 708c4a5a9aSPeng Fan #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ 718c4a5a9aSPeng Fan #define UCR1_SNDBRK (1<<4) /* Send break */ 728c4a5a9aSPeng Fan #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ 738c4a5a9aSPeng Fan #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ 748c4a5a9aSPeng Fan #define UCR1_DOZE (1<<1) /* Doze */ 758c4a5a9aSPeng Fan #define UCR1_UARTEN (1<<0) /* UART enabled */ 768c4a5a9aSPeng Fan 778c4a5a9aSPeng Fan #define UTS_FRCPERR (1<<13) /* Force parity error */ 788c4a5a9aSPeng Fan #define UTS_LOOP (1<<12) /* Loop tx and rx */ 798c4a5a9aSPeng Fan #define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ 808c4a5a9aSPeng Fan #define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ 818c4a5a9aSPeng Fan #define UTS_TXFULL (1<<4) /* TxFIFO full */ 828c4a5a9aSPeng Fan #define UTS_RXFULL (1<<3) /* RxFIFO full */ 838c4a5a9aSPeng Fan #define UTS_SOFTRST (1<<0) /* Software reset */ 848c4a5a9aSPeng Fan 8526267e82SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip) 868c4a5a9aSPeng Fan { 8726267e82SJerome Forissier struct imx_uart_data *pd = 8826267e82SJerome Forissier container_of(chip, struct imx_uart_data, chip); 8926267e82SJerome Forissier 9026267e82SJerome Forissier return io_pa_or_va(&pd->base); 918c4a5a9aSPeng Fan } 928c4a5a9aSPeng Fan 9326267e82SJerome Forissier static void imx_uart_flush(struct serial_chip *chip) 948c4a5a9aSPeng Fan { 9526267e82SJerome Forissier vaddr_t base = chip_to_base(chip); 9626267e82SJerome Forissier 9721145fe5SJordan Rhee 98918bb3a5SEtienne Carriere while (!(io_read32(base + UTS) & UTS_TXEMPTY)) 99918bb3a5SEtienne Carriere if (!(io_read32(base + UCR1) & UCR1_UARTEN)) 10021145fe5SJordan Rhee return; 1018c4a5a9aSPeng Fan } 1028c4a5a9aSPeng Fan 10326267e82SJerome Forissier static int imx_uart_getchar(struct serial_chip *chip) 1048c4a5a9aSPeng Fan { 10526267e82SJerome Forissier vaddr_t base = chip_to_base(chip); 10626267e82SJerome Forissier 107918bb3a5SEtienne Carriere while (io_read32(base + UTS) & UTS_RXEMPTY) 1088c4a5a9aSPeng Fan ; 1098c4a5a9aSPeng Fan 110918bb3a5SEtienne Carriere return (io_read32(base + URXD) & URXD_RX_DATA); 1118c4a5a9aSPeng Fan } 1128c4a5a9aSPeng Fan 11326267e82SJerome Forissier static void imx_uart_putc(struct serial_chip *chip, int ch) 1148c4a5a9aSPeng Fan { 11526267e82SJerome Forissier vaddr_t base = chip_to_base(chip); 1168c4a5a9aSPeng Fan 1174c85b2cfSJordan Rhee /* Wait until there's space in the TX FIFO */ 118918bb3a5SEtienne Carriere while (io_read32(base + UTS) & UTS_TXFULL) 119918bb3a5SEtienne Carriere if (!(io_read32(base + UCR1) & UCR1_UARTEN)) 12021145fe5SJordan Rhee return; 1214c85b2cfSJordan Rhee 122918bb3a5SEtienne Carriere io_write32(base + UTXD, ch); 1238c4a5a9aSPeng Fan } 12426267e82SJerome Forissier 12526267e82SJerome Forissier static const struct serial_ops imx_uart_ops = { 12626267e82SJerome Forissier .flush = imx_uart_flush, 12726267e82SJerome Forissier .getchar = imx_uart_getchar, 12826267e82SJerome Forissier .putc = imx_uart_putc, 12926267e82SJerome Forissier }; 1308d94060aSEtienne Carriere KEEP_PAGER(imx_uart_ops); 13126267e82SJerome Forissier 13226267e82SJerome Forissier void imx_uart_init(struct imx_uart_data *pd, paddr_t base) 13326267e82SJerome Forissier { 13426267e82SJerome Forissier pd->base.pa = base; 13526267e82SJerome Forissier pd->chip.ops = &imx_uart_ops; 13626267e82SJerome Forissier 13726267e82SJerome Forissier /* 13826267e82SJerome Forissier * Do nothing, debug uart(uart0) share with normal world, 13926267e82SJerome Forissier * everything for uart0 initialization is done in bootloader. 14026267e82SJerome Forissier */ 14126267e82SJerome Forissier } 142*f1c2959fSClement Faure 143*f1c2959fSClement Faure #ifdef CFG_DT 144*f1c2959fSClement Faure static struct serial_chip *imx_uart_dev_alloc(void) 145*f1c2959fSClement Faure { 146*f1c2959fSClement Faure struct imx_uart_data *pd = calloc(1, sizeof(*pd)); 147*f1c2959fSClement Faure 148*f1c2959fSClement Faure if (!pd) 149*f1c2959fSClement Faure return NULL; 150*f1c2959fSClement Faure 151*f1c2959fSClement Faure return &pd->chip; 152*f1c2959fSClement Faure } 153*f1c2959fSClement Faure 154*f1c2959fSClement Faure static int imx_uart_dev_init(struct serial_chip *chip, const void *fdt, 155*f1c2959fSClement Faure int offs, const char *parms) 156*f1c2959fSClement Faure { 157*f1c2959fSClement Faure struct imx_uart_data *pd = 158*f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip); 159*f1c2959fSClement Faure vaddr_t vbase = 0; 160*f1c2959fSClement Faure paddr_t pbase = 0; 161*f1c2959fSClement Faure size_t size = 0; 162*f1c2959fSClement Faure 163*f1c2959fSClement Faure if (parms && parms[0]) 164*f1c2959fSClement Faure IMSG("imx_uart: device parameters ignored (%s)", parms); 165*f1c2959fSClement Faure 166*f1c2959fSClement Faure if (dt_map_dev(fdt, offs, &vbase, &size) < 0) 167*f1c2959fSClement Faure return -1; 168*f1c2959fSClement Faure 169*f1c2959fSClement Faure pbase = virt_to_phys((void *)vbase); 170*f1c2959fSClement Faure imx_uart_init(pd, pbase); 171*f1c2959fSClement Faure 172*f1c2959fSClement Faure return 0; 173*f1c2959fSClement Faure } 174*f1c2959fSClement Faure 175*f1c2959fSClement Faure static void imx_uart_dev_free(struct serial_chip *chip) 176*f1c2959fSClement Faure { 177*f1c2959fSClement Faure struct imx_uart_data *pd = 178*f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip); 179*f1c2959fSClement Faure 180*f1c2959fSClement Faure free(pd); 181*f1c2959fSClement Faure } 182*f1c2959fSClement Faure 183*f1c2959fSClement Faure static const struct serial_driver imx_uart_driver = { 184*f1c2959fSClement Faure .dev_alloc = imx_uart_dev_alloc, 185*f1c2959fSClement Faure .dev_init = imx_uart_dev_init, 186*f1c2959fSClement Faure .dev_free = imx_uart_dev_free, 187*f1c2959fSClement Faure }; 188*f1c2959fSClement Faure 189*f1c2959fSClement Faure static const struct dt_device_match imx_match_table[] = { 190*f1c2959fSClement Faure { .compatible = "fsl,imx6q-uart" }, 191*f1c2959fSClement Faure { 0 } 192*f1c2959fSClement Faure }; 193*f1c2959fSClement Faure 194*f1c2959fSClement Faure const struct dt_driver imx_dt_driver __dt_driver = { 195*f1c2959fSClement Faure .name = "imx_uart", 196*f1c2959fSClement Faure .match_table = imx_match_table, 197*f1c2959fSClement Faure .driver = &imx_uart_driver, 198*f1c2959fSClement Faure }; 199*f1c2959fSClement Faure 200*f1c2959fSClement Faure #endif /* CFG_DT */ 201